summaryrefslogtreecommitdiffstats
path: root/mobile/android/tests
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2019-04-23 15:32:23 -0400
committerMatt A. Tobin <email@mattatobin.com>2019-04-23 15:32:23 -0400
commitabe80cc31d5a40ebed743085011fbcda0c1a9a10 (patch)
treefb3762f06b84745b182af281abb107b95a9fcf01 /mobile/android/tests
parent63295d0087eb58a6eb34cad324c4c53d1b220491 (diff)
downloadUXP-abe80cc31d5a40ebed743085011fbcda0c1a9a10.tar
UXP-abe80cc31d5a40ebed743085011fbcda0c1a9a10.tar.gz
UXP-abe80cc31d5a40ebed743085011fbcda0c1a9a10.tar.lz
UXP-abe80cc31d5a40ebed743085011fbcda0c1a9a10.tar.xz
UXP-abe80cc31d5a40ebed743085011fbcda0c1a9a10.zip
Issue #1053 - Drop support Android and remove Fennec - Part 1a: Remove mobile/android
Diffstat (limited to 'mobile/android/tests')
-rw-r--r--mobile/android/tests/.eslintrc18
-rw-r--r--mobile/android/tests/background/junit3/AndroidManifest.xml.in23
-rw-r--r--mobile/android/tests/background/junit3/Makefile.in13
-rw-r--r--mobile/android/tests/background/junit3/background_junit3_sources.mozbuild78
-rw-r--r--mobile/android/tests/background/junit3/instrumentation.ini22
-rw-r--r--mobile/android/tests/background/junit3/moz.build42
-rw-r--r--mobile/android/tests/background/junit3/res/drawable-hdpi/icon.pngbin7639 -> 0 bytes
-rw-r--r--mobile/android/tests/background/junit3/res/drawable-ldpi/icon.pngbin2979 -> 0 bytes
-rw-r--r--mobile/android/tests/background/junit3/res/drawable-mdpi/icon.pngbin4625 -> 0 bytes
-rw-r--r--mobile/android/tests/background/junit3/res/layout/main.xml12
-rw-r--r--mobile/android/tests/background/junit3/res/values/strings.xml6
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestAndroidLogWriters.java68
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestUtils.java159
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestWaitHelper.java356
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/AndroidBrowserRepositoryTestCase.java818
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java636
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java450
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestBookmarks.java1063
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestClientsDatabase.java200
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java128
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java297
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java441
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestPasswordsRepository.java482
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestTopSites.java92
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/TestAccountLoader.java163
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/TestBrowserIDKeyPairGeneration.java49
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/authenticator/TestAccountPickler.java134
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/AndroidSyncTestCase.java52
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/DBHelpers.java84
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/DBProviderTestCase.java73
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/nativecode/test/TestNativeCrypto.java175
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/AndroidSyncTestCaseWithAccounts.java128
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestClientsStage.java95
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestResetting.java198
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestStoreTracking.java377
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java146
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestWebURLFinder.java49
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/BookmarkHelpers.java216
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultBeginDelegate.java33
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultCleanDelegate.java21
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultDelegate.java52
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultFetchDelegate.java106
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultFinishDelegate.java60
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultGuidsSinceDelegate.java19
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultSessionCreationDelegate.java53
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultStoreDelegate.java71
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginDelegate.java22
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginFailDelegate.java16
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFetchDelegate.java32
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFetchSinceDelegate.java47
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFinishDelegate.java17
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFinishFailDelegate.java15
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectGuidsSinceDelegate.java41
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidRequestFetchDelegate.java24
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidTypeStoreDelegate.java18
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectManyStoredDelegate.java48
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectNoGUIDsSinceDelegate.java33
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectNoStoreDelegate.java11
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectStoreCompletedDelegate.java17
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectStoredDelegate.java39
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/HistoryHelpers.java90
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/PasswordHelpers.java94
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java82
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessBeginDelegate.java20
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessCreationDelegate.java18
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFetchDelegate.java22
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFinishDelegate.java20
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessStoreDelegate.java20
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java69
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java40
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java52
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java13
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java66
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java76
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java57
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java63
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockRecord.java34
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java12
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java137
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WBORepository.java231
-rw-r--r--mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WaitHelper.java171
-rw-r--r--mobile/android/tests/background/junit4/resources/dlc_sync_deleted_item.json8
-rw-r--r--mobile/android/tests/background/junit4/resources/dlc_sync_old_format.json23
-rw-r--r--mobile/android/tests/background/junit4/resources/dlc_sync_single_font.json23
-rw-r--r--mobile/android/tests/background/junit4/resources/experiments.json99
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_atom_blogger.xml13
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_atom_feedburner.xml2
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_atom_planetmozilla.xml4996
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_atom_wikipedia.xml34
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_rss10_planetmozilla.xml3860
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_rss20_planetmozilla.xml3853
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_rss_heise.xml1965
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_rss_medium.xml100
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_rss_spon.xml314
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_rss_tumblr.xml95
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_rss_wikipedia.xml21
-rw-r--r--mobile/android/tests/background/junit4/resources/feed_rss_wordpress.xml84
-rw-r--r--mobile/android/tests/background/junit4/resources/robolectric.properties3
-rw-r--r--mobile/android/tests/background/junit4/src/com/keepsafe/switchboard/TestSwitchboard.java142
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestBackoff.java114
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestBrowserIDAuthHeaderProvider.java23
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestClientsEngineStage.java806
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java72
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java436
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestHeaderParsing.java29
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestLineByLineHandling.java115
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestMetaGlobal.java347
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestResource.java102
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestRetryAfter.java87
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestServer11Repository.java48
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestSyncStorageRequest.java269
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/SynchronizerHelpers.java282
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCollectionKeys.java197
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCommandProcessor.java117
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCryptoRecord.java302
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecord.java330
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecordsChannel.java229
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestResetCommands.java153
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestServer11RepositorySession.java231
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestServerLocalSynchronizer.java237
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSyncConfiguration.java39
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSynchronizer.java398
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSynchronizerSession.java306
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestUtils.java154
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/BaseTestStorageRequestDelegate.java61
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessDelegate.java35
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionBeginDelegate.java38
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionCreationDelegate.java36
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionFetchRecordsDelegate.java44
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionFinishDelegate.java37
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionStoreDelegate.java39
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositoryWipeDelegate.java36
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/HTTPServerTestHelper.java226
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockGlobalSessionCallback.java91
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockResourceDelegate.java85
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockServer.java73
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockSyncClientsEngineStage.java71
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockWBOServer.java28
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/test/TestHTTPServerTestHelper.java102
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/GeckoNetworkManagerTest.java51
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/GlobalPageMetadataTest.java174
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/TestGeckoProfile.java254
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/activitystream/TestActivityStream.java85
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/common/log/writers/test/TestLogWriters.java179
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/DelegatingTestContentProvider.java86
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/TestTabsProvider.java338
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/TestTabsProviderRemoteTabs.java244
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/fxa/test/TestFxAccountClient20.java41
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/fxa/test/TestFxAccountUtils.java131
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/test/EntityTestHelper.java34
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java72
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java40
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java51
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java13
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java66
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java76
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java57
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java60
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockRecord.java51
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java11
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java137
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/TestRunner.java125
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WBORepository.java230
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WaitHelper.java172
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestASNUtils.java45
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestDSACryptoImplementation.java60
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestJSONWebTokenUtils.java151
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestRSACryptoImplementation.java56
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/cleanup/TestFileCleanupController.java92
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/cleanup/TestFileCleanupService.java106
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserContractTest.java67
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHighlightsTest.java438
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryTest.java341
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTest.java338
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTestBase.java77
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderVisitsTest.java301
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/distribution/TestReferrerDescriptor.java33
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestDownloadAction.java607
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestStudyAction.java119
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestSyncAction.java276
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestVerifyAction.java123
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/catalog/TestDownloadContentBuilder.java69
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java262
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteBlogger.java74
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteMedium.java66
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteTumblr.java62
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/parser/TestSimpleFeedParser.java323
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/TestSkewHandler.java70
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/MockFxAccountClient.java226
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java205
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/TestStateFactory.java91
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/helpers/AssertUtil.java29
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/home/TestHomeConfigPrefsBackendMigration.java264
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconDescriptor.java56
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconDescriptorComparator.java152
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconRequest.java81
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconRequestBuilder.java159
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconResponse.java148
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconTask.java575
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconsHelper.java139
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestContentProviderLoader.java31
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestDataUriLoader.java46
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestDiskLoader.java94
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconDownloader.java112
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconGenerator.java128
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestJarLoader.java31
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestLegacyLoader.java152
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestMemoryLoader.java78
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestAboutPagesPreparer.java73
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestAddDefaultIconUrl.java79
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterKnownFailureUrls.java60
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterMimeTypes.java67
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterPrivilegedUrls.java86
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestLookupIconUrl.java101
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestColorProcessor.java59
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestDiskProcessor.java100
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestMemoryProcessor.java134
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestResizingProcessor.java111
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/permissions/TestPermissions.java253
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/TestPushManager.java238
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/TestPushState.java70
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/autopush/test/TestAutopushClient.java30
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/autopush/test/TestLiveAutopushClient.java171
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestBase32.java53
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java144
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestHKDF.java143
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java65
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestPBKDF2.java124
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestPersistedCrypto5Keys.java83
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestSRPConstants.java45
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/middleware/test/TestCrypto5MiddlewareRepositorySession.java291
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java165
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java145
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java181
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestUserAgentHeaders.java131
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/BrowserContractHelpersTest.java33
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/VisitsHelperTest.java144
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/test/TestBookmarksInsertionManager.java221
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/domain/TestClientRecord.java103
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/domain/test/TestFormHistoryRecord.java92
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/downloaders/BatchingDownloaderDelegateTest.java186
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/downloaders/BatchingDownloaderTest.java543
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/test/TestRepositorySessionBundle.java47
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/test/TestSafeConstrainedServer11Repository.java144
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/BatchMetaTest.java282
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/BatchingUploaderTest.java441
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/PayloadTest.java137
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/PayloadUploadDelegateTest.java404
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/RecordUploadRunnableTest.java38
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestEnsureCrypto5KeysStage.java237
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestFetchMetaGlobalStage.java391
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestStageLookup.java41
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java203
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestInfoCollections.java101
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestPersistedMetaGlobal.java105
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/measurements/TestSearchCountMeasurements.java161
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/measurements/TestSessionMeasurements.java124
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/pingbuilders/TestTelemetryPingBuilder.java84
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/schedulers/TestTelemetryUploadAllPingsImmediatelyScheduler.java59
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/stores/TestTelemetryJSONFilePingStore.java250
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/tokenserver/test/TestTokenServerClient.java335
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/NetworkUtilsTest.java185
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestContextUtils.java38
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestDateUtil.java89
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestFileUtils.java339
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestIntentUtils.java73
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestStringUtils.java122
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestUUIDUtil.java51
-rw-r--r--mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/publicsuffix/TestPublicSuffix.java62
-rw-r--r--mobile/android/tests/background/moz.build9
-rw-r--r--mobile/android/tests/browser/chrome/basic_article.html16
-rw-r--r--mobile/android/tests/browser/chrome/basic_article_mobile.html19
-rw-r--r--mobile/android/tests/browser/chrome/chrome.ini49
-rw-r--r--mobile/android/tests/browser/chrome/desktopmode_user_agent.sjs11
-rw-r--r--mobile/android/tests/browser/chrome/devicesearch.xml17
-rw-r--r--mobile/android/tests/browser/chrome/head.js72
-rw-r--r--mobile/android/tests/browser/chrome/head_search.js46
-rw-r--r--mobile/android/tests/browser/chrome/memory_page_1.html16
-rw-r--r--mobile/android/tests/browser/chrome/memory_page_2.html16
-rw-r--r--mobile/android/tests/browser/chrome/memory_page_3.html16
-rw-r--r--mobile/android/tests/browser/chrome/memory_page_4.html16
-rw-r--r--mobile/android/tests/browser/chrome/session_formdata_sample.html20
-rw-r--r--mobile/android/tests/browser/chrome/simpleservice.xml15
-rw-r--r--mobile/android/tests/browser/chrome/test_about_logins.html106
-rw-r--r--mobile/android/tests/browser/chrome/test_accounts.html48
-rw-r--r--mobile/android/tests/browser/chrome/test_android_log.html95
-rw-r--r--mobile/android/tests/browser/chrome/test_app_constants.html35
-rw-r--r--mobile/android/tests/browser/chrome/test_awsy_lite.html258
-rw-r--r--mobile/android/tests/browser/chrome/test_debugger_server.html53
-rw-r--r--mobile/android/tests/browser/chrome/test_desktop_useragent.html75
-rw-r--r--mobile/android/tests/browser/chrome/test_device_search_engine.html75
-rw-r--r--mobile/android/tests/browser/chrome/test_get_last_visited.html106
-rw-r--r--mobile/android/tests/browser/chrome/test_hidden_select_option.html103
-rw-r--r--mobile/android/tests/browser/chrome/test_home_provider.html165
-rw-r--r--mobile/android/tests/browser/chrome/test_identity_mode.html58
-rw-r--r--mobile/android/tests/browser/chrome/test_java_addons.html118
-rw-r--r--mobile/android/tests/browser/chrome/test_jni.html82
-rw-r--r--mobile/android/tests/browser/chrome/test_migrate_ui.html57
-rw-r--r--mobile/android/tests/browser/chrome/test_network_manager.html41
-rw-r--r--mobile/android/tests/browser/chrome/test_offline_page.html111
-rw-r--r--mobile/android/tests/browser/chrome/test_reader_view.html56
-rw-r--r--mobile/android/tests/browser/chrome/test_resource_substitutions.html72
-rw-r--r--mobile/android/tests/browser/chrome/test_restricted_profiles.html57
-rw-r--r--mobile/android/tests/browser/chrome/test_select_disabled.html86
-rw-r--r--mobile/android/tests/browser/chrome/test_selectoraddtab.html92
-rw-r--r--mobile/android/tests/browser/chrome/test_session_form_data.html274
-rw-r--r--mobile/android/tests/browser/chrome/test_session_scroll_position.html310
-rw-r--r--mobile/android/tests/browser/chrome/test_session_zombification.html185
-rw-r--r--mobile/android/tests/browser/chrome/test_shared_preferences.html255
-rw-r--r--mobile/android/tests/browser/chrome/test_simple_discovery.html86
-rw-r--r--mobile/android/tests/browser/chrome/test_video_discovery.html154
-rw-r--r--mobile/android/tests/browser/chrome/test_web_channel.html121
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/163.wrating.com/a.gif@a=&c=860010-0503010000bin43 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/163.wrating.com/a1.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/adgeo.163.com/ad_cookies0
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/analytics.163.com/ntes.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/jr@site=netease&affiliate=homepage&cat=homepage&type=adend&location=11
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/jr@site=netease&affiliate=homepage&cat=homepage&type=popup&location=11
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=banner360x65&location=1.html1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=banner360x65&location=2.html1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=1.html1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=2.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=3.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=5.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=6.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=1.html1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=2.html1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=3.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=4.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=5.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=6.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column600x80&location=1.html1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x100&location=1.html1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x100&location=2.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=1.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=2.html1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=3.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=4.html1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x300&location=1.html43
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x300&location=2.html1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=textlinkhouse&location=1.html15
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=textlinkhouse&location=2.html15
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel1/55x20_bai.gifbin1667 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel1/55x20_lan.gifbin1789 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel5/008976/bolon_110302.pngbin501 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel5/360/360100_110318.jpgbin10245 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/6/20110406182512d4541.jpgbin4979 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408075741e084c.jpgbin3946 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040808080199ae7.jpgbin4259 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080835397174e.jpgbin6215 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080847137e997.jpgbin5682 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408085323b9296.jpgbin5246 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408092834ed61d.jpgbin7343 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080930016f866.jpgbin3899 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080934433598e.jpgbin4137 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040809550649773.jpgbin6902 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408104255a47ce.jpgbin4358 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104081119113f37f.jpgbin5600 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040811445023471.jpgbin5544 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040814544385564.jpgbin4738 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040815090608fd9.jpgbin3513 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/9/20110409022720f974c.jpgbin5284 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/netease/wzdzbs.gifbin2664 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/digi/linzj/1102/03/191.jpgbin12682 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/img09/icon/icon.pngbin579 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/attr.pngbin930 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/icon_product_listv0.0.3.pngbin2616 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/iconv0.0.7.pngbin4028 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/neteasy_mallv0.0.1.pngbin911 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/theme_blue.pngbin1782 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/yodao_bg_blue.jpgbin9514 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/game/20110216/ql/x/390x100.jpgbin19460 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/game/20110216/ql/x/600x80.gifbin24228 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/hr/20110216/hz/360x100.jpgbin17913 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/03/ly/390x100.jpgbin19684 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/hy/190x100.jpgbin15226 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/wb/360x65.jpgbin17561 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/yd/190x180.jpgbin17036 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/7/20110407093718ef414.jpgbin2133 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/7/20110407202028db993.jpgbin5987 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104080728304dcb2.jpgbin3565 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408082635b6897.jpgbin4289 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104080828458908d.jpgbin5934 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040808393075049.jpgbin6499 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040809433960d68.jpgbin6093 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408100357df2b1.jpgbin4460 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408115631ad273.jpgbin5471 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408120203d0f08.jpgbin2217 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104081242198a4ba.jpgbin4224 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040812525484a8f.jpgbin3088 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408125931e0a79.jpgbin3858 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408140704d246b.jpgbin4978 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408144428d419d.jpgbin5797 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040814452013ef7.jpgbin2241 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040814525199c07.jpgbin3245 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104082245192ae96.jpgbin4952 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/www/v2011/css/theme_blue1227.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/www/v2011/img/tg_news.jpgbin17987 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/163homepage/biaoshi.gifbin1290 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/163homepage/bj110.gifbin2397 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/rpic/fld3/fld_homepage.js987
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/rpic/fld3/flsclasses.js30
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/techpro/shangpin/20110331/36-65.jpgbin10682 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/techpro/tuangou/20110218/170-80.jpgbin15209 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/yodaoimages/pack.r091221/scripts/autocomplete.163.165290.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/auto/2011/3/30/20110330215354a8c7a.jpgbin4872 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/7/201104071025387042e.jpgbin3085 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/7/20110407103153df111.jpgbin4546 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/8/20110408105903d5d53.jpgbin7608 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/8/20110408110145beb70.jpgbin6091 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/cnews/js/ntes_jslib_1.x.js14
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/edu/2011/4/6/20110406220601277f0.jpgbin3783 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/edu/2011/4/9/20110409001451f646c.jpgbin4987 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/ent/2011/4/8/20110408183341f6142.jpgbin5721 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/20110408091923ca1d8.jpgbin6027 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/20110408100456977e5.jpgbin4119 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/2011040810253254779.jpgbin5955 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/house/2011/4/7/201104070846149dec5.jpgbin3578 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/house/2011/4/8/20110408094024dfb90.gifbin11109 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/lady/2011/4/7/20110407235235eb565.jpgbin4436 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/lady/2011/4/8/20110408082553b8653.jpgbin4341 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/2/24/20110224214610e49c1.jpgbin2161 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/1/20110401105148c65f3.jpgbin4423 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/6/20110406140048c8dea.jpgbin1627 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/6/201104061402503e782.jpgbin3107 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/8/20110408175702d86a7.jpgbin3168 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/mobile/2011/4/8/201104080904537def0.jpgbin5446 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408164530e0dfd.jpgbin2390 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408224146ca253.jpgbin3646 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408234759dabf8.jpgbin4856 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/travel/2011/4/7/2011040719553034b7b.jpgbin6179 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/video/2011/4/8/20110408143144afad3.jpgbin6793 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/www/logo/logo_png.pngbin992 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/auto/2011/4/8/20110408091859b1da7.jpgbin4015 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/auto/2011/4/8/201104080930543aaa8.jpgbin3573 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/book/2011/4/8/20110408102221db369.jpgbin4521 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/digi/2011/4/8/20110408144717d8da9.jpgbin3677 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/20110408074407aed87.jpgbin3444 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/201104080804383b8a7.jpgbin3395 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/2011040809044637924.jpgbin5649 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/5/2011040502293054a8f.jpgbin4196 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/201104081007164a116.jpgbin4072 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/201104081009084803f.jpgbin6167 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/2011040811265683661.jpgbin4767 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/home/2011/4/7/20110407131936bb4ec.pngbin17647 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/house/2011/4/8/201104080927161a54f.jpgbin6032 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/7/2011040711484089cba.jpgbin4902 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/8/20110408014720d3fc0.jpgbin3338 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/8/20110408224817711dd.jpgbin4223 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/life/2011/3/7/20110307134125752e1.jpgbin1661 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/mobile/2011/4/8/2011040809135520264.jpgbin4486 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/photo/0008/2010-01-30/120x90_5U980MMS294H0008.JPGbin3639 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/sports/2011/4/8/20110408211535eae49.jpgbin5071 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/3/1/201103010846298829b.jpgbin3457 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/201104080929109dd6d.pngbin18442 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/20110408121505602ea.jpgbin5538 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/20110408183832fdfa0.pngbin11191 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/7/20110407105038a01d2.jpgbin4582 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/7/2011040715531564880.jpgbin4680 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/8/2011040809594909a0a.jpgbin5232 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/40YCPhfL6uaLg3xA4ISWew==/4227754150194064440.jpgbin25468 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/F4Oc-9fe_HYFRsSk0SRMmA==/4223532025543403580.jpgbin16689 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/VfPeCwJ6ufovjjY9ueyUxA==/4224939400426958880.jpgbin21972 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/chRhUK9Mxz9gdCzkEUzn5w==/4226346775310512150.jpgbin13490 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/nSvNUs-5vbkySqbYp-lnLw==/4226628250287222807.jpgbin26297 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/oimagea4.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2FPjU3gbin1940 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F2WEnFWbin1739 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F2x2iAObin2126 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F40hcYlbin1943 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/oimageb2.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F46NVMebin1902 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/oimageb3.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2FTyjFqbin1757 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/oimagec1.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F3SWBUhbin1512 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/oimagec7.ydstatic.com/image@w=128&h=128&url=http%3A%2F%2F126.fm%2F3cAjJDbin3307 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/img/mail1.gifbin576 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/img/mail2.gifbin574 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/ntes_mail_info_www_1222.js156
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/shownewmsg_www_1222.htm.html25
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/pro.163.com/js.ng/site=netease&affiliate=homepage&cat=homepage&type=flash&location=11
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/qn.163.com/images/qnyh20110411.jpgbin3411 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/show.mediav.com/s@type=1&db=mediav&pub=118_2620_36413&cus=0_0_0_0_0&wh=360x100&btype=1&js=1.html8
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/www.163.com/index.html4024
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/www.163.com/mediav.gif8
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/163.com/zjs.ipinyou.com/2011032517331513260_2342_190180.js1
-rw-r--r--mobile/android/tests/browser/chrome/tp5/README1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/baidu.com/c.baidu.com/c.gif@t=0&q=mozilla&p=0&pn=1.html0
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/baidu.com/open.baidu.com/stat/image/Icon_Aladdin.gifbin534 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/aladdin/img/table/bg.gifbin3241 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/arr.gifbin254 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/baidu_jgylogo1.gifbin708 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/i2.pngbin575 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/js/bdsug.js@v=1.0.3.01
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/s@wd=mozilla.html123
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/user/js/u.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/b.scorecardresearch.com/b2@c1=2&c2=6035051&c3=&c4=www.bbc.co.uk%2Fnews%2F&c5=&c6=&c15=&cv=1.3&cj=1.html0
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/bbc.112.2o7.net/b/ss/bbcwglobalprod/1/H.21--NS/0@AQB=1&pccr=true&AQE=1bin43 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/edge.quantserve.com/quant.js28
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/js.revsci.net/gateway/gw.js@csid=J087814
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbc.co.uk/js/app/av/emp/1_1_3_0_0_426652_426614_1/config.sjson@edition=us&site=news&section=%2FFrontpage195
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/css/screen/shared/19_58/3pt_ads.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/img/1_0_1/cream/hi/news/news-blocks.gifbin1657 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/app/bbccom/19_52/s_code.js1091
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/app/bbccom/19_61/bbccom.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/common/3_2/bbc_fmtj_common.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/config/apps/4_5/bbc_fmtj_config.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/core/3_2/bbc_fmtj.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/locationservices/locator/v4_0/locator.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/50112000/jpg/_50112416_010706746-1.jpgbin11114 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/50906000/jpg/_50906324_006353309-2.jpgbin3541 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/51990000/jpg/_51990536_011672235-1.jpgbin5558 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52015000/jpg/_52015349_flag_reuters_144.jpgbin6663 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52054000/jpg/_52054442_mj.144.jpgbin4326 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52057000/jpg/_52057539_arniecomp.jpgbin3448 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52058000/jpg/_52058296_holdring_thinks.jpgbin2444 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52058000/jpg/_52058744_jex_1012144_de27-1.jpgbin3705 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52063000/jpg/_52063276_52063272.jpgbin4166 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52064000/jpg/_52064940_94471941.jpgbin4893 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52065000/jpg/_52065323_aionscreenshot,ncsoft.jpgbin5113 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52068000/jpg/_52068942_jex_1012675_de09-1.jpgbin3628 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52069000/jpg/_52069270_011711396-1.jpgbin3051 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072075_52072074.jpgbin13528 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072121_-3.jpgbin2890 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072276_jex_1012855_de27-1.jpgbin3829 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52073000/jpg/_52073406_008253948-1.jpgbin6021 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52073000/jpg/_52073764_011717136-1.jpgbin2708 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52074000/jpg/_52074033_jex_1013006_de27.jpgbin4850 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52075000/jpg/_52075786_stewart_getty304.jpgbin4819 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52076000/jpg/_52076863_jex_1013152_de27-1.jpgbin5668 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077604_jex_1013246_de27-1.jpgbin4745 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077792_52077791.jpgbin4397 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077993_ivory_coast.jpgbin5486 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52078000/jpg/_52078134_astuteshoot.jpgbin5378 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52078000/jpg/_52078945_jex_1013338_de27-1.jpgbin5509 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52079000/jpg/_52079170_jex_1013354_de30-1.jpgbin6634 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/sol/shared/img/v4/commonwealth_games_2010/cg_bbccom_banner_sprite2.pngbin42881 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/components/components.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/accordian_overlay.pngbin2910 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/arrow_foldout.gifbin1056 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/arrow_foldout.pngbin351 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/england-map.pngbin3899 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/geo-digest-vertical-panel.gifbin126 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/languages-sprite.gifbin11937 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/livestats-sprite-ko.pngbin4729 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/livestats-sprite.gifbin4687 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/nav-divider.pngbin126 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/news_masthead.gifbin970 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/personalisation-help-icon.gifbin139 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/programmes-iplayer-brand.pngbin2240 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/red-masthead.pngbin37257 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/roadicon.gifbin185 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/scotland-map-hover.pngbin8445 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/scotland-map.png@v.2bin3600 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/sprite_most_watched.gifbin5093 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/sprite_most_watched_ko.pngbin3460 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/story_sprite.gifbin2181 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/subnav-divider.pngbin126 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/wales-map-hover.pngbin2248 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/wales-map.pngbin2599 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/world-map.pngbin10166 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/skin.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/global.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/GVL3-icons-test.pngbin15094 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/carousel-prev-next-3.pngbin1594 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/cbl.pngbin265 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/cbr.pngbin250 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/foldout-arrow.gifbin2284 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-grid-2.pngbin296 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-icons-0-2.gifbin10638 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-icons-0-2.pngbin16784 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-live-icon-inverted.gifbin186 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/icons/listen-charcoal.pngbin300 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/icons/play-charcoal.pngbin222 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/index-quote.pngbin345 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/live-icon-32.gifbin371 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-down.gifbin110 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-down.pngbin180 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-up.gifbin108 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-up.pngbin189 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/most_watched.pngbin1823 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/search.pngbin390 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/select-arrow.pngbin223 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-alert.gifbin1005 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-mail.gifbin256 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-mobile.gifbin123 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-podcast.gifbin210 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-rss.gifbin343 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/story_sprite.gifbin3595 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/story_sprite.pngbin1859 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/traffic_icon.gifbin295 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/transparencies/rgba-0-0-0-07.pngbin130 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/layout/index.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/mobile.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/print.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/type.css300
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/node1.bbcimg.co.uk/glow/gloader.0.1.4.js18
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/pixel.quantserve.com/pixel/p-ccrmZLtMqYB8w.gifbin35 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/pixel.quantserve.com/pixel/r.html0
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/sa.bbc.co.uk/bbc/bbc/s.gifbin43 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/sa.bbc.co.uk/bbc/bbc/s.htmlbin43 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.3.2/newnav/img/search_icon.pngbin287 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/autosuggest_loader.gifbin673 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/blocks/dark.pngbin1023 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/blocks/light.pngbin965 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/main_sprite.pngbin2063 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mast_bg.pngbin158 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mast_colours.pngbin666 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/more_arrow.pngbin3630 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mothball/bg.jpgbin336 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mothball/i.gifbin1278 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/nav_divider.pngbin130 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/panel.pngbin2257 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/search_icon.pngbin287 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/suggest_sprite.pngbin1200 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/suggest_sprite_rtl.pngbin1317 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/tooltip.pngbin1274 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/script/barlesque.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/style/main.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/requirejs/0.6.4/sharedmodules/require.js1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/wwtravel/img/ic/304-170/1300928948164652012_1.jpgbin14679 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/wwtravel/img/ic/304-170/130203147123329681316_1.jpgbin15764 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/arrow.gifbin190 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/header.gifbin3642 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/header_travel.gifbin3642 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/news/index.html2982
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/blst.msn.com/as/wea3/i/en-us/law/30.gifbin939 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/23/6B8E88315584A40B04E32D89551E.jpgbin7805 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/2F/9EFAECEC174B21FB83D10C82522D2.jpgbin3070 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/38/FAF3346E94CF4579ECAB641703868.jpgbin3178 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/5B/CC662FC6233C7449D9C7F9796801D.jpgbin13639 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/76/CAF5FAB7F245F96327F2B4C806D.jpgbin8252 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/80/82E2A652E4A790B140675E74293AD6.jpgbin4090 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/B7/EB75D45B8948F72EE451223E95A96.gifbin2477 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/CE/19F603C3122D48B6554BBD495195.jpgbin9665 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/CF/59B3CB34EF11B221719175143187.jpgbin3115 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/D8/41FF8CA0A47CC8208E684FA1BE6D6.jpgbin10214 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/E2/37BA92E210D341BFDBF4126422A3D2.gifbin657 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/EA/9BECE90994978BFAE6F38561515E8.jpgbin3964 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/FF/6B3EB94D554DA0488C66DC31482D48.jpgbin4099 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/gbl/lg/csl/favicon.icobin4286 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/css/1d/b0ebeba5ed4ca3c158e6d6059f5074.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/07/617475cf39bf6f5c0bd6ecb985335c.gifbin48 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/09/4ebdf19a1ce03cce12e11926256422.gifbin79 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/0c/c57bc2a7d38843d7c4aa8028fc9f82.gifbin1142 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/11/999518480e3c07301320f84f4bd855.pngbin384 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/16/9798fea395258497f598bba500bf83.pngbin2257 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/1a/57011fe37f98be0ee74ce87a62ba9b.pngbin13041 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/50/f63ed0301e8b02a8a42d8590a46291.gifbin1383 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/61/379589e51e05637f600f129f305b52.pngbin1616 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/61/def0ebad64d00fda0702cb7b8179ea.pngbin4670 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/62/b5797d19976f0955d6d5d5c87ec996.jpgbin12284 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/77/b23a82d78a0605243aad8f44e8c079.gifbin56 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/94/8b0fe9bcd1399077fdc9374e5f314d_1.pngbin12823 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/b9/ab98403e7de9ce52839e5de99d27e5.gifbin203 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/c6/7980776cb684844c20339b839ac35e.gifbin7210 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/d7/fb6441a4c45cb3a3b2f592d914a3cd.gifbin72 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/f8/614595fba50d96389708a4135776e4.gifbin43 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/fb/f017d9e8cc630c5e02659b6eaf35fa.gifbin2544 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/ff/290e7f0b12fa8a201581c74c1ae75a.gifbin74 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/icons/BING_websearch_2.jpgbin4082 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/icons/adchoices_gif.gifbin554 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/col.stj.s-msn.com/br/sc/js/jquery/jquery-1.4.2.min.js154
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/static.foxsports.com/content/fscom/img/2011/04/07/040711-Golf-Tiger-Woods-1120pm-PI_20110407142414593_116_175.JPGbin8415 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/udc.msn.com/c.gifbin42 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/www.bing.com/partner/primedns.gifbin43 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/msn.com/www.msn.com/index.html13
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/images/loader.gifbin759 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/images/twitter_logo_header.pngbin3079 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/javascripts/lib/jquery.tipsy.min.js@13021146483
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/javascripts/lib/mustache.js@1302114648403
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1129087853/151aec2f-1534-4f61-9f3e-1e787cb51a8b_mini.pngbin2006 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1139176116/5c42a320-1e91-4d89-a034-0f140d2f23ba_mini.pngbin1946 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1277610502/Untitled-9_mini.jpgbin2185 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/316019228/326994260_1117936370_0_mini.jpegbin544 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/81990615/nightexterior-1_mini.jpgbin1506 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/959692632/13659_1215732676789_1332990286_30703899_6344768_n_mini.jpgbin503 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/sticky/default_profile_images/default_profile_4_mini.pngbin543 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/favicon.icobin1150 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/icon_lock.gifbin226 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/reject_small.gifbin385 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/spinner.gifbin457 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/sprite-icons.pngbin20815 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/toggle_down_dark.pngbin258 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/javascripts/dismissable.js@13021146481
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/stylesheets/following.css@1302114648.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/1239180764/GlassblowerX_mini.jpgbin718 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/1248229613/redsugarskullnecklace4-pola_mini.jpgbin750 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/333032766/5600_106787006838_550741838_2009237_6385345_n_mini.jpgbin536 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/754757071/rawr_mini.jpgbin903 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/874705507/01_3_mini.jpgbin1068 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/959721336/16869_103046893051833_100000395672538_70559_3952672_n_1__mini.jpgbin582 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/ajax.gifbin1737 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arr-inline-form.gifbin68 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arr2.gifbin68 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arrow_right_dark.pngbin398 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/bg-btn-blue.pngbin380 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/bg-btn-signup_gold.pngbin346 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn-bg.gifbin593 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_green_arrow.gifbin1849 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_green_arrow_small.gifbin1563 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_red_small.gifbin1370 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-blue.gifbin635 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-chart.gifbin589 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-dark.gifbin612 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-green.gifbin600 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-mint.gifbin605 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-pink.gifbin609 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-red.gifbin592 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-yellow.gifbin947 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn.gifbin594 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/checkmark.gifbin64 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/close_small.pngbin246 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/commercial/garuda-overlay.gifbin162 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/dialog_arrows_sprite.gifbin232 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divider.pngbin189 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divot.gifbin49 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy-up.pngbin262 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy.gifbin99 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy.pngbin276 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/follow_check.gifbin156 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_chrome_help_banner_back.pngbin12138 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_creation_hint_arrow.gifbin114 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_firefox_help_banner_back.pngbin28756 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_ie_gtb_help_banner_back.pngbin18814 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon-mobile.gifbin66 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_add.pngbin3221 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_direct_reply.gifbin371 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_lock.gifbin226 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_remove.pngbin3255 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_reply.gifbin336 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_throbber.gifbin864 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_trash.gifbin148 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/inline-media.pngbin30404 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/larry-shadowed-big.pngbin3960 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/lock_icon_small.pngbin282 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/more.gifbin129 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/nav_search_submit.pngbin634 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/check.pngbin242 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_129px.pngbin6761 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_146px.pngbin7595 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_170px.pngbin8809 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_236px.pngbin13755 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/gradient-background.pngbin346 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/rays-box.jpgbin4641 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/t_170px.pngbin392 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/petal_spinner.gifbin3971 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/retweet/retweet-x.pngbin238 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/round-btn-hover.gifbin2470 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/round-btn.gifbin2470 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/rss.gifbin408 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/spinner.gifbin457 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/sprite-icons.pngbin20815 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/sprite-icons.png@v3bin20815 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tables/tablesorter-indicators.pngbin451 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/thumb-bird-bw.gifbin972 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-east.gifbin3224 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-north.gifbin3223 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-south.gifbin3222 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-west.gifbin3224 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_closed.gifbin70 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_dark.gifbin150 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_dark.pngbin258 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_light.gifbin154 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_light.pngbin277 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_opened.gifbin68 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_up_dark.gifbin150 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_up_dark.pngbin288 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toptweet-overlay.gifbin295 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/translator/translator.pngbin995 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/trendtip-pointer.gifbin63 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/verified/verified.pngbin737 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/verified/verified_small.pngbin401 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/warning-sign.pngbin4324 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/javascripts/geov1.js@13021146481
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/javascripts/twitter.js@13022155222435
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/phoenix/img/sprite-icons.pngbin20815 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/stylesheets/geo.css@1302114648.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/stylesheets/twitter.css@1302114648.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_background_images/30261844/ICHCTwitterBG.jpgbin172378 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1063331761/LOLmart_150_mini.jpgbin967 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1124077786/batvatar_mini.pngbin4250 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1155395599/Memebase_small_mini.pngbin7866 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1289641028/CH_mini.jpgbin5381 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1296459376/profile_image_1301694822477_mini.jpgbin550 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/700174615/twitter_mini.pngbin845 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/724048626/Picture_3895-1_mini.jpgbin1338 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/959827428/25000_1397284054938_1317351118_31101620_485629_n_mini.jpgbin1437 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/959952929/ci_300x300_mini.jpgbin359 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_1_mini.pngbin619 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_2_mini.pngbin712 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_6_mini.pngbin706 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/arrow_right_dark.pngbin398 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/buttons/bg-btn.gifbin594 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/check.pngbin242 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_129px.pngbin6761 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_146px.pngbin7595 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_170px.pngbin8809 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_236px.pngbin13755 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/gradient-background.pngbin346 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/rays-box.jpgbin4641 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/t_170px.pngbin392 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/sprite-icons.pngbin20815 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/javascripts/api.js@13021146481
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/javascripts/lib/gears_init.js@130211464887
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/stylesheets/buttons_new.css@1302114648.css1
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1092057020/eli_avatar_mini.pngbin1441 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1096286685/newpink_copy_mini.jpgbin942 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1110864280/41628_1144937489_2484_q_mini.jpgbin890 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1213876440/27539_32561485399_2579_n_bigger.jpegbin5378 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1260578495/191281_1758367531945_1621722394_1723810_2598069_o_mini.jpgbin3734 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1299269362/10839_196974151498_693676498_3960874_1853030_n_mini.jpgbin4384 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1302143328/Profile_copy_mini.jpgbin24379 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/sticky/default_profile_images/default_profile_3_mini.pngbin626 -> 0 bytes
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js19
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/twitter.com/ICHCheezburger.html1203
-rwxr-xr-xmobile/android/tests/browser/chrome/tp5/twitter.com/www.google.com/jsapi39
-rw-r--r--mobile/android/tests/browser/chrome/video_controls.html10
-rw-r--r--mobile/android/tests/browser/chrome/video_discovery.html77
-rw-r--r--mobile/android/tests/browser/chrome/video_discovery.sjs27
-rw-r--r--mobile/android/tests/browser/chrome/web_channel.html89
-rw-r--r--mobile/android/tests/browser/junit3/AndroidManifest.xml.in23
-rw-r--r--mobile/android/tests/browser/junit3/Makefile.in13
-rw-r--r--mobile/android/tests/browser/junit3/instrumentation.ini9
-rw-r--r--mobile/android/tests/browser/junit3/moz.build55
-rw-r--r--mobile/android/tests/browser/junit3/res/drawable-hdpi/icon.pngbin7639 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/junit3/res/drawable-ldpi/icon.pngbin2979 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/junit3/res/drawable-mdpi/icon.pngbin4625 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/junit3/res/layout/main.xml12
-rw-r--r--mobile/android/tests/browser/junit3/res/values/strings.xml6
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestDistribution.java37
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoBackgroundThread.java56
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoMenu.java72
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoProfilesProvider.java50
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java153
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestImageDownloader.java205
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestJarReader.java124
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestRawResource.java66
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java473
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserInstrumentationTestRunner.java33
-rw-r--r--mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserTestListener.java42
-rw-r--r--mobile/android/tests/browser/moz.build17
-rw-r--r--mobile/android/tests/browser/robocop/AndroidManifest.xml.in67
-rw-r--r--mobile/android/tests/browser/robocop/Firefox.jpgbin9775 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/Makefile.in67
-rw-r--r--mobile/android/tests/browser/robocop/README12
-rw-r--r--mobile/android/tests/browser/robocop/README.rst61
-rw-r--r--mobile/android/tests/browser/robocop/assets/README4
-rw-r--r--mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v27.dbbin114688 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v28.dbbin116736 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v29.dbbin117760 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v30.dbbin368640 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v31.dbbin352256 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v32.dbbin360448 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v33.dbbin360448 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v34.dbbin610304 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v35.dbbin622593 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/golem_favicon.icobin40648 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/microsoft_favicon.icobin17174 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/nvidia_favicon.icobin25214 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/mock-package.zipbin5650 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/browser.dbbin466944 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/readercache/DWUP3U4ERC6TKJVSYXKJLHHEFY.json1
-rw-r--r--mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/readercache/KWNV7PXD3JFOJBQJVFXI3CQKNE.json1
-rw-r--r--mobile/android/tests/browser/robocop/assets/testcheck2-motionevents444
-rw-r--r--mobile/android/tests/browser/robocop/green.swfbin112 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/javascript_redirect.sjs8
-rw-r--r--mobile/android/tests/browser/robocop/libs/robotium-solo-5.5.4.jarbin129423 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/link_discovery.html8
-rw-r--r--mobile/android/tests/browser/robocop/moz.build34
-rw-r--r--mobile/android/tests/browser/robocop/reader_mode_pages/basic_article.html16
-rw-r--r--mobile/android/tests/browser/robocop/reader_mode_pages/developer.mozilla.org/en/XULRunner/Build_Instructions.html373
-rw-r--r--mobile/android/tests/browser/robocop/reader_mode_pages/not_an_article.html132
-rw-r--r--mobile/android/tests/browser/robocop/res/values/strings.xml9
-rw-r--r--mobile/android/tests/browser/robocop/robocop.ini118
-rw-r--r--mobile/android/tests/browser/robocop/robocop_404.sjs28
-rw-r--r--mobile/android/tests/browser/robocop/robocop_adobe_flash.html17
-rw-r--r--mobile/android/tests/browser/robocop/robocop_autophone.ini1
-rw-r--r--mobile/android/tests/browser/robocop/robocop_big_link.html13
-rw-r--r--mobile/android/tests/browser/robocop/robocop_big_mailto.html13
-rw-r--r--mobile/android/tests/browser/robocop/robocop_blank_01.html7
-rw-r--r--mobile/android/tests/browser/robocop/robocop_blank_02.html8
-rw-r--r--mobile/android/tests/browser/robocop/robocop_blank_03.html7
-rw-r--r--mobile/android/tests/browser/robocop/robocop_blank_04.html7
-rw-r--r--mobile/android/tests/browser/robocop/robocop_blank_05.html7
-rw-r--r--mobile/android/tests/browser/robocop/robocop_boxes.html42
-rw-r--r--mobile/android/tests/browser/robocop/robocop_dynamic.sjs18
-rw-r--r--mobile/android/tests/browser/robocop/robocop_geolocation.html20
-rw-r--r--mobile/android/tests/browser/robocop/robocop_getusermedia.html86
-rw-r--r--mobile/android/tests/browser/robocop/robocop_getusermedia2.html83
-rw-r--r--mobile/android/tests/browser/robocop/robocop_head.js829
-rw-r--r--mobile/android/tests/browser/robocop/robocop_input.html165
-rw-r--r--mobile/android/tests/browser/robocop/robocop_javascript.html20
-rw-r--r--mobile/android/tests/browser/robocop/robocop_link_to_slow_loading.html12
-rw-r--r--mobile/android/tests/browser/robocop/robocop_login_01.html21
-rw-r--r--mobile/android/tests/browser/robocop/robocop_login_02.html21
-rw-r--r--mobile/android/tests/browser/robocop/robocop_offline_storage.html8
-rw-r--r--mobile/android/tests/browser/robocop/robocop_picture_link.html13
-rw-r--r--mobile/android/tests/browser/robocop/robocop_popup.html12
-rw-r--r--mobile/android/tests/browser/robocop/robocop_search.html11
-rw-r--r--mobile/android/tests/browser/robocop/robocop_slow_loading.html23
-rw-r--r--mobile/android/tests/browser/robocop/robocop_suggestions.sjs32
-rw-r--r--mobile/android/tests/browser/robocop/robocop_testharness.js74
-rw-r--r--mobile/android/tests/browser/robocop/robocop_text_page.html27
-rw-r--r--mobile/android/tests/browser/robocop/roboextender/Makefile.in9
-rw-r--r--mobile/android/tests/browser/robocop/roboextender/base/robocop_home_banner.html37
-rw-r--r--mobile/android/tests/browser/robocop/roboextender/base/robocop_prompt_gridinput.html51
-rw-r--r--mobile/android/tests/browser/robocop/roboextender/bootstrap.js65
-rw-r--r--mobile/android/tests/browser/robocop/roboextender/chrome.manifest1
-rw-r--r--mobile/android/tests/browser/robocop/roboextender/install.rdf19
-rw-r--r--mobile/android/tests/browser/robocop/roboextender/moz.build12
-rw-r--r--mobile/android/tests/browser/robocop/simple_redirect.sjs5
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Actions.java126
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Assert.java25
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Driver.java44
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Element.java27
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecInstrumentationTestRunner.java79
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecMochitestAssert.java254
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeActions.java482
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeDriver.java392
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeElement.java116
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecTalosAssert.java74
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/LaunchFennecWithConfigurationActivity.java40
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/PaintedSurface.java105
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RoboCopException.java24
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopShare1.java17
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopShare2.java17
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopUtils.java58
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/StructuredLogger.java188
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/AboutHomeTest.java252
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseRobocopTest.java288
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseTest.java976
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/ContentContextMenuTest.java135
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/ContentProviderTest.java255
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/DatabaseHelper.java170
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/JavascriptBridgeTest.java107
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/JavascriptTest.java87
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/MotionEventHelper.java210
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/MotionEventReplayer.java224
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/PixelTest.java117
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/SelectionHandlerTest.java56
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/SessionTest.java407
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/StringHelper.java401
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/UITest.java203
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/UITestContext.java51
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/AboutHomeComponent.java193
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/AppMenuComponent.java295
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/BaseComponent.java36
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/GeckoViewComponent.java343
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/TabStripComponent.java56
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/ToolbarComponent.java326
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/AssertionHelper.java112
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/DeviceHelper.java108
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/FrameworkHelper.java94
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/GeckoClickHelper.java50
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/GeckoHelper.java49
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/HelperInitializer.java30
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/JavascriptBridge.java394
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/JavascriptMessageParser.java100
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/NavigationHelper.java104
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/RobotiumHelper.java43
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/WaitHelper.java215
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testANRReporter.java240
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutHomePageNavigation.java107
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutHomeVisibility.java57
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutPage.java47
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAccessibleCarets.java76
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testActivityStreamContextMenu.java94
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAddSearchEngine.java172
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAddonManager.java79
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAdobeFlash.java39
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAppMenuPathways.java77
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAxisLocking.java58
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBackButtonInEditMode.java47
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmark.java72
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarkFolders.java169
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarkKeyword.java28
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarklets.java46
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarksPanel.java174
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserDatabaseHelperUpgrades.java150
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserDiscovery.java13
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java1921
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserSearchVisibility.java69
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBug1217581.java31
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testCheck2.java61
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testCheck3.java61
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDBUtils.java70
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDistribution.java556
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDoorHanger.java205
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testEventDispatcher.java450
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFilePicker.java52
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFilterOpenTab.java133
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFindInPage.java107
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFlingCorrectness.java52
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFormHistory.java104
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGeckoProfile.java295
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGeckoRequest.java121
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGetUserMedia.java159
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHistory.java74
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHistoryService.java12
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHomeBanner.java94
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHomeListsProvider.java118
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testICODecoder.java238
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java349
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputUrlBar.java136
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testJarReader.java70
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testJavascriptBridge.java69
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLinkContextMenu.java37
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLoad.java23
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLoginsProvider.java387
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testMailToContextMenu.java26
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java288
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNewTab.java65
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testOSLocale.java137
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPanCorrectness.java49
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordEncrypt.java125
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordProvider.java104
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPermissions.java72
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPictureLinkContextMenu.java52
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPrefsObserver.java81
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPrivateBrowsing.java89
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPromptGridInput.java47
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReaderCacheMigration.java62
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReaderModeTitle.java19
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReadingListCache.java12
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReadingListToBookmarksMigration.java217
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testRestrictions.java39
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testRuntimePermissionsAPI.java48
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSearchHistoryProvider.java379
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSearchSuggestions.java115
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionHistory.java37
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionOOMRestore.java54
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionOOMSave.java87
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testShareLink.java265
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSnackbarAPI.java52
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testStateWhileLoading.java40
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testStumblerSetting.java90
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testThumbnails.java116
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testTrackingProtection.java65
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testUITelemetry.java56
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testUnifiedTelemetryClientId.java265
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testVideoControls.java9
-rw-r--r--mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testVkbOverlap.java105
-rw-r--r--mobile/android/tests/browser/robocop/testAccessibleCarets.html45
-rw-r--r--mobile/android/tests/browser/robocop/testAccessibleCarets.js323
-rw-r--r--mobile/android/tests/browser/robocop/testAccessibleCarets2.html23
-rw-r--r--mobile/android/tests/browser/robocop/testBrowserDiscovery.js150
-rw-r--r--mobile/android/tests/browser/robocop/testEventDispatcher.js44
-rw-r--r--mobile/android/tests/browser/robocop/testFilePicker.js73
-rw-r--r--mobile/android/tests/browser/robocop/testFindInPage.js89
-rw-r--r--mobile/android/tests/browser/robocop/testGeckoRequest.js40
-rw-r--r--mobile/android/tests/browser/robocop/testHistoryService.js128
-rw-r--r--mobile/android/tests/browser/robocop/testJavascriptBridge.js52
-rw-r--r--mobile/android/tests/browser/robocop/testReaderCacheMigration.js23
-rw-r--r--mobile/android/tests/browser/robocop/testReadingListCache.js126
-rw-r--r--mobile/android/tests/browser/robocop/testRuntimePermissionsAPI.js20
-rw-r--r--mobile/android/tests/browser/robocop/testSnackbarAPI.js21
-rw-r--r--mobile/android/tests/browser/robocop/testTrackingProtection.js166
-rw-r--r--mobile/android/tests/browser/robocop/testUITelemetry.js154
-rw-r--r--mobile/android/tests/browser/robocop/testUnifiedTelemetryClientId.js50
-rw-r--r--mobile/android/tests/browser/robocop/testVideoControls.js157
-rw-r--r--mobile/android/tests/browser/robocop/test_viewport.sjs33
-rw-r--r--mobile/android/tests/browser/robocop/tracking_bad.html12
-rw-r--r--mobile/android/tests/browser/robocop/tracking_good.html12
-rw-r--r--mobile/android/tests/browser/robocop/video-pattern.oggbin299507 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/video-pattern.webmbin220609 -> 0 bytes
-rw-r--r--mobile/android/tests/browser/robocop/video_controls.html10
-rw-r--r--mobile/android/tests/javaaddons/AndroidManifest.xml.in14
-rw-r--r--mobile/android/tests/javaaddons/Makefile.in11
-rw-r--r--mobile/android/tests/javaaddons/moz.build23
-rw-r--r--mobile/android/tests/javaaddons/res/values/strings.xml3
-rw-r--r--mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/ClassWithNoRecognizedConstructors.java11
-rw-r--r--mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/JavaAddonV0.java24
-rw-r--r--mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/JavaAddonV1.java59
-rw-r--r--mobile/android/tests/moz.build18
1072 files changed, 0 insertions, 95357 deletions
diff --git a/mobile/android/tests/.eslintrc b/mobile/android/tests/.eslintrc
deleted file mode 100644
index 6784be2d6..000000000
--- a/mobile/android/tests/.eslintrc
+++ /dev/null
@@ -1,18 +0,0 @@
-globals:
- # TODO: Verify that these are correct.
- Point: false
- SpecialPowers: false
- XPCNativeWrapper: false
- add_task: false
- add_test: false
- do_check_eq: false
- do_check_false: false
- do_check_neq: false
- do_check_true: false
- do_print: false
- do_register_cleanup: false
- do_report_result: false
- do_test_finished: false
- do_test_pending: false
- do_throw: false
- run_next_test: false
diff --git a/mobile/android/tests/background/junit3/AndroidManifest.xml.in b/mobile/android/tests/background/junit3/AndroidManifest.xml.in
deleted file mode 100644
index 09f1a25a1..000000000
--- a/mobile/android/tests/background/junit3/AndroidManifest.xml.in
+++ /dev/null
@@ -1,23 +0,0 @@
-#filter substitution
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.mozilla.gecko.background.tests"
- sharedUserId="@MOZ_ANDROID_SHARED_ID@"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-sdk android:minSdkVersion="8"
- android:targetSdkVersion="@ANDROID_TARGET_SDK@" />
-
- <application
- android:debuggable="true"
- android:icon="@drawable/icon"
- android:label="@ANDROID_BACKGROUND_APP_DISPLAYNAME@">
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation
- android:label="@string/app_name"
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="@ANDROID_BACKGROUND_TARGET_PACKAGE_NAME@" />
-</manifest>
diff --git a/mobile/android/tests/background/junit3/Makefile.in b/mobile/android/tests/background/junit3/Makefile.in
deleted file mode 100644
index f7f40ca78..000000000
--- a/mobile/android/tests/background/junit3/Makefile.in
+++ /dev/null
@@ -1,13 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ANDROID_EXTRA_JARS := \
- background-junit3.jar \
- $(NULL)
-
-ANDROID_MANIFEST_FILE := $(CURDIR)/AndroidManifest.xml
-
-include $(topsrcdir)/config/rules.mk
-
-tools:: $(ANDROID_APK_NAME).apk
diff --git a/mobile/android/tests/background/junit3/background_junit3_sources.mozbuild b/mobile/android/tests/background/junit3/background_junit3_sources.mozbuild
deleted file mode 100644
index 021af2eb8..000000000
--- a/mobile/android/tests/background/junit3/background_junit3_sources.mozbuild
+++ /dev/null
@@ -1,78 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-background_junit3_sources = [
- 'src/org/mozilla/gecko/background/common/TestAndroidLogWriters.java',
- 'src/org/mozilla/gecko/background/common/TestUtils.java',
- 'src/org/mozilla/gecko/background/common/TestWaitHelper.java',
- 'src/org/mozilla/gecko/background/db/AndroidBrowserRepositoryTestCase.java',
- 'src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java',
- 'src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java',
- 'src/org/mozilla/gecko/background/db/TestBookmarks.java',
- 'src/org/mozilla/gecko/background/db/TestClientsDatabase.java',
- 'src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java',
- 'src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java',
- 'src/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java',
- 'src/org/mozilla/gecko/background/db/TestPasswordsRepository.java',
- 'src/org/mozilla/gecko/background/db/TestTopSites.java',
- 'src/org/mozilla/gecko/background/fxa/authenticator/TestAccountPickler.java',
- 'src/org/mozilla/gecko/background/fxa/TestAccountLoader.java',
- 'src/org/mozilla/gecko/background/fxa/TestBrowserIDKeyPairGeneration.java',
- 'src/org/mozilla/gecko/background/helpers/AndroidSyncTestCase.java',
- 'src/org/mozilla/gecko/background/helpers/DBHelpers.java',
- 'src/org/mozilla/gecko/background/helpers/DBProviderTestCase.java',
- 'src/org/mozilla/gecko/background/nativecode/test/TestNativeCrypto.java',
- 'src/org/mozilla/gecko/background/sync/AndroidSyncTestCaseWithAccounts.java',
- 'src/org/mozilla/gecko/background/sync/helpers/BookmarkHelpers.java',
- 'src/org/mozilla/gecko/background/sync/helpers/DefaultBeginDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/DefaultCleanDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/DefaultDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/DefaultFetchDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/DefaultFinishDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/DefaultGuidsSinceDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/DefaultSessionCreationDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/DefaultStoreDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectBeginDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectBeginFailDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectFetchDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectFetchSinceDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectFinishDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectFinishFailDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectGuidsSinceDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidRequestFetchDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidTypeStoreDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectManyStoredDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectNoGUIDsSinceDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectNoStoreDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectStoreCompletedDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/ExpectStoredDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/HistoryHelpers.java',
- 'src/org/mozilla/gecko/background/sync/helpers/PasswordHelpers.java',
- 'src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java',
- 'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessBeginDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessCreationDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFetchDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFinishDelegate.java',
- 'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessStoreDelegate.java',
- 'src/org/mozilla/gecko/background/sync/TestClientsStage.java',
- 'src/org/mozilla/gecko/background/sync/TestResetting.java',
- 'src/org/mozilla/gecko/background/sync/TestStoreTracking.java',
- 'src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java',
- 'src/org/mozilla/gecko/background/sync/TestWebURLFinder.java',
- 'src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java',
- 'src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java',
- 'src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java',
- 'src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java',
- 'src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java',
- 'src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java',
- 'src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java',
- 'src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java',
- 'src/org/mozilla/gecko/background/testhelpers/MockRecord.java',
- 'src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java',
- 'src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java',
- 'src/org/mozilla/gecko/background/testhelpers/WaitHelper.java',
- 'src/org/mozilla/gecko/background/testhelpers/WBORepository.java',
-]
diff --git a/mobile/android/tests/background/junit3/instrumentation.ini b/mobile/android/tests/background/junit3/instrumentation.ini
deleted file mode 100644
index e2c7b2ea1..000000000
--- a/mobile/android/tests/background/junit3/instrumentation.ini
+++ /dev/null
@@ -1,22 +0,0 @@
-[DEFAULT]
-subsuite = background
-
-[src/org/mozilla/gecko/background/common/TestAndroidLogWriters.java]
-[src/org/mozilla/gecko/background/common/TestUtils.java]
-[src/org/mozilla/gecko/background/common/TestWaitHelper.java]
-[src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java]
-[src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java]
-[src/org/mozilla/gecko/background/db/TestBookmarks.java]
-[src/org/mozilla/gecko/background/db/TestClientsDatabase.java]
-[src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java]
-[src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java]
-[src/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java]
-[src/org/mozilla/gecko/background/db/TestPasswordsRepository.java]
-[src/org/mozilla/gecko/background/fxa/TestBrowserIDKeyPairGeneration.java]
-[src/org/mozilla/gecko/background/fxa/authenticator/TestAccountPickler.java]
-[src/org/mozilla/gecko/background/nativecode/test/TestNativeCrypto.java]
-[src/org/mozilla/gecko/background/sync/TestClientsStage.java]
-[src/org/mozilla/gecko/background/sync/TestResetting.java]
-[src/org/mozilla/gecko/background/sync/TestStoreTracking.java]
-[src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java]
-[src/org/mozilla/gecko/background/sync/TestWebURLFinder.java]
diff --git a/mobile/android/tests/background/junit3/moz.build b/mobile/android/tests/background/junit3/moz.build
deleted file mode 100644
index 3e81e1e32..000000000
--- a/mobile/android/tests/background/junit3/moz.build
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
-
-ANDROID_APK_NAME = 'background-junit3-debug'
-ANDROID_APK_PACKAGE = 'org.mozilla.gecko.background.tests'
-
-include('background_junit3_sources.mozbuild')
-
-jar = add_java_jar('background-junit3')
-jar.sources += background_junit3_sources
-jar.extra_jars += [
- CONFIG['ANDROID_SUPPORT_V4_AAR_LIB'],
- CONFIG['ANDROID_RECYCLERVIEW_V7_AAR_LIB'],
- TOPOBJDIR + '/mobile/android/base/constants.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-R.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-browser.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-mozglue.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-thirdparty.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-util.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-view.jar',
- TOPOBJDIR + '/mobile/android/base/services.jar',
- TOPOBJDIR + '/mobile/android/base/sync-thirdparty.jar',
-]
-
-if CONFIG['MOZ_ANDROID_MLS_STUMBLER']:
- jar.extra_jars += [
- TOPOBJDIR + '/mobile/android/stumbler/stumbler.jar',
- ]
-
-ANDROID_INSTRUMENTATION_MANIFESTS += ['instrumentation.ini']
-
-DEFINES['ANDROID_BACKGROUND_TARGET_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
-DEFINES['ANDROID_BACKGROUND_APP_DISPLAYNAME'] = '%s Background Tests' % CONFIG['MOZ_APP_DISPLAYNAME']
-DEFINES['MOZ_ANDROID_SHARED_ID'] = CONFIG['MOZ_ANDROID_SHARED_ID']
-OBJDIR_PP_FILES.mobile.android.tests.background.junit3 += [
- 'AndroidManifest.xml.in',
-]
diff --git a/mobile/android/tests/background/junit3/res/drawable-hdpi/icon.png b/mobile/android/tests/background/junit3/res/drawable-hdpi/icon.png
deleted file mode 100644
index e83438eee..000000000
--- a/mobile/android/tests/background/junit3/res/drawable-hdpi/icon.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/background/junit3/res/drawable-ldpi/icon.png b/mobile/android/tests/background/junit3/res/drawable-ldpi/icon.png
deleted file mode 100644
index 0483c95e9..000000000
--- a/mobile/android/tests/background/junit3/res/drawable-ldpi/icon.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/background/junit3/res/drawable-mdpi/icon.png b/mobile/android/tests/background/junit3/res/drawable-mdpi/icon.png
deleted file mode 100644
index 86b4dee54..000000000
--- a/mobile/android/tests/background/junit3/res/drawable-mdpi/icon.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/background/junit3/res/layout/main.xml b/mobile/android/tests/background/junit3/res/layout/main.xml
deleted file mode 100644
index 14dbff7e0..000000000
--- a/mobile/android/tests/background/junit3/res/layout/main.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
-
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/app_name" />
-
-</LinearLayout>
diff --git a/mobile/android/tests/background/junit3/res/values/strings.xml b/mobile/android/tests/background/junit3/res/values/strings.xml
deleted file mode 100644
index d6534d7fa..000000000
--- a/mobile/android/tests/background/junit3/res/values/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <string name="app_name">Gecko Background Tests</string>
-
-</resources>
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestAndroidLogWriters.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestAndroidLogWriters.java
deleted file mode 100644
index 7f4b9bb9c..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestAndroidLogWriters.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.common;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.common.log.writers.AndroidLevelCachingLogWriter;
-import org.mozilla.gecko.background.common.log.writers.AndroidLogWriter;
-import org.mozilla.gecko.background.common.log.writers.LogWriter;
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-
-public class TestAndroidLogWriters extends AndroidSyncTestCase {
- public static final String TEST_LOG_TAG = "TestAndroidLogWriters";
-
- public static final String TEST_MESSAGE_1 = "LOG TEST MESSAGE one";
- public static final String TEST_MESSAGE_2 = "LOG TEST MESSAGE two";
- public static final String TEST_MESSAGE_3 = "LOG TEST MESSAGE three";
-
- public void setUp() {
- Logger.stopLoggingToAll();
- }
-
- public void tearDown() {
- Logger.resetLogging();
- }
-
- /**
- * Verify these *all* appear in the Android log by using
- * <code>adb logcat | grep TestAndroidLogWriters</code> after executing
- * <code>adb shell setprop log.tag.TestAndroidLogWriters ERROR</code>.
- * <p>
- * This writer does not use the Android log levels!
- */
- public void testAndroidLogWriter() {
- LogWriter lw = new AndroidLogWriter();
-
- Logger.error(TEST_LOG_TAG, TEST_MESSAGE_1, new RuntimeException());
- Logger.startLoggingTo(lw);
- Logger.error(TEST_LOG_TAG, TEST_MESSAGE_2);
- Logger.warn(TEST_LOG_TAG, TEST_MESSAGE_2);
- Logger.info(TEST_LOG_TAG, TEST_MESSAGE_2);
- Logger.debug(TEST_LOG_TAG, TEST_MESSAGE_2);
- Logger.trace(TEST_LOG_TAG, TEST_MESSAGE_2);
- Logger.stopLoggingTo(lw);
- Logger.error(TEST_LOG_TAG, TEST_MESSAGE_3, new RuntimeException());
- }
-
- /**
- * Verify only *some* of these appear in the Android log by using
- * <code>adb logcat | grep TestAndroidLogWriters</code> after executing
- * <code>adb shell setprop log.tag.TestAndroidLogWriters INFO</code>.
- * <p>
- * This writer should use the Android log levels!
- */
- public void testAndroidLevelCachingLogWriter() throws Exception {
- LogWriter lw = new AndroidLevelCachingLogWriter(new AndroidLogWriter());
-
- Logger.error(TEST_LOG_TAG, TEST_MESSAGE_1, new RuntimeException());
- Logger.startLoggingTo(lw);
- Logger.error(TEST_LOG_TAG, TEST_MESSAGE_2);
- Logger.warn(TEST_LOG_TAG, TEST_MESSAGE_2);
- Logger.info(TEST_LOG_TAG, TEST_MESSAGE_2);
- Logger.debug(TEST_LOG_TAG, TEST_MESSAGE_2);
- Logger.trace(TEST_LOG_TAG, TEST_MESSAGE_2);
- Logger.stopLoggingTo(lw);
- Logger.error(TEST_LOG_TAG, TEST_MESSAGE_3, new RuntimeException());
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestUtils.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestUtils.java
deleted file mode 100644
index 270eae6f6..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestUtils.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.common;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.sync.Utils;
-
-import android.os.Bundle;
-
-public class TestUtils extends AndroidSyncTestCase {
- protected static void assertStages(String[] all, String[] sync, String[] skip, String[] expected) {
- final Set<String> sAll = new HashSet<String>();
- for (String s : all) {
- sAll.add(s);
- }
- List<String> sSync = null;
- if (sync != null) {
- sSync = new ArrayList<String>();
- for (String s : sync) {
- sSync.add(s);
- }
- }
- List<String> sSkip = null;
- if (skip != null) {
- sSkip = new ArrayList<String>();
- for (String s : skip) {
- sSkip.add(s);
- }
- }
- List<String> stages = new ArrayList<String>(Utils.getStagesToSync(sAll, sSync, sSkip));
- Collections.sort(stages);
- List<String> exp = new ArrayList<String>();
- for (String e : expected) {
- exp.add(e);
- }
- assertEquals(exp, stages);
- }
-
- public void testGetStagesToSync() {
- final String[] all = new String[] { "other1", "other2", "skip1", "skip2", "sync1", "sync2" };
- assertStages(all, null, null, all);
- assertStages(all, new String[] { "sync1" }, null, new String[] { "sync1" });
- assertStages(all, null, new String[] { "skip1", "skip2" }, new String[] { "other1", "other2", "sync1", "sync2" });
- assertStages(all, new String[] { "sync1", "sync2" }, new String[] { "skip1", "skip2" }, new String[] { "sync1", "sync2" });
- }
-
- protected static void assertStagesFromBundle(String[] all, String[] sync, String[] skip, String[] expected) {
- final Set<String> sAll = new HashSet<String>();
- for (String s : all) {
- sAll.add(s);
- }
- final Bundle bundle = new Bundle();
- Utils.putStageNamesToSync(bundle, sync, skip);
-
- Collection<String> ss = Utils.getStagesToSyncFromBundle(sAll, bundle);
- List<String> stages = new ArrayList<String>(ss);
- Collections.sort(stages);
- List<String> exp = new ArrayList<String>();
- for (String e : expected) {
- exp.add(e);
- }
- assertEquals(exp, stages);
- }
-
- public void testGetStagesToSyncFromBundle() {
- final String[] all = new String[] { "other1", "other2", "skip1", "skip2", "sync1", "sync2" };
- assertStagesFromBundle(all, null, null, all);
- assertStagesFromBundle(all, new String[] { "sync1" }, null, new String[] { "sync1" });
- assertStagesFromBundle(all, null, new String[] { "skip1", "skip2" }, new String[] { "other1", "other2", "sync1", "sync2" });
- assertStagesFromBundle(all, new String[] { "sync1", "sync2" }, new String[] { "skip1", "skip2" }, new String[] { "sync1", "sync2" });
- }
-
- public static void deleteDirectoryRecursively(final File dir) throws IOException {
- if (!dir.isDirectory()) {
- throw new IllegalStateException("Given directory, " + dir + ", is not a directory!");
- }
-
- for (File f : dir.listFiles()) {
- if (f.isDirectory()) {
- deleteDirectoryRecursively(f);
- } else if (!f.delete()) {
- // Since this method is for testing, we assume we should be able to do this.
- throw new IOException("Could not delete file, " + f.getAbsolutePath() + ". Permissions?");
- }
- }
-
- if (!dir.delete()) {
- throw new IOException("Could not delete dir, " + dir.getAbsolutePath() + ".");
- }
- }
-
- public void testDeleteDirectoryRecursively() throws Exception {
- final String TEST_DIR = getApplicationContext().getCacheDir().getAbsolutePath() +
- "-testDeleteDirectory-" + System.currentTimeMillis();
-
- // Non-existent directory.
- final File nonexistent = new File("nonexistentDirectory"); // Hopefully. ;)
- assertFalse(nonexistent.exists());
- try {
- deleteDirectoryRecursively(nonexistent);
- fail("deleteDirectoryRecursively on a nonexistent directory should throw Exception");
- } catch (IllegalStateException e) { }
-
- // Empty dir.
- File dir = mkdir(TEST_DIR);
- deleteDirectoryRecursively(dir);
- assertFalse(dir.exists());
-
- // Filled dir.
- dir = mkdir(TEST_DIR);
- populateDir(dir);
- deleteDirectoryRecursively(dir);
- assertFalse(dir.exists());
-
- // Filled dir with empty dir.
- dir = mkdir(TEST_DIR);
- populateDir(dir);
- File subDir = new File(TEST_DIR + File.separator + "subDir");
- assertTrue(subDir.mkdir());
- deleteDirectoryRecursively(dir);
- assertFalse(subDir.exists()); // For short-circuiting errors.
- assertFalse(dir.exists());
-
- // Filled dir with filled dir.
- dir = mkdir(TEST_DIR);
- populateDir(dir);
- subDir = new File(TEST_DIR + File.separator + "subDir");
- assertTrue(subDir.mkdir());
- populateDir(subDir);
- deleteDirectoryRecursively(dir);
- assertFalse(subDir.exists()); // For short-circuiting errors.
- assertFalse(dir.exists());
- }
-
- private File mkdir(final String name) {
- final File dir = new File(name);
- assertTrue(dir.mkdir());
- return dir;
- }
-
- private void populateDir(final File dir) throws IOException {
- assertTrue(dir.isDirectory());
- final String dirPath = dir.getAbsolutePath();
- for (int i = 0; i < 3; i++) {
- final File f = new File(dirPath + File.separator + i);
- assertTrue(f.createNewFile()); // Throws IOException if file could not be created.
- }
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestWaitHelper.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestWaitHelper.java
deleted file mode 100644
index 1f818e0cf..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestWaitHelper.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.common;
-
-import junit.framework.AssertionFailedError;
-
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.background.testhelpers.WaitHelper.InnerError;
-import org.mozilla.gecko.background.testhelpers.WaitHelper.TimeoutError;
-import org.mozilla.gecko.sync.ThreadPool;
-
-public class TestWaitHelper extends AndroidSyncTestCase {
- private static final String ERROR_UNIQUE_IDENTIFIER = "error unique identifier";
-
- public static int NO_WAIT = 1; // Milliseconds.
- public static int SHORT_WAIT = 100; // Milliseconds.
- public static int LONG_WAIT = 3 * SHORT_WAIT;
-
- private Object notifyMonitor = new Object();
- // Guarded by notifyMonitor.
- private boolean performNotifyCalled = false;
- private boolean performNotifyErrorCalled = false;
- private void setPerformNotifyCalled() {
- synchronized (notifyMonitor) {
- performNotifyCalled = true;
- }
- }
- private void setPerformNotifyErrorCalled() {
- synchronized (notifyMonitor) {
- performNotifyErrorCalled = true;
- }
- }
- private void resetNotifyCalled() {
- synchronized (notifyMonitor) {
- performNotifyCalled = false;
- performNotifyErrorCalled = false;
- }
- }
- private void assertBothCalled() {
- synchronized (notifyMonitor) {
- assertTrue(performNotifyCalled);
- assertTrue(performNotifyErrorCalled);
- }
- }
- private void assertErrorCalled() {
- synchronized (notifyMonitor) {
- assertFalse(performNotifyCalled);
- assertTrue(performNotifyErrorCalled);
- }
- }
- private void assertCalled() {
- synchronized (notifyMonitor) {
- assertTrue(performNotifyCalled);
- assertFalse(performNotifyErrorCalled);
- }
- }
-
- public WaitHelper waitHelper;
-
- public TestWaitHelper() {
- super();
- }
-
- public void setUp() {
- WaitHelper.resetTestWaiter();
- waitHelper = WaitHelper.getTestWaiter();
- resetNotifyCalled();
- }
-
- public void tearDown() {
- assertTrue(waitHelper.isIdle());
- }
-
- public Runnable performNothingRunnable() {
- return new Runnable() {
- public void run() {
- }
- };
- }
-
- public Runnable performNotifyRunnable() {
- return new Runnable() {
- public void run() {
- setPerformNotifyCalled();
- waitHelper.performNotify();
- }
- };
- }
-
- public Runnable performNotifyAfterDelayRunnable(final int delayInMillis) {
- return new Runnable() {
- public void run() {
- try {
- Thread.sleep(delayInMillis);
- } catch (InterruptedException e) {
- fail("Interrupted.");
- }
-
- setPerformNotifyCalled();
- waitHelper.performNotify();
- }
- };
- }
-
- public Runnable performNotifyErrorRunnable() {
- return new Runnable() {
- public void run() {
- setPerformNotifyCalled();
- waitHelper.performNotify(new AssertionFailedError(ERROR_UNIQUE_IDENTIFIER));
- }
- };
- }
-
- public Runnable inThreadPool(final Runnable runnable) {
- return new Runnable() {
- @Override
- public void run() {
- ThreadPool.run(runnable);
- }
- };
- }
-
- public Runnable inThread(final Runnable runnable) {
- return new Runnable() {
- @Override
- public void run() {
- new Thread(runnable).start();
- }
- };
- }
-
- protected void expectAssertionFailedError(Runnable runnable) {
- try {
- waitHelper.performWait(runnable);
- } catch (InnerError e) {
- AssertionFailedError inner = (AssertionFailedError)e.innerError;
- setPerformNotifyErrorCalled();
- String message = inner.getMessage();
- assertTrue("Expected '" + message + "' to contain '" + ERROR_UNIQUE_IDENTIFIER + "'",
- message.contains(ERROR_UNIQUE_IDENTIFIER));
- }
- }
-
- protected void expectAssertionFailedErrorAfterDelay(int wait, Runnable runnable) {
- try {
- waitHelper.performWait(wait, runnable);
- } catch (InnerError e) {
- AssertionFailedError inner = (AssertionFailedError)e.innerError;
- setPerformNotifyErrorCalled();
- String message = inner.getMessage();
- assertTrue("Expected '" + message + "' to contain '" + ERROR_UNIQUE_IDENTIFIER + "'",
- message.contains(ERROR_UNIQUE_IDENTIFIER));
- }
- }
-
- public void testPerformWait() {
- waitHelper.performWait(performNotifyRunnable());
- assertCalled();
- }
-
- public void testPerformWaitInThread() {
- waitHelper.performWait(inThread(performNotifyRunnable()));
- assertCalled();
- }
-
- public void testPerformWaitInThreadPool() {
- waitHelper.performWait(inThreadPool(performNotifyRunnable()));
- assertCalled();
- }
-
- public void testPerformTimeoutWait() {
- waitHelper.performWait(SHORT_WAIT, performNotifyRunnable());
- assertCalled();
- }
-
- public void testPerformTimeoutWaitInThread() {
- waitHelper.performWait(SHORT_WAIT, inThread(performNotifyRunnable()));
- assertCalled();
- }
-
- public void testPerformTimeoutWaitInThreadPool() {
- waitHelper.performWait(SHORT_WAIT, inThreadPool(performNotifyRunnable()));
- assertCalled();
- }
-
- public void testPerformErrorWaitInThread() {
- expectAssertionFailedError(inThread(performNotifyErrorRunnable()));
- assertBothCalled();
- }
-
- public void testPerformErrorWaitInThreadPool() {
- expectAssertionFailedError(inThreadPool(performNotifyErrorRunnable()));
- assertBothCalled();
- }
-
- public void testPerformErrorTimeoutWaitInThread() {
- expectAssertionFailedErrorAfterDelay(SHORT_WAIT, inThread(performNotifyErrorRunnable()));
- assertBothCalled();
- }
-
- public void testPerformErrorTimeoutWaitInThreadPool() {
- expectAssertionFailedErrorAfterDelay(SHORT_WAIT, inThreadPool(performNotifyErrorRunnable()));
- assertBothCalled();
- }
-
- public void testTimeout() {
- try {
- waitHelper.performWait(SHORT_WAIT, performNothingRunnable());
- } catch (TimeoutError e) {
- setPerformNotifyErrorCalled();
- assertEquals(SHORT_WAIT, e.waitTimeInMillis);
- }
- assertErrorCalled();
- }
-
- /**
- * This will pass. The sequence in the main thread is:
- * - A short delay.
- * - performNotify is called.
- * - performWait is called and immediately finds that performNotify was called before.
- */
- public void testDelay() {
- try {
- waitHelper.performWait(1, performNotifyAfterDelayRunnable(SHORT_WAIT));
- } catch (AssertionFailedError e) {
- setPerformNotifyErrorCalled();
- assertTrue(e.getMessage(), e.getMessage().contains("TIMEOUT"));
- }
- assertCalled();
- }
-
- public Runnable performNotifyMultipleTimesRunnable() {
- return new Runnable() {
- public void run() {
- waitHelper.performNotify();
- setPerformNotifyCalled();
- waitHelper.performNotify();
- }
- };
- }
-
- public void testPerformNotifyMultipleTimesFails() {
- try {
- waitHelper.performWait(NO_WAIT, performNotifyMultipleTimesRunnable()); // Not run on thread, so runnable executes before performWait looks for notifications.
- } catch (WaitHelper.MultipleNotificationsError e) {
- setPerformNotifyErrorCalled();
- }
- assertBothCalled();
- assertFalse(waitHelper.isIdle()); // First perform notify should be hanging around.
- waitHelper.performWait(NO_WAIT, performNothingRunnable());
- }
-
- public void testNestedWaitsAndNotifies() {
- waitHelper.performWait(new Runnable() {
- @Override
- public void run() {
- waitHelper.performWait(new Runnable() {
- public void run() {
- setPerformNotifyCalled();
- waitHelper.performNotify();
- }
- });
- setPerformNotifyErrorCalled();
- waitHelper.performNotify();
- }
- });
- assertBothCalled();
- }
-
- public void testAssertIsReported() {
- try {
- waitHelper.performWait(1, new Runnable() {
- @Override
- public void run() {
- assertTrue("unique identifier", false);
- }
- });
- } catch (AssertionFailedError e) {
- setPerformNotifyErrorCalled();
- assertTrue(e.getMessage(), e.getMessage().contains("unique identifier"));
- }
- assertErrorCalled();
- }
-
- /**
- * The inner wait will timeout, but the outer wait will succeed. The sequence in the helper thread is:
- * - A short delay.
- * - performNotify is called.
- *
- * The sequence in the main thread is:
- * - performWait is called and times out because the helper thread does not call
- * performNotify quickly enough.
- */
- public void testDelayInThread() throws InterruptedException {
- waitHelper.performWait(new Runnable() {
- @Override
- public void run() {
- try {
- waitHelper.performWait(NO_WAIT, inThread(new Runnable() {
- public void run() {
- try {
- Thread.sleep(SHORT_WAIT);
- } catch (InterruptedException e) {
- fail("Interrupted.");
- }
-
- setPerformNotifyCalled();
- waitHelper.performNotify();
- }
- }));
- } catch (WaitHelper.TimeoutError e) {
- setPerformNotifyErrorCalled();
- assertEquals(NO_WAIT, e.waitTimeInMillis);
- }
- }
- });
- assertBothCalled();
- }
-
- /**
- * The inner wait will timeout, but the outer wait will succeed. The sequence in the helper thread is:
- * - A short delay.
- * - performNotify is called.
- *
- * The sequence in the main thread is:
- * - performWait is called and times out because the helper thread does not call
- * performNotify quickly enough.
- */
- public void testDelayInThreadPool() throws InterruptedException {
- waitHelper.performWait(new Runnable() {
- @Override
- public void run() {
- try {
- waitHelper.performWait(NO_WAIT, inThreadPool(new Runnable() {
- public void run() {
- try {
- Thread.sleep(SHORT_WAIT);
- } catch (InterruptedException e) {
- fail("Interrupted.");
- }
-
- setPerformNotifyCalled();
- waitHelper.performNotify();
- }
- }));
- } catch (WaitHelper.TimeoutError e) {
- setPerformNotifyErrorCalled();
- assertEquals(NO_WAIT, e.waitTimeInMillis);
- }
- }
- });
- assertBothCalled();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/AndroidBrowserRepositoryTestCase.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/AndroidBrowserRepositoryTestCase.java
deleted file mode 100644
index da980735b..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/AndroidBrowserRepositoryTestCase.java
+++ /dev/null
@@ -1,818 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.sync.helpers.DefaultBeginDelegate;
-import org.mozilla.gecko.background.sync.helpers.DefaultCleanDelegate;
-import org.mozilla.gecko.background.sync.helpers.DefaultFetchDelegate;
-import org.mozilla.gecko.background.sync.helpers.DefaultFinishDelegate;
-import org.mozilla.gecko.background.sync.helpers.DefaultSessionCreationDelegate;
-import org.mozilla.gecko.background.sync.helpers.DefaultStoreDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectBeginDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectBeginFailDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectFetchSinceDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectFinishDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectFinishFailDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectGuidsSinceDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectInvalidRequestFetchDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectManyStoredDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectStoreCompletedDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectStoredDelegate;
-import org.mozilla.gecko.background.sync.helpers.SessionTestHelper;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepositoryDataAccessor;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import android.content.ContentValues;
-import android.content.Context;
-
-public abstract class AndroidBrowserRepositoryTestCase extends AndroidSyncTestCase {
- protected static String LOG_TAG = "BrowserRepositoryTest";
-
- protected static void wipe(AndroidBrowserRepositoryDataAccessor helper) {
- Logger.debug(LOG_TAG, "Wiping.");
- try {
- helper.wipe();
- } catch (NullPointerException e) {
- // This will be handled in begin, here we can just ignore
- // the error if it actually occurs since this is just test
- // code. We will throw a ProfileDatabaseException. This
- // error shouldn't occur in the future, but results from
- // trying to access content providers before Fennec has
- // been run at least once.
- Logger.error(LOG_TAG, "ProfileDatabaseException seen in wipe. Begin should fail");
- fail("NullPointerException in wipe.");
- }
- }
-
- @Override
- public void setUp() {
- AndroidBrowserRepositoryDataAccessor helper = getDataAccessor();
- wipe(helper);
- assertTrue(WaitHelper.getTestWaiter().isIdle());
- closeDataAccessor(helper);
- }
-
- public void tearDown() {
- assertTrue(WaitHelper.getTestWaiter().isIdle());
- }
-
- protected RepositorySession createSession() {
- return SessionTestHelper.createSession(
- getApplicationContext(),
- getRepository());
- }
-
- protected RepositorySession createAndBeginSession() {
- return SessionTestHelper.createAndBeginSession(
- getApplicationContext(),
- getRepository());
- }
-
- protected static void dispose(RepositorySession session) {
- if (session != null) {
- session.abort();
- }
- }
-
- /**
- * Hook to return an ExpectFetchDelegate, possibly with special GUIDs ignored.
- */
- public ExpectFetchDelegate preparedExpectFetchDelegate(Record[] expected) {
- return new ExpectFetchDelegate(expected);
- }
-
- /**
- * Hook to return an ExpectGuidsSinceDelegate, possibly with special GUIDs ignored.
- */
- public ExpectGuidsSinceDelegate preparedExpectGuidsSinceDelegate(String[] expected) {
- return new ExpectGuidsSinceDelegate(expected);
- }
-
- /**
- * Hook to return an ExpectGuidsSinceDelegate expecting only special GUIDs (if there are any).
- */
- public ExpectGuidsSinceDelegate preparedExpectOnlySpecialGuidsSinceDelegate() {
- return new ExpectGuidsSinceDelegate(new String[] {});
- }
-
- /**
- * Hook to return an ExpectFetchSinceDelegate, possibly with special GUIDs ignored.
- */
- public ExpectFetchSinceDelegate preparedExpectFetchSinceDelegate(long timestamp, String[] expected) {
- return new ExpectFetchSinceDelegate(timestamp, expected);
- }
-
- public static Runnable storeRunnable(final RepositorySession session, final Record record, final DefaultStoreDelegate delegate) {
- return new Runnable() {
- @Override
- public void run() {
- session.setStoreDelegate(delegate);
- try {
- session.store(record);
- session.storeDone();
- } catch (NoStoreDelegateException e) {
- fail("NoStoreDelegateException should not occur.");
- }
- }
- };
- }
-
- public static Runnable storeRunnable(final RepositorySession session, final Record record) {
- return storeRunnable(session, record, new ExpectStoredDelegate(record.guid));
- }
-
- public static Runnable storeManyRunnable(final RepositorySession session, final Record[] records, final DefaultStoreDelegate delegate) {
- return new Runnable() {
- @Override
- public void run() {
- session.setStoreDelegate(delegate);
- try {
- for (Record record : records) {
- session.store(record);
- }
- session.storeDone();
- } catch (NoStoreDelegateException e) {
- fail("NoStoreDelegateException should not occur.");
- }
- }
- };
- }
-
- public static Runnable storeManyRunnable(final RepositorySession session, final Record[] records) {
- return storeManyRunnable(session, records, new ExpectManyStoredDelegate(records));
- }
-
- /**
- * Store a record and don't expect a store callback until we're done.
- *
- * @param session
- * @param record
- * @return Runnable.
- */
- public static Runnable quietStoreRunnable(final RepositorySession session, final Record record) {
- return storeRunnable(session, record, new ExpectStoreCompletedDelegate());
- }
-
- public static Runnable beginRunnable(final RepositorySession session, final DefaultBeginDelegate delegate) {
- return new Runnable() {
- @Override
- public void run() {
- try {
- session.begin(delegate);
- } catch (InvalidSessionTransitionException e) {
- performNotify(e);
- }
- }
- };
- }
-
- public static Runnable finishRunnable(final RepositorySession session, final DefaultFinishDelegate delegate) {
- return new Runnable() {
- @Override
- public void run() {
- try {
- session.finish(delegate);
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- };
- }
-
- public static Runnable fetchAllRunnable(final RepositorySession session, final ExpectFetchDelegate delegate) {
- return new Runnable() {
- @Override
- public void run() {
- session.fetchAll(delegate);
- }
- };
- }
-
- public Runnable fetchAllRunnable(final RepositorySession session, final Record[] expectedRecords) {
- return fetchAllRunnable(session, preparedExpectFetchDelegate(expectedRecords));
- }
-
- public Runnable guidsSinceRunnable(final RepositorySession session, final long timestamp, final String[] expected) {
- return new Runnable() {
- @Override
- public void run() {
- session.guidsSince(timestamp, preparedExpectGuidsSinceDelegate(expected));
- }
- };
- }
-
- public Runnable fetchSinceRunnable(final RepositorySession session, final long timestamp, final String[] expected) {
- return new Runnable() {
- @Override
- public void run() {
- session.fetchSince(timestamp, preparedExpectFetchSinceDelegate(timestamp, expected));
- }
- };
- }
-
- public static Runnable fetchRunnable(final RepositorySession session, final String[] guids, final DefaultFetchDelegate delegate) {
- return new Runnable() {
- @Override
- public void run() {
- try {
- session.fetch(guids, delegate);
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- };
- }
- public Runnable fetchRunnable(final RepositorySession session, final String[] guids, final Record[] expected) {
- return fetchRunnable(session, guids, preparedExpectFetchDelegate(expected));
- }
-
- public static Runnable cleanRunnable(final Repository repository, final boolean success, final Context context, final DefaultCleanDelegate delegate) {
- return new Runnable() {
- @Override
- public void run() {
- repository.clean(success, delegate, context);
- }
- };
- }
-
- protected abstract Repository getRepository();
- protected abstract AndroidBrowserRepositoryDataAccessor getDataAccessor();
-
- protected static void doStore(RepositorySession session, Record[] records) {
- performWait(storeManyRunnable(session, records));
- }
-
- // Tests to implement
- public abstract void testFetchAll();
- public abstract void testGuidsSinceReturnMultipleRecords();
- public abstract void testGuidsSinceReturnNoRecords();
- public abstract void testFetchSinceOneRecord();
- public abstract void testFetchSinceReturnNoRecords();
- public abstract void testFetchOneRecordByGuid();
- public abstract void testFetchMultipleRecordsByGuids();
- public abstract void testFetchNoRecordByGuid();
- public abstract void testWipe();
- public abstract void testStore();
- public abstract void testRemoteNewerTimeStamp();
- public abstract void testLocalNewerTimeStamp();
- public abstract void testDeleteRemoteNewer();
- public abstract void testDeleteLocalNewer();
- public abstract void testDeleteRemoteLocalNonexistent();
- public abstract void testStoreIdenticalExceptGuid();
- public abstract void testCleanMultipleRecords();
-
-
- /*
- * Test abstractions
- */
- protected void basicStoreTest(Record record) {
- final RepositorySession session = createAndBeginSession();
- performWait(storeRunnable(session, record));
- }
-
- protected void basicFetchAllTest(Record[] expected) {
- Logger.debug("rnewman", "Starting testFetchAll.");
- RepositorySession session = createAndBeginSession();
- Logger.debug("rnewman", "Prepared.");
-
- AndroidBrowserRepositoryDataAccessor helper = getDataAccessor();
- helper.dumpDB();
- performWait(storeManyRunnable(session, expected));
-
- helper.dumpDB();
- performWait(fetchAllRunnable(session, expected));
-
- closeDataAccessor(helper);
- dispose(session);
- }
-
- /*
- * Tests for clean
- */
- // Input: 4 records; 2 which are to be cleaned, 2 which should remain after the clean
- protected void cleanMultipleRecords(Record delete0, Record delete1, Record keep0, Record keep1, Record keep2) {
- RepositorySession session = createAndBeginSession();
- doStore(session, new Record[] {
- delete0, delete1, keep0, keep1, keep2
- });
-
- // Force two records to appear deleted.
- AndroidBrowserRepositoryDataAccessor db = getDataAccessor();
- ContentValues cv = new ContentValues();
- cv.put(BrowserContract.SyncColumns.IS_DELETED, 1);
- db.updateByGuid(delete0.guid, cv);
- db.updateByGuid(delete1.guid, cv);
-
- final DefaultCleanDelegate delegate = new DefaultCleanDelegate() {
- public void onCleaned(Repository repo) {
- performNotify();
- }
- };
-
- final Runnable cleanRunnable = cleanRunnable(
- getRepository(),
- true,
- getApplicationContext(),
- delegate);
-
- performWait(cleanRunnable);
- performWait(fetchAllRunnable(session, preparedExpectFetchDelegate(new Record[] { keep0, keep1, keep2})));
- closeDataAccessor(db);
- dispose(session);
- }
-
- /*
- * Tests for guidsSince
- */
- protected void guidsSinceReturnMultipleRecords(Record record0, Record record1) {
- RepositorySession session = createAndBeginSession();
- long timestamp = System.currentTimeMillis();
-
- String[] expected = new String[2];
- expected[0] = record0.guid;
- expected[1] = record1.guid;
-
- Logger.debug(getName(), "Storing two records...");
- performWait(storeManyRunnable(session, new Record[] { record0, record1 }));
- Logger.debug(getName(), "Getting guids since " + timestamp + "; expecting " + expected.length);
- performWait(guidsSinceRunnable(session, timestamp, expected));
- dispose(session);
- }
-
- protected void guidsSinceReturnNoRecords(Record record0) {
- RepositorySession session = createAndBeginSession();
-
- // Store 1 record in the past.
- performWait(storeRunnable(session, record0));
-
- String[] expected = {};
- performWait(guidsSinceRunnable(session, System.currentTimeMillis() + 1000, expected));
- dispose(session);
- }
-
- /*
- * Tests for fetchSince
- */
- protected void fetchSinceOneRecord(Record record0, Record record1) {
- RepositorySession session = createAndBeginSession();
-
- performWait(storeRunnable(session, record0));
- long timestamp = System.currentTimeMillis();
- Logger.debug("fetchSinceOneRecord", "Entering synchronized section. Timestamp " + timestamp);
- synchronized(this) {
- try {
- wait(1000);
- } catch (InterruptedException e) {
- Logger.warn("fetchSinceOneRecord", "Interrupted.", e);
- }
- }
- Logger.debug("fetchSinceOneRecord", "Storing.");
- performWait(storeRunnable(session, record1));
-
- Logger.debug("fetchSinceOneRecord", "Fetching record 1.");
- String[] expectedOne = new String[] { record1.guid };
- performWait(fetchSinceRunnable(session, timestamp + 10, expectedOne));
-
- Logger.debug("fetchSinceOneRecord", "Fetching both, relying on inclusiveness.");
- String[] expectedBoth = new String[] { record0.guid, record1.guid };
- performWait(fetchSinceRunnable(session, timestamp - 3000, expectedBoth));
-
- Logger.debug("fetchSinceOneRecord", "Done.");
- dispose(session);
- }
-
- protected void fetchSinceReturnNoRecords(Record record) {
- RepositorySession session = createAndBeginSession();
-
- performWait(storeRunnable(session, record));
-
- long timestamp = System.currentTimeMillis();
-
- performWait(fetchSinceRunnable(session, timestamp + 2000, new String[] {}));
- dispose(session);
- }
-
- protected void fetchOneRecordByGuid(Record record0, Record record1) {
- RepositorySession session = createAndBeginSession();
-
- Record[] store = new Record[] { record0, record1 };
- performWait(storeManyRunnable(session, store));
-
- String[] guids = new String[] { record0.guid };
- Record[] expected = new Record[] { record0 };
- performWait(fetchRunnable(session, guids, expected));
- dispose(session);
- }
-
- protected void fetchMultipleRecordsByGuids(Record record0,
- Record record1, Record record2) {
- RepositorySession session = createAndBeginSession();
-
- Record[] store = new Record[] { record0, record1, record2 };
- performWait(storeManyRunnable(session, store));
-
- String[] guids = new String[] { record0.guid, record2.guid };
- Record[] expected = new Record[] { record0, record2 };
- performWait(fetchRunnable(session, guids, expected));
- dispose(session);
- }
-
- protected void fetchNoRecordByGuid(Record record) {
- RepositorySession session = createAndBeginSession();
-
- performWait(storeRunnable(session, record));
- performWait(fetchRunnable(session,
- new String[] { Utils.generateGuid() },
- new Record[] {}));
- dispose(session);
- }
-
- /*
- * Test wipe
- */
- protected void doWipe(final Record record0, final Record record1) {
- final RepositorySession session = createAndBeginSession();
- final Runnable run = new Runnable() {
- @Override
- public void run() {
- session.wipe(new RepositorySessionWipeDelegate() {
- public void onWipeSucceeded() {
- performNotify();
- }
- public void onWipeFailed(Exception ex) {
- fail("wipe should have succeeded");
- performNotify();
- }
- @Override
- public RepositorySessionWipeDelegate deferredWipeDelegate(final ExecutorService executor) {
- final RepositorySessionWipeDelegate self = this;
- return new RepositorySessionWipeDelegate() {
-
- @Override
- public void onWipeSucceeded() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- self.onWipeSucceeded();
- }}).start();
- }
-
- @Override
- public void onWipeFailed(final Exception ex) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- self.onWipeFailed(ex);
- }}).start();
- }
-
- @Override
- public RepositorySessionWipeDelegate deferredWipeDelegate(ExecutorService newExecutor) {
- if (newExecutor == executor) {
- return this;
- }
- throw new IllegalArgumentException("Can't re-defer this delegate.");
- }
- };
- }
- });
- }
- };
-
- // Store 2 records.
- Record[] records = new Record[] { record0, record1 };
- performWait(storeManyRunnable(session, records));
- performWait(fetchAllRunnable(session, records));
-
- // Wipe.
- performWait(run);
- dispose(session);
- }
-
- /*
- * TODO adding or subtracting from lastModified timestamps does NOTHING
- * since it gets overwritten when we store stuff. See other tests
- * for ways to do this properly.
- */
-
- /*
- * Record being stored has newer timestamp than existing local record, local
- * record has not been modified since last sync.
- */
- protected void remoteNewerTimeStamp(Record local, Record remote) {
- final RepositorySession session = createAndBeginSession();
-
- // Record existing and hasn't changed since before lastSync.
- // Automatically will be assigned lastModified = current time.
- performWait(storeRunnable(session, local));
-
- remote.guid = local.guid;
-
- // Get the timestamp and make remote newer than it
- ExpectFetchDelegate timestampDelegate = preparedExpectFetchDelegate(new Record[] { local });
- performWait(fetchRunnable(session, new String[] { remote.guid }, timestampDelegate));
- remote.lastModified = timestampDelegate.records.get(0).lastModified + 1000;
- performWait(storeRunnable(session, remote));
-
- Record[] expected = new Record[] { remote };
- ExpectFetchDelegate delegate = preparedExpectFetchDelegate(expected);
- performWait(fetchAllRunnable(session, delegate));
- dispose(session);
- }
-
- /*
- * Local record has a newer timestamp than the record being stored. For now,
- * we just take newer (local) record)
- */
- protected void localNewerTimeStamp(Record local, Record remote) {
- final RepositorySession session = createAndBeginSession();
-
- performWait(storeRunnable(session, local));
-
- remote.guid = local.guid;
-
- // Get the timestamp and make remote older than it
- ExpectFetchDelegate timestampDelegate = preparedExpectFetchDelegate(new Record[] { local });
- performWait(fetchRunnable(session, new String[] { remote.guid }, timestampDelegate));
- remote.lastModified = timestampDelegate.records.get(0).lastModified - 1000;
- performWait(storeRunnable(session, remote));
-
- // Do a fetch and make sure that we get back the local record.
- Record[] expected = new Record[] { local };
- performWait(fetchAllRunnable(session, preparedExpectFetchDelegate(expected)));
- dispose(session);
- }
-
- /*
- * Insert a record that is marked as deleted, remote has newer timestamp
- */
- protected void deleteRemoteNewer(Record local, Record remote) {
- final RepositorySession session = createAndBeginSession();
-
- // Record existing and hasn't changed since before lastSync.
- // Automatically will be assigned lastModified = current time.
- performWait(storeRunnable(session, local));
-
- // Pass the same record to store, but mark it deleted and modified
- // more recently
- ExpectFetchDelegate timestampDelegate = preparedExpectFetchDelegate(new Record[] { local });
- performWait(fetchRunnable(session, new String[] { local.guid }, timestampDelegate));
- remote.lastModified = timestampDelegate.records.get(0).lastModified + 1000;
- remote.deleted = true;
- remote.guid = local.guid;
- performWait(storeRunnable(session, remote));
-
- performWait(fetchAllRunnable(session, preparedExpectFetchDelegate(new Record[]{})));
- dispose(session);
- }
-
- // Store two records that are identical (this has different meanings based on the
- // type of record) other than their guids. The record existing locally already
- // should have its guid replaced (the assumption is that the record existed locally
- // and then sync was enabled and this record existed on another sync'd device).
- public void storeIdenticalExceptGuid(Record record0) {
- Logger.debug("storeIdenticalExceptGuid", "Started.");
- final RepositorySession session = createAndBeginSession();
- Logger.debug("storeIdenticalExceptGuid", "Session is " + session);
- performWait(storeRunnable(session, record0));
- Logger.debug("storeIdenticalExceptGuid", "Stored record0.");
- DefaultFetchDelegate timestampDelegate = getTimestampDelegate(record0.guid);
-
- performWait(fetchRunnable(session, new String[] { record0.guid }, timestampDelegate));
- Logger.debug("storeIdenticalExceptGuid", "fetchRunnable done.");
- record0.lastModified = timestampDelegate.records.get(0).lastModified + 3000;
- record0.guid = Utils.generateGuid();
- Logger.debug("storeIdenticalExceptGuid", "Storing modified...");
- performWait(storeRunnable(session, record0));
- Logger.debug("storeIdenticalExceptGuid", "Stored modified.");
-
- Record[] expected = new Record[] { record0 };
- performWait(fetchAllRunnable(session, preparedExpectFetchDelegate(expected)));
- Logger.debug("storeIdenticalExceptGuid", "Fetched all. Returning.");
- dispose(session);
- }
-
- // Special delegate so that we don't verify parenting is correct since
- // at some points it won't be since parent folder hasn't been stored.
- private DefaultFetchDelegate getTimestampDelegate(final String guid) {
- return new DefaultFetchDelegate() {
- @Override
- public void onFetchCompleted(final long fetchEnd) {
- assertEquals(guid, this.records.get(0).guid);
- performNotify();
- }
- };
- }
-
- /*
- * Insert a record that is marked as deleted, local has newer timestamp
- * and was not marked deleted (so keep it)
- */
- protected void deleteLocalNewer(Record local, Record remote) {
- Logger.debug("deleteLocalNewer", "Begin.");
- final RepositorySession session = createAndBeginSession();
-
- Logger.debug("deleteLocalNewer", "Storing local...");
- performWait(storeRunnable(session, local));
-
- // Create an older version of a record with the same GUID.
- remote.guid = local.guid;
-
- Logger.debug("deleteLocalNewer", "Fetching...");
-
- // Get the timestamp and make remote older than it
- Record[] expected = new Record[] { local };
- ExpectFetchDelegate timestampDelegate = preparedExpectFetchDelegate(expected);
- performWait(fetchRunnable(session, new String[] { remote.guid }, timestampDelegate));
-
- Logger.debug("deleteLocalNewer", "Fetched.");
- remote.lastModified = timestampDelegate.records.get(0).lastModified - 1000;
-
- Logger.debug("deleteLocalNewer", "Last modified is " + remote.lastModified);
- remote.deleted = true;
- Logger.debug("deleteLocalNewer", "Storing deleted...");
- performWait(quietStoreRunnable(session, remote)); // This appears to do a lot of work...?!
-
- // Do a fetch and make sure that we get back the first (local) record.
- performWait(fetchAllRunnable(session, preparedExpectFetchDelegate(expected)));
- Logger.debug("deleteLocalNewer", "Fetched and done!");
- dispose(session);
- }
-
- /*
- * Insert a record that is marked as deleted, record never existed locally
- */
- protected void deleteRemoteLocalNonexistent(Record remote) {
- final RepositorySession session = createAndBeginSession();
-
- long timestamp = 1000000000;
-
- // Pass a record marked deleted to store, doesn't exist locally
- remote.lastModified = timestamp;
- remote.deleted = true;
- performWait(quietStoreRunnable(session, remote));
-
- ExpectFetchDelegate delegate = preparedExpectFetchDelegate(new Record[]{});
- performWait(fetchAllRunnable(session, delegate));
- dispose(session);
- }
-
- /*
- * Tests that don't require specific records based on type of repository.
- * These tests don't need to be overriden in subclasses, they will just work.
- */
- public void testCreateSessionNullContext() {
- Logger.debug(LOG_TAG, "In testCreateSessionNullContext.");
- Repository repo = getRepository();
- try {
- repo.createSession(new DefaultSessionCreationDelegate(), null);
- fail("Should throw.");
- } catch (Exception ex) {
- assertNotNull(ex);
- }
- }
-
- public void testStoreNullRecord() {
- final RepositorySession session = createAndBeginSession();
- try {
- session.setStoreDelegate(new DefaultStoreDelegate());
- session.store(null);
- fail("Should throw.");
- } catch (Exception ex) {
- assertNotNull(ex);
- }
- dispose(session);
- }
-
- public void testFetchNoGuids() {
- final RepositorySession session = createAndBeginSession();
- performWait(fetchRunnable(session, new String[] {}, new ExpectInvalidRequestFetchDelegate()));
- dispose(session);
- }
-
- public void testFetchNullGuids() {
- final RepositorySession session = createAndBeginSession();
- performWait(fetchRunnable(session, null, new ExpectInvalidRequestFetchDelegate()));
- dispose(session);
- }
-
- public void testBeginOnNewSession() {
- final RepositorySession session = createSession();
- performWait(beginRunnable(session, new ExpectBeginDelegate()));
- dispose(session);
- }
-
- public void testBeginOnRunningSession() {
- final RepositorySession session = createAndBeginSession();
- try {
- session.begin(new ExpectBeginFailDelegate());
- } catch (InvalidSessionTransitionException e) {
- dispose(session);
- return;
- }
- fail("Should have caught InvalidSessionTransitionException.");
- }
-
- public void testBeginOnFinishedSession() throws InactiveSessionException {
- final RepositorySession session = createAndBeginSession();
- performWait(finishRunnable(session, new ExpectFinishDelegate()));
- try {
- session.begin(new ExpectBeginFailDelegate());
- } catch (InvalidSessionTransitionException e) {
- Logger.debug(getName(), "Yay! Got an exception.", e);
- dispose(session);
- return;
- } catch (Exception e) {
- Logger.debug(getName(), "Yay! Got an exception.", e);
- dispose(session);
- return;
- }
- fail("Should have caught InvalidSessionTransitionException.");
- }
-
- public void testFinishOnFinishedSession() throws InactiveSessionException {
- final RepositorySession session = createAndBeginSession();
- performWait(finishRunnable(session, new ExpectFinishDelegate()));
- try {
- session.finish(new ExpectFinishFailDelegate());
- } catch (InactiveSessionException e) {
- dispose(session);
- return;
- }
- fail("Should have caught InactiveSessionException.");
- }
-
- public void testFetchOnInactiveSession() throws InactiveSessionException {
- final RepositorySession session = createSession();
- try {
- session.fetch(new String[] { Utils.generateGuid() }, new DefaultFetchDelegate());
- } catch (InactiveSessionException e) {
- // Yay.
- dispose(session);
- return;
- };
- fail("Should have caught InactiveSessionException.");
- }
-
- public void testFetchOnFinishedSession() {
- final RepositorySession session = createAndBeginSession();
- Logger.debug(getName(), "Finishing...");
- performWait(finishRunnable(session, new ExpectFinishDelegate()));
- try {
- session.fetch(new String[] { Utils.generateGuid() }, new DefaultFetchDelegate());
- } catch (InactiveSessionException e) {
- // Yay.
- dispose(session);
- return;
- };
- fail("Should have caught InactiveSessionException.");
- }
-
- public void testGuidsSinceOnUnstartedSession() {
- final RepositorySession session = createSession();
- Runnable run = new Runnable() {
- @Override
- public void run() {
- session.guidsSince(System.currentTimeMillis(),
- new RepositorySessionGuidsSinceDelegate() {
- public void onGuidsSinceSucceeded(String[] guids) {
- fail("Session inactive, should fail");
- performNotify();
- }
-
- public void onGuidsSinceFailed(Exception ex) {
- verifyInactiveException(ex);
- performNotify();
- }
- });
- }
- };
- performWait(run);
- dispose(session);
- }
-
- private static void verifyInactiveException(Exception ex) {
- if (!(ex instanceof InactiveSessionException)) {
- fail("Wrong exception type");
- }
- }
-
- protected void closeDataAccessor(AndroidBrowserRepositoryDataAccessor dataAccessor) {
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java
deleted file mode 100644
index 71563a46c..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java
+++ /dev/null
@@ -1,636 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import java.util.ArrayList;
-
-import org.json.simple.JSONArray;
-import org.mozilla.gecko.background.sync.helpers.BookmarkHelpers;
-import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectFetchSinceDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectFinishDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectGuidsSinceDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectInvalidTypeStoreDelegate;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.NullCursorException;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksDataAccessor;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepository;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepositorySession;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepository;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepositoryDataAccessor;
-import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.mozilla.gecko.sync.repositories.android.RepoUtils;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-
-public class TestAndroidBrowserBookmarksRepository extends AndroidBrowserRepositoryTestCase {
-
- @Override
- protected AndroidBrowserRepository getRepository() {
-
- /**
- * Override this chain in order to avoid our test code having to create two
- * sessions all the time.
- */
- return new AndroidBrowserBookmarksRepository() {
- @Override
- protected void sessionCreator(RepositorySessionCreationDelegate delegate, Context context) {
- AndroidBrowserBookmarksRepositorySession session;
- session = new AndroidBrowserBookmarksRepositorySession(this, context) {
- @Override
- protected synchronized void trackGUID(String guid) {
- System.out.println("Ignoring trackGUID call: this is a test!");
- }
- };
- delegate.deferredCreationDelegate().onSessionCreated(session);
- }
- };
- }
-
- @Override
- protected AndroidBrowserRepositoryDataAccessor getDataAccessor() {
- return new AndroidBrowserBookmarksDataAccessor(getApplicationContext());
- }
-
- /**
- * Hook to return an ExpectFetchDelegate, possibly with special GUIDs ignored.
- */
- @Override
- public ExpectFetchDelegate preparedExpectFetchDelegate(Record[] expected) {
- ExpectFetchDelegate delegate = new ExpectFetchDelegate(expected);
- delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet());
- return delegate;
- }
-
- /**
- * Hook to return an ExpectGuidsSinceDelegate expecting only special GUIDs (if there are any).
- */
- public ExpectGuidsSinceDelegate preparedExpectOnlySpecialGuidsSinceDelegate() {
- ExpectGuidsSinceDelegate delegate = new ExpectGuidsSinceDelegate(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet().toArray(new String[] {}));
- return delegate;
- }
-
- /**
- * Hook to return an ExpectGuidsSinceDelegate, possibly with special GUIDs ignored.
- */
- @Override
- public ExpectGuidsSinceDelegate preparedExpectGuidsSinceDelegate(String[] expected) {
- ExpectGuidsSinceDelegate delegate = new ExpectGuidsSinceDelegate(expected);
- delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet());
- return delegate;
- }
-
- /**
- * Hook to return an ExpectFetchSinceDelegate, possibly with special GUIDs ignored.
- */
- public ExpectFetchSinceDelegate preparedExpectFetchSinceDelegate(long timestamp, String[] expected) {
- ExpectFetchSinceDelegate delegate = new ExpectFetchSinceDelegate(timestamp, expected);
- delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet());
- return delegate;
- }
-
- // NOTE NOTE NOTE
- // Must store folder before records if we we are checking that the
- // records returned are the same as those sent in. If the folder isn't stored
- // first, the returned records won't be identical to those stored because we
- // aren't able to find the parent name/guid when we do a fetch. If you don't want
- // to store a folder first, store your record in "mobile" or one of the folders
- // that always exists.
-
- public void testFetchOneWithChildren() {
- BookmarkRecord folder = BookmarkHelpers.createFolder1();
- BookmarkRecord bookmark1 = BookmarkHelpers.createBookmark1();
- BookmarkRecord bookmark2 = BookmarkHelpers.createBookmark2();
-
- RepositorySession session = createAndBeginSession();
-
- Record[] records = new Record[] { folder, bookmark1, bookmark2 };
- performWait(storeManyRunnable(session, records));
-
- AndroidBrowserRepositoryDataAccessor helper = getDataAccessor();
- helper.dumpDB();
- closeDataAccessor(helper);
-
- String[] guids = new String[] { folder.guid };
- Record[] expected = new Record[] { folder };
- performWait(fetchRunnable(session, guids, expected));
- dispose(session);
- }
-
- @Override
- public void testFetchAll() {
- Record[] expected = new Record[3];
- expected[0] = BookmarkHelpers.createFolder1();
- expected[1] = BookmarkHelpers.createBookmark1();
- expected[2] = BookmarkHelpers.createBookmark2();
- basicFetchAllTest(expected);
- }
-
- @Override
- public void testGuidsSinceReturnMultipleRecords() {
- BookmarkRecord record0 = BookmarkHelpers.createBookmark1();
- BookmarkRecord record1 = BookmarkHelpers.createBookmark2();
- guidsSinceReturnMultipleRecords(record0, record1);
- }
-
- @Override
- public void testGuidsSinceReturnNoRecords() {
- guidsSinceReturnNoRecords(BookmarkHelpers.createBookmarkInMobileFolder1());
- }
-
- @Override
- public void testFetchSinceOneRecord() {
- fetchSinceOneRecord(BookmarkHelpers.createBookmarkInMobileFolder1(),
- BookmarkHelpers.createBookmarkInMobileFolder2());
- }
-
- @Override
- public void testFetchSinceReturnNoRecords() {
- fetchSinceReturnNoRecords(BookmarkHelpers.createBookmark1());
- }
-
- @Override
- public void testFetchOneRecordByGuid() {
- fetchOneRecordByGuid(BookmarkHelpers.createBookmarkInMobileFolder1(),
- BookmarkHelpers.createBookmarkInMobileFolder2());
- }
-
- @Override
- public void testFetchMultipleRecordsByGuids() {
- BookmarkRecord record0 = BookmarkHelpers.createFolder1();
- BookmarkRecord record1 = BookmarkHelpers.createBookmark1();
- BookmarkRecord record2 = BookmarkHelpers.createBookmark2();
- fetchMultipleRecordsByGuids(record0, record1, record2);
- }
-
- @Override
- public void testFetchNoRecordByGuid() {
- fetchNoRecordByGuid(BookmarkHelpers.createBookmark1());
- }
-
-
- @Override
- public void testWipe() {
- doWipe(BookmarkHelpers.createBookmarkInMobileFolder1(),
- BookmarkHelpers.createBookmarkInMobileFolder2());
- }
-
- @Override
- public void testStore() {
- basicStoreTest(BookmarkHelpers.createBookmark1());
- }
-
-
- public void testStoreFolder() {
- basicStoreTest(BookmarkHelpers.createFolder1());
- }
-
- /**
- * TODO: 2011-12-24, tests disabled because we no longer fail
- * a store call if we get an unknown record type.
- */
- /*
- * Test storing each different type of Bookmark record.
- * We expect any records with type other than "bookmark"
- * or "folder" to fail. For now we throw these away.
- */
- /*
- public void testStoreMicrosummary() {
- basicStoreFailTest(BookmarkHelpers.createMicrosummary());
- }
-
- public void testStoreQuery() {
- basicStoreFailTest(BookmarkHelpers.createQuery());
- }
-
- public void testStoreLivemark() {
- basicStoreFailTest(BookmarkHelpers.createLivemark());
- }
-
- public void testStoreSeparator() {
- basicStoreFailTest(BookmarkHelpers.createSeparator());
- }
- */
-
- protected void basicStoreFailTest(Record record) {
- final RepositorySession session = createAndBeginSession();
- performWait(storeRunnable(session, record, new ExpectInvalidTypeStoreDelegate()));
- dispose(session);
- }
-
- /*
- * Re-parenting tests
- */
- // Insert two records missing parent, then insert their parent.
- // Make sure they end up with the correct parent on fetch.
- public void testBasicReparenting() throws InactiveSessionException {
- Record[] expected = new Record[] {
- BookmarkHelpers.createBookmark1(),
- BookmarkHelpers.createBookmark2(),
- BookmarkHelpers.createFolder1()
- };
- doMultipleFolderReparentingTest(expected);
- }
-
- // Insert 3 folders and 4 bookmarks in different orders
- // and make sure they come out parented correctly
- public void testMultipleFolderReparenting1() throws InactiveSessionException {
- Record[] expected = new Record[] {
- BookmarkHelpers.createBookmark1(),
- BookmarkHelpers.createBookmark2(),
- BookmarkHelpers.createBookmark3(),
- BookmarkHelpers.createFolder1(),
- BookmarkHelpers.createBookmark4(),
- BookmarkHelpers.createFolder3(),
- BookmarkHelpers.createFolder2(),
- };
- doMultipleFolderReparentingTest(expected);
- }
-
- public void testMultipleFolderReparenting2() throws InactiveSessionException {
- Record[] expected = new Record[] {
- BookmarkHelpers.createBookmark1(),
- BookmarkHelpers.createBookmark2(),
- BookmarkHelpers.createBookmark3(),
- BookmarkHelpers.createFolder1(),
- BookmarkHelpers.createBookmark4(),
- BookmarkHelpers.createFolder3(),
- BookmarkHelpers.createFolder2(),
- };
- doMultipleFolderReparentingTest(expected);
- }
-
- public void testMultipleFolderReparenting3() throws InactiveSessionException {
- Record[] expected = new Record[] {
- BookmarkHelpers.createBookmark1(),
- BookmarkHelpers.createBookmark2(),
- BookmarkHelpers.createBookmark3(),
- BookmarkHelpers.createFolder1(),
- BookmarkHelpers.createBookmark4(),
- BookmarkHelpers.createFolder3(),
- BookmarkHelpers.createFolder2(),
- };
- doMultipleFolderReparentingTest(expected);
- }
-
- private void doMultipleFolderReparentingTest(Record[] expected) throws InactiveSessionException {
- final RepositorySession session = createAndBeginSession();
- doStore(session, expected);
- ExpectFetchDelegate delegate = preparedExpectFetchDelegate(expected);
- performWait(fetchAllRunnable(session, delegate));
- performWait(finishRunnable(session, new ExpectFinishDelegate()));
- }
-
- /*
- * Test storing identical records with different guids.
- * For bookmarks identical is defined by the following fields
- * being the same: title, uri, type, parentName
- */
- @Override
- public void testStoreIdenticalExceptGuid() {
- storeIdenticalExceptGuid(BookmarkHelpers.createBookmarkInMobileFolder1());
- }
-
- /*
- * More complicated situation in which we insert a folder
- * followed by a couple of its children. We then insert
- * the folder again but with a different guid. Children
- * must still get correct parent when they are fetched.
- * Store a record after with the new guid as the parent
- * and make sure it works as well.
- */
- public void testStoreIdenticalFoldersWithChildren() {
- final RepositorySession session = createAndBeginSession();
- Record record0 = BookmarkHelpers.createFolder1();
-
- // Get timestamp so that the conflicting folder that we store below is newer.
- // Children won't come back on this fetch since they haven't been stored, so remove them
- // before our delegate throws a failure.
- BookmarkRecord rec0 = (BookmarkRecord) record0;
- rec0.children = new JSONArray();
- performWait(storeRunnable(session, record0));
-
- ExpectFetchDelegate timestampDelegate = preparedExpectFetchDelegate(new Record[] { rec0 });
- performWait(fetchRunnable(session, new String[] { record0.guid }, timestampDelegate));
-
- AndroidBrowserRepositoryDataAccessor helper = getDataAccessor();
- helper.dumpDB();
- closeDataAccessor(helper);
-
- Record record1 = BookmarkHelpers.createBookmark1();
- Record record2 = BookmarkHelpers.createBookmark2();
- Record record3 = BookmarkHelpers.createFolder1();
- BookmarkRecord bmk3 = (BookmarkRecord) record3;
- record3.guid = Utils.generateGuid();
- record3.lastModified = timestampDelegate.records.get(0).lastModified + 3000;
- assertFalse(record0.guid.equals(record3.guid));
-
- // Store an additional record after inserting the duplicate folder
- // with new GUID. Make sure it comes back as well.
- Record record4 = BookmarkHelpers.createBookmark3();
- BookmarkRecord bmk4 = (BookmarkRecord) record4;
- bmk4.parentID = bmk3.guid;
- bmk4.parentName = bmk3.parentName;
-
- doStore(session, new Record[] {
- record1, record2, record3, bmk4
- });
- BookmarkRecord bmk1 = (BookmarkRecord) record1;
- bmk1.parentID = record3.guid;
- BookmarkRecord bmk2 = (BookmarkRecord) record2;
- bmk2.parentID = record3.guid;
- Record[] expect = new Record[] {
- bmk1, bmk2, record3
- };
- fetchAllRunnable(session, preparedExpectFetchDelegate(expect));
- dispose(session);
- }
-
- @Override
- public void testRemoteNewerTimeStamp() {
- BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1();
- BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2();
- remoteNewerTimeStamp(local, remote);
- }
-
- @Override
- public void testLocalNewerTimeStamp() {
- BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1();
- BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2();
- localNewerTimeStamp(local, remote);
- }
-
- @Override
- public void testDeleteRemoteNewer() {
- BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1();
- BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2();
- deleteRemoteNewer(local, remote);
- }
-
- @Override
- public void testDeleteLocalNewer() {
- BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1();
- BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2();
- deleteLocalNewer(local, remote);
- }
-
- @Override
- public void testDeleteRemoteLocalNonexistent() {
- BookmarkRecord remote = BookmarkHelpers.createBookmark2();
- deleteRemoteLocalNonexistent(remote);
- }
-
- @Override
- public void testCleanMultipleRecords() {
- cleanMultipleRecords(
- BookmarkHelpers.createBookmarkInMobileFolder1(),
- BookmarkHelpers.createBookmarkInMobileFolder2(),
- BookmarkHelpers.createBookmark1(),
- BookmarkHelpers.createBookmark2(),
- BookmarkHelpers.createFolder1());
- }
-
- public void testBasicPositioning() {
- final RepositorySession session = createAndBeginSession();
- Record[] expected = new Record[] {
- BookmarkHelpers.createBookmark1(),
- BookmarkHelpers.createFolder1(),
- BookmarkHelpers.createBookmark2()
- };
- System.out.println("TEST: Inserting " + expected[0].guid + ", "
- + expected[1].guid + ", "
- + expected[2].guid);
- doStore(session, expected);
-
- ExpectFetchDelegate delegate = preparedExpectFetchDelegate(expected);
- performWait(fetchAllRunnable(session, delegate));
-
- int found = 0;
- boolean foundFolder = false;
- for (int i = 0; i < delegate.records.size(); i++) {
- BookmarkRecord rec = (BookmarkRecord) delegate.records.get(i);
- if (rec.guid.equals(expected[0].guid)) {
- assertEquals(0, ((BookmarkRecord) delegate.records.get(i)).androidPosition);
- found++;
- } else if (rec.guid.equals(expected[2].guid)) {
- assertEquals(1, ((BookmarkRecord) delegate.records.get(i)).androidPosition);
- found++;
- } else if (rec.guid.equals(expected[1].guid)) {
- foundFolder = true;
- } else {
- System.out.println("TEST: found " + rec.guid);
- }
- }
- assertTrue(foundFolder);
- assertEquals(2, found);
- dispose(session);
- }
-
- public void testSqlInjectPurgeDeleteAndUpdateByGuid() {
- // Some setup.
- RepositorySession session = createAndBeginSession();
- AndroidBrowserRepositoryDataAccessor db = getDataAccessor();
-
- ContentValues cv = new ContentValues();
- cv.put(BrowserContract.SyncColumns.IS_DELETED, 1);
-
- // Create and insert 2 bookmarks, 2nd one is evil (attempts injection).
- BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1();
- BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2();
- bmk2.guid = "' or '1'='1";
-
- db.insert(bmk1);
- db.insert(bmk2);
-
- // Test 1 - updateByGuid() handles evil bookmarks correctly.
- db.updateByGuid(bmk2.guid, cv);
-
- // Query bookmarks table.
- Cursor cur = getAllBookmarks();
- int numBookmarks = cur.getCount();
-
- // Ensure only the evil bookmark is marked for deletion.
- try {
- cur.moveToFirst();
- while (!cur.isAfterLast()) {
- String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID);
- boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1;
-
- if (guid.equals(bmk2.guid)) {
- assertTrue(deleted);
- } else {
- assertFalse(deleted);
- }
- cur.moveToNext();
- }
- } finally {
- cur.close();
- }
-
- // Test 2 - Ensure purgeDelete()'s call to delete() deletes only 1 record.
- try {
- db.purgeDeleted();
- } catch (NullCursorException e) {
- e.printStackTrace();
- }
-
- cur = getAllBookmarks();
- int numBookmarksAfterDeletion = cur.getCount();
-
- // Ensure we have only 1 deleted row.
- assertEquals(numBookmarksAfterDeletion, numBookmarks - 1);
-
- // Ensure only the evil bookmark is deleted.
- try {
- cur.moveToFirst();
- while (!cur.isAfterLast()) {
- String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID);
- boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1;
-
- if (guid.equals(bmk2.guid)) {
- fail("Evil guid was not deleted!");
- } else {
- assertFalse(deleted);
- }
- cur.moveToNext();
- }
- } finally {
- cur.close();
- }
- dispose(session);
- }
-
- protected Cursor getAllBookmarks() {
- Context context = getApplicationContext();
- Cursor cur = context.getContentResolver().query(BrowserContractHelpers.BOOKMARKS_CONTENT_URI,
- BrowserContractHelpers.BookmarkColumns, null, null, null);
- return cur;
- }
-
- public void testSqlInjectFetch() {
- // Some setup.
- RepositorySession session = createAndBeginSession();
- AndroidBrowserRepositoryDataAccessor db = getDataAccessor();
-
- // Create and insert 4 bookmarks, last one is evil (attempts injection).
- BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1();
- BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2();
- BookmarkRecord bmk3 = BookmarkHelpers.createBookmark3();
- BookmarkRecord bmk4 = BookmarkHelpers.createBookmark4();
- bmk4.guid = "' or '1'='1";
-
- db.insert(bmk1);
- db.insert(bmk2);
- db.insert(bmk3);
- db.insert(bmk4);
-
- // Perform a fetch.
- Cursor cur = null;
- try {
- cur = db.fetch(new String[] { bmk3.guid, bmk4.guid });
- } catch (NullCursorException e1) {
- e1.printStackTrace();
- }
-
- // Ensure the correct number (2) of records were fetched and with the correct guids.
- if (cur == null) {
- fail("No records were fetched.");
- }
-
- try {
- if (cur.getCount() != 2) {
- fail("Wrong number of guids fetched!");
- }
- cur.moveToFirst();
- while (!cur.isAfterLast()) {
- String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID);
- if (!guid.equals(bmk3.guid) && !guid.equals(bmk4.guid)) {
- fail("Wrong guids were fetched!");
- }
- cur.moveToNext();
- }
- } finally {
- cur.close();
- }
- dispose(session);
- }
-
- public void testSqlInjectDelete() {
- // Some setup.
- RepositorySession session = createAndBeginSession();
- AndroidBrowserRepositoryDataAccessor db = getDataAccessor();
-
- // Create and insert 2 bookmarks, 2nd one is evil (attempts injection).
- BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1();
- BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2();
- bmk2.guid = "' or '1'='1";
-
- db.insert(bmk1);
- db.insert(bmk2);
-
- // Note size of table before delete.
- Cursor cur = getAllBookmarks();
- int numBookmarks = cur.getCount();
-
- db.purgeGuid(bmk2.guid);
-
- // Note size of table after delete.
- cur = getAllBookmarks();
- int numBookmarksAfterDelete = cur.getCount();
-
- // Ensure size of table after delete is *only* 1 less.
- assertEquals(numBookmarksAfterDelete, numBookmarks - 1);
-
- try {
- cur.moveToFirst();
- while (!cur.isAfterLast()) {
- String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID);
- if (guid.equals(bmk2.guid)) {
- fail("Guid was not deleted!");
- }
- cur.moveToNext();
- }
- } finally {
- cur.close();
- }
- dispose(session);
- }
-
- /**
- * Verify that data accessor's bulkInsert actually inserts.
- * @throws NullCursorException
- */
- public void testBulkInsert() throws NullCursorException {
- RepositorySession session = createAndBeginSession();
- AndroidBrowserRepositoryDataAccessor db = getDataAccessor();
-
- // Have to set androidID of parent manually.
- Cursor cur = db.fetch(new String[] { "mobile" } );
- assertEquals(1, cur.getCount());
- cur.moveToFirst();
- int mobileAndroidID = RepoUtils.getIntFromCursor(cur, BrowserContract.Bookmarks._ID);
-
- BookmarkRecord bookmark1 = BookmarkHelpers.createBookmarkInMobileFolder1();
- BookmarkRecord bookmark2 = BookmarkHelpers.createBookmarkInMobileFolder2();
- bookmark1.androidParentID = mobileAndroidID;
- bookmark2.androidParentID = mobileAndroidID;
- ArrayList<Record> recordList = new ArrayList<Record>();
- recordList.add(bookmark1);
- recordList.add(bookmark2);
- db.bulkInsert(recordList);
-
- String[] guids = new String[] { bookmark1.guid, bookmark2.guid };
- Record[] expected = new Record[] { bookmark1, bookmark2 };
- performWait(fetchRunnable(session, guids, expected));
- dispose(session);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java
deleted file mode 100644
index ffde59575..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import java.util.ArrayList;
-
-import org.json.simple.JSONObject;
-import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate;
-import org.mozilla.gecko.background.sync.helpers.HistoryHelpers;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.NullCursorException;
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserHistoryDataAccessor;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserHistoryRepository;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserHistoryRepositorySession;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepository;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepositoryDataAccessor;
-import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.mozilla.gecko.sync.repositories.android.RepoUtils;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class TestAndroidBrowserHistoryRepository extends AndroidBrowserRepositoryTestCase {
-
- @Override
- protected AndroidBrowserRepository getRepository() {
-
- /**
- * Override this chain in order to avoid our test code having to create two
- * sessions all the time.
- */
- return new AndroidBrowserHistoryRepository() {
- @Override
- protected void sessionCreator(RepositorySessionCreationDelegate delegate, Context context) {
- AndroidBrowserHistoryRepositorySession session;
- session = new AndroidBrowserHistoryRepositorySession(this, context) {
- @Override
- protected synchronized void trackGUID(String guid) {
- System.out.println("Ignoring trackGUID call: this is a test!");
- }
- };
- delegate.onSessionCreated(session);
- }
- };
- }
-
- @Override
- protected AndroidBrowserRepositoryDataAccessor getDataAccessor() {
- return new AndroidBrowserHistoryDataAccessor(getApplicationContext());
- }
-
- @Override
- public void testFetchAll() {
- Record[] expected = new Record[2];
- expected[0] = HistoryHelpers.createHistory3();
- expected[1] = HistoryHelpers.createHistory2();
- basicFetchAllTest(expected);
- }
-
- /*
- * Test storing identical records with different guids.
- * For bookmarks identical is defined by the following fields
- * being the same: title, uri, type, parentName
- */
- @Override
- public void testStoreIdenticalExceptGuid() {
- storeIdenticalExceptGuid(HistoryHelpers.createHistory1());
- }
-
- @Override
- public void testCleanMultipleRecords() {
- cleanMultipleRecords(
- HistoryHelpers.createHistory1(),
- HistoryHelpers.createHistory2(),
- HistoryHelpers.createHistory3(),
- HistoryHelpers.createHistory4(),
- HistoryHelpers.createHistory5()
- );
- }
-
- @Override
- public void testGuidsSinceReturnMultipleRecords() {
- HistoryRecord record0 = HistoryHelpers.createHistory1();
- HistoryRecord record1 = HistoryHelpers.createHistory2();
- guidsSinceReturnMultipleRecords(record0, record1);
- }
-
- @Override
- public void testGuidsSinceReturnNoRecords() {
- guidsSinceReturnNoRecords(HistoryHelpers.createHistory3());
- }
-
- @Override
- public void testFetchSinceOneRecord() {
- fetchSinceOneRecord(HistoryHelpers.createHistory1(),
- HistoryHelpers.createHistory2());
- }
-
- @Override
- public void testFetchSinceReturnNoRecords() {
- fetchSinceReturnNoRecords(HistoryHelpers.createHistory3());
- }
-
- @Override
- public void testFetchOneRecordByGuid() {
- fetchOneRecordByGuid(HistoryHelpers.createHistory1(),
- HistoryHelpers.createHistory2());
- }
-
- @Override
- public void testFetchMultipleRecordsByGuids() {
- HistoryRecord record0 = HistoryHelpers.createHistory1();
- HistoryRecord record1 = HistoryHelpers.createHistory2();
- HistoryRecord record2 = HistoryHelpers.createHistory3();
- fetchMultipleRecordsByGuids(record0, record1, record2);
- }
-
- @Override
- public void testFetchNoRecordByGuid() {
- fetchNoRecordByGuid(HistoryHelpers.createHistory1());
- }
-
- @Override
- public void testWipe() {
- doWipe(HistoryHelpers.createHistory2(), HistoryHelpers.createHistory3());
- }
-
- @Override
- public void testStore() {
- basicStoreTest(HistoryHelpers.createHistory1());
- }
-
- @Override
- public void testRemoteNewerTimeStamp() {
- HistoryRecord local = HistoryHelpers.createHistory1();
- HistoryRecord remote = HistoryHelpers.createHistory2();
- remoteNewerTimeStamp(local, remote);
- }
-
- @Override
- public void testLocalNewerTimeStamp() {
- HistoryRecord local = HistoryHelpers.createHistory1();
- HistoryRecord remote = HistoryHelpers.createHistory2();
- localNewerTimeStamp(local, remote);
- }
-
- @Override
- public void testDeleteRemoteNewer() {
- HistoryRecord local = HistoryHelpers.createHistory1();
- HistoryRecord remote = HistoryHelpers.createHistory2();
- deleteRemoteNewer(local, remote);
- }
-
- @Override
- public void testDeleteLocalNewer() {
- HistoryRecord local = HistoryHelpers.createHistory1();
- HistoryRecord remote = HistoryHelpers.createHistory2();
- deleteLocalNewer(local, remote);
- }
-
- @Override
- public void testDeleteRemoteLocalNonexistent() {
- deleteRemoteLocalNonexistent(HistoryHelpers.createHistory2());
- }
-
- /**
- * Exists to provide access to record string logic.
- */
- protected class HelperHistorySession extends AndroidBrowserHistoryRepositorySession {
- public HelperHistorySession(Repository repository, Context context) {
- super(repository, context);
- }
-
- public boolean sameRecordString(HistoryRecord r1, HistoryRecord r2) {
- return buildRecordString(r1).equals(buildRecordString(r2));
- }
- }
-
- /**
- * Verifies that two history records with the same URI but different
- * titles will be reconciled locally.
- */
- public void testRecordStringCollisionAndEquality() {
- final AndroidBrowserHistoryRepository repo = new AndroidBrowserHistoryRepository();
- final HelperHistorySession testSession = new HelperHistorySession(repo, getApplicationContext());
-
- final long now = RepositorySession.now();
-
- final HistoryRecord record0 = new HistoryRecord(null, "history", now + 1, false);
- final HistoryRecord record1 = new HistoryRecord(null, "history", now + 2, false);
- final HistoryRecord record2 = new HistoryRecord(null, "history", now + 3, false);
-
- record0.histURI = "http://example.com/foo";
- record1.histURI = "http://example.com/foo";
- record2.histURI = "http://example.com/bar";
- record0.title = "Foo 0";
- record1.title = "Foo 1";
- record2.title = "Foo 2";
-
- // Ensure that two records with the same URI produce the same record string,
- // and two records with different URIs do not.
- assertTrue(testSession.sameRecordString(record0, record1));
- assertFalse(testSession.sameRecordString(record0, record2));
-
- // Two records are congruent if they have the same URI and their
- // identifiers match (which is why these all have null GUIDs).
- assertTrue(record0.congruentWith(record0));
- assertTrue(record0.congruentWith(record1));
- assertTrue(record1.congruentWith(record0));
- assertFalse(record0.congruentWith(record2));
- assertFalse(record1.congruentWith(record2));
- assertFalse(record2.congruentWith(record1));
- assertFalse(record2.congruentWith(record0));
-
- // None of these records are equal, because they have different titles.
- // (Except for being equal to themselves, of course.)
- assertTrue(record0.equalPayloads(record0));
- assertTrue(record1.equalPayloads(record1));
- assertTrue(record2.equalPayloads(record2));
- assertFalse(record0.equalPayloads(record1));
- assertFalse(record1.equalPayloads(record0));
- assertFalse(record1.equalPayloads(record2));
- }
-
- /*
- * Tests for adding some visits to a history record
- * and doing a fetch.
- */
- @SuppressWarnings("unchecked")
- public void testAddOneVisit() {
- final RepositorySession session = createAndBeginSession();
-
- HistoryRecord record0 = HistoryHelpers.createHistory3();
- performWait(storeRunnable(session, record0));
-
- // Add one visit to the count and put in a new
- // last visited date.
- ContentValues cv = new ContentValues();
- int visits = record0.visits.size() + 1;
- long newVisitTime = System.currentTimeMillis();
- cv.put(BrowserContract.History.VISITS, visits);
- cv.put(BrowserContract.History.DATE_LAST_VISITED, newVisitTime);
- final AndroidBrowserRepositoryDataAccessor dataAccessor = getDataAccessor();
- dataAccessor.updateByGuid(record0.guid, cv);
-
- // Add expected visit to record for verification.
- JSONObject expectedVisit = new JSONObject();
- expectedVisit.put("date", newVisitTime * 1000); // Microseconds.
- expectedVisit.put("type", 1L);
- record0.visits.add(expectedVisit);
-
- performWait(fetchRunnable(session, new String[] { record0.guid }, new ExpectFetchDelegate(new Record[] { record0 })));
- closeDataAccessor(dataAccessor);
- }
-
- @SuppressWarnings("unchecked")
- public void testAddMultipleVisits() {
- final RepositorySession session = createAndBeginSession();
-
- HistoryRecord record0 = HistoryHelpers.createHistory4();
- performWait(storeRunnable(session, record0));
-
- // Add three visits to the count and put in a new
- // last visited date.
- ContentValues cv = new ContentValues();
- int visits = record0.visits.size() + 3;
- long newVisitTime = System.currentTimeMillis();
- cv.put(BrowserContract.History.VISITS, visits);
- cv.put(BrowserContract.History.DATE_LAST_VISITED, newVisitTime);
- final AndroidBrowserRepositoryDataAccessor dataAccessor = getDataAccessor();
- dataAccessor.updateByGuid(record0.guid, cv);
-
- // Now shift to microsecond timing for visits.
- long newMicroVisitTime = newVisitTime * 1000;
-
- // Add expected visits to record for verification
- JSONObject expectedVisit = new JSONObject();
- expectedVisit.put("date", newMicroVisitTime);
- expectedVisit.put("type", 1L);
- record0.visits.add(expectedVisit);
- expectedVisit = new JSONObject();
- expectedVisit.put("date", newMicroVisitTime - 1000);
- expectedVisit.put("type", 1L);
- record0.visits.add(expectedVisit);
- expectedVisit = new JSONObject();
- expectedVisit.put("date", newMicroVisitTime - 2000);
- expectedVisit.put("type", 1L);
- record0.visits.add(expectedVisit);
-
- ExpectFetchDelegate delegate = new ExpectFetchDelegate(new Record[] { record0 });
- performWait(fetchRunnable(session, new String[] { record0.guid }, delegate));
-
- Record fetched = delegate.records.get(0);
- assertTrue(record0.equalPayloads(fetched));
- closeDataAccessor(dataAccessor);
- }
-
- public void testInvalidHistoryItemIsSkipped() throws NullCursorException {
- final AndroidBrowserHistoryRepositorySession session = (AndroidBrowserHistoryRepositorySession) createAndBeginSession();
- final AndroidBrowserRepositoryDataAccessor dbHelper = session.getDBHelper();
-
- final long now = System.currentTimeMillis();
- final HistoryRecord emptyURL = new HistoryRecord(Utils.generateGuid(), "history", now, false);
- final HistoryRecord noVisits = new HistoryRecord(Utils.generateGuid(), "history", now, false);
- final HistoryRecord aboutURL = new HistoryRecord(Utils.generateGuid(), "history", now, false);
-
- emptyURL.fennecDateVisited = now;
- emptyURL.fennecVisitCount = 1;
- emptyURL.histURI = "";
- emptyURL.title = "Something";
-
- noVisits.fennecDateVisited = now;
- noVisits.fennecVisitCount = 0;
- noVisits.histURI = "http://example.org/novisits";
- noVisits.title = "Something Else";
-
- aboutURL.fennecDateVisited = now;
- aboutURL.fennecVisitCount = 1;
- aboutURL.histURI = "about:home";
- aboutURL.title = "Fennec Home";
-
- Uri one = dbHelper.insert(emptyURL);
- Uri two = dbHelper.insert(noVisits);
- Uri tre = dbHelper.insert(aboutURL);
- assertNotNull(one);
- assertNotNull(two);
- assertNotNull(tre);
-
- // The records are in the DB.
- final Cursor all = dbHelper.fetchAll();
- assertEquals(3, all.getCount());
- all.close();
-
- // But aren't returned by fetching.
- performWait(fetchAllRunnable(session, new Record[] {}));
-
- // And we'd ignore about:home if we downloaded it.
- assertTrue(session.shouldIgnore(aboutURL));
-
- session.abort();
- }
-
- public void testSqlInjectPurgeDelete() {
- // Some setup.
- RepositorySession session = createAndBeginSession();
- final AndroidBrowserRepositoryDataAccessor db = getDataAccessor();
-
- try {
- ContentValues cv = new ContentValues();
- cv.put(BrowserContract.SyncColumns.IS_DELETED, 1);
-
- // Create and insert 2 history entries, 2nd one is evil (attempts injection).
- HistoryRecord h1 = HistoryHelpers.createHistory1();
- HistoryRecord h2 = HistoryHelpers.createHistory2();
- h2.guid = "' or '1'='1";
-
- db.insert(h1);
- db.insert(h2);
-
- // Test 1 - updateByGuid() handles evil history entries correctly.
- db.updateByGuid(h2.guid, cv);
-
- // Query history table.
- Cursor cur = getAllHistory();
- int numHistory = cur.getCount();
-
- // Ensure only the evil history entry is marked for deletion.
- try {
- cur.moveToFirst();
- while (!cur.isAfterLast()) {
- String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID);
- boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1;
-
- if (guid.equals(h2.guid)) {
- assertTrue(deleted);
- } else {
- assertFalse(deleted);
- }
- cur.moveToNext();
- }
- } finally {
- cur.close();
- }
-
- // Test 2 - Ensure purgeDelete()'s call to delete() deletes only 1 record.
- try {
- db.purgeDeleted();
- } catch (NullCursorException e) {
- e.printStackTrace();
- }
-
- cur = getAllHistory();
- int numHistoryAfterDeletion = cur.getCount();
-
- // Ensure we have only 1 deleted row.
- assertEquals(numHistoryAfterDeletion, numHistory - 1);
-
- // Ensure only the evil history is deleted.
- try {
- cur.moveToFirst();
- while (!cur.isAfterLast()) {
- String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID);
- boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1;
-
- if (guid.equals(h2.guid)) {
- fail("Evil guid was not deleted!");
- } else {
- assertFalse(deleted);
- }
- cur.moveToNext();
- }
- } finally {
- cur.close();
- }
- } finally {
- closeDataAccessor(db);
- session.abort();
- }
- }
-
- protected Cursor getAllHistory() {
- Context context = getApplicationContext();
- Cursor cur = context.getContentResolver().query(BrowserContractHelpers.HISTORY_CONTENT_URI,
- BrowserContractHelpers.HistoryColumns, null, null, null);
- return cur;
- }
-
- public void testDataAccessorBulkInsert() throws NullCursorException {
- final AndroidBrowserHistoryRepositorySession session = (AndroidBrowserHistoryRepositorySession) createAndBeginSession();
- AndroidBrowserHistoryDataAccessor db = (AndroidBrowserHistoryDataAccessor) session.getDBHelper();
-
- ArrayList<HistoryRecord> records = new ArrayList<HistoryRecord>();
- records.add(HistoryHelpers.createHistory1());
- records.add(HistoryHelpers.createHistory2());
- records.add(HistoryHelpers.createHistory3());
- db.bulkInsert(records);
-
- performWait(fetchAllRunnable(session, preparedExpectFetchDelegate(records.toArray(new Record[records.size()]))));
- session.abort();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestBookmarks.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestBookmarks.java
deleted file mode 100644
index 783aea1ff..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestBookmarks.java
+++ /dev/null
@@ -1,1063 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-
-import org.json.simple.JSONArray;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.sync.helpers.BookmarkHelpers;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessBeginDelegate;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessCreationDelegate;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessFetchDelegate;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessFinishDelegate;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessStoreDelegate;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserContract.Bookmarks;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
-import org.mozilla.gecko.sync.repositories.NullCursorException;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksDataAccessor;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepository;
-import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepositorySession;
-import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class TestBookmarks extends AndroidSyncTestCase {
-
- protected static final String LOG_TAG = "BookmarksTest";
-
- /**
- * Trivial test that forbidden records such as pinned items
- * will be ignored if processed.
- */
- public void testForbiddenItemsAreIgnored() {
- final AndroidBrowserBookmarksRepository repo = new AndroidBrowserBookmarksRepository();
- final long now = System.currentTimeMillis();
- final String bookmarksCollection = "bookmarks";
-
- final BookmarkRecord pinned = new BookmarkRecord("pinpinpinpin", "bookmarks", now - 1, false);
- final BookmarkRecord normal = new BookmarkRecord("baaaaaaaaaaa", "bookmarks", now - 2, false);
-
- final BookmarkRecord pinnedItems = new BookmarkRecord(Bookmarks.PINNED_FOLDER_GUID,
- bookmarksCollection, now - 4, false);
-
- normal.type = "bookmark";
- pinned.type = "bookmark";
- pinnedItems.type = "folder";
-
- pinned.parentID = Bookmarks.PINNED_FOLDER_GUID;
- normal.parentID = Bookmarks.TOOLBAR_FOLDER_GUID;
-
- pinnedItems.parentID = Bookmarks.PLACES_FOLDER_GUID;
-
- inBegunSession(repo, new SimpleSuccessBeginDelegate() {
- @Override
- public void onBeginSucceeded(RepositorySession session) {
- assertTrue(((AndroidBrowserBookmarksRepositorySession) session).shouldIgnore(pinned));
- assertTrue(((AndroidBrowserBookmarksRepositorySession) session).shouldIgnore(pinnedItems));
- assertFalse(((AndroidBrowserBookmarksRepositorySession) session).shouldIgnore(normal));
- finishAndNotify(session);
- }
- });
- }
-
- /**
- * Trivial test that pinned items will be skipped if present in the DB.
- */
- public void testPinnedItemsAreNotRetrieved() {
- final AndroidBrowserBookmarksRepository repo = new AndroidBrowserBookmarksRepository();
-
- // Ensure that they exist.
- setUpFennecPinnedItemsRecord();
-
- // They're there in the DB…
- final ArrayList<String> roots = fetchChildrenDirect(Bookmarks.FIXED_ROOT_ID);
- Logger.info(LOG_TAG, "Roots: " + roots);
- assertTrue(roots.contains(Bookmarks.PINNED_FOLDER_GUID));
-
- final ArrayList<String> pinned = fetchChildrenDirect(Bookmarks.FIXED_PINNED_LIST_ID);
- Logger.info(LOG_TAG, "Pinned: " + pinned);
- assertTrue(pinned.contains("dapinneditem"));
-
- // … but not when we fetch.
- final ArrayList<String> guids = fetchGUIDs(repo);
- assertFalse(guids.contains(Bookmarks.PINNED_FOLDER_GUID));
- assertFalse(guids.contains("dapinneditem"));
- }
-
- public void testRetrieveFolderHasAccurateChildren() {
- AndroidBrowserBookmarksRepository repo = new AndroidBrowserBookmarksRepository();
-
- final long now = System.currentTimeMillis();
-
- final String folderGUID = "eaaaaaaaafff";
- BookmarkRecord folder = new BookmarkRecord(folderGUID, "bookmarks", now - 5, false);
- BookmarkRecord bookmarkA = new BookmarkRecord("daaaaaaaaaaa", "bookmarks", now - 1, false);
- BookmarkRecord bookmarkB = new BookmarkRecord("baaaaaaaabbb", "bookmarks", now - 3, false);
- BookmarkRecord bookmarkC = new BookmarkRecord("aaaaaaaaaccc", "bookmarks", now - 2, false);
-
- folder.children = childrenFromRecords(bookmarkA, bookmarkB, bookmarkC);
- folder.sortIndex = 150;
- folder.title = "Test items";
- folder.parentID = "toolbar";
- folder.parentName = "Bookmarks Toolbar";
- folder.type = "folder";
-
- bookmarkA.parentID = folderGUID;
- bookmarkA.bookmarkURI = "http://example.com/A";
- bookmarkA.title = "Title A";
- bookmarkA.type = "bookmark";
-
- bookmarkB.parentID = folderGUID;
- bookmarkB.bookmarkURI = "http://example.com/B";
- bookmarkB.title = "Title B";
- bookmarkB.type = "bookmark";
-
- bookmarkC.parentID = folderGUID;
- bookmarkC.bookmarkURI = "http://example.com/C";
- bookmarkC.title = "Title C";
- bookmarkC.type = "bookmark";
-
- BookmarkRecord[] folderOnly = new BookmarkRecord[1];
- BookmarkRecord[] children = new BookmarkRecord[3];
-
- folderOnly[0] = folder;
-
- children[0] = bookmarkA;
- children[1] = bookmarkB;
- children[2] = bookmarkC;
-
- wipe();
- Logger.debug(getName(), "Storing just folder...");
- storeRecordsInSession(repo, folderOnly, null);
-
- // We don't have any children, despite our insistence upon storing.
- assertChildrenAreOrdered(repo, folderGUID, new Record[] {});
-
- // Now store the children.
- Logger.debug(getName(), "Storing children...");
- storeRecordsInSession(repo, children, null);
-
- // Now we have children, but their order is not determined, because
- // they were stored out-of-session with the original folder.
- assertChildrenAreUnordered(repo, folderGUID, children);
-
- // Now if we store the folder record again, they'll be put in the
- // right place.
- folder.lastModified++;
- Logger.debug(getName(), "Storing just folder again...");
- storeRecordsInSession(repo, folderOnly, null);
- Logger.debug(getName(), "Fetching children yet again...");
- assertChildrenAreOrdered(repo, folderGUID, children);
-
- // Now let's see what happens when we see records in the same session.
- BookmarkRecord[] parentMixed = new BookmarkRecord[4];
- BookmarkRecord[] parentFirst = new BookmarkRecord[4];
- BookmarkRecord[] parentLast = new BookmarkRecord[4];
-
- // None of our records have a position set.
- assertTrue(bookmarkA.androidPosition <= 0);
- assertTrue(bookmarkB.androidPosition <= 0);
- assertTrue(bookmarkC.androidPosition <= 0);
-
- parentMixed[1] = folder;
- parentMixed[0] = bookmarkA;
- parentMixed[2] = bookmarkC;
- parentMixed[3] = bookmarkB;
-
- parentFirst[0] = folder;
- parentFirst[1] = bookmarkC;
- parentFirst[2] = bookmarkA;
- parentFirst[3] = bookmarkB;
-
- parentLast[3] = folder;
- parentLast[0] = bookmarkB;
- parentLast[1] = bookmarkA;
- parentLast[2] = bookmarkC;
-
- wipe();
- storeRecordsInSession(repo, parentMixed, null);
- assertChildrenAreOrdered(repo, folderGUID, children);
-
- wipe();
- storeRecordsInSession(repo, parentFirst, null);
- assertChildrenAreOrdered(repo, folderGUID, children);
-
- wipe();
- storeRecordsInSession(repo, parentLast, null);
- assertChildrenAreOrdered(repo, folderGUID, children);
-
- // Ensure that records are ordered even if we re-process the folder.
- wipe();
- storeRecordsInSession(repo, parentLast, null);
- folder.lastModified++;
- storeRecordsInSession(repo, folderOnly, null);
- assertChildrenAreOrdered(repo, folderGUID, children);
- }
-
- public void testMergeFoldersPreservesSaneOrder() {
- AndroidBrowserBookmarksRepository repo = new AndroidBrowserBookmarksRepository();
-
- final long now = System.currentTimeMillis();
- final String folderGUID = "mobile";
-
- wipe();
- final long mobile = setUpFennecMobileRecord();
-
- // No children.
- assertChildrenAreUnordered(repo, folderGUID, new Record[] {});
-
- // Add some, as Fennec would.
- fennecAddBookmark("Bookmark One", "http://example.com/fennec/One");
- fennecAddBookmark("Bookmark Two", "http://example.com/fennec/Two");
-
- Logger.debug(getName(), "Fetching children...");
- JSONArray folderChildren = fetchChildrenForGUID(repo, folderGUID);
-
- assertTrue(folderChildren != null);
- Logger.debug(getName(), "Children are " + folderChildren.toJSONString());
- assertEquals(2, folderChildren.size());
- String guidOne = (String) folderChildren.get(0);
- String guidTwo = (String) folderChildren.get(1);
-
- // Make sure positions were saved.
- assertChildrenAreDirect(mobile, new String[] {
- guidOne,
- guidTwo
- });
-
- // Add some through Sync.
- BookmarkRecord folder = new BookmarkRecord(folderGUID, "bookmarks", now, false);
- BookmarkRecord bookmarkA = new BookmarkRecord("daaaaaaaaaaa", "bookmarks", now, false);
- BookmarkRecord bookmarkB = new BookmarkRecord("baaaaaaaabbb", "bookmarks", now, false);
-
- folder.children = childrenFromRecords(bookmarkA, bookmarkB);
- folder.sortIndex = 150;
- folder.title = "Mobile Bookmarks";
- folder.parentID = "places";
- folder.parentName = "";
- folder.type = "folder";
-
- bookmarkA.parentID = folderGUID;
- bookmarkA.parentName = "Mobile Bookmarks"; // Using this title exercises Bug 748898.
- bookmarkA.bookmarkURI = "http://example.com/A";
- bookmarkA.title = "Title A";
- bookmarkA.type = "bookmark";
-
- bookmarkB.parentID = folderGUID;
- bookmarkB.parentName = "mobile";
- bookmarkB.bookmarkURI = "http://example.com/B";
- bookmarkB.title = "Title B";
- bookmarkB.type = "bookmark";
-
- BookmarkRecord[] parentMixed = new BookmarkRecord[3];
- parentMixed[0] = bookmarkA;
- parentMixed[1] = folder;
- parentMixed[2] = bookmarkB;
-
- storeRecordsInSession(repo, parentMixed, null);
-
- BookmarkRecord expectedOne = new BookmarkRecord(guidOne, "bookmarks", now - 10, false);
- BookmarkRecord expectedTwo = new BookmarkRecord(guidTwo, "bookmarks", now - 10, false);
-
- // We want the server to win in this case, and otherwise to preserve order.
- // TODO
- assertChildrenAreOrdered(repo, folderGUID, new Record[] {
- bookmarkA,
- bookmarkB,
- expectedOne,
- expectedTwo
- });
-
- // Furthermore, the children of that folder should be correct in the DB.
- ContentResolver cr = getApplicationContext().getContentResolver();
- final long folderId = fennecGetFolderId(cr, folderGUID);
- Logger.debug(getName(), "Folder " + folderGUID + " => " + folderId);
-
- assertChildrenAreDirect(folderId, new String[] {
- bookmarkA.guid,
- bookmarkB.guid,
- expectedOne.guid,
- expectedTwo.guid
- });
- }
-
- /**
- * Apply a folder record whose children array is already accurately
- * stored in the database. Verify that the parent folder is not flagged
- * for reupload (i.e., that its modified time is *ahem* unmodified).
- */
- public void testNoReorderingMeansNoReupload() {
- AndroidBrowserBookmarksRepository repo = new AndroidBrowserBookmarksRepository();
-
- final long now = System.currentTimeMillis();
-
- final String folderGUID = "eaaaaaaaafff";
- BookmarkRecord folder = new BookmarkRecord(folderGUID, "bookmarks", now -5, false);
- BookmarkRecord bookmarkA = new BookmarkRecord("daaaaaaaaaaa", "bookmarks", now -1, false);
- BookmarkRecord bookmarkB = new BookmarkRecord("baaaaaaaabbb", "bookmarks", now -3, false);
-
- folder.children = childrenFromRecords(bookmarkA, bookmarkB);
- folder.sortIndex = 150;
- folder.title = "Test items";
- folder.parentID = "toolbar";
- folder.parentName = "Bookmarks Toolbar";
- folder.type = "folder";
-
- bookmarkA.parentID = folderGUID;
- bookmarkA.bookmarkURI = "http://example.com/A";
- bookmarkA.title = "Title A";
- bookmarkA.type = "bookmark";
-
- bookmarkB.parentID = folderGUID;
- bookmarkB.bookmarkURI = "http://example.com/B";
- bookmarkB.title = "Title B";
- bookmarkB.type = "bookmark";
-
- BookmarkRecord[] abf = new BookmarkRecord[3];
- BookmarkRecord[] justFolder = new BookmarkRecord[1];
-
- abf[0] = bookmarkA;
- abf[1] = bookmarkB;
- abf[2] = folder;
-
- justFolder[0] = folder;
-
- final String[] abGUIDs = new String[] { bookmarkA.guid, bookmarkB.guid };
- final Record[] abRecords = new Record[] { bookmarkA, bookmarkB };
- final String[] baGUIDs = new String[] { bookmarkB.guid, bookmarkA.guid };
- final Record[] baRecords = new Record[] { bookmarkB, bookmarkA };
-
- wipe();
- Logger.debug(getName(), "Storing A, B, folder...");
- storeRecordsInSession(repo, abf, null);
-
- ContentResolver cr = getApplicationContext().getContentResolver();
- final long folderID = fennecGetFolderId(cr, folderGUID);
- assertChildrenAreOrdered(repo, folderGUID, abRecords);
- assertChildrenAreDirect(folderID, abGUIDs);
-
- // To ensure an interval.
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- }
-
- // Store the same folder record again, and check the tracking.
- // Because the folder array didn't change,
- // the item is still tracked to not be uploaded.
- folder.lastModified = System.currentTimeMillis() + 1;
- HashSet<String> tracked = new HashSet<String>();
- storeRecordsInSession(repo, justFolder, tracked);
- assertChildrenAreOrdered(repo, folderGUID, abRecords);
- assertChildrenAreDirect(folderID, abGUIDs);
-
- assertTrue(tracked.contains(folderGUID));
-
- // Store again, but with a different order.
- tracked = new HashSet<String>();
- folder.children = childrenFromRecords(bookmarkB, bookmarkA);
- folder.lastModified = System.currentTimeMillis() + 1;
- storeRecordsInSession(repo, justFolder, tracked);
- assertChildrenAreOrdered(repo, folderGUID, baRecords);
- assertChildrenAreDirect(folderID, baGUIDs);
-
- // Now it's going to be reuploaded.
- assertFalse(tracked.contains(folderGUID));
- }
-
- /**
- * Exercise the deletion of folders when their children have not been
- * marked as deleted. In a database with constraints, this would fail
- * if we simply deleted the records, so we move them first.
- */
- public void testFolderDeletionOrphansChildren() {
- AndroidBrowserBookmarksRepository repo = new AndroidBrowserBookmarksRepository();
-
- long now = System.currentTimeMillis();
-
- // Add a folder and four children.
- final String folderGUID = "eaaaaaaaafff";
- BookmarkRecord folder = new BookmarkRecord(folderGUID, "bookmarks", now -5, false);
- BookmarkRecord bookmarkA = new BookmarkRecord("daaaaaaaaaaa", "bookmarks", now -1, false);
- BookmarkRecord bookmarkB = new BookmarkRecord("baaaaaaaabbb", "bookmarks", now -3, false);
- BookmarkRecord bookmarkC = new BookmarkRecord("daaaaaaaaccc", "bookmarks", now -7, false);
- BookmarkRecord bookmarkD = new BookmarkRecord("baaaaaaaaddd", "bookmarks", now -4, false);
-
- folder.children = childrenFromRecords(bookmarkA, bookmarkB, bookmarkC, bookmarkD);
- folder.sortIndex = 150;
- folder.title = "Test items";
- folder.parentID = "toolbar";
- folder.parentName = "Bookmarks Toolbar";
- folder.type = "folder";
-
- bookmarkA.parentID = folderGUID;
- bookmarkA.bookmarkURI = "http://example.com/A";
- bookmarkA.title = "Title A";
- bookmarkA.type = "bookmark";
-
- bookmarkB.parentID = folderGUID;
- bookmarkB.bookmarkURI = "http://example.com/B";
- bookmarkB.title = "Title B";
- bookmarkB.type = "bookmark";
-
- bookmarkC.parentID = folderGUID;
- bookmarkC.bookmarkURI = "http://example.com/C";
- bookmarkC.title = "Title C";
- bookmarkC.type = "bookmark";
-
- bookmarkD.parentID = folderGUID;
- bookmarkD.bookmarkURI = "http://example.com/D";
- bookmarkD.title = "Title D";
- bookmarkD.type = "bookmark";
-
- BookmarkRecord[] abfcd = new BookmarkRecord[5];
- BookmarkRecord[] justFolder = new BookmarkRecord[1];
- abfcd[0] = bookmarkA;
- abfcd[1] = bookmarkB;
- abfcd[2] = folder;
- abfcd[3] = bookmarkC;
- abfcd[4] = bookmarkD;
-
- justFolder[0] = folder;
-
- final String[] abcdGUIDs = new String[] { bookmarkA.guid, bookmarkB.guid, bookmarkC.guid, bookmarkD.guid };
- final Record[] abcdRecords = new Record[] { bookmarkA, bookmarkB, bookmarkC, bookmarkD };
-
- wipe();
- Logger.debug(getName(), "Storing A, B, folder, C, D...");
- storeRecordsInSession(repo, abfcd, null);
-
- // Verify that it worked.
- ContentResolver cr = getApplicationContext().getContentResolver();
- final long folderID = fennecGetFolderId(cr, folderGUID);
- assertChildrenAreOrdered(repo, folderGUID, abcdRecords);
- assertChildrenAreDirect(folderID, abcdGUIDs);
-
- now = System.currentTimeMillis();
-
- // Add one child to unsorted bookmarks.
- BookmarkRecord unsortedA = new BookmarkRecord("yiamunsorted", "bookmarks", now, false);
- unsortedA.parentID = "unfiled";
- unsortedA.title = "Unsorted A";
- unsortedA.type = "bookmark";
- unsortedA.androidPosition = 0;
-
- BookmarkRecord[] ua = new BookmarkRecord[1];
- ua[0] = unsortedA;
-
- storeRecordsInSession(repo, ua, null);
-
- // Ensure that the database is in this state.
- assertChildrenAreOrdered(repo, "unfiled", ua);
-
- // Delete the second child, the folder, and then the third child.
- bookmarkB.bookmarkURI = bookmarkC.bookmarkURI = folder.bookmarkURI = null;
- bookmarkB.deleted = bookmarkC.deleted = folder.deleted = true;
- bookmarkB.title = bookmarkC.title = folder.title = null;
-
- // Nulling the type of folder is very important: it verifies
- // that the session can behave correctly according to local type.
- bookmarkB.type = bookmarkC.type = folder.type = null;
-
- bookmarkB.lastModified = bookmarkC.lastModified = folder.lastModified = now = System.currentTimeMillis();
-
- BookmarkRecord[] deletions = new BookmarkRecord[] { bookmarkB, folder, bookmarkC };
- storeRecordsInSession(repo, deletions, null);
-
- // Verify that the unsorted bookmarks folder contains its child and the
- // first and fourth children of the now-deleted folder.
- // Also verify that the folder is gone.
- long unsortedID = fennecGetFolderId(cr, "unfiled");
- long toolbarID = fennecGetFolderId(cr, "toolbar");
- String[] expected = new String[] { unsortedA.guid, bookmarkA.guid, bookmarkD.guid };
-
- // This will trigger positioning.
- assertChildrenAreUnordered(repo, "unfiled", new Record[] { unsortedA, bookmarkA, bookmarkD });
- assertChildrenAreDirect(unsortedID, expected);
- assertChildrenAreDirect(toolbarID, new String[] {});
- }
-
- /**
- * A test where we expect to replace a local folder with a new folder (with a
- * new GUID), whilst adding children to it. Verifies that replace and insert
- * co-operate.
- */
- public void testInsertAndReplaceGuid() {
- AndroidBrowserBookmarksRepository repo = new AndroidBrowserBookmarksRepository();
- wipe();
-
- BookmarkRecord folder1 = BookmarkHelpers.createFolder1();
- BookmarkRecord folder2 = BookmarkHelpers.createFolder2(); // child of folder1
- BookmarkRecord folder3 = BookmarkHelpers.createFolder3(); // child of folder2
- BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); // child of folder1
- BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); // child of folder1
- BookmarkRecord bmk3 = BookmarkHelpers.createBookmark3(); // child of folder2
- BookmarkRecord bmk4 = BookmarkHelpers.createBookmark4(); // child of folder3
-
- BookmarkRecord[] records = new BookmarkRecord[] {
- folder1, folder2, folder3,
- bmk1, bmk4
- };
- storeRecordsInSession(repo, records, null);
-
- assertChildrenAreUnordered(repo, folder1.guid, new Record[] { bmk1, folder2 });
- assertChildrenAreUnordered(repo, folder2.guid, new Record[] { folder3 });
- assertChildrenAreUnordered(repo, folder3.guid, new Record[] { bmk4 });
-
- // Replace folder3 with a record with a new GUID, and add bmk4 as folder3's child.
- final long now = System.currentTimeMillis();
- folder3.guid = Utils.generateGuid();
- folder3.lastModified = now;
- bmk4.title = bmk4.title + "/NEW";
- bmk4.parentID = folder3.guid; // Incoming child knows its parent.
- bmk4.parentName = folder3.title;
- bmk4.lastModified = now;
-
- // Order of store should not matter.
- ArrayList<BookmarkRecord> changedRecords = new ArrayList<BookmarkRecord>();
- changedRecords.add(bmk2); changedRecords.add(bmk3); changedRecords.add(bmk4); changedRecords.add(folder3);
- Collections.shuffle(changedRecords);
- storeRecordsInSession(repo, changedRecords.toArray(new BookmarkRecord[changedRecords.size()]), null);
-
- assertChildrenAreUnordered(repo, folder1.guid, new Record[] { bmk1, bmk2, folder2 });
- assertChildrenAreUnordered(repo, folder2.guid, new Record[] { bmk3, folder3 });
- assertChildrenAreUnordered(repo, folder3.guid, new Record[] { bmk4 });
-
- assertNotNull(fetchGUID(repo, folder3.guid));
- assertEquals(bmk4.title, fetchGUID(repo, bmk4.guid).title);
- }
-
- /**
- * A test where we expect to replace a local folder with a new folder (with a
- * new title but the same GUID), whilst adding children to it. Verifies that
- * replace and insert co-operate.
- */
- public void testInsertAndReplaceTitle() {
- AndroidBrowserBookmarksRepository repo = new AndroidBrowserBookmarksRepository();
- wipe();
-
- BookmarkRecord folder1 = BookmarkHelpers.createFolder1();
- BookmarkRecord folder2 = BookmarkHelpers.createFolder2(); // child of folder1
- BookmarkRecord folder3 = BookmarkHelpers.createFolder3(); // child of folder2
- BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); // child of folder1
- BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); // child of folder1
- BookmarkRecord bmk3 = BookmarkHelpers.createBookmark3(); // child of folder2
- BookmarkRecord bmk4 = BookmarkHelpers.createBookmark4(); // child of folder3
-
- BookmarkRecord[] records = new BookmarkRecord[] {
- folder1, folder2, folder3,
- bmk1, bmk4
- };
- storeRecordsInSession(repo, records, null);
-
- assertChildrenAreUnordered(repo, folder1.guid, new Record[] { bmk1, folder2 });
- assertChildrenAreUnordered(repo, folder2.guid, new Record[] { folder3 });
- assertChildrenAreUnordered(repo, folder3.guid, new Record[] { bmk4 });
-
- // Rename folder1, and add bmk2 as folder1's child.
- final long now = System.currentTimeMillis();
- folder1.title = folder1.title + "/NEW";
- folder1.lastModified = now;
- bmk2.title = bmk2.title + "/NEW";
- bmk2.parentID = folder1.guid; // Incoming child knows its parent.
- bmk2.parentName = folder1.title;
- bmk2.lastModified = now;
-
- // Order of store should not matter.
- ArrayList<BookmarkRecord> changedRecords = new ArrayList<BookmarkRecord>();
- changedRecords.add(bmk2); changedRecords.add(bmk3); changedRecords.add(folder1);
- Collections.shuffle(changedRecords);
- storeRecordsInSession(repo, changedRecords.toArray(new BookmarkRecord[changedRecords.size()]), null);
-
- assertChildrenAreUnordered(repo, folder1.guid, new Record[] { bmk1, bmk2, folder2 });
- assertChildrenAreUnordered(repo, folder2.guid, new Record[] { bmk3, folder3 });
- assertChildrenAreUnordered(repo, folder3.guid, new Record[] { bmk4 });
-
- assertEquals(folder1.title, fetchGUID(repo, folder1.guid).title);
- assertEquals(bmk2.title, fetchGUID(repo, bmk2.guid).title);
- }
-
- /**
- * Create and begin a new session, handing control to the delegate when started.
- * Returns when the delegate has notified.
- */
- public void inBegunSession(final AndroidBrowserBookmarksRepository repo,
- final RepositorySessionBeginDelegate beginDelegate) {
- Runnable go = new Runnable() {
- @Override
- public void run() {
- RepositorySessionCreationDelegate delegate = new SimpleSuccessCreationDelegate() {
- @Override
- public void onSessionCreated(final RepositorySession session) {
- try {
- session.begin(beginDelegate);
- } catch (InvalidSessionTransitionException e) {
- performNotify(e);
- }
- }
- };
- repo.createSession(delegate, getApplicationContext());
- }
- };
- performWait(go);
- }
-
- /**
- * Finish the provided session, notifying on success.
- *
- * @param session
- */
- public void finishAndNotify(final RepositorySession session) {
- try {
- session.finish(new SimpleSuccessFinishDelegate() {
- @Override
- public void onFinishSucceeded(RepositorySession session,
- RepositorySessionBundle bundle) {
- performNotify();
- }
- });
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
-
- /**
- * Simple helper class for fetching all records.
- * The fetched records' GUIDs are stored in `fetchedGUIDs`.
- */
- public class SimpleFetchAllBeginDelegate extends SimpleSuccessBeginDelegate {
- public final ArrayList<String> fetchedGUIDs = new ArrayList<String>();
-
- @Override
- public void onBeginSucceeded(final RepositorySession session) {
- RepositorySessionFetchRecordsDelegate fetchDelegate = new SimpleSuccessFetchDelegate() {
-
- @Override
- public void onFetchedRecord(Record record) {
- fetchedGUIDs.add(record.guid);
- }
-
- @Override
- public void onFetchCompleted(long end) {
- finishAndNotify(session);
- }
- };
- session.fetchSince(0, fetchDelegate);
- }
- }
-
- /**
- * Simple helper class for fetching a single record by GUID.
- * The fetched record is stored in `fetchedRecord`.
- */
- public class SimpleFetchOneBeginDelegate extends SimpleSuccessBeginDelegate {
- public final String guid;
- public Record fetchedRecord = null;
-
- public SimpleFetchOneBeginDelegate(String guid) {
- this.guid = guid;
- }
-
- @Override
- public void onBeginSucceeded(final RepositorySession session) {
- RepositorySessionFetchRecordsDelegate fetchDelegate = new SimpleSuccessFetchDelegate() {
-
- @Override
- public void onFetchedRecord(Record record) {
- fetchedRecord = record;
- }
-
- @Override
- public void onFetchCompleted(long end) {
- finishAndNotify(session);
- }
- };
- try {
- session.fetch(new String[] { guid }, fetchDelegate);
- } catch (InactiveSessionException e) {
- performNotify("Session is inactive.", e);
- }
- }
- }
-
- /**
- * Create a new session for the given repository, storing each record
- * from the provided array. Notifies on failure or success.
- *
- * Optionally populates a provided Collection with tracked items.
- * @param repo
- * @param records
- * @param tracked
- */
- public void storeRecordsInSession(AndroidBrowserBookmarksRepository repo,
- final BookmarkRecord[] records,
- final Collection<String> tracked) {
- SimpleSuccessBeginDelegate beginDelegate = new SimpleSuccessBeginDelegate() {
- @Override
- public void onBeginSucceeded(final RepositorySession session) {
- RepositorySessionStoreDelegate storeDelegate = new SimpleSuccessStoreDelegate() {
-
- @Override
- public void onStoreCompleted(final long storeEnd) {
- // Pass back whatever we tracked.
- if (tracked != null) {
- Iterator<String> iter = session.getTrackedRecordIDs();
- while (iter.hasNext()) {
- tracked.add(iter.next());
- }
- }
- finishAndNotify(session);
- }
-
- @Override
- public void onRecordStoreSucceeded(String guid) {
- }
- };
- session.setStoreDelegate(storeDelegate);
- for (BookmarkRecord record : records) {
- try {
- session.store(record);
- } catch (NoStoreDelegateException e) {
- // Never happens.
- }
- }
- session.storeDone();
- }
- };
- inBegunSession(repo, beginDelegate);
- }
-
- public ArrayList<String> fetchGUIDs(AndroidBrowserBookmarksRepository repo) {
- SimpleFetchAllBeginDelegate beginDelegate = new SimpleFetchAllBeginDelegate();
- inBegunSession(repo, beginDelegate);
- return beginDelegate.fetchedGUIDs;
- }
-
- public BookmarkRecord fetchGUID(AndroidBrowserBookmarksRepository repo,
- final String guid) {
- Logger.info(LOG_TAG, "Fetching for " + guid);
- SimpleFetchOneBeginDelegate beginDelegate = new SimpleFetchOneBeginDelegate(guid);
- inBegunSession(repo, beginDelegate);
- Logger.info(LOG_TAG, "Fetched " + beginDelegate.fetchedRecord);
- assertTrue(beginDelegate.fetchedRecord != null);
- return (BookmarkRecord) beginDelegate.fetchedRecord;
- }
-
- public JSONArray fetchChildrenForGUID(AndroidBrowserBookmarksRepository repo,
- final String guid) {
- return fetchGUID(repo, guid).children;
- }
-
- @SuppressWarnings("unchecked")
- protected static JSONArray childrenFromRecords(BookmarkRecord... records) {
- JSONArray children = new JSONArray();
- for (BookmarkRecord record : records) {
- children.add(record.guid);
- }
- return children;
- }
-
-
- protected void updateRow(ContentValues values) {
- Uri uri = BrowserContractHelpers.BOOKMARKS_CONTENT_URI;
- final String where = BrowserContract.Bookmarks.GUID + " = ?";
- final String[] args = new String[] { values.getAsString(BrowserContract.Bookmarks.GUID) };
- getApplicationContext().getContentResolver().update(uri, values, where, args);
- }
-
- protected Uri insertRow(ContentValues values) {
- Uri uri = BrowserContractHelpers.BOOKMARKS_CONTENT_URI;
- return getApplicationContext().getContentResolver().insert(uri, values);
- }
-
- protected static ContentValues specialFolder() {
- ContentValues values = new ContentValues();
-
- final long now = System.currentTimeMillis();
- values.put(Bookmarks.DATE_CREATED, now);
- values.put(Bookmarks.DATE_MODIFIED, now);
- values.put(Bookmarks.TYPE, BrowserContract.Bookmarks.TYPE_FOLDER);
-
- return values;
- }
-
- protected static ContentValues fennecMobileRecordWithoutTitle() {
- ContentValues values = specialFolder();
- values.put(BrowserContract.SyncColumns.GUID, "mobile");
- values.putNull(BrowserContract.Bookmarks.TITLE);
-
- return values;
- }
-
- protected ContentValues fennecPinnedItemsRecord() {
- final ContentValues values = specialFolder();
- final String title = getApplicationContext().getResources().getString(R.string.bookmarks_folder_pinned);
-
- values.put(BrowserContract.SyncColumns.GUID, Bookmarks.PINNED_FOLDER_GUID);
- values.put(Bookmarks._ID, Bookmarks.FIXED_PINNED_LIST_ID);
- values.put(Bookmarks.PARENT, Bookmarks.FIXED_ROOT_ID);
- values.put(Bookmarks.TITLE, title);
- return values;
- }
-
- protected static ContentValues fennecPinnedChildItemRecord() {
- ContentValues values = new ContentValues();
-
- final long now = System.currentTimeMillis();
-
- values.put(BrowserContract.SyncColumns.GUID, "dapinneditem");
- values.put(Bookmarks.DATE_CREATED, now);
- values.put(Bookmarks.DATE_MODIFIED, now);
- values.put(Bookmarks.TYPE, BrowserContract.Bookmarks.TYPE_BOOKMARK);
- values.put(Bookmarks.URL, "user-entered:foobar");
- values.put(Bookmarks.PARENT, Bookmarks.FIXED_PINNED_LIST_ID);
- values.put(Bookmarks.TITLE, "Foobar");
- return values;
- }
-
- protected long setUpFennecMobileRecordWithoutTitle() {
- ContentResolver cr = getApplicationContext().getContentResolver();
- ContentValues values = fennecMobileRecordWithoutTitle();
- updateRow(values);
- return fennecGetMobileBookmarksFolderId(cr);
- }
-
- protected long setUpFennecMobileRecord() {
- ContentResolver cr = getApplicationContext().getContentResolver();
- ContentValues values = fennecMobileRecordWithoutTitle();
- values.put(BrowserContract.Bookmarks.PARENT, BrowserContract.Bookmarks.FIXED_ROOT_ID);
- String title = getApplicationContext().getResources().getString(R.string.bookmarks_folder_mobile);
- values.put(BrowserContract.Bookmarks.TITLE, title);
- updateRow(values);
- return fennecGetMobileBookmarksFolderId(cr);
- }
-
- protected void setUpFennecPinnedItemsRecord() {
- insertRow(fennecPinnedItemsRecord());
- insertRow(fennecPinnedChildItemRecord());
- }
-
- //
- // Fennec fake layer.
- //
- private Uri appendProfile(Uri uri) {
- final String defaultProfile = "default"; // Fennec constant removed in Bug 715307.
- return uri.buildUpon().appendQueryParameter(BrowserContract.PARAM_PROFILE, defaultProfile).build();
- }
-
- private long fennecGetFolderId(ContentResolver cr, String guid) {
- Cursor c = null;
- try {
- c = cr.query(appendProfile(BrowserContractHelpers.BOOKMARKS_CONTENT_URI),
- new String[] { BrowserContract.Bookmarks._ID },
- BrowserContract.Bookmarks.GUID + " = ?",
- new String[] { guid },
- null);
-
- if (c.moveToFirst()) {
- return c.getLong(c.getColumnIndexOrThrow(BrowserContract.Bookmarks._ID));
- }
- return -1;
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
-
- private long fennecGetMobileBookmarksFolderId(ContentResolver cr) {
- return fennecGetFolderId(cr, BrowserContract.Bookmarks.MOBILE_FOLDER_GUID);
- }
-
- public void fennecAddBookmark(String title, String uri) {
- ContentResolver cr = getApplicationContext().getContentResolver();
-
- long folderId = fennecGetMobileBookmarksFolderId(cr);
- if (folderId < 0) {
- return;
- }
-
- ContentValues values = new ContentValues();
- values.put(BrowserContract.Bookmarks.TITLE, title);
- values.put(BrowserContract.Bookmarks.URL, uri);
- values.put(BrowserContract.Bookmarks.PARENT, folderId);
-
- // Restore deleted record if possible
- values.put(BrowserContract.Bookmarks.IS_DELETED, 0);
-
- Logger.debug(getName(), "Adding bookmark " + title + ", " + uri + " in " + folderId);
- int updated = cr.update(appendProfile(BrowserContractHelpers.BOOKMARKS_CONTENT_URI),
- values,
- BrowserContract.Bookmarks.URL + " = ?",
- new String[] { uri });
-
- if (updated == 0) {
- Uri insert = cr.insert(appendProfile(BrowserContractHelpers.BOOKMARKS_CONTENT_URI), values);
- long idFromUri = ContentUris.parseId(insert);
- Logger.debug(getName(), "Inserted " + uri + " as " + idFromUri);
- Logger.debug(getName(), "Position is " + getPosition(idFromUri));
- }
- }
-
- private long getPosition(long idFromUri) {
- ContentResolver cr = getApplicationContext().getContentResolver();
- Cursor c = cr.query(appendProfile(BrowserContractHelpers.BOOKMARKS_CONTENT_URI),
- new String[] { BrowserContract.Bookmarks.POSITION },
- BrowserContract.Bookmarks._ID + " = ?",
- new String[] { String.valueOf(idFromUri) },
- null);
- if (!c.moveToFirst()) {
- return -2;
- }
- return c.getLong(0);
- }
-
- protected AndroidBrowserBookmarksDataAccessor dataAccessor = null;
- protected AndroidBrowserBookmarksDataAccessor getDataAccessor() {
- if (dataAccessor == null) {
- dataAccessor = new AndroidBrowserBookmarksDataAccessor(getApplicationContext());
- }
- return dataAccessor;
- }
-
- protected void wipe() {
- Logger.debug(getName(), "Wiping.");
- getDataAccessor().wipe();
- }
-
- protected void assertChildrenAreOrdered(AndroidBrowserBookmarksRepository repo, String guid, Record[] expected) {
- Logger.debug(getName(), "Fetching children...");
- JSONArray folderChildren = fetchChildrenForGUID(repo, guid);
-
- assertTrue(folderChildren != null);
- Logger.debug(getName(), "Children are " + folderChildren.toJSONString());
- assertEquals(expected.length, folderChildren.size());
- for (int i = 0; i < expected.length; ++i) {
- assertEquals(expected[i].guid, ((String) folderChildren.get(i)));
- }
- }
-
- protected void assertChildrenAreUnordered(AndroidBrowserBookmarksRepository repo, String guid, Record[] expected) {
- Logger.debug(getName(), "Fetching children...");
- JSONArray folderChildren = fetchChildrenForGUID(repo, guid);
-
- assertTrue(folderChildren != null);
- Logger.debug(getName(), "Children are " + folderChildren.toJSONString());
- assertEquals(expected.length, folderChildren.size());
- for (Record record : expected) {
- folderChildren.contains(record.guid);
- }
- }
-
- /**
- * Return a sequence of children GUIDs for the provided folder ID.
- */
- protected ArrayList<String> fetchChildrenDirect(long id) {
- Logger.debug(getName(), "Fetching children directly from DB...");
- final ArrayList<String> out = new ArrayList<String>();
- final AndroidBrowserBookmarksDataAccessor accessor = new AndroidBrowserBookmarksDataAccessor(getApplicationContext());
- Cursor cur = null;
- try {
- cur = accessor.getChildren(id);
- } catch (NullCursorException e) {
- fail("Got null cursor.");
- }
- try {
- if (!cur.moveToFirst()) {
- return out;
- }
- final int guidCol = cur.getColumnIndex(BrowserContract.SyncColumns.GUID);
- while (!cur.isAfterLast()) {
- out.add(cur.getString(guidCol));
- cur.moveToNext();
- }
- } finally {
- cur.close();
- }
- return out;
- }
-
- /**
- * Assert that the children of the provided ID are correct and positioned in the database.
- * @param id
- * @param guids
- */
- protected void assertChildrenAreDirect(long id, String[] guids) {
- Logger.debug(getName(), "Fetching children directly from DB...");
- AndroidBrowserBookmarksDataAccessor accessor = new AndroidBrowserBookmarksDataAccessor(getApplicationContext());
- Cursor cur = null;
- try {
- cur = accessor.getChildren(id);
- } catch (NullCursorException e) {
- fail("Got null cursor.");
- }
- try {
- if (guids == null || guids.length == 0) {
- assertFalse(cur.moveToFirst());
- return;
- }
-
- assertTrue(cur.moveToFirst());
- int i = 0;
- final int guidCol = cur.getColumnIndex(BrowserContract.SyncColumns.GUID);
- final int posCol = cur.getColumnIndex(BrowserContract.Bookmarks.POSITION);
- while (!cur.isAfterLast()) {
- assertTrue(i < guids.length);
- final String guid = cur.getString(guidCol);
- final int pos = cur.getInt(posCol);
- Logger.debug(getName(), "Fetched child: " + guid + " has position " + pos);
- assertEquals(guids[i], guid);
- assertEquals(i, pos);
-
- ++i;
- cur.moveToNext();
- }
- assertEquals(guids.length, i);
- } finally {
- cur.close();
- }
- }
-}
-
-/**
-TODO
-
-Test for storing a record that will reconcile to mobile; postcondition is
-that there's still a directory called mobile that includes all the items that
-it used to.
-
-mobile folder created without title.
-Unsorted put in mobile???
-Tests for children retrieval
-Tests for children merge
-Tests for modify retrieve parent when child added, removed, reordered (oh, reorder is hard! Any change, then.)
-Safety mode?
-Test storing folder first, contents first.
-Store folder in next session. Verify order recovery.
-
-
-*/
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestClientsDatabase.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestClientsDatabase.java
deleted file mode 100644
index 198073fcf..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestClientsDatabase.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import java.util.ArrayList;
-
-import org.json.simple.JSONArray;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.NullCursorException;
-import org.mozilla.gecko.sync.repositories.android.ClientsDatabase;
-import org.mozilla.gecko.sync.repositories.android.RepoUtils;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-import org.mozilla.gecko.sync.setup.Constants;
-
-import android.database.Cursor;
-import android.test.AndroidTestCase;
-
-public class TestClientsDatabase extends AndroidTestCase {
-
- protected ClientsDatabase db;
-
- public void setUp() {
- db = new ClientsDatabase(mContext);
- db.wipeDB();
- }
-
- public void testStoreAndFetch() {
- ClientRecord record = new ClientRecord();
- String profileConst = Constants.DEFAULT_PROFILE;
- db.store(profileConst, record);
-
- Cursor cur = null;
- try {
- // Test stored item gets fetched correctly.
- cur = db.fetchClientsCursor(record.guid, profileConst);
- assertTrue(cur.moveToFirst());
- assertEquals(1, cur.getCount());
-
- String guid = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_ACCOUNT_GUID);
- String profileId = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_PROFILE);
- String clientName = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_NAME);
- String clientType = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_TYPE);
-
- assertEquals(record.guid, guid);
- assertEquals(profileConst, profileId);
- assertEquals(record.name, clientName);
- assertEquals(record.type, clientType);
- } catch (NullCursorException e) {
- fail("Should not have NullCursorException");
- } finally {
- if (cur != null) {
- cur.close();
- }
- }
- }
-
- public void testStoreAndFetchSpecificCommands() {
- String accountGUID = Utils.generateGuid();
- ArrayList<String> args = new ArrayList<String>();
- args.add("URI of Page");
- args.add("Sender GUID");
- args.add("Title of Page");
- String jsonArgs = JSONArray.toJSONString(args);
-
- Cursor cur = null;
- try {
- db.store(accountGUID, "displayURI", jsonArgs);
-
- // This row should not show up in the fetch.
- args.add("Another arg.");
- db.store(accountGUID, "displayURI", JSONArray.toJSONString(args));
-
- // Test stored item gets fetched correctly.
- cur = db.fetchSpecificCommand(accountGUID, "displayURI", jsonArgs);
- assertTrue(cur.moveToFirst());
- assertEquals(1, cur.getCount());
-
- String guid = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_ACCOUNT_GUID);
- String commandType = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_COMMAND);
- String fetchedArgs = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_ARGS);
-
- assertEquals(accountGUID, guid);
- assertEquals("displayURI", commandType);
- assertEquals(jsonArgs, fetchedArgs);
- } catch (NullCursorException e) {
- fail("Should not have NullCursorException");
- } finally {
- if (cur != null) {
- cur.close();
- }
- }
- }
-
- public void testFetchCommandsForClient() {
- String accountGUID = Utils.generateGuid();
- ArrayList<String> args = new ArrayList<String>();
- args.add("URI of Page");
- args.add("Sender GUID");
- args.add("Title of Page");
- String jsonArgs = JSONArray.toJSONString(args);
-
- Cursor cur = null;
- try {
- db.store(accountGUID, "displayURI", jsonArgs);
-
- // This row should ALSO show up in the fetch.
- args.add("Another arg.");
- db.store(accountGUID, "displayURI", JSONArray.toJSONString(args));
-
- // Test both stored items with the same GUID but different command are fetched.
- cur = db.fetchCommandsForClient(accountGUID);
- assertTrue(cur.moveToFirst());
- assertEquals(2, cur.getCount());
- } catch (NullCursorException e) {
- fail("Should not have NullCursorException");
- } finally {
- if (cur != null) {
- cur.close();
- }
- }
- }
-
- @SuppressWarnings("resource")
- public void testDelete() {
- ClientRecord record1 = new ClientRecord();
- ClientRecord record2 = new ClientRecord();
- String profileConst = Constants.DEFAULT_PROFILE;
-
- db.store(profileConst, record1);
- db.store(profileConst, record2);
-
- Cursor cur = null;
- try {
- // Test record doesn't exist after delete.
- db.deleteClient(record1.guid, profileConst);
- cur = db.fetchClientsCursor(record1.guid, profileConst);
- assertFalse(cur.moveToFirst());
- assertEquals(0, cur.getCount());
-
- // Test record2 still there after deleting record1.
- cur = db.fetchClientsCursor(record2.guid, profileConst);
- assertTrue(cur.moveToFirst());
- assertEquals(1, cur.getCount());
-
- String guid = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_ACCOUNT_GUID);
- String profileId = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_PROFILE);
- String clientName = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_NAME);
- String clientType = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_TYPE);
-
- assertEquals(record2.guid, guid);
- assertEquals(profileConst, profileId);
- assertEquals(record2.name, clientName);
- assertEquals(record2.type, clientType);
- } catch (NullCursorException e) {
- fail("Should not have NullCursorException");
- } finally {
- if (cur != null) {
- cur.close();
- }
- }
- }
-
- @SuppressWarnings("resource")
- public void testWipe() {
- ClientRecord record1 = new ClientRecord();
- ClientRecord record2 = new ClientRecord();
- String profileConst = Constants.DEFAULT_PROFILE;
-
- db.store(profileConst, record1);
- db.store(profileConst, record2);
-
-
- Cursor cur = null;
- try {
- // Test before wipe the records are there.
- cur = db.fetchClientsCursor(record2.guid, profileConst);
- assertTrue(cur.moveToFirst());
- assertEquals(1, cur.getCount());
- cur = db.fetchClientsCursor(record2.guid, profileConst);
- assertTrue(cur.moveToFirst());
- assertEquals(1, cur.getCount());
-
- // Test after wipe neither record exists.
- db.wipeClientsTable();
- cur = db.fetchClientsCursor(record2.guid, profileConst);
- assertFalse(cur.moveToFirst());
- assertEquals(0, cur.getCount());
- cur = db.fetchClientsCursor(record1.guid, profileConst);
- assertFalse(cur.moveToFirst());
- assertEquals(0, cur.getCount());
- } catch (NullCursorException e) {
- fail("Should not have NullCursorException");
- } finally {
- if (cur != null) {
- cur.close();
- }
- }
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java
deleted file mode 100644
index 65b14e860..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.mozilla.gecko.background.testhelpers.CommandHelpers;
-import org.mozilla.gecko.sync.CommandProcessor.Command;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.NullCursorException;
-import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.test.AndroidTestCase;
-
-public class TestClientsDatabaseAccessor extends AndroidTestCase {
-
- public class StubbedClientsDatabaseAccessor extends ClientsDatabaseAccessor {
- public StubbedClientsDatabaseAccessor(Context mContext) {
- super(mContext);
- }
- }
-
- StubbedClientsDatabaseAccessor db;
-
- public void setUp() {
- db = new StubbedClientsDatabaseAccessor(mContext);
- db.wipeDB();
- }
-
- public void tearDown() {
- db.close();
- }
-
- public void testStoreArrayListAndFetch() throws NullCursorException {
- ArrayList<ClientRecord> list = new ArrayList<ClientRecord>();
- ClientRecord record1 = new ClientRecord(Utils.generateGuid());
- ClientRecord record2 = new ClientRecord(Utils.generateGuid());
- ClientRecord record3 = new ClientRecord(Utils.generateGuid());
-
- list.add(record1);
- list.add(record2);
- db.store(list);
-
- ClientRecord r1 = db.fetchClient(record1.guid);
- ClientRecord r2 = db.fetchClient(record2.guid);
- ClientRecord r3 = db.fetchClient(record3.guid);
-
- assertNotNull(r1);
- assertNotNull(r2);
- assertNull(r3);
- assertTrue(record1.equals(r1));
- assertTrue(record2.equals(r2));
- assertFalse(record3.equals(r3));
- }
-
- public void testStoreAndFetchCommandsForClient() {
- String accountGUID1 = Utils.generateGuid();
- String accountGUID2 = Utils.generateGuid();
-
- Command command1 = CommandHelpers.getCommand1();
- Command command2 = CommandHelpers.getCommand2();
- Command command3 = CommandHelpers.getCommand3();
-
- Cursor cur = null;
- try {
- db.store(accountGUID1, command1);
- db.store(accountGUID1, command2);
- db.store(accountGUID2, command3);
-
- List<Command> commands = db.fetchCommandsForClient(accountGUID1);
- assertEquals(2, commands.size());
- assertEquals(1, commands.get(0).args.size());
- assertEquals(1, commands.get(1).args.size());
- } catch (NullCursorException e) {
- fail("Should not have NullCursorException");
- } finally {
- if (cur != null) {
- cur.close();
- }
- }
- }
-
- public void testNumClients() {
- final int COUNT = 5;
- ArrayList<ClientRecord> list = new ArrayList<ClientRecord>();
- for (int i = 0; i < 5; i++) {
- list.add(new ClientRecord());
- }
- db.store(list);
- assertEquals(COUNT, db.clientsCount());
- }
-
- public void testFetchAll() throws NullCursorException {
- ArrayList<ClientRecord> list = new ArrayList<ClientRecord>();
- ClientRecord record1 = new ClientRecord(Utils.generateGuid());
- ClientRecord record2 = new ClientRecord(Utils.generateGuid());
-
- list.add(record1);
- list.add(record2);
-
- boolean thrown = false;
- try {
- Map<String, ClientRecord> records = db.fetchAllClients();
-
- assertNotNull(records);
- assertEquals(0, records.size());
-
- db.store(list);
- records = db.fetchAllClients();
- assertNotNull(records);
- assertEquals(2, records.size());
- assertTrue(record1.equals(records.get(record1.guid)));
- assertTrue(record2.equals(records.get(record2.guid)));
-
- // put() should throw an exception since records is immutable.
- records.put(null, null);
- } catch (UnsupportedOperationException e) {
- thrown = true;
- }
- assertTrue(thrown);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java
deleted file mode 100644
index 02d393ce8..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import org.json.simple.JSONArray;
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate;
-import org.mozilla.gecko.background.sync.helpers.SessionTestHelper;
-import org.mozilla.gecko.background.testhelpers.MockClientsDataDelegate;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserContract.Clients;
-import org.mozilla.gecko.sync.repositories.NoContentProviderException;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
-import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
-import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository.FennecTabsRepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-import org.mozilla.gecko.sync.repositories.domain.TabsRecord;
-
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.os.RemoteException;
-
-public class TestFennecTabsRepositorySession extends AndroidSyncTestCase {
- public static final MockClientsDataDelegate clientsDataDelegate = new MockClientsDataDelegate();
- public static final String TEST_CLIENT_GUID = clientsDataDelegate.getAccountGUID();
- public static final String TEST_CLIENT_NAME = clientsDataDelegate.getClientName();
- public static final String TEST_CLIENT_DEVICE_TYPE = "phablet";
-
- // Override these to test against data that is not live.
- public static final String TEST_TABS_CLIENT_GUID_IS_LOCAL_SELECTION = BrowserContract.Tabs.CLIENT_GUID + " IS ?";
- public static final String[] TEST_TABS_CLIENT_GUID_IS_LOCAL_SELECTION_ARGS = new String[] { TEST_CLIENT_GUID };
-
- public static final String TEST_CLIENTS_GUID_IS_LOCAL_SELECTION = BrowserContract.Clients.GUID + " IS ?";
- public static final String[] TEST_CLIENTS_GUID_IS_LOCAL_SELECTION_ARGS = new String[] { TEST_CLIENT_GUID };
-
- protected ContentProviderClient tabsClient = null;
- protected ContentProviderClient clientsClient = null;
-
- protected ContentProviderClient getTabsClient() {
- final ContentResolver cr = getApplicationContext().getContentResolver();
- return cr.acquireContentProviderClient(BrowserContractHelpers.TABS_CONTENT_URI);
- }
-
- protected ContentProviderClient getClientsClient() {
- final ContentResolver cr = getApplicationContext().getContentResolver();
- return cr.acquireContentProviderClient(BrowserContractHelpers.CLIENTS_CONTENT_URI);
- }
-
- public TestFennecTabsRepositorySession() throws NoContentProviderException {
- super();
- }
-
- @Override
- public void setUp() {
- if (tabsClient == null) {
- tabsClient = getTabsClient();
- }
- if (clientsClient == null) {
- clientsClient = getClientsClient();
- }
- }
-
- protected int deleteTestClient(final ContentProviderClient clientsClient) throws RemoteException {
- if (clientsClient == null) {
- return -1;
- }
- return clientsClient.delete(BrowserContractHelpers.CLIENTS_CONTENT_URI, TEST_CLIENTS_GUID_IS_LOCAL_SELECTION, TEST_CLIENTS_GUID_IS_LOCAL_SELECTION_ARGS);
- }
-
- protected int deleteAllTestTabs(final ContentProviderClient tabsClient) throws RemoteException {
- if (tabsClient == null) {
- return -1;
- }
- return tabsClient.delete(BrowserContractHelpers.TABS_CONTENT_URI,
- TEST_TABS_CLIENT_GUID_IS_LOCAL_SELECTION, TEST_TABS_CLIENT_GUID_IS_LOCAL_SELECTION_ARGS);
- }
-
- @Override
- protected void tearDown() throws Exception {
- if (tabsClient != null) {
- deleteAllTestTabs(tabsClient);
-
- tabsClient.release();
- tabsClient = null;
- }
-
- if (clientsClient != null) {
- deleteTestClient(clientsClient);
-
- clientsClient.release();
- clientsClient = null;
- }
- }
-
- protected FennecTabsRepository getRepository() {
- /**
- * Override this chain in order to avoid our test code having to create two
- * sessions all the time.
- */
- return new FennecTabsRepository(clientsDataDelegate) {
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- try {
- final FennecTabsRepositorySession session = new FennecTabsRepositorySession(this, context) {
- @Override
- protected synchronized void trackGUID(String guid) {
- }
-
- @Override
- protected String localClientSelection() {
- return TEST_TABS_CLIENT_GUID_IS_LOCAL_SELECTION;
- }
-
- @Override
- protected String[] localClientSelectionArgs() {
- return TEST_TABS_CLIENT_GUID_IS_LOCAL_SELECTION_ARGS;
- }
- };
- delegate.onSessionCreated(session);
- } catch (Exception e) {
- delegate.onSessionCreateFailed(e);
- }
- }
- };
- }
-
- protected FennecTabsRepositorySession createSession() {
- return (FennecTabsRepositorySession) SessionTestHelper.createSession(
- getApplicationContext(),
- getRepository());
- }
-
- protected FennecTabsRepositorySession createAndBeginSession() {
- return (FennecTabsRepositorySession) SessionTestHelper.createAndBeginSession(
- getApplicationContext(),
- getRepository());
- }
-
- protected Runnable fetchSinceRunnable(final RepositorySession session, final long timestamp, final Record[] expectedRecords) {
- return new Runnable() {
- @Override
- public void run() {
- session.fetchSince(timestamp, new ExpectFetchDelegate(expectedRecords));
- }
- };
- }
-
- protected Runnable fetchAllRunnable(final RepositorySession session, final Record[] expectedRecords) {
- return new Runnable() {
- @Override
- public void run() {
- session.fetchAll(new ExpectFetchDelegate(expectedRecords));
- }
- };
- }
-
- protected Tab testTab1;
- protected Tab testTab2;
- protected Tab testTab3;
-
- @SuppressWarnings("unchecked")
- private void insertSomeTestTabs(ContentProviderClient tabsClient) throws RemoteException {
- final JSONArray history1 = new JSONArray();
- history1.add("http://test.com/test1.html");
- testTab1 = new Tab("test title 1", "http://test.com/test1.png", history1, 1000);
-
- final JSONArray history2 = new JSONArray();
- history2.add("http://test.com/test2.html#1");
- history2.add("http://test.com/test2.html#2");
- history2.add("http://test.com/test2.html#3");
- testTab2 = new Tab("test title 2", "http://test.com/test2.png", history2, 2000);
-
- final JSONArray history3 = new JSONArray();
- history3.add("http://test.com/test3.html#1");
- history3.add("http://test.com/test3.html#2");
- testTab3 = new Tab("test title 3", "http://test.com/test3.png", history3, 3000);
-
- tabsClient.insert(BrowserContractHelpers.TABS_CONTENT_URI, testTab1.toContentValues(TEST_CLIENT_GUID, 0));
- tabsClient.insert(BrowserContractHelpers.TABS_CONTENT_URI, testTab2.toContentValues(TEST_CLIENT_GUID, 1));
- tabsClient.insert(BrowserContractHelpers.TABS_CONTENT_URI, testTab3.toContentValues(TEST_CLIENT_GUID, 2));
- }
-
- protected TabsRecord insertTestTabsAndExtractTabsRecord() throws RemoteException {
- insertSomeTestTabs(tabsClient);
-
- final String positionAscending = BrowserContract.Tabs.POSITION + " ASC";
- Cursor cursor = null;
- try {
- cursor = tabsClient.query(BrowserContractHelpers.TABS_CONTENT_URI, null,
- TEST_TABS_CLIENT_GUID_IS_LOCAL_SELECTION, TEST_TABS_CLIENT_GUID_IS_LOCAL_SELECTION_ARGS, positionAscending);
- CursorDumper.dumpCursor(cursor);
-
- final TabsRecord tabsRecord = FennecTabsRepository.tabsRecordFromCursor(cursor, TEST_CLIENT_GUID, TEST_CLIENT_NAME);
-
- assertEquals(TEST_CLIENT_GUID, tabsRecord.guid);
- assertEquals(TEST_CLIENT_NAME, tabsRecord.clientName);
-
- assertNotNull(tabsRecord.tabs);
- assertEquals(cursor.getCount(), tabsRecord.tabs.size());
-
- return tabsRecord;
- } finally {
- cursor.close();
- }
- }
-
- public void testFetchAll() throws NoContentProviderException, RemoteException {
- final TabsRecord tabsRecord = insertTestTabsAndExtractTabsRecord();
-
- final FennecTabsRepositorySession session = createAndBeginSession();
- performWait(fetchAllRunnable(session, new Record[] { tabsRecord }));
-
- session.abort();
- }
-
- public void testFetchSince() throws NoContentProviderException, RemoteException {
- final TabsRecord tabsRecord = insertTestTabsAndExtractTabsRecord();
-
- final FennecTabsRepositorySession session = createAndBeginSession();
-
- // Not all tabs are modified after this, but the record should contain them all.
- performWait(fetchSinceRunnable(session, 1000, new Record[] { tabsRecord }));
-
- // No tabs are modified after this, but our client name has changed in the interim.
- performWait(fetchSinceRunnable(session, 4000, new Record[] { tabsRecord }));
-
- // No tabs are modified after this, and our client name hasn't changed, so
- // we shouldn't get a record at all. Note: this runs after our static
- // initializer that sets the client data timestamp.
- final long now = System.currentTimeMillis();
- performWait(fetchSinceRunnable(session, now, new Record[] { }));
-
- // No tabs are modified after this, but our client name has changed, so
- // again we get a record.
- clientsDataDelegate.setClientName("new client name", System.currentTimeMillis());
- performWait(fetchSinceRunnable(session, now, new Record[] { tabsRecord }));
-
- session.abort();
- }
-
- // Verify that storing a tabs record writes a clients record with the correct
- // device type to the Fennec clients provider.
- public void testStore() throws NoContentProviderException, RemoteException {
- // Get a valid tabsRecord to write.
- final TabsRecord tabsRecord = insertTestTabsAndExtractTabsRecord();
- deleteAllTestTabs(tabsClient);
- deleteTestClient(clientsClient);
-
- final ContentResolver cr = getApplicationContext().getContentResolver();
- final ContentProviderClient clientsClient = cr.acquireContentProviderClient(BrowserContractHelpers.CLIENTS_CONTENT_URI);
-
- try {
- // This clients DB is not the Fennec DB; it's Sync's own clients DB.
- final ClientsDatabaseAccessor db = new ClientsDatabaseAccessor(getApplicationContext());
- try {
- ClientRecord clientRecord = new ClientRecord(TEST_CLIENT_GUID);
- clientRecord.name = TEST_CLIENT_NAME;
- clientRecord.type = TEST_CLIENT_DEVICE_TYPE;
- db.store(clientRecord);
- } finally {
- db.close();
- }
-
- final FennecTabsRepositorySession session = createAndBeginSession();
- performWait(AndroidBrowserRepositoryTestCase.storeRunnable(session, tabsRecord));
-
- session.abort();
-
- // This store should write Sync's idea of the client's device_type to Fennec's clients CP.
- final Cursor cursor = clientsClient.query(BrowserContractHelpers.CLIENTS_CONTENT_URI, null,
- TEST_CLIENTS_GUID_IS_LOCAL_SELECTION, TEST_CLIENTS_GUID_IS_LOCAL_SELECTION_ARGS, null);
- assertNotNull(cursor);
-
- try {
- assertTrue(cursor.moveToFirst());
- assertEquals(TEST_CLIENT_GUID, cursor.getString(cursor.getColumnIndex(Clients.GUID)));
- assertEquals(TEST_CLIENT_NAME, cursor.getString(cursor.getColumnIndex(Clients.NAME)));
- assertEquals(TEST_CLIENT_DEVICE_TYPE, cursor.getString(cursor.getColumnIndex(Clients.DEVICE_TYPE)));
- assertTrue(cursor.isLast());
- } finally {
- cursor.close();
- }
- } finally {
- // We can't delete only our test client due to a Fennec CP issue with guid vs. client_guid.
- clientsClient.delete(BrowserContractHelpers.CLIENTS_CONTENT_URI, null, null);
- clientsClient.release();
- }
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java
deleted file mode 100644
index 5d5014b75..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java
+++ /dev/null
@@ -1,441 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectFetchSinceDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectGuidsSinceDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectNoStoreDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectStoredDelegate;
-import org.mozilla.gecko.background.sync.helpers.SessionTestHelper;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.NoContentProviderException;
-import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.mozilla.gecko.sync.repositories.android.FormHistoryRepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
-import org.mozilla.gecko.sync.repositories.domain.FormHistoryRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import android.content.ContentProviderClient;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-
-public class TestFormHistoryRepositorySession extends AndroidSyncTestCase {
- protected ContentProviderClient formsProvider = null;
-
- public TestFormHistoryRepositorySession() throws NoContentProviderException {
- super();
- }
-
- public void setUp() {
- if (formsProvider == null) {
- try {
- formsProvider = FormHistoryRepositorySession.acquireContentProvider(getApplicationContext());
- } catch (NoContentProviderException e) {
- fail("Failed to acquireContentProvider: " + e);
- }
- }
-
- try {
- FormHistoryRepositorySession.purgeDatabases(formsProvider);
- } catch (RemoteException e) {
- fail("Failed to purgeDatabases: " + e);
- }
- }
-
- public void tearDown() {
- if (formsProvider != null) {
- formsProvider.release();
- formsProvider = null;
- }
- }
-
- protected FormHistoryRepositorySession.FormHistoryRepository getRepository() {
- /**
- * Override this chain in order to avoid our test code having to create two
- * sessions all the time.
- */
- return new FormHistoryRepositorySession.FormHistoryRepository() {
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- try {
- final FormHistoryRepositorySession session = new FormHistoryRepositorySession(this, context) {
- @Override
- protected synchronized void trackGUID(String guid) {
- }
- };
- delegate.onSessionCreated(session);
- } catch (Exception e) {
- delegate.onSessionCreateFailed(e);
- }
- }
- };
- }
-
-
- protected FormHistoryRepositorySession createSession() {
- return (FormHistoryRepositorySession) SessionTestHelper.createSession(
- getApplicationContext(),
- getRepository());
- }
-
- protected FormHistoryRepositorySession createAndBeginSession() {
- return (FormHistoryRepositorySession) SessionTestHelper.createAndBeginSession(
- getApplicationContext(),
- getRepository());
- }
-
- public void testAcquire() throws NoContentProviderException {
- final FormHistoryRepositorySession session = createAndBeginSession();
- assertNotNull(session.getFormsProvider());
- session.abort();
- }
-
- protected int numRecords(FormHistoryRepositorySession session, Uri uri) throws RemoteException {
- Cursor cur = null;
- try {
- cur = session.getFormsProvider().query(uri, null, null, null, null);
- return cur.getCount();
- } finally {
- if (cur != null) {
- cur.close();
- }
- }
- }
-
- protected long after0;
- protected long after1;
- protected long after2;
- protected long after3;
- protected long after4;
- protected FormHistoryRecord regular1;
- protected FormHistoryRecord regular2;
- protected FormHistoryRecord deleted1;
- protected FormHistoryRecord deleted2;
-
- public void insertTwoRecords(FormHistoryRepositorySession session) throws RemoteException {
- Uri regularUri = BrowserContractHelpers.FORM_HISTORY_CONTENT_URI;
- Uri deletedUri = BrowserContractHelpers.DELETED_FORM_HISTORY_CONTENT_URI;
- after0 = System.currentTimeMillis();
-
- regular1 = new FormHistoryRecord("guid1", "forms", System.currentTimeMillis(), false);
- regular1.fieldName = "fieldName1";
- regular1.fieldValue = "value1";
- final ContentValues cv1 = new ContentValues();
- cv1.put(BrowserContract.FormHistory.GUID, regular1.guid);
- cv1.put(BrowserContract.FormHistory.FIELD_NAME, regular1.fieldName);
- cv1.put(BrowserContract.FormHistory.VALUE, regular1.fieldValue);
- cv1.put(BrowserContract.FormHistory.FIRST_USED, 1000 * regular1.lastModified); // Microseconds.
-
- int regularInserted = session.getFormsProvider().bulkInsert(regularUri, new ContentValues[] { cv1 });
- assertEquals(1, regularInserted);
- after1 = System.currentTimeMillis();
-
- deleted1 = new FormHistoryRecord("guid3", "forms", -1, true);
- final ContentValues cv3 = new ContentValues();
- cv3.put(BrowserContract.FormHistory.GUID, deleted1.guid);
- // cv3.put(BrowserContract.DeletedFormHistory.TIME_DELETED, record3.lastModified); // Set by CP.
-
- int deletedInserted = session.getFormsProvider().bulkInsert(deletedUri, new ContentValues[] { cv3 });
- assertEquals(1, deletedInserted);
- after2 = System.currentTimeMillis();
-
- regular2 = null;
- deleted2 = null;
- }
-
- public void insertFourRecords(FormHistoryRepositorySession session) throws RemoteException {
- Uri regularUri = BrowserContractHelpers.FORM_HISTORY_CONTENT_URI;
- Uri deletedUri = BrowserContractHelpers.DELETED_FORM_HISTORY_CONTENT_URI;
-
- insertTwoRecords(session);
-
- regular2 = new FormHistoryRecord("guid2", "forms", System.currentTimeMillis(), false);
- regular2.fieldName = "fieldName2";
- regular2.fieldValue = "value2";
- final ContentValues cv2 = new ContentValues();
- cv2.put(BrowserContract.FormHistory.GUID, regular2.guid);
- cv2.put(BrowserContract.FormHistory.FIELD_NAME, regular2.fieldName);
- cv2.put(BrowserContract.FormHistory.VALUE, regular2.fieldValue);
- cv2.put(BrowserContract.FormHistory.FIRST_USED, 1000 * regular2.lastModified); // Microseconds.
-
- int regularInserted = session.getFormsProvider().bulkInsert(regularUri, new ContentValues[] { cv2 });
- assertEquals(1, regularInserted);
- after3 = System.currentTimeMillis();
-
- deleted2 = new FormHistoryRecord("guid4", "forms", -1, true);
- final ContentValues cv4 = new ContentValues();
- cv4.put(BrowserContract.FormHistory.GUID, deleted2.guid);
- // cv4.put(BrowserContract.DeletedFormHistory.TIME_DELETED, record4.lastModified); // Set by CP.
-
- int deletedInserted = session.getFormsProvider().bulkInsert(deletedUri, new ContentValues[] { cv4 });
- assertEquals(1, deletedInserted);
- after4 = System.currentTimeMillis();
- }
-
- public void testWipe() throws NoContentProviderException, RemoteException {
- final FormHistoryRepositorySession session = createAndBeginSession();
-
- insertTwoRecords(session);
- assertTrue(numRecords(session, BrowserContractHelpers.FORM_HISTORY_CONTENT_URI) > 0);
- assertTrue(numRecords(session, BrowserContractHelpers.DELETED_FORM_HISTORY_CONTENT_URI) > 0);
-
- performWait(WaitHelper.onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- session.wipe(new RepositorySessionWipeDelegate() {
- public void onWipeSucceeded() {
- performNotify();
- }
- public void onWipeFailed(Exception ex) {
- performNotify("Wipe should have succeeded", ex);
- }
- @Override
- public RepositorySessionWipeDelegate deferredWipeDelegate(final ExecutorService executor) {
- return this;
- }
- });
- }
- }));
-
- assertEquals(0, numRecords(session, BrowserContractHelpers.FORM_HISTORY_CONTENT_URI));
- assertEquals(0, numRecords(session, BrowserContractHelpers.DELETED_FORM_HISTORY_CONTENT_URI));
-
- session.abort();
- }
-
- protected Runnable fetchSinceRunnable(final RepositorySession session, final long timestamp, final String[] expectedGuids) {
- return new Runnable() {
- @Override
- public void run() {
- session.fetchSince(timestamp, new ExpectFetchSinceDelegate(timestamp, expectedGuids));
- }
- };
- }
-
- protected Runnable fetchAllRunnable(final RepositorySession session, final Record[] expectedRecords) {
- return new Runnable() {
- @Override
- public void run() {
- session.fetchAll(new ExpectFetchDelegate(expectedRecords));
- }
- };
- }
-
- protected Runnable fetchRunnable(final RepositorySession session, final String[] guids, final Record[] expectedRecords) {
- return new Runnable() {
- @Override
- public void run() {
- try {
- session.fetch(guids, new ExpectFetchDelegate(expectedRecords));
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- };
- }
-
- public void testFetchAll() throws NoContentProviderException, RemoteException {
- final FormHistoryRepositorySession session = createAndBeginSession();
-
- insertTwoRecords(session);
-
- performWait(fetchAllRunnable(session, new Record[] { regular1, deleted1 }));
-
- session.abort();
- }
-
- public void testFetchByGuid() throws NoContentProviderException, RemoteException {
- final FormHistoryRepositorySession session = createAndBeginSession();
-
- insertTwoRecords(session);
-
- performWait(fetchRunnable(session,
- new String[] { regular1.guid, deleted1.guid },
- new Record[] { regular1, deleted1 }));
- performWait(fetchRunnable(session,
- new String[] { regular1.guid },
- new Record[] { regular1 }));
- performWait(fetchRunnable(session,
- new String[] { deleted1.guid, "NON_EXISTENT_GUID?" },
- new Record[] { deleted1 }));
- performWait(fetchRunnable(session,
- new String[] { "FIRST_NON_EXISTENT_GUID", "SECOND_NON_EXISTENT_GUID?" },
- new Record[] { }));
-
- session.abort();
- }
-
- public void testFetchSince() throws NoContentProviderException, RemoteException {
- final FormHistoryRepositorySession session = createAndBeginSession();
-
- insertFourRecords(session);
-
- performWait(fetchSinceRunnable(session,
- after0, new String[] { regular1.guid, deleted1.guid, regular2.guid, deleted2.guid }));
- performWait(fetchSinceRunnable(session,
- after1, new String[] { deleted1.guid, regular2.guid, deleted2.guid }));
- performWait(fetchSinceRunnable(session,
- after2, new String[] { regular2.guid, deleted2.guid }));
- performWait(fetchSinceRunnable(session,
- after3, new String[] { deleted2.guid }));
- performWait(fetchSinceRunnable(session,
- after4, new String[] { }));
-
- session.abort();
- }
-
- protected Runnable guidsSinceRunnable(final RepositorySession session, final long timestamp, final String[] expectedGuids) {
- return new Runnable() {
- @Override
- public void run() {
- session.guidsSince(timestamp, new ExpectGuidsSinceDelegate(expectedGuids));
- }
- };
- }
-
- public void testGuidsSince() throws NoContentProviderException, RemoteException {
- final FormHistoryRepositorySession session = createAndBeginSession();
-
- insertTwoRecords(session);
-
- performWait(guidsSinceRunnable(session,
- after0, new String[] { regular1.guid, deleted1.guid }));
- performWait(guidsSinceRunnable(session,
- after1, new String[] { deleted1.guid}));
- performWait(guidsSinceRunnable(session,
- after2, new String[] { }));
-
- session.abort();
- }
-
- protected Runnable storeRunnable(final RepositorySession session, final Record record, final RepositorySessionStoreDelegate delegate) {
- return new Runnable() {
- @Override
- public void run() {
- session.setStoreDelegate(delegate);
- try {
- session.store(record);
- session.storeDone();
- } catch (NoStoreDelegateException e) {
- performNotify("NoStoreDelegateException should not occur.", e);
- }
- }
- };
- }
-
- public void testStoreRemoteNew() throws NoContentProviderException, RemoteException {
- final FormHistoryRepositorySession session = createAndBeginSession();
-
- insertTwoRecords(session);
-
- FormHistoryRecord rec;
-
- // remote regular, local missing => should store.
- rec = new FormHistoryRecord("new1", "forms", System.currentTimeMillis(), false);
- rec.fieldName = "fieldName1";
- rec.fieldValue = "fieldValue1";
- performWait(storeRunnable(session, rec, new ExpectStoredDelegate(rec.guid)));
- performWait(fetchRunnable(session, new String[] { rec.guid }, new Record[] { rec }));
-
- // remote deleted, local missing => should delete, but at the moment we ignore.
- rec = new FormHistoryRecord("new2", "forms", System.currentTimeMillis(), true);
- performWait(storeRunnable(session, rec, new ExpectNoStoreDelegate()));
- performWait(fetchRunnable(session, new String[] { rec.guid }, new Record[] { }));
-
- session.abort();
- }
-
- public void testStoreRemoteNewer() throws NoContentProviderException, RemoteException {
- final FormHistoryRepositorySession session = createAndBeginSession();
-
- insertFourRecords(session);
- long newTimestamp = System.currentTimeMillis();
-
- FormHistoryRecord rec;
-
- // remote regular, local regular, remote newer => should update.
- rec = new FormHistoryRecord(regular1.guid, regular1.collection, newTimestamp, false);
- rec.fieldName = regular1.fieldName;
- rec.fieldValue = regular1.fieldValue + "NEW";
- performWait(storeRunnable(session, rec, new ExpectStoredDelegate(rec.guid)));
- performWait(fetchRunnable(session, new String[] { regular1.guid }, new Record[] { rec }));
-
- // remote deleted, local regular, remote newer => should delete everything.
- rec = new FormHistoryRecord(regular2.guid, regular2.collection, newTimestamp, true);
- performWait(storeRunnable(session, rec, new ExpectStoredDelegate(rec.guid)));
- performWait(fetchRunnable(session, new String[] { regular2.guid }, new Record[] { }));
-
- // remote regular, local deleted, remote newer => should update.
- rec = new FormHistoryRecord(deleted1.guid, deleted1.collection, newTimestamp, false);
- rec.fieldName = regular1.fieldName;
- rec.fieldValue = regular1.fieldValue + "NEW";
- performWait(storeRunnable(session, rec, new ExpectStoredDelegate(rec.guid)));
- performWait(fetchRunnable(session, new String[] { deleted1.guid }, new Record[] { rec }));
-
- // remote deleted, local deleted, remote newer => should delete everything.
- rec = new FormHistoryRecord(deleted2.guid, deleted2.collection, newTimestamp, true);
- performWait(storeRunnable(session, rec, new ExpectNoStoreDelegate()));
- performWait(fetchRunnable(session, new String[] { deleted2.guid }, new Record[] { }));
-
- session.abort();
- }
-
- public void testStoreRemoteOlder() throws NoContentProviderException, RemoteException {
- final FormHistoryRepositorySession session = createAndBeginSession();
-
- long oldTimestamp = System.currentTimeMillis() - 100;
- insertFourRecords(session);
-
- FormHistoryRecord rec;
-
- // remote regular, local regular, remote older => should ignore.
- rec = new FormHistoryRecord(regular1.guid, regular1.collection, oldTimestamp, false);
- rec.fieldName = regular1.fieldName;
- rec.fieldValue = regular1.fieldValue + "NEW";
- performWait(storeRunnable(session, rec, new ExpectNoStoreDelegate()));
-
- // remote deleted, local regular, remote older => should ignore.
- rec = new FormHistoryRecord(regular2.guid, regular2.collection, oldTimestamp, true);
- performWait(storeRunnable(session, rec, new ExpectNoStoreDelegate()));
-
- // remote regular, local deleted, remote older => should ignore.
- rec = new FormHistoryRecord(deleted1.guid, deleted1.collection, oldTimestamp, false);
- rec.fieldName = regular1.fieldName;
- rec.fieldValue = regular1.fieldValue + "NEW";
- performWait(storeRunnable(session, rec, new ExpectNoStoreDelegate()));
-
- // remote deleted, local deleted, remote older => should ignore.
- rec = new FormHistoryRecord(deleted2.guid, deleted2.collection, oldTimestamp, true);
- performWait(storeRunnable(session, rec, new ExpectNoStoreDelegate()));
-
- session.abort();
- }
-
- public void testStoreDifferentGuid() throws NoContentProviderException, RemoteException {
- final FormHistoryRepositorySession session = createAndBeginSession();
-
- insertTwoRecords(session);
-
- FormHistoryRecord rec = (FormHistoryRecord) regular1.copyWithIDs("distinct", 999);
- performWait(storeRunnable(session, rec, new ExpectStoredDelegate(rec.guid)));
- // Existing record should take remote record's GUID.
- performWait(fetchAllRunnable(session, new Record[] { rec, deleted1 }));
-
- session.abort();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestPasswordsRepository.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestPasswordsRepository.java
deleted file mode 100644
index 210c8ca8c..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestPasswordsRepository.java
+++ /dev/null
@@ -1,482 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectFetchSinceDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectGuidsSinceDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectNoStoreDelegate;
-import org.mozilla.gecko.background.sync.helpers.ExpectStoredDelegate;
-import org.mozilla.gecko.background.sync.helpers.PasswordHelpers;
-import org.mozilla.gecko.background.sync.helpers.SessionTestHelper;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.mozilla.gecko.sync.repositories.android.PasswordsRepositorySession;
-import org.mozilla.gecko.sync.repositories.android.RepoUtils;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
-import org.mozilla.gecko.sync.repositories.domain.PasswordRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import android.content.ContentProviderClient;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.os.RemoteException;
-
-public class TestPasswordsRepository extends AndroidSyncTestCase {
- private final String NEW_PASSWORD1 = "password";
- private final String NEW_PASSWORD2 = "drowssap";
-
- @Override
- public void setUp() {
- wipe();
- assertTrue(WaitHelper.getTestWaiter().isIdle());
- }
-
- public void testFetchAll() {
- RepositorySession session = createAndBeginSession();
- Record[] expected = new Record[] { PasswordHelpers.createPassword1(),
- PasswordHelpers.createPassword2() };
-
- performWait(storeRunnable(session, expected[0]));
- performWait(storeRunnable(session, expected[1]));
-
- performWait(fetchAllRunnable(session, expected));
- dispose(session);
- }
-
- public void testGuidsSinceReturnMultipleRecords() {
- RepositorySession session = createAndBeginSession();
-
- PasswordRecord record1 = PasswordHelpers.createPassword1();
- PasswordRecord record2 = PasswordHelpers.createPassword2();
-
- updatePassword(NEW_PASSWORD1, record1);
- long timestamp = updatePassword(NEW_PASSWORD2, record2);
-
- String[] expected = new String[] { record1.guid, record2.guid };
-
- performWait(storeRunnable(session, record1));
- performWait(storeRunnable(session, record2));
-
- performWait(guidsSinceRunnable(session, timestamp, expected));
- dispose(session);
- }
-
- public void testGuidsSinceReturnNoRecords() {
- RepositorySession session = createAndBeginSession();
-
- // Store 1 record in the past.
- performWait(storeRunnable(session, PasswordHelpers.createPassword1()));
-
- String[] expected = {};
- performWait(guidsSinceRunnable(session, System.currentTimeMillis() + 1000, expected));
- dispose(session);
- }
-
- public void testFetchSinceOneRecord() {
- RepositorySession session = createAndBeginSession();
-
- // Passwords fetchSince checks timePasswordChanged, not insertion time.
- PasswordRecord record1 = PasswordHelpers.createPassword1();
- long timeModified1 = updatePassword(NEW_PASSWORD1, record1);
- performWait(storeRunnable(session, record1));
-
- PasswordRecord record2 = PasswordHelpers.createPassword2();
- long timeModified2 = updatePassword(NEW_PASSWORD2, record2);
- performWait(storeRunnable(session, record2));
-
- String[] expectedOne = new String[] { record2.guid };
- performWait(fetchSinceRunnable(session, timeModified2 - 10, expectedOne));
-
- String[] expectedBoth = new String[] { record1.guid, record2.guid };
- performWait(fetchSinceRunnable(session, timeModified1 - 10, expectedBoth));
-
- dispose(session);
- }
-
- public void testFetchSinceReturnNoRecords() {
- RepositorySession session = createAndBeginSession();
-
- performWait(storeRunnable(session, PasswordHelpers.createPassword2()));
-
- long timestamp = System.currentTimeMillis();
-
- performWait(fetchSinceRunnable(session, timestamp + 2000, new String[] {}));
- dispose(session);
- }
-
- public void testFetchOneRecordByGuid() {
- RepositorySession session = createAndBeginSession();
- Record record = PasswordHelpers.createPassword1();
- performWait(storeRunnable(session, record));
- performWait(storeRunnable(session, PasswordHelpers.createPassword2()));
-
- String[] guids = new String[] { record.guid };
- Record[] expected = new Record[] { record };
- performWait(fetchRunnable(session, guids, expected));
- dispose(session);
- }
-
- public void testFetchMultipleRecordsByGuids() {
- RepositorySession session = createAndBeginSession();
- PasswordRecord record1 = PasswordHelpers.createPassword1();
- PasswordRecord record2 = PasswordHelpers.createPassword2();
- PasswordRecord record3 = PasswordHelpers.createPassword3();
-
- performWait(storeRunnable(session, record1));
- performWait(storeRunnable(session, record2));
- performWait(storeRunnable(session, record3));
-
- String[] guids = new String[] { record1.guid, record2.guid };
- Record[] expected = new Record[] { record1, record2 };
- performWait(fetchRunnable(session, guids, expected));
- dispose(session);
- }
-
- public void testFetchNoRecordByGuid() {
- RepositorySession session = createAndBeginSession();
- Record record = PasswordHelpers.createPassword1();
-
- performWait(storeRunnable(session, record));
- performWait(fetchRunnable(session,
- new String[] { Utils.generateGuid() },
- new Record[] {}));
- dispose(session);
- }
-
- public void testStore() {
- final RepositorySession session = createAndBeginSession();
- performWait(storeRunnable(session, PasswordHelpers.createPassword1()));
- dispose(session);
- }
-
- public void testRemoteNewerTimeStamp() {
- final RepositorySession session = createAndBeginSession();
-
- // Store updated local record.
- PasswordRecord local = PasswordHelpers.createPassword1();
- updatePassword(NEW_PASSWORD1, local, System.currentTimeMillis() - 1000);
- performWait(storeRunnable(session, local));
-
- // Sync a remote record version that is newer.
- PasswordRecord remote = PasswordHelpers.createPassword2();
- remote.guid = local.guid;
- updatePassword(NEW_PASSWORD2, remote);
- performWait(storeRunnable(session, remote));
-
- // Make a fetch, expecting only the newer (remote) record.
- performWait(fetchAllRunnable(session, new Record[] { remote }));
-
- // Store an older local record.
- PasswordRecord local2 = PasswordHelpers.createPassword3();
- updatePassword(NEW_PASSWORD2, local2, System.currentTimeMillis() - 1000);
- performWait(storeRunnable(session, local2));
-
- // Sync a remote record version that is newer and is deleted.
- PasswordRecord remote2 = PasswordHelpers.createPassword3();
- remote2.guid = local2.guid;
- remote2.deleted = true;
- updatePassword(NEW_PASSWORD2, remote2);
- performWait(storeRunnable(session, remote2));
-
- // Make a fetch, expecting the local record to be deleted.
- performWait(fetchRunnable(session, new String[] { remote2.guid }, new Record[] {}));
-
- // Store an older deleted local record.
- PasswordRecord local3 = PasswordHelpers.createPassword4();
- updatePassword(NEW_PASSWORD2, local3, System.currentTimeMillis() - 1000);
- local3.deleted = true;
- storeLocalDeletedRecord(local3, System.currentTimeMillis() - 1000);
-
- // Sync a remote record version that is newer and is deleted.
- PasswordRecord remote3 = PasswordHelpers.createPassword5();
- remote3.guid = local3.guid;
- remote3.deleted = true;
- updatePassword(NEW_PASSWORD2, remote3);
- performWait(storeRunnable(session, remote3));
-
- // Make a fetch, expecting the local record to be deleted.
- performWait(fetchRunnable(session, new String[] { remote3.guid }, new Record[] {}));
- dispose(session);
- }
-
- public void testLocalNewerTimeStamp() {
- final RepositorySession session = createAndBeginSession();
- // Remote record updated before local record.
- PasswordRecord remote = PasswordHelpers.createPassword1();
- updatePassword(NEW_PASSWORD1, remote, System.currentTimeMillis() - 1000);
-
- // Store updated local record.
- PasswordRecord local = PasswordHelpers.createPassword2();
- updatePassword(NEW_PASSWORD2, local);
- performWait(storeRunnable(session, local));
-
- // Sync a remote record version that is older.
- remote.guid = local.guid;
- performWait(storeRunnable(session, remote));
-
- // Make a fetch, expecting only the newer (local) record.
- performWait(fetchAllRunnable(session, new Record[] { local }));
-
- // Remote record updated before local record.
- PasswordRecord remote2 = PasswordHelpers.createPassword3();
- updatePassword(NEW_PASSWORD1, remote2, System.currentTimeMillis() - 1000);
-
- // Store updated local record that is deleted.
- PasswordRecord local2 = PasswordHelpers.createPassword3();
- updatePassword(NEW_PASSWORD2, local2);
- local2.deleted = true;
- storeLocalDeletedRecord(local2, System.currentTimeMillis());
-
- // Sync a remote record version that is older.
- remote2.guid = local2.guid;
- performWait(storeRunnable(session, remote2, new ExpectNoStoreDelegate()));
-
- // Make a fetch, expecting only the deleted newer (local) record.
- performWait(fetchRunnable(session, new String[] { local2.guid }, new Record[] { local2 }));
-
- // Remote record updated before local record.
- PasswordRecord remote3 = PasswordHelpers.createPassword4();
- updatePassword(NEW_PASSWORD1, remote3, System.currentTimeMillis() - 1000);
-
- // Store updated local record that is deleted.
- PasswordRecord local3 = PasswordHelpers.createPassword4();
- updatePassword(NEW_PASSWORD2, local3);
- local3.deleted = true;
- storeLocalDeletedRecord(local3, System.currentTimeMillis());
-
- // Sync a remote record version that is older and is deleted.
- remote3.guid = local3.guid;
- remote3.deleted = true;
- performWait(storeRunnable(session, remote3));
-
- // Make a fetch, expecting the local record to be deleted.
- performWait(fetchRunnable(session, new String[] { local3.guid }, new Record[] {}));
- dispose(session);
- }
-
- /*
- * Store two records that are identical except for guid. Expect to find the
- * remote one after reconciling.
- */
- public void testStoreIdenticalExceptGuid() {
- RepositorySession session = createAndBeginSession();
- PasswordRecord record = PasswordHelpers.createPassword1();
- record.guid = "before1";
- // Store record.
- performWait(storeRunnable(session, record));
-
- // Store same record, but with different guid.
- record.guid = Utils.generateGuid();
- performWait(storeRunnable(session, record));
-
- performWait(fetchAllRunnable(session, new Record[] { record }));
- dispose(session);
-
- session = createAndBeginSession();
-
- PasswordRecord record2 = PasswordHelpers.createPassword2();
- record2.guid = "before2";
- // Store record.
- performWait(storeRunnable(session, record2));
-
- // Store same record, but with different guid.
- record2.guid = Utils.generateGuid();
- performWait(storeRunnable(session, record2));
-
- performWait(fetchAllRunnable(session, new Record[] { record, record2 }));
- dispose(session);
- }
-
- /*
- * Store two records that are identical except for guid when they both point
- * to the same site and there are multiple records for that site. Expect to
- * find the remote one after reconciling.
- */
- public void testStoreIdenticalExceptGuidOnSameSite() {
- RepositorySession session = createAndBeginSession();
- PasswordRecord record1 = PasswordHelpers.createPassword1();
- record1.encryptedUsername = "original";
- record1.guid = "before1";
- PasswordRecord record2 = PasswordHelpers.createPassword1();
- record2.encryptedUsername = "different";
- record1.guid = "before2";
- // Store records.
- performWait(storeRunnable(session, record1));
- performWait(storeRunnable(session, record2));
- performWait(fetchAllRunnable(session, new Record[] { record1, record2 }));
-
- dispose(session);
- session = createAndBeginSession();
-
- // Store same records, but with different guids.
- record1.guid = Utils.generateGuid();
- performWait(storeRunnable(session, record1));
- performWait(fetchAllRunnable(session, new Record[] { record1, record2 }));
-
- record2.guid = Utils.generateGuid();
- performWait(storeRunnable(session, record2));
- performWait(fetchAllRunnable(session, new Record[] { record1, record2 }));
-
- dispose(session);
- }
-
- public void testRawFetch() throws RemoteException {
- RepositorySession session = createAndBeginSession();
- Record[] expected = new Record[] { PasswordHelpers.createPassword1(),
- PasswordHelpers.createPassword2() };
-
- performWait(storeRunnable(session, expected[0]));
- performWait(storeRunnable(session, expected[1]));
-
- ContentProviderClient client = getApplicationContext().getContentResolver().acquireContentProviderClient(BrowserContract.PASSWORDS_AUTHORITY_URI);
- Cursor cursor = client.query(BrowserContractHelpers.PASSWORDS_CONTENT_URI, null, null, null, null);
- assertEquals(2, cursor.getCount());
- cursor.moveToFirst();
- Set<String> guids = new HashSet<String>();
- while (!cursor.isAfterLast()) {
- String guid = RepoUtils.getStringFromCursor(cursor, BrowserContract.Passwords.GUID);
- guids.add(guid);
- cursor.moveToNext();
- }
- cursor.close();
- assertEquals(2, guids.size());
- assertTrue(guids.contains(expected[0].guid));
- assertTrue(guids.contains(expected[1].guid));
- dispose(session);
- }
-
- // Helper methods.
- private RepositorySession createAndBeginSession() {
- return SessionTestHelper.createAndBeginSession(
- getApplicationContext(),
- getRepository());
- }
-
- private Repository getRepository() {
- /**
- * Override this chain in order to avoid our test code having to create two
- * sessions all the time. Don't track records, so they filtering doesn't happen.
- */
- return new PasswordsRepositorySession.PasswordsRepository() {
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- PasswordsRepositorySession session;
- session = new PasswordsRepositorySession(this, context) {
- @Override
- protected synchronized void trackGUID(String guid) {
- }
- };
- delegate.onSessionCreated(session);
- }
- };
- }
-
- private void wipe() {
- Context context = getApplicationContext();
- context.getContentResolver().delete(BrowserContractHelpers.PASSWORDS_CONTENT_URI, null, null);
- context.getContentResolver().delete(BrowserContractHelpers.DELETED_PASSWORDS_CONTENT_URI, null, null);
- }
-
- private void storeLocalDeletedRecord(Record record, long time) {
- // Wipe data-store
- wipe();
- // Store record in deleted table.
- ContentValues contentValues = new ContentValues();
- contentValues.put(BrowserContract.DeletedColumns.GUID, record.guid);
- contentValues.put(BrowserContract.DeletedColumns.TIME_DELETED, time);
- contentValues.put(BrowserContract.DeletedColumns.ID, record.androidID);
- getApplicationContext().getContentResolver().insert(BrowserContractHelpers.DELETED_PASSWORDS_CONTENT_URI, contentValues);
- }
-
- private static void dispose(RepositorySession session) {
- if (session != null) {
- session.abort();
- }
- }
-
- private static long updatePassword(String password, PasswordRecord record, long timestamp) {
- record.encryptedPassword = password;
- long modifiedTime = System.currentTimeMillis();
- record.timePasswordChanged = record.lastModified = modifiedTime;
- return modifiedTime;
- }
-
- private static long updatePassword(String password, PasswordRecord record) {
- return updatePassword(password, record, System.currentTimeMillis());
- }
-
- // Runnable Helpers.
- private static Runnable storeRunnable(final RepositorySession session, final Record record) {
- return storeRunnable(session, record, new ExpectStoredDelegate(record.guid));
- }
-
- private static Runnable storeRunnable(final RepositorySession session, final Record record, final RepositorySessionStoreDelegate delegate) {
- return new Runnable() {
- @Override
- public void run() {
- session.setStoreDelegate(delegate);
- try {
- session.store(record);
- session.storeDone();
- } catch (NoStoreDelegateException e) {
- fail("NoStoreDelegateException should not occur.");
- }
- }
- };
- }
-
- private static Runnable fetchAllRunnable(final RepositorySession session, final Record[] records) {
- return new Runnable() {
- @Override
- public void run() {
- session.fetchAll(new ExpectFetchDelegate(records));
- }
- };
- }
-
- private static Runnable guidsSinceRunnable(final RepositorySession session, final long timestamp, final String[] expected) {
- return new Runnable() {
- @Override
- public void run() {
- session.guidsSince(timestamp, new ExpectGuidsSinceDelegate(expected));
- }
- };
- }
-
- private static Runnable fetchSinceRunnable(final RepositorySession session, final long timestamp, final String[] expected) {
- return new Runnable() {
- @Override
- public void run() {
- session.fetchSince(timestamp, new ExpectFetchSinceDelegate(timestamp, expected));
- }
- };
- }
-
- private static Runnable fetchRunnable(final RepositorySession session, final String[] guids, final Record[] expected) {
- return new Runnable() {
- @Override
- public void run() {
- try {
- session.fetch(guids, new ExpectFetchDelegate(expected));
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- };
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestTopSites.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestTopSites.java
deleted file mode 100644
index 003fc7172..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestTopSites.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.SuggestedSites;
-import org.mozilla.gecko.sync.setup.Constants;
-
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.test.ActivityInstrumentationTestCase2;
-
-/**
- * Exercise BrowserDB's getTopSites
- *
- * @author ahunt
- *
- */
-public class TestTopSites extends ActivityInstrumentationTestCase2<Activity> {
- Context mContext;
- SuggestedSites mSuggestedSites;
-
- public TestTopSites() {
- super(Activity.class);
- }
-
- @Override
- public void setUp() {
- mContext = getInstrumentation().getTargetContext();
- mSuggestedSites = new SuggestedSites(mContext);
-
- // By default we're using StubBrowserDB which has no suggested sites available.
- BrowserDB.from(GeckoProfile.get(mContext, Constants.DEFAULT_PROFILE)).setSuggestedSites(mSuggestedSites);
- }
-
- @Override
- public void tearDown() {
- BrowserDB.from(GeckoProfile.get(mContext, Constants.DEFAULT_PROFILE)).setSuggestedSites(null);
- }
-
- public void testGetTopSites() {
- final int SUGGESTED_LIMIT = 6;
- final int TOTAL_LIMIT = 50;
-
- ContentResolver cr = mContext.getContentResolver();
-
- final Uri uri = BrowserContract.TopSites.CONTENT_URI
- .buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_PROFILE,
- Constants.DEFAULT_PROFILE)
- .appendQueryParameter(BrowserContract.PARAM_LIMIT,
- String.valueOf(SUGGESTED_LIMIT))
- .appendQueryParameter(BrowserContract.PARAM_SUGGESTEDSITES_LIMIT,
- String.valueOf(TOTAL_LIMIT))
- .build();
-
- final Cursor c = cr.query(uri,
- new String[] { Combined._ID,
- Combined.URL,
- Combined.TITLE,
- Combined.BOOKMARK_ID,
- Combined.HISTORY_ID },
- null,
- null,
- null);
-
- int suggestedCount = 0;
- try {
- while (c.moveToNext()) {
- int type = c.getInt(c.getColumnIndexOrThrow(BrowserContract.Bookmarks.TYPE));
- assertEquals(BrowserContract.TopSites.TYPE_SUGGESTED, type);
- suggestedCount++;
- }
- } finally {
- c.close();
- }
-
- Cursor suggestedSitesCursor = mSuggestedSites.get(SUGGESTED_LIMIT);
-
- assertEquals(suggestedSitesCursor.getCount(), suggestedCount);
-
- suggestedSitesCursor.close();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/TestAccountLoader.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/TestAccountLoader.java
deleted file mode 100644
index 3009cac3e..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/TestAccountLoader.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package org.mozilla.gecko.background.fxa;
-
-import android.accounts.Account;
-import android.content.Context;
-import android.content.Loader;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
-import org.mozilla.gecko.background.sync.AndroidSyncTestCaseWithAccounts;
-import org.mozilla.gecko.fxa.AccountLoader;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.fxa.login.Separated;
-import org.mozilla.gecko.fxa.login.State;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * A version of https://android.googlesource.com/platform/frameworks/base/+/c91893511dc1b9e634648406c9ae61b15476e65d/test-runner/src/android/test/LoaderTestCase.java,
- * hacked to work with the v4 support library, and patched to work around
- * https://code.google.com/p/android/issues/detail?id=40987.
- */
-public class TestAccountLoader extends AndroidSyncTestCaseWithAccounts {
- // Test account names must start with TEST_USERNAME in order to be recognized
- // as test accounts and deleted in tearDown.
- private static final String TEST_USERNAME = "testAccount@mozilla.com";
- private static final String TEST_ACCOUNTTYPE = FxAccountConstants.ACCOUNT_TYPE;
-
- private static final String TEST_SYNCKEY = "testSyncKey";
- private static final String TEST_SYNCPASSWORD = "testSyncPassword";
-
- private static final String TEST_TOKEN_SERVER_URI = "testTokenServerURI";
- private static final String TEST_PROFILE_SERVER_URI = "testProfileServerURI";
- private static final String TEST_AUTH_SERVER_URI = "testAuthServerURI";
- private static final String TEST_PROFILE = "testProfile";
-
- public TestAccountLoader() {
- super(TEST_ACCOUNTTYPE, TEST_USERNAME);
- }
-
- static {
- // Force class loading of AsyncTask on the main thread so that it's handlers are tied to
- // the main thread and responses from the worker thread get delivered on the main thread.
- // The tests are run on another thread, allowing them to block waiting on a response from
- // the code running on the main thread. The main thread can't block since the AsyncTask
- // results come in via the event loop.
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... args) {
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- }
- };
- }
-
- /**
- * Runs a Loader synchronously and returns the result of the load. The loader will
- * be started, stopped, and destroyed by this method so it cannot be reused.
- *
- * @param loader The loader to run synchronously
- * @return The result from the loader
- */
- public <T> T getLoaderResultSynchronously(final Loader<T> loader) {
- // The test thread blocks on this queue until the loader puts it's result in
- final ArrayBlockingQueue<AtomicReference<T>> queue = new ArrayBlockingQueue<AtomicReference<T>>(1);
-
- // This callback runs on the "main" thread and unblocks the test thread
- // when it puts the result into the blocking queue
- final Loader.OnLoadCompleteListener<T> listener = new Loader.OnLoadCompleteListener<T>() {
- @Override
- public void onLoadComplete(Loader<T> completedLoader, T data) {
- // Shut the loader down
- completedLoader.unregisterListener(this);
- completedLoader.stopLoading();
- completedLoader.reset();
- // Store the result, unblocking the test thread
- queue.add(new AtomicReference<T>(data));
- }
- };
-
- // This handler runs on the "main" thread of the process since AsyncTask
- // is documented as needing to run on the main thread and many Loaders use
- // AsyncTask
- final Handler mainThreadHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- loader.registerListener(0, listener);
- loader.startLoading();
- }
- };
-
- // Ask the main thread to start the loading process
- mainThreadHandler.sendEmptyMessage(0);
-
- // Block on the queue waiting for the result of the load to be inserted
- T result;
- while (true) {
- try {
- result = queue.take().get();
- break;
- } catch (InterruptedException e) {
- throw new RuntimeException("waiting thread interrupted", e);
- }
- }
- return result;
- }
-
- public void testInitialLoad() throws UnsupportedEncodingException, GeneralSecurityException, URISyntaxException {
- // This is tricky. We can't mock the AccountManager easily -- see
- // https://groups.google.com/d/msg/android-mock/VXyzvKTMUGs/Y26wVPrl50sJ --
- // and we don't want to delete any existing accounts on device. So our test
- // needs to be adaptive (and therefore a little race-prone).
-
- final Context context = getApplicationContext();
- final AccountLoader loader = new AccountLoader(context);
-
- final boolean firefoxAccountsExist = FirefoxAccounts.firefoxAccountsExist(context);
-
- if (firefoxAccountsExist) {
- assertFirefoxAccount(getLoaderResultSynchronously((Loader<Account>) loader));
- return;
- }
-
- // This account will get cleaned up in tearDown.
- final State state = new Separated(TEST_USERNAME, "uid", false); // State choice is arbitrary.
- final AndroidFxAccount account = AndroidFxAccount.addAndroidAccount(context,
- TEST_USERNAME, TEST_PROFILE, TEST_AUTH_SERVER_URI, TEST_TOKEN_SERVER_URI, TEST_PROFILE_SERVER_URI,
- state, AndroidSyncTestCaseWithAccounts.TEST_SYNC_AUTOMATICALLY_MAP_WITH_ALL_AUTHORITIES_DISABLED);
- assertNotNull(account);
- assertFirefoxAccount(getLoaderResultSynchronously((Loader<Account>) loader));
- }
-
- protected void assertFirefoxAccount(Account account) {
- assertNotNull(account);
- assertEquals(FxAccountConstants.ACCOUNT_TYPE, account.type);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/TestBrowserIDKeyPairGeneration.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/TestBrowserIDKeyPairGeneration.java
deleted file mode 100644
index 18fb58a97..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/TestBrowserIDKeyPairGeneration.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.fxa;
-
-import java.security.GeneralSecurityException;
-
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.browserid.BrowserIDKeyPair;
-import org.mozilla.gecko.browserid.DSACryptoImplementation;
-import org.mozilla.gecko.browserid.JSONWebTokenUtils;
-import org.mozilla.gecko.browserid.RSACryptoImplementation;
-import org.mozilla.gecko.browserid.SigningPrivateKey;
-import org.mozilla.gecko.browserid.VerifyingPublicKey;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Utils;
-
-public class TestBrowserIDKeyPairGeneration extends AndroidSyncTestCase {
- public void doTestEncodeDecode(BrowserIDKeyPair keyPair) throws Exception {
- SigningPrivateKey privateKey = keyPair.getPrivate();
- VerifyingPublicKey publicKey = keyPair.getPublic();
-
- ExtendedJSONObject o = new ExtendedJSONObject();
- o.put("key", Utils.generateGuid());
-
- String token = JSONWebTokenUtils.encode(o.toJSONString(), privateKey);
- assertNotNull(token);
-
- String payload = JSONWebTokenUtils.decode(token, publicKey);
- assertEquals(o.toJSONString(), payload);
-
- try {
- JSONWebTokenUtils.decode(token + "x", publicKey);
- fail("Expected exception.");
- } catch (GeneralSecurityException e) {
- // Do nothing.
- }
- }
-
- public void testEncodeDecodeSuccessRSA() throws Exception {
- doTestEncodeDecode(RSACryptoImplementation.generateKeyPair(1024));
- doTestEncodeDecode(RSACryptoImplementation.generateKeyPair(2048));
- }
-
- public void testEncodeDecodeSuccessDSA() throws Exception {
- doTestEncodeDecode(DSACryptoImplementation.generateKeyPair(512));
- doTestEncodeDecode(DSACryptoImplementation.generateKeyPair(1024));
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/authenticator/TestAccountPickler.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/authenticator/TestAccountPickler.java
deleted file mode 100644
index d50bd47e0..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/fxa/authenticator/TestAccountPickler.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.fxa.authenticator;
-
-import org.mozilla.gecko.background.sync.AndroidSyncTestCaseWithAccounts;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.fxa.authenticator.AccountPickler;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.fxa.login.Separated;
-import org.mozilla.gecko.fxa.login.State;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Utils;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.test.RenamingDelegatingContext;
-
-public class TestAccountPickler extends AndroidSyncTestCaseWithAccounts {
- private static final String TEST_TOKEN_SERVER_URI = "tokenServerURI";
- private static final String TEST_PROFILE_SERVER_URI = "profileServerURI";
- private static final String TEST_AUTH_SERVER_URI = "serverURI";
- private static final String TEST_PROFILE = "profile";
- private final static String FILENAME_PREFIX = "TestAccountPickler-";
- private final static String PICKLE_FILENAME = "pickle";
-
- private final static String TEST_ACCOUNTTYPE = FxAccountConstants.ACCOUNT_TYPE;
-
- // Test account names must start with TEST_USERNAME in order to be recognized
- // as test accounts and deleted in tearDown.
- public static final String TEST_USERNAME = "testFirefoxAccount@mozilla.com";
-
- public Account account;
- public RenamingDelegatingContext context;
-
- public TestAccountPickler() {
- super(TEST_ACCOUNTTYPE, TEST_USERNAME);
- }
-
- @Override
- public void setUp() {
- super.setUp();
- this.account = null;
- // Randomize the filename prefix in case we don't clean up correctly.
- this.context = new RenamingDelegatingContext(getApplicationContext(), FILENAME_PREFIX +
- Math.random() * 1000001 + "-");
- this.accountManager = AccountManager.get(context);
- }
-
- @Override
- public void tearDown() {
- super.tearDown();
- this.context.deleteFile(PICKLE_FILENAME);
- }
-
- public AndroidFxAccount addTestAccount() throws Exception {
- final State state = new Separated(TEST_USERNAME, "uid", false); // State choice is arbitrary.
- final AndroidFxAccount account = AndroidFxAccount.addAndroidAccount(context, TEST_USERNAME,
- TEST_PROFILE, TEST_AUTH_SERVER_URI, TEST_TOKEN_SERVER_URI, TEST_PROFILE_SERVER_URI, state,
- AndroidSyncTestCaseWithAccounts.TEST_SYNC_AUTOMATICALLY_MAP_WITH_ALL_AUTHORITIES_DISABLED);
- assertNotNull(account);
- assertNotNull(account.getProfile());
- assertTrue(testAccountsExist()); // Sanity check.
- this.account = account.getAndroidAccount(); // To remove in tearDown() if we throw.
- return account;
- }
-
- public void testPickle() throws Exception {
- final AndroidFxAccount account = addTestAccount();
-
- final long now = System.currentTimeMillis();
- final ExtendedJSONObject o = AccountPickler.toJSON(account, now);
- assertNotNull(o.toJSONString());
-
- assertEquals(3, o.getLong(AccountPickler.KEY_PICKLE_VERSION).longValue());
- assertTrue(o.getLong(AccountPickler.KEY_PICKLE_TIMESTAMP).longValue() < System.currentTimeMillis());
-
- assertEquals(AndroidFxAccount.CURRENT_ACCOUNT_VERSION, o.getIntegerSafely(AccountPickler.KEY_ACCOUNT_VERSION).intValue());
- assertEquals(FxAccountConstants.ACCOUNT_TYPE, o.getString(AccountPickler.KEY_ACCOUNT_TYPE));
-
- assertEquals(TEST_USERNAME, o.getString(AccountPickler.KEY_EMAIL));
- assertEquals(TEST_PROFILE, o.getString(AccountPickler.KEY_PROFILE));
- assertEquals(TEST_AUTH_SERVER_URI, o.getString(AccountPickler.KEY_IDP_SERVER_URI));
- assertEquals(TEST_TOKEN_SERVER_URI, o.getString(AccountPickler.KEY_TOKEN_SERVER_URI));
- assertEquals(TEST_PROFILE_SERVER_URI, o.getString(AccountPickler.KEY_PROFILE_SERVER_URI));
-
- assertNotNull(o.getObject(AccountPickler.KEY_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP));
- assertNotNull(o.get(AccountPickler.KEY_BUNDLE));
- }
-
- public void testPickleAndUnpickle() throws Exception {
- final AndroidFxAccount inputAccount = addTestAccount();
-
- AccountPickler.pickle(inputAccount, PICKLE_FILENAME);
- final ExtendedJSONObject inputJSON = AccountPickler.toJSON(inputAccount, 0);
- final State inputState = inputAccount.getState();
- assertNotNull(inputJSON);
- assertNotNull(inputState);
-
- // unpickle adds an account to the AccountManager so delete it first.
- deleteTestAccounts();
- assertFalse(testAccountsExist());
-
- final AndroidFxAccount unpickledAccount = AccountPickler.unpickle(context, PICKLE_FILENAME);
- assertNotNull(unpickledAccount);
- final ExtendedJSONObject unpickledJSON = AccountPickler.toJSON(unpickledAccount, 0);
- final State unpickledState = unpickledAccount.getState();
- assertNotNull(unpickledJSON);
- assertNotNull(unpickledState);
-
- assertEquals(inputJSON, unpickledJSON);
- assertStateEquals(inputState, unpickledState);
- }
-
- public void testDeletePickle() throws Exception {
- final AndroidFxAccount account = addTestAccount();
- AccountPickler.pickle(account, PICKLE_FILENAME);
-
- final String s = Utils.readFile(context, PICKLE_FILENAME);
- assertNotNull(s);
- assertTrue(s.length() > 0);
-
- AccountPickler.deletePickle(context, PICKLE_FILENAME);
- assertFileNotPresent(context, PICKLE_FILENAME);
- }
-
- private void assertStateEquals(final State expected, final State actual) throws Exception {
- // TODO: Write and use State.equals. Thus, this is only thorough for the State base class.
- assertEquals(expected.getStateLabel(), actual.getStateLabel());
- assertEquals(expected.email, actual.email);
- assertEquals(expected.uid, actual.uid);
- assertEquals(expected.verified, actual.verified);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/AndroidSyncTestCase.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/AndroidSyncTestCase.java
deleted file mode 100644
index 5cdbe44f4..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/AndroidSyncTestCase.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.helpers;
-
-import junit.framework.AssertionFailedError;
-
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-
-import android.app.Activity;
-import android.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
-
-/**
- * AndroidSyncTestCase provides helper methods for testing.
- */
-public class AndroidSyncTestCase extends ActivityInstrumentationTestCase2<Activity> {
- protected static String LOG_TAG = "AndroidSyncTestCase";
-
- public AndroidSyncTestCase() {
- super(Activity.class);
- WaitHelper.resetTestWaiter();
- }
-
- public Context getApplicationContext() {
- return this.getInstrumentation().getTargetContext();
- }
-
- public static void performWait(Runnable runnable) {
- try {
- WaitHelper.getTestWaiter().performWait(runnable);
- } catch (WaitHelper.InnerError e) {
- AssertionFailedError inner = new AssertionFailedError("Caught error in performWait");
- inner.initCause(e.innerError);
- throw inner;
- }
- }
-
- public static void performNotify() {
- WaitHelper.getTestWaiter().performNotify();
- }
-
- public static void performNotify(Throwable e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
-
- public static void performNotify(String reason, Throwable e) {
- AssertionFailedError er = new AssertionFailedError(reason + ": " + e.getMessage());
- er.initCause(e);
- WaitHelper.getTestWaiter().performNotify(er);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/DBHelpers.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/DBHelpers.java
deleted file mode 100644
index c37f1e8bd..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/DBHelpers.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.helpers;
-
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import junit.framework.Assert;
-
-public class DBHelpers {
-
- /*
- * Works for strings and int-ish values.
- */
- public static void assertCursorContains(Object[][] expected, Cursor actual) {
- Assert.assertEquals(expected.length, actual.getCount());
- int i = 0, j = 0;
- Object[] row;
-
- do {
- row = expected[i];
- for (j = 0; j < row.length; ++j) {
- Object atIndex = row[j];
- if (atIndex == null) {
- continue;
- }
- if (atIndex instanceof String) {
- Assert.assertEquals(atIndex, actual.getString(j));
- } else {
- Assert.assertEquals(atIndex, actual.getInt(j));
- }
- }
- ++i;
- } while (actual.moveToPosition(i));
- }
-
- public static int getRowCount(SQLiteDatabase db, String table) {
- return getRowCount(db, table, null, null);
- }
-
- public static int getRowCount(SQLiteDatabase db, String table, String selection, String[] selectionArgs) {
- final Cursor c = db.query(table, null, selection, selectionArgs, null, null, null);
- try {
- return c.getCount();
- } finally {
- c.close();
- }
- }
-
- /**
- * Returns an ID that is non-existent in the given sqlite table. Assumes that a column named
- * "id" exists.
- */
- public static int getNonExistentID(SQLiteDatabase db, String table) {
- // XXX: We should use selectionArgs to concatenate table, but sqlite throws a syntax error on
- // "?" because it wants to ensure id is a valid column in table.
- final Cursor c = db.rawQuery("SELECT MAX(id) + 1 FROM " + table, null);
- try {
- if (!c.moveToNext()) {
- return 0;
- }
- return c.getInt(0);
- } finally {
- c.close();
- }
- }
-
- /**
- * Returns an ID that exists in the given sqlite table. Assumes that a column named * "id"
- * exists.
- */
- public static long getExistentID(SQLiteDatabase db, String table) {
- final Cursor c = db.query(table, new String[] {"id"}, null, null, null, null, null, "1");
- try {
- if (!c.moveToNext()) {
- throw new IllegalStateException("Given table does not contain any entries.");
- }
- return c.getInt(0);
- } finally {
- c.close();
- }
- }
-
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/DBProviderTestCase.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/DBProviderTestCase.java
deleted file mode 100644
index ccfeb8d63..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/helpers/DBProviderTestCase.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.helpers;
-
-import java.io.File;
-
-import android.content.ContentProvider;
-import android.content.Context;
-import android.test.AndroidTestCase;
-import android.test.mock.MockContentResolver;
-
-/**
- * Because ProviderTestCase2 is unable to handle custom DB paths.
- */
-public abstract class DBProviderTestCase<T extends ContentProvider> extends
- AndroidTestCase {
-
- Class<T> providerClass;
- String providerAuthority;
-
- protected File fakeProfileDirectory;
- private MockContentResolver resolver;
- private T provider;
-
- public DBProviderTestCase(Class<T> providerClass, String providerAuthority) {
- this.providerClass = providerClass;
- this.providerAuthority = providerAuthority;
- }
-
- public T getProvider() {
- return provider;
- }
-
- public MockContentResolver getMockContentResolver() {
- return resolver;
- }
-
- protected String getCacheSuffix() {
- return this.getClass().getName() + "-" + System.currentTimeMillis();
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- File cache = getContext().getCacheDir();
- fakeProfileDirectory = new File(cache.getAbsolutePath() + getCacheSuffix());
- System.out.println("Test: Creating profile directory " + fakeProfileDirectory.getAbsolutePath());
- if (!fakeProfileDirectory.mkdir()) {
- throw new IllegalStateException("Could not create temporary directory.");
- }
-
- final Context context = getContext();
- assertNotNull(context);
- resolver = new MockContentResolver();
- provider = providerClass.newInstance();
- provider.attachInfo(context, null);
- assertNotNull(provider);
- resolver.addProvider(providerAuthority, getProvider());
- }
-
- @Override
- protected void tearDown() throws Exception {
- // We don't check return values.
- System.out.println("Test: Cleaning up " + fakeProfileDirectory.getAbsolutePath());
- for (File child : fakeProfileDirectory.listFiles()) {
- child.delete();
- }
- fakeProfileDirectory.delete();
- super.tearDown();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/nativecode/test/TestNativeCrypto.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/nativecode/test/TestNativeCrypto.java
deleted file mode 100644
index d24f28491..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/nativecode/test/TestNativeCrypto.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.nativecode.test;
-
-import java.io.UnsupportedEncodingException;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-
-import junit.framework.TestCase;
-
-import org.mozilla.gecko.background.nativecode.NativeCrypto;
-import org.mozilla.gecko.sync.Utils;
-
-/*
- * Tests the Java wrapper over native implementations of crypto code. Test vectors from:
- * * PBKDF2SHA256:
- * - <https://github.com/ircmaxell/PHP-PasswordLib/blob/master/test/Data/Vectors/pbkdf2-draft-josefsson-sha256.test-vectors>
- * - <https://gitorious.org/scrypt/nettle-scrypt/blobs/37c0d5288e991604fe33dba2f1724986a8dddf56/testsuite/pbkdf2-test.c>
- * * SHA-1:
- * - <http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c>
- */
-public class TestNativeCrypto extends TestCase {
-
- public final void testPBKDF2SHA256A() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "password";
- String s = "salt";
- int dkLen = 32;
-
- checkPBKDF2SHA256(p, s, 1, dkLen, "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b");
- checkPBKDF2SHA256(p, s, 4096, dkLen, "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a");
- }
-
- public final void testPBKDF2SHA256B() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "passwordPASSWORDpassword";
- String s = "saltSALTsaltSALTsaltSALTsaltSALTsalt";
- int dkLen = 40;
-
- checkPBKDF2SHA256(p, s, 4096, dkLen, "348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9");
- }
-
- public final void testPBKDF2SHA256scryptA() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "passwd";
- String s = "salt";
- int dkLen = 64;
-
- checkPBKDF2SHA256(p, s, 1, dkLen, "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783");
- }
-
- public final void testPBKDF2SHA256scryptB() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "Password";
- String s = "NaCl";
- int dkLen = 64;
-
- checkPBKDF2SHA256(p, s, 80000, dkLen, "4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d");
- }
-
- public final void testPBKDF2SHA256C() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "pass\0word";
- String s = "sa\0lt";
- int dkLen = 16;
-
- checkPBKDF2SHA256(p, s, 4096, dkLen, "89b69d0516f829893c696226650a8687");
- }
-
- /*
- // This test takes two or three minutes to run, so we don't.
- public final void testPBKDF2SHA256D() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "password";
- String s = "salt";
- int dkLen = 32;
-
- checkPBKDF2SHA256(p, s, 16777216, dkLen, "cf81c66fe8cfc04d1f31ecb65dab4089f7f179e89b3b0bcb17ad10e3ac6eba46");
- }
- */
-
- public final void testTimePBKDF2SHA256() throws UnsupportedEncodingException, GeneralSecurityException {
- checkPBKDF2SHA256("password", "salt", 80000, 32, null);
- }
-
- public final void testPBKDF2SHA256InvalidLenArg() throws UnsupportedEncodingException, GeneralSecurityException {
- final String p = "password";
- final String s = "salt";
- final int c = 1;
- final int dkLen = -1; // Should always be positive.
-
- try {
- NativeCrypto.pbkdf2SHA256(p.getBytes("US-ASCII"), s.getBytes("US-ASCII"), c, dkLen);
- fail("Expected sha256 to throw with negative dkLen argument.");
- } catch (IllegalArgumentException e) { } // Expected.
- }
-
- public final void testSHA1() throws UnsupportedEncodingException {
- final String[] inputs = new String[] {
- "abc",
- "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
- "" // To be filled in below.
- };
- final String baseStr = "01234567";
- final int repetitions = 80;
- final StringBuilder builder = new StringBuilder(baseStr.length() * repetitions);
- for (int i = 0; i < 80; ++i) {
- builder.append(baseStr);
- }
- inputs[2] = builder.toString();
-
- final String[] expecteds = new String[] {
- "a9993e364706816aba3e25717850c26c9cd0d89d",
- "84983e441c3bd26ebaae4aa1f95129e5e54670f1",
- "dea356a2cddd90c7a7ecedc5ebb563934f460452"
- };
-
- for (int i = 0; i < inputs.length; ++i) {
- final byte[] input = inputs[i].getBytes("US-ASCII");
- final String expected = expecteds[i];
-
- final byte[] actual = NativeCrypto.sha1(input);
- assertNotNull("Hashed value is non-null", actual);
- assertExpectedBytes(expected, actual);
- }
- }
-
- /**
- * Test to ensure the output of our SHA1 algo is the same as MessageDigest's. This is important
- * because we intend to replace MessageDigest in FHR with this SHA-1 algo (bug 959652).
- */
- public final void testSHA1AgainstMessageDigest() throws UnsupportedEncodingException,
- NoSuchAlgorithmException {
- final String[] inputs = {
- "password",
- "saranghae",
- "aoeusnthaoeusnthaoeusnth \0 12345098765432109876_!"
- };
-
- final MessageDigest digest = MessageDigest.getInstance("SHA-1");
- for (final String input : inputs) {
- final byte[] inputBytes = input.getBytes("US-ASCII");
-
- final byte[] mdBytes = digest.digest(inputBytes);
- final byte[] ourBytes = NativeCrypto.sha1(inputBytes);
- assertTrue("MessageDigest hash is the same as NativeCrypto SHA-1 hash",
- Arrays.equals(ourBytes, mdBytes));
- }
- }
-
- private void checkPBKDF2SHA256(String p, String s, int c, int dkLen,
- final String expectedStr)
- throws GeneralSecurityException, UnsupportedEncodingException {
- long start = System.currentTimeMillis();
- byte[] key = NativeCrypto.pbkdf2SHA256(p.getBytes("US-ASCII"), s.getBytes("US-ASCII"), c, dkLen);
- assertNotNull(key);
-
- long end = System.currentTimeMillis();
-
- System.err.println("SHA-256 " + c + " took " + (end - start) + "ms");
- if (expectedStr == null) {
- return;
- }
-
- assertEquals(dkLen, Utils.hex2Byte(expectedStr).length);
- assertExpectedBytes(expectedStr, key);
- }
-
- private void assertExpectedBytes(final String expectedStr, byte[] key) {
- assertEquals(expectedStr, Utils.byte2Hex(key));
- byte[] expected = Utils.hex2Byte(expectedStr);
-
- assertEquals(expected.length, key.length);
- for (int i = 0; i < key.length; i++) {
- assertEquals(expected[i], key[i]);
- }
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/AndroidSyncTestCaseWithAccounts.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/AndroidSyncTestCaseWithAccounts.java
deleted file mode 100644
index e0e4e8bb1..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/AndroidSyncTestCaseWithAccounts.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
-import android.content.Context;
-import android.test.InstrumentationTestCase;
-
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-public class AndroidSyncTestCaseWithAccounts extends AndroidSyncTestCase {
- public final String testAccountType;
- public final String testAccountPrefix;
-
- protected Context context;
- protected AccountManager accountManager;
- protected int numAccounts;
-
- public static final Map<String, Boolean> TEST_SYNC_AUTOMATICALLY_MAP_WITH_ALL_AUTHORITIES_DISABLED;
- static {
- final Map<String, Boolean> m = new HashMap<String, Boolean>();
- for (String authority : AndroidFxAccount.DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP.keySet()) {
- m.put(authority, false);
- }
- TEST_SYNC_AUTOMATICALLY_MAP_WITH_ALL_AUTHORITIES_DISABLED = m;
- }
-
- public AndroidSyncTestCaseWithAccounts(String accountType, String accountPrefix) {
- super();
- this.testAccountType = accountType;
- this.testAccountPrefix = accountPrefix;
- }
-
- @Override
- public void setUp() {
- context = getApplicationContext();
- accountManager = AccountManager.get(context);
- deleteTestAccounts(); // Always start with no test accounts.
- numAccounts = accountManager.getAccountsByType(testAccountType).length;
- }
-
- public List<Account> getTestAccounts() {
- final List<Account> testAccounts = new ArrayList<Account>();
-
- final Account[] accounts = accountManager.getAccountsByType(testAccountType);
- for (Account account : accounts) {
- if (account.name.startsWith(testAccountPrefix)) {
- testAccounts.add(account);
- }
- }
-
- return testAccounts;
- }
-
- public static void deleteAccount(final InstrumentationTestCase test, final AccountManager accountManager, final Account account) {
- performWait(new Runnable() {
- @Override
- public void run() {
- try {
- test.runTestOnUiThread(new Runnable() {
- final AccountManagerCallback<Boolean> callback = new AccountManagerCallback<Boolean>() {
- @Override
- public void run(AccountManagerFuture<Boolean> future) {
- try {
- future.getResult(5L, TimeUnit.SECONDS);
- } catch (Exception e) {
- }
- performNotify();
- }
- };
-
- @Override
- public void run() {
- accountManager.removeAccount(account, callback, null);
- }
- });
- } catch (Throwable e) {
- performNotify(e);
- }
- }
- });
- }
-
- public void deleteTestAccounts() {
- for (Account account : getTestAccounts()) {
- deleteAccount(this, accountManager, account);
- }
- }
-
- public boolean testAccountsExist() {
- // Note that we don't use FirefoxAccounts.firefoxAccountsExist because it unpickles.
- return !getTestAccounts().isEmpty();
- }
-
- @Override
- public void tearDown() {
- deleteTestAccounts();
- assertEquals(numAccounts, accountManager.getAccountsByType(testAccountType).length);
- }
-
- public static void assertFileNotPresent(final Context context, final String filename) throws Exception {
- // Verify file is not present.
- FileInputStream fis = null;
- try {
- fis = context.openFileInput(filename);
- fail("Should get FileNotFoundException.");
- } catch (FileNotFoundException e) {
- // Do nothing; file should not exist.
- } finally {
- if (fis != null) {
- fis.close();
- }
- }
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestClientsStage.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestClientsStage.java
deleted file mode 100644
index 39e24b4d4..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestClientsStage.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync;
-
-import org.json.simple.JSONArray;
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.testhelpers.DefaultGlobalSessionCallback;
-import org.mozilla.gecko.background.testhelpers.MockClientsDataDelegate;
-import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-import org.mozilla.gecko.sync.stage.SyncClientsEngineStage;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-
-public class TestClientsStage extends AndroidSyncTestCase {
- private static final String TEST_USERNAME = "johndoe";
- private static final String TEST_PASSWORD = "password";
- private static final String TEST_SYNC_KEY = "abcdeabcdeabcdeabcdeabcdea";
-
- @Override
- public void setUp() {
- ClientsDatabaseAccessor db = new ClientsDatabaseAccessor(getApplicationContext());
- db.wipeDB();
- db.close();
- }
-
- public void testWipeClearsClients() throws Exception {
-
- // Wiping clients is equivalent to a reset and dropping all local stored client records.
- // Resetting is defined as being the same as for other engines -- discard local
- // and remote timestamps, tracked failed records, and tracked records to fetch.
-
- final Context context = getApplicationContext();
- final ClientsDatabaseAccessor dataAccessor = new ClientsDatabaseAccessor(context);
- final GlobalSessionCallback callback = new DefaultGlobalSessionCallback();
- final ClientsDataDelegate delegate = new MockClientsDataDelegate();
-
- final KeyBundle keyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY);
- final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD);
- final SharedPreferences prefs = new MockSharedPreferences();
- final SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, authHeaderProvider, prefs);
- config.syncKeyBundle = keyBundle;
- GlobalSession session = new GlobalSession(config, callback, context, delegate);
-
- SyncClientsEngineStage stage = new SyncClientsEngineStage() {
-
- @Override
- public synchronized ClientsDatabaseAccessor getClientsDatabaseAccessor() {
- if (db == null) {
- db = dataAccessor;
- }
- return db;
- }
- };
-
- final String guid = "clientabcdef";
- long lastModified = System.currentTimeMillis();
- ClientRecord record = new ClientRecord(guid, "clients", lastModified , false);
- record.name = "John's Phone";
- record.type = "mobile";
- record.device = "Some Device";
- record.os = "iOS";
- record.commands = new JSONArray();
-
- dataAccessor.store(record);
- assertEquals(1, dataAccessor.clientsCount());
-
- final ClientRecord stored = dataAccessor.fetchAllClients().get(guid);
- assertNotNull(stored);
- assertEquals("John's Phone", stored.name);
- assertEquals("mobile", stored.type);
- assertEquals("Some Device", stored.device);
- assertEquals("iOS", stored.os);
-
- stage.wipeLocal(session);
-
- try {
- assertEquals(0, dataAccessor.clientsCount());
- assertEquals(0L, session.config.getPersistedServerClientRecordTimestamp());
- assertEquals(0, session.getClientsDelegate().getClientsCount());
- } finally {
- dataAccessor.close();
- }
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestResetting.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestResetting.java
deleted file mode 100644
index 52af2ad01..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestResetting.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync;
-
-import android.content.SharedPreferences;
-
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.testhelpers.BaseMockServerSyncStage;
-import org.mozilla.gecko.background.testhelpers.DefaultGlobalSessionCallback;
-import org.mozilla.gecko.background.testhelpers.MockRecord;
-import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
-import org.mozilla.gecko.background.testhelpers.WBORepository;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.EngineSettings;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.MetaGlobalException;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SynchronizerConfiguration;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-import org.mozilla.gecko.sync.stage.NoSuchStageException;
-import org.mozilla.gecko.sync.synchronizer.Synchronizer;
-
-/**
- * Test the on-device side effects of reset operations on a stage.
- *
- * See also "TestResetCommands" in the unit test suite.
- */
-public class TestResetting extends AndroidSyncTestCase {
- private static final String TEST_USERNAME = "johndoe";
- private static final String TEST_PASSWORD = "password";
- private static final String TEST_SYNC_KEY = "abcdeabcdeabcdeabcdeabcdea";
-
- @Override
- public void setUp() {
- assertTrue(WaitHelper.getTestWaiter().isIdle());
- }
-
- /**
- * Set up a mock stage that synchronizes two mock repositories. Apply various
- * reset/sync/wipe permutations and check state.
- */
- public void testResetAndWipeStage() throws Exception {
-
- final long startTime = System.currentTimeMillis();
- final GlobalSessionCallback callback = createGlobalSessionCallback();
- final GlobalSession session = createDefaultGlobalSession(callback);
-
- final ExecutableMockServerSyncStage stage = new ExecutableMockServerSyncStage() {
- @Override
- public void onSynchronized(Synchronizer synchronizer) {
- try {
- assertTrue(startTime <= synchronizer.bundleA.getTimestamp());
- assertTrue(startTime <= synchronizer.bundleB.getTimestamp());
-
- // Call up to allow the usual persistence etc. to happen.
- super.onSynchronized(synchronizer);
- } catch (Throwable e) {
- performNotify(e);
- return;
- }
- performNotify();
- }
- };
-
- final boolean bumpTimestamps = true;
- WBORepository local = new WBORepository(bumpTimestamps);
- WBORepository remote = new WBORepository(bumpTimestamps);
-
- stage.name = "mock";
- stage.collection = "mock";
- stage.local = local;
- stage.remote = remote;
-
- stage.executeSynchronously(session);
-
- // Verify the persisted values.
- assertConfigTimestampsGreaterThan(stage.leakConfig(), startTime, startTime);
-
- // Reset.
- stage.resetLocal(session);
-
- // Verify that they're gone.
- assertConfigTimestampsEqual(stage.leakConfig(), 0, 0);
-
- // Now sync data, ensure that timestamps come back.
- final long afterReset = System.currentTimeMillis();
- final String recordGUID = "abcdefghijkl";
- local.wbos.put(recordGUID, new MockRecord(recordGUID, "mock", startTime, false));
-
- // Sync again with data and verify timestamps and data.
- stage.executeSynchronously(session);
-
- assertConfigTimestampsGreaterThan(stage.leakConfig(), afterReset, afterReset);
- assertEquals(1, remote.wbos.size());
- assertEquals(1, local.wbos.size());
-
- Record remoteRecord = remote.wbos.get(recordGUID);
- assertNotNull(remoteRecord);
- assertNotNull(local.wbos.get(recordGUID));
- assertEquals(recordGUID, remoteRecord.guid);
- assertTrue(afterReset <= remoteRecord.lastModified);
-
- // Reset doesn't clear data.
- stage.resetLocal(session);
- assertConfigTimestampsEqual(stage.leakConfig(), 0, 0);
- assertEquals(1, remote.wbos.size());
- assertEquals(1, local.wbos.size());
- remoteRecord = remote.wbos.get(recordGUID);
- assertNotNull(remoteRecord);
- assertNotNull(local.wbos.get(recordGUID));
-
- // Wipe does. Recover from reset...
- final long beforeWipe = System.currentTimeMillis();
- stage.executeSynchronously(session);
- assertEquals(1, remote.wbos.size());
- assertEquals(1, local.wbos.size());
- assertConfigTimestampsGreaterThan(stage.leakConfig(), beforeWipe, beforeWipe);
-
- // ... then wipe.
- stage.wipeLocal(session);
- assertConfigTimestampsEqual(stage.leakConfig(), 0, 0);
- assertEquals(1, remote.wbos.size()); // We don't wipe the server.
- assertEquals(0, local.wbos.size()); // We do wipe local.
- }
-
- /**
- * A stage that joins two Repositories with no wrapping.
- */
- public class ExecutableMockServerSyncStage extends BaseMockServerSyncStage {
- /**
- * Run this stage synchronously.
- */
- public void executeSynchronously(final GlobalSession session) {
- final BaseMockServerSyncStage self = this;
- performWait(new Runnable() {
- @Override
- public void run() {
- try {
- self.execute(session);
- } catch (NoSuchStageException e) {
- performNotify(e);
- }
- }
- });
- }
- }
-
- private GlobalSession createDefaultGlobalSession(final GlobalSessionCallback callback) throws Exception {
- final KeyBundle keyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY);
- final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD);
- final SharedPreferences prefs = new MockSharedPreferences();
- final SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, authHeaderProvider, prefs);
- config.syncKeyBundle = keyBundle;
- return new GlobalSession(config, callback, getApplicationContext(), null) {
- @Override
- public boolean isEngineRemotelyEnabled(String engineName,
- EngineSettings engineSettings)
- throws MetaGlobalException {
- return true;
- }
-
- @Override
- public void advance() {
- // So we don't proceed and run other stages.
- }
- };
- }
-
- private static GlobalSessionCallback createGlobalSessionCallback() {
- return new DefaultGlobalSessionCallback() {
-
- @Override
- public void handleAborted(GlobalSession globalSession, String reason) {
- performNotify(new Exception("Aborted"));
- }
-
- @Override
- public void handleError(GlobalSession globalSession, Exception ex) {
- performNotify(ex);
- }
- };
- }
-
- private static void assertConfigTimestampsGreaterThan(SynchronizerConfiguration config, long local, long remote) {
- assertTrue(local <= config.localBundle.getTimestamp());
- assertTrue(remote <= config.remoteBundle.getTimestamp());
- }
-
- private static void assertConfigTimestampsEqual(SynchronizerConfiguration config, long local, long remote) {
- assertEquals(local, config.localBundle.getTimestamp());
- assertEquals(remote, config.remoteBundle.getTimestamp());
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestStoreTracking.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestStoreTracking.java
deleted file mode 100644
index bac6c7f49..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestStoreTracking.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-
-import junit.framework.AssertionFailedError;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessBeginDelegate;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessCreationDelegate;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessFetchDelegate;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessFinishDelegate;
-import org.mozilla.gecko.background.sync.helpers.SimpleSuccessStoreDelegate;
-import org.mozilla.gecko.background.testhelpers.WBORepository;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-import org.mozilla.gecko.sync.synchronizer.Synchronizer;
-import org.mozilla.gecko.sync.synchronizer.SynchronizerDelegate;
-
-import android.content.Context;
-
-public class TestStoreTracking extends AndroidSyncTestCase {
- public void assertEq(Object expected, Object actual) {
- try {
- assertEquals(expected, actual);
- } catch (AssertionFailedError e) {
- performNotify(e);
- }
- }
-
- public class TrackingWBORepository extends WBORepository {
- @Override
- public synchronized boolean shouldTrack() {
- return true;
- }
- }
-
- public void doTestStoreRetrieveByGUID(final WBORepository repository,
- final RepositorySession session,
- final String expectedGUID,
- final Record record) {
-
- final SimpleSuccessStoreDelegate storeDelegate = new SimpleSuccessStoreDelegate() {
-
- @Override
- public void onRecordStoreSucceeded(String guid) {
- Logger.debug(getName(), "Stored " + guid);
- assertEq(expectedGUID, guid);
- }
-
- @Override
- public void onStoreCompleted(long storeEnd) {
- Logger.debug(getName(), "Store completed at " + storeEnd + ".");
- try {
- session.fetch(new String[] { expectedGUID }, new SimpleSuccessFetchDelegate() {
- @Override
- public void onFetchedRecord(Record record) {
- Logger.debug(getName(), "Hurrah! Fetched record " + record.guid);
- assertEq(expectedGUID, record.guid);
- }
-
- @Override
- public void onFetchCompleted(final long fetchEnd) {
- Logger.debug(getName(), "Fetch completed at " + fetchEnd + ".");
-
- // But fetching by time returns nothing.
- session.fetchSince(0, new SimpleSuccessFetchDelegate() {
- private AtomicBoolean fetched = new AtomicBoolean(false);
-
- @Override
- public void onFetchedRecord(Record record) {
- Logger.debug(getName(), "Fetched record " + record.guid);
- fetched.set(true);
- performNotify(new AssertionFailedError("Should have fetched no record!"));
- }
-
- @Override
- public void onFetchCompleted(final long fetchEnd) {
- if (fetched.get()) {
- Logger.debug(getName(), "Not finishing session: record retrieved.");
- return;
- }
- try {
- session.finish(new SimpleSuccessFinishDelegate() {
- @Override
- public void onFinishSucceeded(RepositorySession session,
- RepositorySessionBundle bundle) {
- performNotify();
- }
- });
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- });
- }
- });
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- };
-
- session.setStoreDelegate(storeDelegate);
- try {
- Logger.debug(getName(), "Storing...");
- session.store(record);
- session.storeDone();
- } catch (NoStoreDelegateException e) {
- // Should not happen.
- }
- }
-
- private void doTestNewSessionRetrieveByTime(final WBORepository repository,
- final String expectedGUID) {
- final SimpleSuccessCreationDelegate createDelegate = new SimpleSuccessCreationDelegate() {
- @Override
- public void onSessionCreated(final RepositorySession session) {
- Logger.debug(getName(), "Session created.");
- try {
- session.begin(new SimpleSuccessBeginDelegate() {
- @Override
- public void onBeginSucceeded(final RepositorySession session) {
- // Now we get a result.
- session.fetchSince(0, new SimpleSuccessFetchDelegate() {
-
- @Override
- public void onFetchedRecord(Record record) {
- assertEq(expectedGUID, record.guid);
- }
-
- @Override
- public void onFetchCompleted(long end) {
- try {
- session.finish(new SimpleSuccessFinishDelegate() {
- @Override
- public void onFinishSucceeded(RepositorySession session,
- RepositorySessionBundle bundle) {
- // Hooray!
- performNotify();
- }
- });
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- });
- }
- });
- } catch (InvalidSessionTransitionException e) {
- performNotify(e);
- }
- }
- };
- Runnable create = new Runnable() {
- @Override
- public void run() {
- repository.createSession(createDelegate, getApplicationContext());
- }
- };
-
- performWait(create);
- }
-
- /**
- * Store a record in one session. Verify that fetching by GUID returns
- * the record. Verify that fetching by timestamp fails to return records.
- * Start a new session. Verify that fetching by timestamp returns the
- * stored record.
- *
- * Invokes doTestStoreRetrieveByGUID, doTestNewSessionRetrieveByTime.
- */
- public void testStoreRetrieveByGUID() {
- Logger.debug(getName(), "Started.");
- final WBORepository r = new TrackingWBORepository();
- final long now = System.currentTimeMillis();
- final String expectedGUID = "abcdefghijkl";
- final Record record = new BookmarkRecord(expectedGUID, "bookmarks", now , false);
-
- final RepositorySessionCreationDelegate createDelegate = new SimpleSuccessCreationDelegate() {
- @Override
- public void onSessionCreated(RepositorySession session) {
- Logger.debug(getName(), "Session created: " + session);
- try {
- session.begin(new SimpleSuccessBeginDelegate() {
- @Override
- public void onBeginSucceeded(final RepositorySession session) {
- doTestStoreRetrieveByGUID(r, session, expectedGUID, record);
- }
- });
- } catch (InvalidSessionTransitionException e) {
- performNotify(e);
- }
- }
- };
-
- final Context applicationContext = getApplicationContext();
-
- // This has to happen on a new thread so that we
- // can wait for it!
- Runnable create = onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- r.createSession(createDelegate, applicationContext);
- }
- });
-
- Runnable retrieve = onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- doTestNewSessionRetrieveByTime(r, expectedGUID);
- performNotify();
- }
- });
-
- performWait(create);
- performWait(retrieve);
- }
-
- private Runnable onThreadRunnable(final Runnable r) {
- return new Runnable() {
- @Override
- public void run() {
- new Thread(r).start();
- }
- };
- }
-
-
- public class CountingWBORepository extends TrackingWBORepository {
- public AtomicLong counter = new AtomicLong(0L);
- public class CountingWBORepositorySession extends WBORepositorySession {
- private static final String LOG_TAG = "CountingRepoSession";
-
- public CountingWBORepositorySession(WBORepository repository) {
- super(repository);
- }
-
- @Override
- public void store(final Record record) throws NoStoreDelegateException {
- Logger.debug(LOG_TAG, "Counter now " + counter.incrementAndGet());
- super.store(record);
- }
- }
-
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- delegate.deferredCreationDelegate().onSessionCreated(new CountingWBORepositorySession(this));
- }
- }
-
- public class TestRecord extends Record {
- public TestRecord(String guid, String collection, long lastModified,
- boolean deleted) {
- super(guid, collection, lastModified, deleted);
- }
-
- @Override
- public void initFromEnvelope(CryptoRecord payload) {
- return;
- }
-
- @Override
- public CryptoRecord getEnvelope() {
- return null;
- }
-
- @Override
- protected void populatePayload(ExtendedJSONObject payload) {
- }
-
- @Override
- protected void initFromPayload(ExtendedJSONObject payload) {
- }
-
- @Override
- public Record copyWithIDs(String guid, long androidID) {
- return new TestRecord(guid, this.collection, this.lastModified, this.deleted);
- }
- }
-
- /**
- * Create two repositories, syncing from one to the other. Ensure
- * that records stored from one aren't re-uploaded.
- */
- public void testStoreBetweenRepositories() {
- final CountingWBORepository repoA = new CountingWBORepository(); // "Remote". First source.
- final CountingWBORepository repoB = new CountingWBORepository(); // "Local". First sink.
- long now = System.currentTimeMillis();
-
- TestRecord recordA1 = new TestRecord("aacdefghiaaa", "coll", now - 30, false);
- TestRecord recordA2 = new TestRecord("aacdefghibbb", "coll", now - 20, false);
- TestRecord recordB1 = new TestRecord("aacdefghiaaa", "coll", now - 10, false);
- TestRecord recordB2 = new TestRecord("aacdefghibbb", "coll", now - 40, false);
-
- TestRecord recordA3 = new TestRecord("nncdefghibbb", "coll", now, false);
- TestRecord recordB3 = new TestRecord("nncdefghiaaa", "coll", now, false);
-
- // A1 and B1 are the same, but B's version is newer. We expect A1 to be downloaded
- // and B1 to be uploaded.
- // A2 and B2 are the same, but A's version is newer. We expect A2 to be downloaded
- // and B2 to not be uploaded.
- // Both A3 and B3 are new. We expect them to go in each direction.
- // Expected counts, then:
- // Repo A: B1 + B3
- // Repo B: A1 + A2 + A3
- repoB.wbos.put(recordB1.guid, recordB1);
- repoB.wbos.put(recordB2.guid, recordB2);
- repoB.wbos.put(recordB3.guid, recordB3);
- repoA.wbos.put(recordA1.guid, recordA1);
- repoA.wbos.put(recordA2.guid, recordA2);
- repoA.wbos.put(recordA3.guid, recordA3);
-
- final Synchronizer s = new Synchronizer();
- s.repositoryA = repoA;
- s.repositoryB = repoB;
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- s.synchronize(getApplicationContext(), new SynchronizerDelegate() {
-
- @Override
- public void onSynchronized(Synchronizer synchronizer) {
- long countA = repoA.counter.get();
- long countB = repoB.counter.get();
- Logger.debug(getName(), "Counts: " + countA + ", " + countB);
- assertEq(2L, countA);
- assertEq(3L, countB);
-
- // Testing for store timestamp 'hack'.
- // We fetched from A first, and so its bundle timestamp will be the last
- // stored time. We fetched from B second, so its bundle timestamp will be
- // the last fetched time.
- final long timestampA = synchronizer.bundleA.getTimestamp();
- final long timestampB = synchronizer.bundleB.getTimestamp();
- Logger.debug(getName(), "Repo A timestamp: " + timestampA);
- Logger.debug(getName(), "Repo B timestamp: " + timestampB);
- Logger.debug(getName(), "Repo A fetch done: " + repoA.stats.fetchCompleted);
- Logger.debug(getName(), "Repo A store done: " + repoA.stats.storeCompleted);
- Logger.debug(getName(), "Repo B fetch done: " + repoB.stats.fetchCompleted);
- Logger.debug(getName(), "Repo B store done: " + repoB.stats.storeCompleted);
-
- assertTrue(timestampB <= timestampA);
- assertTrue(repoA.stats.fetchCompleted <= timestampA);
- assertTrue(repoA.stats.storeCompleted >= repoA.stats.fetchCompleted);
- assertEquals(repoA.stats.storeCompleted, timestampA);
- assertEquals(repoB.stats.fetchCompleted, timestampB);
- performNotify();
- }
-
- @Override
- public void onSynchronizeFailed(Synchronizer synchronizer,
- Exception lastException, String reason) {
- Logger.debug(getName(), "Failed.");
- performNotify(new AssertionFailedError("Should not fail."));
- }
- });
- }
- };
-
- performWait(onThreadRunnable(r));
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java
deleted file mode 100644
index 389aaf891..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.sync.SyncConfiguration;
-
-import android.content.SharedPreferences;
-
-public class TestSyncConfiguration extends AndroidSyncTestCase {
- public static final String TEST_PREFS_NAME = "test";
-
- public SharedPreferences getPrefs(String name, int mode) {
- return this.getApplicationContext().getSharedPreferences(name, mode);
- }
-
- /**
- * Ensure that declined engines persist through prefs.
- */
- public void testDeclinedEngineNames() {
- SyncConfiguration config = null;
- SharedPreferences prefs = getPrefs(TEST_PREFS_NAME, 0);
-
- config = newSyncConfiguration();
- config.declinedEngineNames = new HashSet<String>();
- config.declinedEngineNames.add("test1");
- config.declinedEngineNames.add("test2");
- config.persistToPrefs();
- assertTrue(prefs.contains(SyncConfiguration.PREF_DECLINED_ENGINE_NAMES));
- config = newSyncConfiguration();
- Set<String> expected = new HashSet<String>();
- for (String name : new String[] { "test1", "test2" }) {
- expected.add(name);
- }
- assertEquals(expected, config.declinedEngineNames);
-
- config.declinedEngineNames = null;
- config.persistToPrefs();
- assertFalse(prefs.contains(SyncConfiguration.PREF_DECLINED_ENGINE_NAMES));
- config = newSyncConfiguration();
- assertNotNull(config.declinedEngineNames);
- assertTrue(config.declinedEngineNames.isEmpty());
- }
-
- public void testEnabledEngineNames() {
- SyncConfiguration config = null;
- SharedPreferences prefs = getPrefs(TEST_PREFS_NAME, 0);
-
- config = newSyncConfiguration();
- config.enabledEngineNames = new HashSet<String>();
- config.enabledEngineNames.add("test1");
- config.enabledEngineNames.add("test2");
- config.persistToPrefs();
- assertTrue(prefs.contains(SyncConfiguration.PREF_ENABLED_ENGINE_NAMES));
- config = newSyncConfiguration();
- Set<String> expected = new HashSet<String>();
- for (String name : new String[] { "test1", "test2" }) {
- expected.add(name);
- }
- assertEquals(expected, config.enabledEngineNames);
-
- config.enabledEngineNames = null;
- config.persistToPrefs();
- assertFalse(prefs.contains(SyncConfiguration.PREF_ENABLED_ENGINE_NAMES));
- config = newSyncConfiguration();
- assertNull(config.enabledEngineNames);
- }
-
- public void testSyncID() {
- SyncConfiguration config = null;
- SharedPreferences prefs = getPrefs(TEST_PREFS_NAME, 0);
-
- config = newSyncConfiguration();
- config.syncID = "test1";
- config.persistToPrefs();
- assertTrue(prefs.contains(SyncConfiguration.PREF_SYNC_ID));
- config = newSyncConfiguration();
- assertEquals("test1", config.syncID);
- }
-
- public void testStoreSelectedEnginesToPrefs() {
- SharedPreferences prefs = getPrefs(TEST_PREFS_NAME, 0);
- // Store engines, excluding history/forms special case.
- Map<String, Boolean> expectedEngines = new HashMap<String, Boolean>();
- expectedEngines.put("test1", true);
- expectedEngines.put("test2", false);
- expectedEngines.put("test3", true);
-
- SyncConfiguration.storeSelectedEnginesToPrefs(prefs, expectedEngines);
-
- // Read values from selectedEngines.
- assertTrue(prefs.contains(SyncConfiguration.PREF_USER_SELECTED_ENGINES_TO_SYNC));
- SyncConfiguration config = null;
- config = newSyncConfiguration();
- config.loadFromPrefs(prefs);
- assertEquals(expectedEngines, config.userSelectedEngines);
- }
-
- /**
- * Tests dependency of forms engine on history engine.
- */
- public void testSelectedEnginesHistoryAndForms() {
- SharedPreferences prefs = getPrefs(TEST_PREFS_NAME, 0);
- // Store engines, excluding history/forms special case.
- Map<String, Boolean> storedEngines = new HashMap<String, Boolean>();
- storedEngines.put("history", true);
-
- SyncConfiguration.storeSelectedEnginesToPrefs(prefs, storedEngines);
-
- // Expected engines.
- storedEngines.put("forms", true);
- // Read values from selectedEngines.
- assertTrue(prefs.contains(SyncConfiguration.PREF_USER_SELECTED_ENGINES_TO_SYNC));
- SyncConfiguration config = null;
- config = newSyncConfiguration();
- config.loadFromPrefs(prefs);
- assertEquals(storedEngines, config.userSelectedEngines);
- }
-
- public void testsSelectedEnginesNoHistoryNorForms() {
- SharedPreferences prefs = getPrefs(TEST_PREFS_NAME, 0);
- // Store engines, excluding history/forms special case.
- Map<String, Boolean> storedEngines = new HashMap<String, Boolean>();
- storedEngines.put("forms", true);
-
- SyncConfiguration.storeSelectedEnginesToPrefs(prefs, storedEngines);
-
- // Read values from selectedEngines.
- assertTrue(prefs.contains(SyncConfiguration.PREF_USER_SELECTED_ENGINES_TO_SYNC));
- SyncConfiguration config = null;
- config = newSyncConfiguration();
- config.loadFromPrefs(prefs);
- // Forms should not be selected if history is not present.
- assertTrue(config.userSelectedEngines.isEmpty());
- }
-
- protected SyncConfiguration newSyncConfiguration() {
- return new SyncConfiguration(null, null, getPrefs(TEST_PREFS_NAME, 0));
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestWebURLFinder.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestWebURLFinder.java
deleted file mode 100644
index a7ebb71d5..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestWebURLFinder.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync;
-
-import java.util.Arrays;
-
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.sync.setup.activities.WebURLFinder;
-
-/**
- * These tests are on device because the WebKit APIs are stubs on desktop.
- */
-public class TestWebURLFinder extends AndroidSyncTestCase {
- public String find(String string) {
- return new WebURLFinder(string).bestWebURL();
- }
-
- public String find(String[] strings) {
- return new WebURLFinder(Arrays.asList(strings)).bestWebURL();
- }
-
- public void testNoEmail() {
- assertNull(find("test@test.com"));
- }
-
- public void testSchemeFirst() {
- assertEquals("http://scheme.com", find("test.com http://scheme.com"));
- }
-
- public void testFullURL() {
- assertEquals("http://scheme.com:8080/inner#anchor&arg=1", find("test.com http://scheme.com:8080/inner#anchor&arg=1"));
- }
-
- public void testNoScheme() {
- assertEquals("noscheme.com", find("noscheme.com"));
- }
-
- public void testNoBadScheme() {
- assertNull(find("file:///test javascript:///test.js"));
- }
-
- public void testStrings() {
- assertEquals("http://test.com", find(new String[] { "http://test.com", "noscheme.com" }));
- assertEquals("http://test.com", find(new String[] { "noschemefirst.com", "http://test.com" }));
- assertEquals("http://test.com/inner#test", find(new String[] { "noschemefirst.com", "http://test.com/inner#test", "http://second.org/fark" }));
- assertEquals("http://test.com", find(new String[] { "javascript:///test.js", "http://test.com" }));
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/BookmarkHelpers.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/BookmarkHelpers.java
deleted file mode 100644
index 0fcd762f4..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/BookmarkHelpers.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.json.simple.JSONArray;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-
-public class BookmarkHelpers {
-
- private static String mobileFolderGuid = "mobile";
- private static String mobileFolderName = "mobile";
- private static String topFolderGuid = Utils.generateGuid();
- private static String topFolderName = "My Top Folder";
- private static String middleFolderGuid = Utils.generateGuid();
- private static String middleFolderName = "My Middle Folder";
- private static String bottomFolderGuid = Utils.generateGuid();
- private static String bottomFolderName = "My Bottom Folder";
- private static String bmk1Guid = Utils.generateGuid();
- private static String bmk2Guid = Utils.generateGuid();
- private static String bmk3Guid = Utils.generateGuid();
- private static String bmk4Guid = Utils.generateGuid();
-
- /*
- * Helpers for creating bookmark records of different types
- */
- public static BookmarkRecord createBookmarkInMobileFolder1() {
- BookmarkRecord rec = createBookmark1();
- rec.guid = Utils.generateGuid();
- rec.parentID = mobileFolderGuid;
- rec.parentName = mobileFolderName;
- return rec;
- }
-
- public static BookmarkRecord createBookmarkInMobileFolder2() {
- BookmarkRecord rec = createBookmark2();
- rec.guid = Utils.generateGuid();
- rec.parentID = mobileFolderGuid;
- rec.parentName = mobileFolderName;
- return rec;
- }
-
- @SuppressWarnings("unchecked")
- public static BookmarkRecord createBookmark1() {
- BookmarkRecord record = new BookmarkRecord();
- JSONArray tags = new JSONArray();
- tags.add("tag1");
- tags.add("tag2");
- tags.add("tag3");
- record.guid = bmk1Guid;
- record.title = "Foo!!!";
- record.bookmarkURI = "http://foo.bar.com";
- record.description = "This is a description for foo.bar.com";
- record.tags = tags;
- record.keyword = "fooooozzzzz";
- record.parentID = topFolderGuid;
- record.parentName = topFolderName;
- record.type = "bookmark";
- return record;
- }
-
- @SuppressWarnings("unchecked")
- public static BookmarkRecord createBookmark2() {
- BookmarkRecord record = new BookmarkRecord();
- JSONArray tags = new JSONArray();
- tags.add("tag1");
- tags.add("tag2");
- record.guid = bmk2Guid;
- record.title = "Bar???";
- record.bookmarkURI = "http://bar.foo.com";
- record.description = "This is a description for Bar???";
- record.tags = tags;
- record.keyword = "keywordzzz";
- record.parentID = topFolderGuid;
- record.parentName = topFolderName;
- record.type = "bookmark";
- return record;
- }
-
- @SuppressWarnings("unchecked")
- public static BookmarkRecord createBookmark3() {
- BookmarkRecord record = new BookmarkRecord();
- JSONArray tags = new JSONArray();
- tags.add("tag1");
- tags.add("tag2");
- record.guid = bmk3Guid;
- record.title = "Bmk3";
- record.bookmarkURI = "http://bmk3.com";
- record.description = "This is a description for bmk3";
- record.tags = tags;
- record.keyword = "snooozzz";
- record.parentID = middleFolderGuid;
- record.parentName = middleFolderName;
- record.type = "bookmark";
- return record;
- }
-
- @SuppressWarnings("unchecked")
- public static BookmarkRecord createBookmark4() {
- BookmarkRecord record = new BookmarkRecord();
- JSONArray tags = new JSONArray();
- tags.add("tag1");
- tags.add("tag2");
- record.guid = bmk4Guid;
- record.title = "Bmk4";
- record.bookmarkURI = "http://bmk4.com";
- record.description = "This is a description for bmk4?";
- record.tags = tags;
- record.keyword = "booooozzz";
- record.parentID = bottomFolderGuid;
- record.parentName = bottomFolderName;
- record.type = "bookmark";
- return record;
- }
-
- @SuppressWarnings("unchecked")
- public static BookmarkRecord createMicrosummary() {
- BookmarkRecord record = new BookmarkRecord();
- JSONArray tags = new JSONArray();
- tags.add("tag1");
- tags.add("tag2");
- record.guid = Utils.generateGuid();
- record.title = "Microsummary 1";
- record.bookmarkURI = "www.bmkuri.com";
- record.description = "microsummary description";
- record.tags = tags;
- record.keyword = "keywordzzz";
- record.parentID = topFolderGuid;
- record.parentName = topFolderName;
- record.type = "microsummary";
- return record;
- }
-
- public static BookmarkRecord createQuery() {
- BookmarkRecord record = new BookmarkRecord();
- record.guid = Utils.generateGuid();
- record.title = "Query 1";
- record.bookmarkURI = "http://www.query.com";
- record.description = "Query 1 description";
- record.tags = new JSONArray();
- record.keyword = "queryKeyword";
- record.parentID = topFolderGuid;
- record.parentName = topFolderName;
- record.type = "query";
- return record;
- }
-
- @SuppressWarnings("unchecked")
- public static BookmarkRecord createFolder1() {
- BookmarkRecord record = new BookmarkRecord();
- record.guid = topFolderGuid;
- record.title = topFolderName;
- record.parentID = "mobile";
- record.parentName = "mobile";
- JSONArray children = new JSONArray();
- children.add(bmk1Guid);
- children.add(bmk2Guid);
- record.children = children;
- record.type = "folder";
- return record;
- }
-
- @SuppressWarnings("unchecked")
- public static BookmarkRecord createFolder2() {
- BookmarkRecord record = new BookmarkRecord();
- record.guid = middleFolderGuid;
- record.title = middleFolderName;
- record.parentID = topFolderGuid;
- record.parentName = topFolderName;
- JSONArray children = new JSONArray();
- children.add(bmk3Guid);
- record.children = children;
- record.type = "folder";
- return record;
- }
-
- @SuppressWarnings("unchecked")
- public static BookmarkRecord createFolder3() {
- BookmarkRecord record = new BookmarkRecord();
- record.guid = bottomFolderGuid;
- record.title = bottomFolderName;
- record.parentID = middleFolderGuid;
- record.parentName = middleFolderName;
- JSONArray children = new JSONArray();
- children.add(bmk4Guid);
- record.children = children;
- record.type = "folder";
- return record;
- }
-
- @SuppressWarnings("unchecked")
- public static BookmarkRecord createLivemark() {
- BookmarkRecord record = new BookmarkRecord();
- record.guid = Utils.generateGuid();
- record.title = "Livemark title";
- record.parentID = topFolderGuid;
- record.parentName = topFolderName;
- JSONArray children = new JSONArray();
- children.add(Utils.generateGuid());
- children.add(Utils.generateGuid());
- record.children = children;
- record.type = "livemark";
- return record;
- }
-
- public static BookmarkRecord createSeparator() {
- BookmarkRecord record = new BookmarkRecord();
- record.guid = Utils.generateGuid();
- record.androidPosition = 3;
- record.parentID = topFolderGuid;
- record.parentName = topFolderName;
- record.type = "separator";
- return record;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultBeginDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultBeginDelegate.java
deleted file mode 100644
index 67aa81fff..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultBeginDelegate.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-
-public class DefaultBeginDelegate extends DefaultDelegate implements RepositorySessionBeginDelegate {
- @Override
- public void onBeginFailed(Exception ex) {
- performNotify("Begin failed", ex);
- }
-
- @Override
- public void onBeginSucceeded(RepositorySession session) {
- performNotify("Default begin delegate hit.", null);
- }
-
- @Override
- public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
- DefaultBeginDelegate copy;
- try {
- copy = (DefaultBeginDelegate) this.clone();
- copy.executor = executor;
- return copy;
- } catch (CloneNotSupportedException e) {
- return this;
- }
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultCleanDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultCleanDelegate.java
deleted file mode 100644
index a1f5b7a97..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultCleanDelegate.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCleanDelegate;
-
-public class DefaultCleanDelegate extends DefaultDelegate implements RepositorySessionCleanDelegate {
-
- @Override
- public void onCleaned(Repository repo) {
- performNotify("Default begin delegate hit.", null);
- }
-
- @Override
- public void onCleanFailed(Repository repo, Exception ex) {
- performNotify("Clean failed.", ex);
- }
-
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultDelegate.java
deleted file mode 100644
index 7e9341f02..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultDelegate.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.concurrent.ExecutorService;
-
-import junit.framework.AssertionFailedError;
-
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-
-public abstract class DefaultDelegate {
- protected ExecutorService executor;
-
- protected final WaitHelper waitHelper;
-
- public DefaultDelegate() {
- waitHelper = WaitHelper.getTestWaiter();
- }
-
- public DefaultDelegate(WaitHelper waitHelper) {
- this.waitHelper = waitHelper;
- }
-
- protected WaitHelper getTestWaiter() {
- return waitHelper;
- }
-
- public void performWait(Runnable runnable) throws AssertionFailedError {
- getTestWaiter().performWait(runnable);
- }
-
- public void performNotify() {
- getTestWaiter().performNotify();
- }
-
- public void performNotify(Throwable e) {
- getTestWaiter().performNotify(e);
- }
-
- public void performNotify(String reason, Throwable e) {
- String message = reason;
- if (e != null) {
- message += ": " + e.getMessage();
- }
- AssertionFailedError ex = new AssertionFailedError(message);
- if (e != null) {
- ex.initCause(e);
- }
- getTestWaiter().performNotify(ex);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultFetchDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultFetchDelegate.java
deleted file mode 100644
index 3d7d23bab..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultFetchDelegate.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-
-import junit.framework.AssertionFailedError;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.repositories.delegates.DeferredRepositorySessionFetchRecordsDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-public class DefaultFetchDelegate extends DefaultDelegate implements RepositorySessionFetchRecordsDelegate {
-
- private static final String LOG_TAG = "DefaultFetchDelegate";
- public ArrayList<Record> records = new ArrayList<Record>();
- public Set<String> ignore = new HashSet<String>();
-
- @Override
- public void onFetchFailed(Exception ex, Record record) {
- performNotify("Fetch failed.", ex);
- }
-
- protected void onDone(ArrayList<Record> records, HashMap<String, Record> expected, long end) {
- Logger.debug(LOG_TAG, "onDone.");
- Logger.debug(LOG_TAG, "End timestamp is " + end);
- Logger.debug(LOG_TAG, "Expected is " + expected);
- Logger.debug(LOG_TAG, "Records is " + records);
- Set<String> foundGuids = new HashSet<String>();
- try {
- int expectedCount = 0;
- int expectedFound = 0;
- Logger.debug(LOG_TAG, "Counting expected keys.");
- for (String key : expected.keySet()) {
- if (!ignore.contains(key)) {
- expectedCount++;
- }
- }
- Logger.debug(LOG_TAG, "Expected keys: " + expectedCount);
- for (Record record : records) {
- Logger.debug(LOG_TAG, "Record.");
- Logger.debug(LOG_TAG, record.guid);
-
- // Ignore special GUIDs (e.g., for bookmarks).
- if (!ignore.contains(record.guid)) {
- if (foundGuids.contains(record.guid)) {
- fail("Found duplicate guid " + record.guid);
- }
- Record expect = expected.get(record.guid);
- if (expect == null) {
- fail("Do not expect to get back a record with guid: " + record.guid); // Caught below
- }
- Logger.debug(LOG_TAG, "Checking equality.");
- try {
- assertTrue(expect.equalPayloads(record)); // Caught below
- } catch (Exception e) {
- Logger.error(LOG_TAG, "ONOZ!", e);
- }
- Logger.debug(LOG_TAG, "Checked equality.");
- expectedFound += 1;
- // Track record once we've found it.
- foundGuids.add(record.guid);
- }
- }
- assertEquals(expectedCount, expectedFound); // Caught below
- Logger.debug(LOG_TAG, "Notifying success.");
- performNotify();
- } catch (AssertionFailedError e) {
- Logger.error(LOG_TAG, "Notifying assertion failure.");
- performNotify(e);
- } catch (Exception e) {
- Logger.error(LOG_TAG, "No!");
- performNotify();
- }
- }
-
- public int recordCount() {
- return (this.records == null) ? 0 : this.records.size();
- }
-
- @Override
- public void onFetchedRecord(Record record) {
- Logger.debug(LOG_TAG, "onFetchedRecord(" + record.guid + ")");
- records.add(record);
- }
-
- @Override
- public void onFetchCompleted(final long fetchEnd) {
- Logger.debug(LOG_TAG, "onFetchCompleted. Doing nothing.");
- }
-
- @Override
- public RepositorySessionFetchRecordsDelegate deferredFetchDelegate(final ExecutorService executor) {
- return new DeferredRepositorySessionFetchRecordsDelegate(this, executor);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultFinishDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultFinishDelegate.java
deleted file mode 100644
index 11e451e82..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultFinishDelegate.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
-
-public class DefaultFinishDelegate extends DefaultDelegate implements RepositorySessionFinishDelegate {
-
- @Override
- public void onFinishFailed(Exception ex) {
- performNotify("Finish failed", ex);
- }
-
- @Override
- public void onFinishSucceeded(RepositorySession session, RepositorySessionBundle bundle) {
- performNotify("Hit default finish delegate", null);
- }
-
- @Override
- public RepositorySessionFinishDelegate deferredFinishDelegate(final ExecutorService executor) {
- final RepositorySessionFinishDelegate self = this;
-
- Logger.info("DefaultFinishDelegate", "Deferring…");
- return new RepositorySessionFinishDelegate() {
- @Override
- public void onFinishSucceeded(final RepositorySession session,
- final RepositorySessionBundle bundle) {
- Logger.info("DefaultFinishDelegate", "Executing onFinishSucceeded Runnable…");
- executor.execute(new Runnable() {
- @Override
- public void run() {
- self.onFinishSucceeded(session, bundle);
- }});
- }
-
- @Override
- public void onFinishFailed(final Exception ex) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- self.onFinishFailed(ex);
- }});
- }
-
- @Override
- public RepositorySessionFinishDelegate deferredFinishDelegate(ExecutorService newExecutor) {
- if (newExecutor == executor) {
- return this;
- }
- throw new IllegalArgumentException("Can't re-defer this delegate.");
- }
- };
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultGuidsSinceDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultGuidsSinceDelegate.java
deleted file mode 100644
index 78e3cc84f..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultGuidsSinceDelegate.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate;
-
-public class DefaultGuidsSinceDelegate extends DefaultDelegate implements RepositorySessionGuidsSinceDelegate {
-
- @Override
- public void onGuidsSinceFailed(Exception ex) {
- performNotify("shouldn't fail", ex);
- }
-
- @Override
- public void onGuidsSinceSucceeded(String[] guids) {
- performNotify("default guids since delegate called", null);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultSessionCreationDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultSessionCreationDelegate.java
deleted file mode 100644
index 5d52df84d..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultSessionCreationDelegate.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-
-public class DefaultSessionCreationDelegate extends DefaultDelegate implements
- RepositorySessionCreationDelegate {
-
- @Override
- public void onSessionCreateFailed(Exception ex) {
- performNotify("Session creation failed", ex);
- }
-
- @Override
- public void onSessionCreated(RepositorySession session) {
- performNotify("Should not have been created.", null);
- }
-
- @Override
- public RepositorySessionCreationDelegate deferredCreationDelegate() {
- final RepositorySessionCreationDelegate self = this;
- return new RepositorySessionCreationDelegate() {
-
- @Override
- public void onSessionCreated(final RepositorySession session) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- self.onSessionCreated(session);
- }
- }).start();
- }
-
- @Override
- public void onSessionCreateFailed(final Exception ex) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- self.onSessionCreateFailed(ex);
- }
- }).start();
- }
-
- @Override
- public RepositorySessionCreationDelegate deferredCreationDelegate() {
- return this;
- }
- };
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultStoreDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultStoreDelegate.java
deleted file mode 100644
index 7ba2e6df6..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/DefaultStoreDelegate.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
-
-public class DefaultStoreDelegate extends DefaultDelegate implements RepositorySessionStoreDelegate {
-
- @Override
- public void onRecordStoreFailed(Exception ex, String guid) {
- performNotify("Store failed", ex);
- }
-
- @Override
- public void onRecordStoreSucceeded(String guid) {
- performNotify("DefaultStoreDelegate used", null);
- }
-
- @Override
- public void onStoreCompleted(long storeEnd) {
- performNotify("DefaultStoreDelegate used", null);
- }
-
- @Override
- public RepositorySessionStoreDelegate deferredStoreDelegate(final ExecutorService executor) {
- final RepositorySessionStoreDelegate self = this;
- return new RepositorySessionStoreDelegate() {
-
- @Override
- public void onRecordStoreSucceeded(final String guid) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- self.onRecordStoreSucceeded(guid);
- }
- });
- }
-
- @Override
- public void onRecordStoreFailed(final Exception ex, final String guid) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- self.onRecordStoreFailed(ex, guid);
- }
- });
- }
-
- @Override
- public void onStoreCompleted(final long storeEnd) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- self.onStoreCompleted(storeEnd);
- }
- });
- }
-
- @Override
- public RepositorySessionStoreDelegate deferredStoreDelegate(ExecutorService newExecutor) {
- if (newExecutor == executor) {
- return this;
- }
- throw new IllegalArgumentException("Can't re-defer this delegate.");
- }
- };
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginDelegate.java
deleted file mode 100644
index d320cfd7a..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginDelegate.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import static junit.framework.Assert.assertNotNull;
-import junit.framework.AssertionFailedError;
-
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-
-public class ExpectBeginDelegate extends DefaultBeginDelegate {
- @Override
- public void onBeginSucceeded(RepositorySession session) {
- try {
- assertNotNull(session);
- } catch (AssertionFailedError e) {
- performNotify("Expected non-null session", e);
- return;
- }
- performNotify();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginFailDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginFailDelegate.java
deleted file mode 100644
index ff1807d51..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectBeginFailDelegate.java
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-
-public class ExpectBeginFailDelegate extends DefaultBeginDelegate {
-
- @Override
- public void onBeginFailed(Exception ex) {
- if (!(ex instanceof InvalidSessionTransitionException)) {
- performNotify("Expected InvalidSessionTransititionException but got ", ex);
- }
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFetchDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFetchDelegate.java
deleted file mode 100644
index 5cfe5327a..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFetchDelegate.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.HashMap;
-
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-public class ExpectFetchDelegate extends DefaultFetchDelegate {
- private HashMap<String, Record> expect = new HashMap<String, Record>();
-
- public ExpectFetchDelegate(Record[] records) {
- for(int i = 0; i < records.length; i++) {
- expect.put(records[i].guid, records[i]);
- }
- }
-
- @Override
- public void onFetchedRecord(Record record) {
- this.records.add(record);
- }
-
- @Override
- public void onFetchCompleted(final long fetchEnd) {
- super.onDone(this.records, this.expect, fetchEnd);
- }
-
- public Record recordAt(int i) {
- return this.records.get(i);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFetchSinceDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFetchSinceDelegate.java
deleted file mode 100644
index 7dcada0d4..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFetchSinceDelegate.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import java.util.Arrays;
-
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import junit.framework.AssertionFailedError;
-
-public class ExpectFetchSinceDelegate extends DefaultFetchDelegate {
- private String[] expected;
- private long earliest;
-
- public ExpectFetchSinceDelegate(long timestamp, String[] guids) {
- expected = guids;
- earliest = timestamp;
- Arrays.sort(expected);
- }
-
- @Override
- public void onFetchCompleted(final long fetchEnd) {
- AssertionFailedError err = null;
- try {
- int countSpecials = 0;
- for (Record record : records) {
- // Check if record should be ignored.
- if (!ignore.contains(record.guid)) {
- assertFalse(-1 == Arrays.binarySearch(this.expected, record.guid));
- } else {
- countSpecials++;
- }
- // Check that record is later than timestamp-earliest.
- assertTrue(record.lastModified >= this.earliest);
- }
- assertEquals(this.expected.length, records.size() - countSpecials);
- } catch (AssertionFailedError e) {
- err = e;
- }
- performNotify(err);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFinishDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFinishDelegate.java
deleted file mode 100644
index 0b6f1de88..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFinishDelegate.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-
-public class ExpectFinishDelegate extends DefaultFinishDelegate {
-
- @Override
- public void onFinishSucceeded(RepositorySession session, RepositorySessionBundle bundle) {
- Logger.info("ExpectFinishDelegate", "Finish succeeded.");
- performNotify();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFinishFailDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFinishFailDelegate.java
deleted file mode 100644
index df83432bc..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectFinishFailDelegate.java
+++ /dev/null
@@ -1,15 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-
-public class ExpectFinishFailDelegate extends DefaultFinishDelegate {
- @Override
- public void onFinishFailed(Exception ex) {
- if (!(ex instanceof InvalidSessionTransitionException)) {
- performNotify("Expected InvalidSessionTransititionException but got ", ex);
- }
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectGuidsSinceDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectGuidsSinceDelegate.java
deleted file mode 100644
index 435ba7502..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectGuidsSinceDelegate.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-import junit.framework.AssertionFailedError;
-
-public class ExpectGuidsSinceDelegate extends DefaultGuidsSinceDelegate {
- private String[] expected;
- public Set<String> ignore = new HashSet<String>();
-
- public ExpectGuidsSinceDelegate(String[] guids) {
- expected = guids;
- Arrays.sort(expected);
- }
-
- @Override
- public void onGuidsSinceSucceeded(String[] guids) {
- AssertionFailedError err = null;
- try {
- int notIgnored = 0;
- for (String guid : guids) {
- if (!ignore.contains(guid)) {
- notIgnored++;
- assertFalse(-1 == Arrays.binarySearch(this.expected, guid));
- }
- }
- assertEquals(this.expected.length, notIgnored);
- } catch (AssertionFailedError e) {
- err = e;
- }
- performNotify(err);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidRequestFetchDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidRequestFetchDelegate.java
deleted file mode 100644
index 73035869c..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidRequestFetchDelegate.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.mozilla.gecko.sync.repositories.InvalidRequestException;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-public class ExpectInvalidRequestFetchDelegate extends DefaultFetchDelegate {
- public static final String LOG_TAG = "ExpInvRequestFetchDel";
-
- @Override
- public void onFetchFailed(Exception ex, Record rec) {
- if (ex instanceof InvalidRequestException) {
- onDone();
- } else {
- performNotify("Expected InvalidRequestException but got ", ex);
- }
- }
-
- private void onDone() {
- performNotify();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidTypeStoreDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidTypeStoreDelegate.java
deleted file mode 100644
index 5ce56ee5f..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidTypeStoreDelegate.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import static junit.framework.Assert.assertEquals;
-
-import org.mozilla.gecko.sync.repositories.InvalidBookmarkTypeException;
-
-public class ExpectInvalidTypeStoreDelegate extends DefaultStoreDelegate {
-
- @Override
- public void onRecordStoreFailed(Exception ex, String guid) {
- assertEquals(InvalidBookmarkTypeException.class, ex.getClass());
- performNotify();
- }
-
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectManyStoredDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectManyStoredDelegate.java
deleted file mode 100644
index 2a8df0228..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectManyStoredDelegate.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
-import java.util.HashSet;
-import java.util.concurrent.atomic.AtomicLong;
-
-import junit.framework.AssertionFailedError;
-
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-public class ExpectManyStoredDelegate extends DefaultStoreDelegate {
- HashSet<String> expectedGUIDs;
- AtomicLong stored;
-
- public ExpectManyStoredDelegate(Record[] records) {
- HashSet<String> s = new HashSet<String>();
- for (Record record : records) {
- s.add(record.guid);
- }
- expectedGUIDs = s;
- stored = new AtomicLong(0);
- }
-
- @Override
- public void onStoreCompleted(long storeEnd) {
- try {
- assertEquals(expectedGUIDs.size(), stored.get());
- performNotify();
- } catch (AssertionFailedError e) {
- performNotify(e);
- }
- }
-
- @Override
- public void onRecordStoreSucceeded(String guid) {
- try {
- assertTrue(expectedGUIDs.contains(guid));
- } catch (AssertionFailedError e) {
- performNotify(e);
- }
- stored.incrementAndGet();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectNoGUIDsSinceDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectNoGUIDsSinceDelegate.java
deleted file mode 100644
index a9f11d7b0..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectNoGUIDsSinceDelegate.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import static junit.framework.Assert.assertEquals;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import junit.framework.AssertionFailedError;
-
-public class ExpectNoGUIDsSinceDelegate extends DefaultGuidsSinceDelegate {
-
- public Set<String> ignore = new HashSet<String>();
-
- @Override
- public void onGuidsSinceSucceeded(String[] guids) {
- AssertionFailedError err = null;
- try {
- int nonIgnored = 0;
- for (int i = 0; i < guids.length; i++) {
- if (!ignore.contains(guids[i])) {
- nonIgnored++;
- }
- }
- assertEquals(0, nonIgnored);
- } catch (AssertionFailedError e) {
- err = e;
- }
- performNotify(err);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectNoStoreDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectNoStoreDelegate.java
deleted file mode 100644
index 93626898e..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectNoStoreDelegate.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-public class ExpectNoStoreDelegate extends ExpectStoreCompletedDelegate {
- @Override
- public void onRecordStoreSucceeded(String guid) {
- performNotify("Should not have stored record " + guid, null);
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectStoreCompletedDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectStoreCompletedDelegate.java
deleted file mode 100644
index b3cc909a1..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectStoreCompletedDelegate.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-public class ExpectStoreCompletedDelegate extends DefaultStoreDelegate {
-
- @Override
- public void onRecordStoreSucceeded(String guid) {
- // That's fine.
- }
-
- @Override
- public void onStoreCompleted(long storeEnd) {
- performNotify();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectStoredDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectStoredDelegate.java
deleted file mode 100644
index dc2e8a2d1..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/ExpectStoredDelegate.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import junit.framework.AssertionFailedError;
-
-public class ExpectStoredDelegate extends DefaultStoreDelegate {
- String expectedGUID;
- String storedGuid;
-
- public ExpectStoredDelegate(String guid) {
- this.expectedGUID = guid;
- }
-
- @Override
- public synchronized void onStoreCompleted(long storeEnd) {
- try {
- assertNotNull(storedGuid);
- performNotify();
- } catch (AssertionFailedError e) {
- performNotify("GUID " + this.expectedGUID + " was not stored", e);
- }
- }
-
- @Override
- public synchronized void onRecordStoreSucceeded(String guid) {
- this.storedGuid = guid;
- try {
- if (this.expectedGUID != null) {
- assertEquals(this.expectedGUID, guid);
- }
- } catch (AssertionFailedError e) {
- performNotify(e);
- }
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/HistoryHelpers.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/HistoryHelpers.java
deleted file mode 100644
index 68f80043e..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/HistoryHelpers.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
-
-public class HistoryHelpers {
-
- @SuppressWarnings("unchecked")
- private static JSONArray getVisits1() {
- JSONArray json = new JSONArray();
- JSONObject obj = new JSONObject();
- obj.put("date", 1320087601465600000L);
- obj.put("type", 2L);
- json.add(obj);
- obj = new JSONObject();
- obj.put("date", 1320084970724990000L);
- obj.put("type", 1L);
- json.add(obj);
- obj = new JSONObject();
- obj.put("date", 1319764134412287000L);
- obj.put("type", 1L);
- json.add(obj);
- obj = new JSONObject();
- obj.put("date", 1319681306455594000L);
- obj.put("type", 2L);
- json.add(obj);
- return json;
- }
-
- @SuppressWarnings("unchecked")
- private static JSONArray getVisits2() {
- JSONArray json = new JSONArray();
- JSONObject obj = new JSONObject();
- obj = new JSONObject();
- obj.put("date", 1319764134412345000L);
- obj.put("type", 4L);
- json.add(obj);
- obj = new JSONObject();
- obj.put("date", 1319681306454321000L);
- obj.put("type", 3L);
- json.add(obj);
- return json;
- }
-
- public static HistoryRecord createHistory1() {
- HistoryRecord record = new HistoryRecord();
- record.title = "History 1";
- record.histURI = "http://history.page1.com";
- record.visits = getVisits1();
- return record;
- }
-
-
- public static HistoryRecord createHistory2() {
- HistoryRecord record = new HistoryRecord();
- record.title = "History 2";
- record.histURI = "http://history.page2.com";
- record.visits = getVisits2();
- return record;
- }
-
- public static HistoryRecord createHistory3() {
- HistoryRecord record = new HistoryRecord();
- record.title = "History 3";
- record.histURI = "http://history.page3.com";
- record.visits = getVisits2();
- return record;
- }
-
- public static HistoryRecord createHistory4() {
- HistoryRecord record = new HistoryRecord();
- record.title = "History 4";
- record.histURI = "http://history.page4.com";
- record.visits = getVisits1();
- return record;
- }
-
- public static HistoryRecord createHistory5() {
- HistoryRecord record = new HistoryRecord();
- record.title = "History 5";
- record.histURI = "http://history.page5.com";
- record.visits = getVisits2();
- return record;
- }
-
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/PasswordHelpers.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/PasswordHelpers.java
deleted file mode 100644
index 87400a2b0..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/PasswordHelpers.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.mozilla.gecko.sync.repositories.domain.PasswordRecord;
-
-public class PasswordHelpers {
-
- public static PasswordRecord createPassword1() {
- PasswordRecord rec = new PasswordRecord();
- rec.encType = "some type";
- rec.formSubmitURL = "http://submit.html";
- rec.hostname = "http://hostname";
- rec.httpRealm = "httpRealm";
- rec.encryptedPassword ="12345";
- rec.passwordField = "box.pass.field";
- rec.timeCreated = 111111111L;
- rec.timeLastUsed = 123412352435L;
- rec.timePasswordChanged = 121111111L;
- rec.timesUsed = 5L;
- rec.encryptedUsername = "jvoll";
- rec.usernameField = "box.user.field";
- return rec;
- }
-
- public static PasswordRecord createPassword2() {
- PasswordRecord rec = new PasswordRecord();
- rec.encType = "some type";
- rec.formSubmitURL = "http://submit2.html";
- rec.hostname = "http://hostname2";
- rec.httpRealm = "httpRealm2";
- rec.encryptedPassword ="54321";
- rec.passwordField = "box.pass.field2";
- rec.timeCreated = 12111111111L;
- rec.timeLastUsed = 123412352213L;
- rec.timePasswordChanged = 123111111111L;
- rec.timesUsed = 2L;
- rec.encryptedUsername = "rnewman";
- rec.usernameField = "box.user.field2";
- return rec;
- }
-
- public static PasswordRecord createPassword3() {
- PasswordRecord rec = new PasswordRecord();
- rec.encType = "some type3";
- rec.formSubmitURL = "http://submit3.html";
- rec.hostname = "http://hostname3";
- rec.httpRealm = "httpRealm3";
- rec.encryptedPassword ="54321";
- rec.passwordField = "box.pass.field3";
- rec.timeCreated = 100000000000L;
- rec.timeLastUsed = 123412352213L;
- rec.timePasswordChanged = 110000000000L;
- rec.timesUsed = 2L;
- rec.encryptedUsername = "rnewman";
- rec.usernameField = "box.user.field3";
- return rec;
- }
-
- public static PasswordRecord createPassword4() {
- PasswordRecord rec = new PasswordRecord();
- rec.encType = "some type";
- rec.formSubmitURL = "http://submit4.html";
- rec.hostname = "http://hostname4";
- rec.httpRealm = "httpRealm4";
- rec.encryptedPassword ="54324";
- rec.passwordField = "box.pass.field4";
- rec.timeCreated = 101000000000L;
- rec.timeLastUsed = 123412354444L;
- rec.timePasswordChanged = 110000000000L;
- rec.timesUsed = 4L;
- rec.encryptedUsername = "rnewman4";
- rec.usernameField = "box.user.field4";
- return rec;
- }
-
- public static PasswordRecord createPassword5() {
- PasswordRecord rec = new PasswordRecord();
- rec.encType = "some type5";
- rec.formSubmitURL = "http://submit5.html";
- rec.hostname = "http://hostname5";
- rec.httpRealm = "httpRealm5";
- rec.encryptedPassword ="54325";
- rec.passwordField = "box.pass.field5";
- rec.timeCreated = 101000000000L;
- rec.timeLastUsed = 123412352555L;
- rec.timePasswordChanged = 111111111111L;
- rec.timesUsed = 5L;
- rec.encryptedUsername = "jvoll5";
- rec.usernameField = "box.user.field5";
- return rec;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java
deleted file mode 100644
index 9c9e6719b..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import static junit.framework.Assert.assertNotNull;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-
-import android.content.Context;
-
-public class SessionTestHelper {
-
- protected static RepositorySession prepareRepositorySession(
- final Context context,
- final boolean begin,
- final Repository repository) {
-
- final WaitHelper testWaiter = WaitHelper.getTestWaiter();
-
- final String logTag = "prepareRepositorySession";
- class CreationDelegate extends DefaultSessionCreationDelegate {
- private RepositorySession session;
- synchronized void setSession(RepositorySession session) {
- this.session = session;
- }
- synchronized RepositorySession getSession() {
- return this.session;
- }
-
- @Override
- public void onSessionCreated(final RepositorySession session) {
- assertNotNull(session);
- Logger.info(logTag, "Setting session to " + session);
- setSession(session);
- if (begin) {
- Logger.info(logTag, "Calling session.begin on new session.");
- // The begin callbacks will notify.
- try {
- session.begin(new ExpectBeginDelegate());
- } catch (InvalidSessionTransitionException e) {
- testWaiter.performNotify(e);
- }
- } else {
- Logger.info(logTag, "Notifying after setting new session.");
- testWaiter.performNotify();
- }
- }
- }
-
- final CreationDelegate delegate = new CreationDelegate();
- try {
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- repository.createSession(delegate, context);
- }
- };
- testWaiter.performWait(runnable);
- } catch (IllegalArgumentException ex) {
- Logger.warn(logTag, "Caught IllegalArgumentException.");
- }
-
- Logger.info(logTag, "Retrieving new session.");
- final RepositorySession session = delegate.getSession();
- assertNotNull(session);
-
- return session;
- }
-
- public static RepositorySession createSession(final Context context, final Repository repository) {
- return prepareRepositorySession(context, false, repository);
- }
-
- public static RepositorySession createAndBeginSession(Context context, Repository repository) {
- return prepareRepositorySession(context, true, repository);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessBeginDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessBeginDelegate.java
deleted file mode 100644
index 0eb477be7..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessBeginDelegate.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-
-public abstract class SimpleSuccessBeginDelegate extends DefaultDelegate implements RepositorySessionBeginDelegate {
- @Override
- public void onBeginFailed(Exception ex) {
- performNotify("Begin failed", ex);
- }
-
- @Override
- public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessCreationDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessCreationDelegate.java
deleted file mode 100644
index 3b3b3d5fa..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessCreationDelegate.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-
-public abstract class SimpleSuccessCreationDelegate extends DefaultDelegate implements RepositorySessionCreationDelegate {
- @Override
- public void onSessionCreateFailed(Exception ex) {
- performNotify("Session creation failed", ex);
- }
-
- @Override
- public RepositorySessionCreationDelegate deferredCreationDelegate() {
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFetchDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFetchDelegate.java
deleted file mode 100644
index f0e9428ba..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFetchDelegate.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-public abstract class SimpleSuccessFetchDelegate extends DefaultDelegate implements
- RepositorySessionFetchRecordsDelegate {
- @Override
- public void onFetchFailed(Exception ex, Record record) {
- performNotify("Fetch failed", ex);
- }
-
- @Override
- public RepositorySessionFetchRecordsDelegate deferredFetchDelegate(ExecutorService executor) {
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFinishDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFinishDelegate.java
deleted file mode 100644
index 5ac1bcde7..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFinishDelegate.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
-
-public abstract class SimpleSuccessFinishDelegate extends DefaultDelegate implements RepositorySessionFinishDelegate {
- @Override
- public void onFinishFailed(Exception ex) {
- performNotify("Finish failed", ex);
- }
-
- @Override
- public RepositorySessionFinishDelegate deferredFinishDelegate(ExecutorService executor) {
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessStoreDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessStoreDelegate.java
deleted file mode 100644
index c725c4a46..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessStoreDelegate.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync.helpers;
-
-import java.util.concurrent.ExecutorService;
-
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
-
-public abstract class SimpleSuccessStoreDelegate extends DefaultDelegate implements RepositorySessionStoreDelegate {
- @Override
- public void onRecordStoreFailed(Exception ex, String guid) {
- performNotify("Store failed", ex);
- }
-
- @Override
- public RepositorySessionStoreDelegate deferredStoreDelegate(ExecutorService executor) {
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java
deleted file mode 100644
index d2a8b8476..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.NoCollectionKeysSetException;
-import org.mozilla.gecko.sync.SynchronizerConfiguration;
-import org.mozilla.gecko.sync.repositories.RecordFactory;
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.stage.ServerSyncStage;
-
-import java.net.URISyntaxException;
-
-/**
- * A stage that joins two Repositories with no wrapping.
- */
-public abstract class BaseMockServerSyncStage extends ServerSyncStage {
-
- public Repository local;
- public Repository remote;
- public String name;
- public String collection;
- public int version = 1;
-
- @Override
- public boolean isEnabled() {
- return true;
- }
-
- @Override
- protected String getCollection() {
- return collection;
- }
-
- @Override
- protected Repository getLocalRepository() {
- return local;
- }
-
- @Override
- protected Repository getRemoteRepository() throws URISyntaxException {
- return remote;
- }
-
- @Override
- protected String getEngineName() {
- return name;
- }
-
- @Override
- public Integer getStorageVersion() {
- return version;
- }
-
- @Override
- protected RecordFactory getRecordFactory() {
- return null;
- }
-
- @Override
- protected Repository wrappedServerRepo()
- throws NoCollectionKeysSetException, URISyntaxException {
- return getRemoteRepository();
- }
-
- public SynchronizerConfiguration leakConfig() throws Exception {
- return this.getConfig();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java
deleted file mode 100644
index 48217f1b0..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.json.simple.JSONArray;
-import org.mozilla.gecko.sync.CommandProcessor.Command;
-
-public class CommandHelpers {
-
- @SuppressWarnings("unchecked")
- public static Command getCommand1() {
- JSONArray args = new JSONArray();
- args.add("argsA");
- return new Command("displayURI", args);
- }
-
- @SuppressWarnings("unchecked")
- public static Command getCommand2() {
- JSONArray args = new JSONArray();
- args.add("argsB");
- return new Command("displayURI", args);
- }
-
- @SuppressWarnings("unchecked")
- public static Command getCommand3() {
- JSONArray args = new JSONArray();
- args.add("argsC");
- return new Command("displayURI", args);
- }
-
- @SuppressWarnings("unchecked")
- public static Command getCommand4() {
- JSONArray args = new JSONArray();
- args.add("URI of Page");
- args.add("Sender ID");
- args.add("Title of Page");
- return new Command("displayURI", args);
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java
deleted file mode 100644
index c8be7e330..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import java.net.URI;
-
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-public class DefaultGlobalSessionCallback implements GlobalSessionCallback {
-
- @Override
- public void requestBackoff(long backoff) {
- }
-
- @Override
- public void informUnauthorizedResponse(GlobalSession globalSession,
- URI oldClusterURL) {
- }
-
- @Override
- public void informUpgradeRequiredResponse(GlobalSession session) {
- }
-
- @Override
- public void informMigrated(GlobalSession globalSession) {
- }
-
- @Override
- public void handleAborted(GlobalSession globalSession, String reason) {
- }
-
- @Override
- public void handleError(GlobalSession globalSession, Exception ex) {
- }
-
- @Override
- public void handleSuccess(GlobalSession globalSession) {
- }
-
- @Override
- public void handleStageCompleted(Stage currentState,
- GlobalSession globalSession) {
- }
-
- @Override
- public boolean shouldBackOffStorage() {
- return false;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java
deleted file mode 100644
index d8380df97..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.stage.AbstractNonRepositorySyncStage;
-
-public class MockAbstractNonRepositorySyncStage extends AbstractNonRepositorySyncStage {
- @Override
- public void execute() {
- session.advance();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java
deleted file mode 100644
index f4af51f64..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
-
-public class MockClientsDataDelegate implements ClientsDataDelegate {
- private String accountGUID;
- private String clientName;
- private int clientsCount;
- private long clientDataTimestamp = 0;
-
- @Override
- public synchronized String getAccountGUID() {
- if (accountGUID == null) {
- accountGUID = Utils.generateGuid();
- }
- return accountGUID;
- }
-
- @Override
- public synchronized String getDefaultClientName() {
- return "Default client";
- }
-
- @Override
- public synchronized void setClientName(String clientName, long now) {
- this.clientName = clientName;
- this.clientDataTimestamp = now;
- }
-
- @Override
- public synchronized String getClientName() {
- if (clientName == null) {
- setClientName(getDefaultClientName(), System.currentTimeMillis());
- }
- return clientName;
- }
-
- @Override
- public synchronized void setClientsCount(int clientsCount) {
- this.clientsCount = clientsCount;
- }
-
- @Override
- public synchronized int getClientsCount() {
- return clientsCount;
- }
-
- @Override
- public synchronized boolean isLocalGUID(String guid) {
- return getAccountGUID().equals(guid);
- }
-
- @Override
- public synchronized long getLastModifiedTimestamp() {
- return clientDataTimestamp;
- }
-
- @Override
- public String getFormFactor() {
- return "phone";
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java
deleted file mode 100644
index 5e574e33d..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import org.mozilla.gecko.sync.CommandProcessor.Command;
-import org.mozilla.gecko.sync.repositories.NullCursorException;
-import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-
-public class MockClientsDatabaseAccessor extends ClientsDatabaseAccessor {
- public boolean storedRecord = false;
- public boolean dbWiped = false;
- public boolean clientsTableWiped = false;
- public boolean closed = false;
- public boolean storedArrayList = false;
- public boolean storedCommand;
-
- @Override
- public void store(ClientRecord record) {
- storedRecord = true;
- }
-
- @Override
- public void store(Collection<ClientRecord> records) {
- storedArrayList = false;
- }
-
- @Override
- public void store(String accountGUID, Command command) throws NullCursorException {
- storedCommand = true;
- }
-
- @Override
- public ClientRecord fetchClient(String profileID) throws NullCursorException {
- return null;
- }
-
- @Override
- public Map<String, ClientRecord> fetchAllClients() throws NullCursorException {
- return null;
- }
-
- @Override
- public List<Command> fetchCommandsForClient(String accountGUID) throws NullCursorException {
- return null;
- }
-
- @Override
- public int clientsCount() {
- return 0;
- }
-
- @Override
- public void wipeDB() {
- dbWiped = true;
- }
-
- @Override
- public void wipeClientsTable() {
- clientsTableWiped = true;
- }
-
- @Override
- public void close() {
- closed = true;
- }
-
- public void resetVars() {
- storedRecord = dbWiped = clientsTableWiped = closed = storedArrayList = false;
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java
deleted file mode 100644
index 63afdd1ac..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.EngineSettings;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.stage.CompletedStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-import java.io.IOException;
-import java.util.HashMap;
-
-
-public class MockGlobalSession extends MockPrefsGlobalSession {
-
- public MockGlobalSession(String username, String password, KeyBundle keyBundle, GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException {
- this(new SyncConfiguration(username, new BasicAuthHeaderProvider(username, password), new MockSharedPreferences(), keyBundle), callback);
- }
-
- public MockGlobalSession(SyncConfiguration config, GlobalSessionCallback callback)
- throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
- super(config, callback, null, null);
- }
-
- @Override
- public boolean isEngineRemotelyEnabled(String engine, EngineSettings engineSettings) {
- return false;
- }
-
- @Override
- protected void prepareStages() {
- super.prepareStages();
- HashMap<Stage, GlobalSyncStage> newStages = new HashMap<Stage, GlobalSyncStage>(this.stages);
-
- for (Stage stage : this.stages.keySet()) {
- newStages.put(stage, new MockServerSyncStage());
- }
-
- // This signals that the global session is complete.
- newStages.put(Stage.completed, new CompletedStage());
-
- this.stages = newStages;
- }
-
- public MockGlobalSession withStage(Stage stage, GlobalSyncStage syncStage) {
- stages.put(stage, syncStage);
-
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
deleted file mode 100644
index 2ff29453f..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-
-import java.io.IOException;
-
-/**
- * GlobalSession touches the Android prefs system. Stub that out.
- */
-public class MockPrefsGlobalSession extends GlobalSession {
-
- public MockSharedPreferences prefs;
-
- public MockPrefsGlobalSession(
- SyncConfiguration config, GlobalSessionCallback callback, Context context,
- ClientsDataDelegate clientsDelegate)
- throws SyncConfigurationException, IllegalArgumentException, IOException,
- NonObjectJSONException {
- super(config, callback, context, clientsDelegate);
- }
-
- public static MockPrefsGlobalSession getSession(
- String username, String password,
- KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
- ClientsDataDelegate clientsDelegate)
- throws SyncConfigurationException, IllegalArgumentException, IOException,
- NonObjectJSONException {
- return getSession(username, new BasicAuthHeaderProvider(username, password), null,
- syncKeyBundle, callback, context, clientsDelegate);
- }
-
- public static MockPrefsGlobalSession getSession(
- String username, AuthHeaderProvider authHeaderProvider, String prefsPath,
- KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
- ClientsDataDelegate clientsDelegate)
- throws SyncConfigurationException, IllegalArgumentException, IOException,
- NonObjectJSONException {
-
- final SharedPreferences prefs = new MockSharedPreferences();
- final SyncConfiguration config = new SyncConfiguration(username, authHeaderProvider, prefs);
- config.syncKeyBundle = syncKeyBundle;
- return new MockPrefsGlobalSession(config, callback, context, clientsDelegate);
- }
-
- @Override
- public Context getContext() {
- return null;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockRecord.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockRecord.java
deleted file mode 100644
index d3a05bcec..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockRecord.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-public class MockRecord extends Record {
-
- public MockRecord(String guid, String collection, long lastModified, boolean deleted) {
- super(guid, collection, lastModified, deleted);
- }
-
- @Override
- protected void populatePayload(ExtendedJSONObject payload) {
- }
-
- @Override
- protected void initFromPayload(ExtendedJSONObject payload) {
- }
-
- @Override
- public Record copyWithIDs(String guid, long androidID) {
- MockRecord r = new MockRecord(guid, this.collection, this.lastModified, this.deleted);
- r.androidID = androidID;
- return r;
- }
-
- @Override
- public String toJSONString() {
- return "{\"id\":\"" + guid + "\", \"payload\": \"foo\"}";
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java
deleted file mode 100644
index 02b72b676..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-
-public class MockServerSyncStage extends BaseMockServerSyncStage {
- @Override
- public void execute() {
- session.advance();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java
deleted file mode 100644
index bc49fa7fb..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import android.content.SharedPreferences;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A programmable mock content provider.
- */
-public class MockSharedPreferences implements SharedPreferences, SharedPreferences.Editor {
- private HashMap<String, Object> mValues;
- private HashMap<String, Object> mTempValues;
-
- public MockSharedPreferences() {
- mValues = new HashMap<String, Object>();
- mTempValues = new HashMap<String, Object>();
- }
-
- public Editor edit() {
- return this;
- }
-
- public boolean contains(String key) {
- return mValues.containsKey(key);
- }
-
- public Map<String, ?> getAll() {
- return new HashMap<String, Object>(mValues);
- }
-
- public boolean getBoolean(String key, boolean defValue) {
- if (mValues.containsKey(key)) {
- return ((Boolean)mValues.get(key)).booleanValue();
- }
- return defValue;
- }
-
- public float getFloat(String key, float defValue) {
- if (mValues.containsKey(key)) {
- return ((Float)mValues.get(key)).floatValue();
- }
- return defValue;
- }
-
- public int getInt(String key, int defValue) {
- if (mValues.containsKey(key)) {
- return ((Integer)mValues.get(key)).intValue();
- }
- return defValue;
- }
-
- public long getLong(String key, long defValue) {
- if (mValues.containsKey(key)) {
- return ((Long)mValues.get(key)).longValue();
- }
- return defValue;
- }
-
- public String getString(String key, String defValue) {
- if (mValues.containsKey(key))
- return (String)mValues.get(key);
- return defValue;
- }
-
- @SuppressWarnings("unchecked")
- public Set<String> getStringSet(String key, Set<String> defValues) {
- if (mValues.containsKey(key)) {
- return (Set<String>) mValues.get(key);
- }
- return defValues;
- }
-
- public void registerOnSharedPreferenceChangeListener(
- OnSharedPreferenceChangeListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public void unregisterOnSharedPreferenceChangeListener(
- OnSharedPreferenceChangeListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public Editor putBoolean(String key, boolean value) {
- mTempValues.put(key, Boolean.valueOf(value));
- return this;
- }
-
- public Editor putFloat(String key, float value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putInt(String key, int value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putLong(String key, long value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putString(String key, String value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putStringSet(String key, Set<String> values) {
- mTempValues.put(key, values);
- return this;
- }
-
- public Editor remove(String key) {
- mTempValues.remove(key);
- return this;
- }
-
- public Editor clear() {
- mTempValues.clear();
- return this;
- }
-
- @SuppressWarnings("unchecked")
- public boolean commit() {
- mValues = (HashMap<String, Object>)mTempValues.clone();
- return true;
- }
-
- public void apply() {
- commit();
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WBORepository.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WBORepository.java
deleted file mode 100644
index bd2e7f791..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WBORepository.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
-import org.mozilla.gecko.sync.repositories.RecordFilter;
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.repositories.StoreTrackingRepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import android.content.Context;
-
-public class WBORepository extends Repository {
-
- public class WBORepositoryStats {
- public long created = -1;
- public long begun = -1;
- public long fetchBegan = -1;
- public long fetchCompleted = -1;
- public long storeBegan = -1;
- public long storeCompleted = -1;
- public long finished = -1;
- }
-
- public static final String LOG_TAG = "WBORepository";
-
- // Access to stats is not guarded.
- public WBORepositoryStats stats;
-
- // Whether or not to increment the timestamp of stored records.
- public final boolean bumpTimestamps;
-
- public class WBORepositorySession extends StoreTrackingRepositorySession {
-
- protected WBORepository wboRepository;
- protected ExecutorService delegateExecutor = Executors.newSingleThreadExecutor();
- public ConcurrentHashMap<String, Record> wbos;
-
- public WBORepositorySession(WBORepository repository) {
- super(repository);
-
- wboRepository = repository;
- wbos = new ConcurrentHashMap<String, Record>();
- stats = new WBORepositoryStats();
- stats.created = now();
- }
-
- @Override
- protected synchronized void trackGUID(String guid) {
- if (wboRepository.shouldTrack()) {
- super.trackGUID(guid);
- }
- }
-
- @Override
- public void guidsSince(long timestamp,
- RepositorySessionGuidsSinceDelegate delegate) {
- throw new RuntimeException("guidsSince not implemented.");
- }
-
- @Override
- public void fetchSince(long timestamp,
- RepositorySessionFetchRecordsDelegate delegate) {
- long fetchBegan = now();
- stats.fetchBegan = fetchBegan;
- RecordFilter filter = storeTracker.getFilter();
-
- for (Entry<String, Record> entry : wbos.entrySet()) {
- Record record = entry.getValue();
- if (record.lastModified >= timestamp) {
- if (filter != null &&
- filter.excludeRecord(record)) {
- Logger.debug(LOG_TAG, "Excluding record " + record.guid);
- continue;
- }
- delegate.deferredFetchDelegate(delegateExecutor).onFetchedRecord(record);
- }
- }
- long fetchCompleted = now();
- stats.fetchCompleted = fetchCompleted;
- delegate.deferredFetchDelegate(delegateExecutor).onFetchCompleted(fetchCompleted);
- }
-
- @Override
- public void fetch(final String[] guids,
- final RepositorySessionFetchRecordsDelegate delegate) {
- long fetchBegan = now();
- stats.fetchBegan = fetchBegan;
- for (String guid : guids) {
- if (wbos.containsKey(guid)) {
- delegate.deferredFetchDelegate(delegateExecutor).onFetchedRecord(wbos.get(guid));
- }
- }
- long fetchCompleted = now();
- stats.fetchCompleted = fetchCompleted;
- delegate.deferredFetchDelegate(delegateExecutor).onFetchCompleted(fetchCompleted);
- }
-
- @Override
- public void fetchAll(final RepositorySessionFetchRecordsDelegate delegate) {
- long fetchBegan = now();
- stats.fetchBegan = fetchBegan;
- for (Entry<String, Record> entry : wbos.entrySet()) {
- Record record = entry.getValue();
- delegate.deferredFetchDelegate(delegateExecutor).onFetchedRecord(record);
- }
- long fetchCompleted = now();
- stats.fetchCompleted = fetchCompleted;
- delegate.deferredFetchDelegate(delegateExecutor).onFetchCompleted(fetchCompleted);
- }
-
- @Override
- public void store(final Record record) throws NoStoreDelegateException {
- if (delegate == null) {
- throw new NoStoreDelegateException();
- }
- final long now = now();
- if (stats.storeBegan < 0) {
- stats.storeBegan = now;
- }
- Record existing = wbos.get(record.guid);
- Logger.debug(LOG_TAG, "Existing record is " + (existing == null ? "<null>" : (existing.guid + ", " + existing)));
- if (existing != null &&
- existing.lastModified > record.lastModified) {
- Logger.debug(LOG_TAG, "Local record is newer. Not storing.");
- delegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(record.guid);
- return;
- }
- if (existing != null) {
- Logger.debug(LOG_TAG, "Replacing local record.");
- }
-
- // Store a copy of the record with an updated modified time.
- Record toStore = record.copyWithIDs(record.guid, record.androidID);
- if (bumpTimestamps) {
- toStore.lastModified = now;
- }
- wbos.put(record.guid, toStore);
-
- trackRecord(toStore);
- delegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(record.guid);
- }
-
- @Override
- public void wipe(final RepositorySessionWipeDelegate delegate) {
- if (!isActive()) {
- delegate.onWipeFailed(new InactiveSessionException(null));
- return;
- }
-
- Logger.info(LOG_TAG, "Wiping WBORepositorySession.");
- this.wbos = new ConcurrentHashMap<String, Record>();
-
- // Wipe immediately for the convenience of test code.
- wboRepository.wbos = new ConcurrentHashMap<String, Record>();
- delegate.deferredWipeDelegate(delegateExecutor).onWipeSucceeded();
- }
-
- @Override
- public void finish(RepositorySessionFinishDelegate delegate) throws InactiveSessionException {
- Logger.info(LOG_TAG, "Finishing WBORepositorySession: handing back " + this.wbos.size() + " WBOs.");
- wboRepository.wbos = this.wbos;
- stats.finished = now();
- super.finish(delegate);
- }
-
- @Override
- public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
- this.wbos = wboRepository.cloneWBOs();
- stats.begun = now();
- super.begin(delegate);
- }
-
- @Override
- public void storeDone(long end) {
- // TODO: this is not guaranteed to be called after all of the record
- // store callbacks have completed!
- if (stats.storeBegan < 0) {
- stats.storeBegan = end;
- }
- stats.storeCompleted = end;
- delegate.deferredStoreDelegate(delegateExecutor).onStoreCompleted(end);
- }
- }
-
- public ConcurrentHashMap<String, Record> wbos;
-
- public WBORepository(boolean bumpTimestamps) {
- super();
- this.bumpTimestamps = bumpTimestamps;
- this.wbos = new ConcurrentHashMap<String, Record>();
- }
-
- public WBORepository() {
- this(false);
- }
-
- public synchronized boolean shouldTrack() {
- return false;
- }
-
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- delegate.deferredCreationDelegate().onSessionCreated(new WBORepositorySession(this));
- }
-
- public ConcurrentHashMap<String, Record> cloneWBOs() {
- ConcurrentHashMap<String, Record> out = new ConcurrentHashMap<String, Record>();
- for (Entry<String, Record> entry : wbos.entrySet()) {
- out.put(entry.getKey(), entry.getValue()); // Assume that records are
- // immutable.
- }
- return out;
- }
-}
diff --git a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WaitHelper.java b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WaitHelper.java
deleted file mode 100644
index 1a84977cf..000000000
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/WaitHelper.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-import org.mozilla.gecko.background.common.log.Logger;
-
-/**
- * Implements waiting for asynchronous test events.
- *
- * Call WaitHelper.getTestWaiter() to get the unique instance.
- *
- * Call performWait(runnable) to execute runnable synchronously.
- * runnable *must* call performNotify() on all exit paths to signal to
- * the TestWaiter that the runnable has completed.
- *
- * @author rnewman
- * @author nalexander
- */
-public class WaitHelper {
-
- public static final String LOG_TAG = "WaitHelper";
-
- public static class Result {
- public Throwable error;
- public Result() {
- error = null;
- }
-
- public Result(Throwable error) {
- this.error = error;
- }
- }
-
- public static abstract class WaitHelperError extends Error {
- private static final long serialVersionUID = 7074690961681883619L;
- }
-
- /**
- * Immutable.
- *
- * @author rnewman
- */
- public static class TimeoutError extends WaitHelperError {
- private static final long serialVersionUID = 8591672555848651736L;
- public final int waitTimeInMillis;
-
- public TimeoutError(int waitTimeInMillis) {
- this.waitTimeInMillis = waitTimeInMillis;
- }
- }
-
- public static class MultipleNotificationsError extends WaitHelperError {
- private static final long serialVersionUID = -9072736521571635495L;
- }
-
- public static class InterruptedError extends WaitHelperError {
- private static final long serialVersionUID = 8383948170038639308L;
- }
-
- public static class InnerError extends WaitHelperError {
- private static final long serialVersionUID = 3008502618576773778L;
- public Throwable innerError;
-
- public InnerError(Throwable e) {
- innerError = e;
- if (e != null) {
- // Eclipse prints the stack trace of the cause.
- this.initCause(e);
- }
- }
- }
-
- public BlockingQueue<Result> queue = new ArrayBlockingQueue<Result>(1);
-
- /**
- * How long performWait should wait for, in milliseconds, with the
- * convention that a negative value means "wait forever".
- */
- public static int defaultWaitTimeoutInMillis = -1;
-
- public void performWait(Runnable action) throws WaitHelperError {
- this.performWait(defaultWaitTimeoutInMillis, action);
- }
-
- public void performWait(int waitTimeoutInMillis, Runnable action) throws WaitHelperError {
- Logger.debug(LOG_TAG, "performWait called.");
-
- Result result = null;
-
- try {
- if (action != null) {
- try {
- action.run();
- Logger.debug(LOG_TAG, "Action done.");
- } catch (Exception ex) {
- Logger.debug(LOG_TAG, "Performing action threw: " + ex.getMessage());
- throw new InnerError(ex);
- }
- }
-
- if (waitTimeoutInMillis < 0) {
- result = queue.take();
- } else {
- result = queue.poll(waitTimeoutInMillis, TimeUnit.MILLISECONDS);
- }
- Logger.debug(LOG_TAG, "Got result from queue: " + result);
- } catch (InterruptedException e) {
- // We were interrupted.
- Logger.debug(LOG_TAG, "performNotify interrupted with InterruptedException " + e);
- final InterruptedError interruptedError = new InterruptedError();
- interruptedError.initCause(e);
- throw interruptedError;
- }
-
- if (result == null) {
- // We timed out.
- throw new TimeoutError(waitTimeoutInMillis);
- } else if (result.error != null) {
- Logger.debug(LOG_TAG, "Notified with error: " + result.error.getMessage());
-
- // Rethrow any assertion with which we were notified.
- InnerError innerError = new InnerError(result.error);
- throw innerError;
- }
- // Success!
- }
-
- public void performNotify(final Throwable e) {
- if (e != null) {
- Logger.debug(LOG_TAG, "performNotify called with Throwable: " + e.getMessage());
- } else {
- Logger.debug(LOG_TAG, "performNotify called.");
- }
-
- if (!queue.offer(new Result(e))) {
- // This could happen if performNotify is called multiple times (which is an error).
- throw new MultipleNotificationsError();
- }
- }
-
- public void performNotify() {
- this.performNotify(null);
- }
-
- public static Runnable onThreadRunnable(final Runnable r) {
- return new Runnable() {
- @Override
- public void run() {
- new Thread(r).start();
- }
- };
- }
-
- private static WaitHelper singleWaiter = new WaitHelper();
- public static WaitHelper getTestWaiter() {
- return singleWaiter;
- }
-
- public static void resetTestWaiter() {
- singleWaiter = new WaitHelper();
- }
-
- public boolean isIdle() {
- return queue.isEmpty();
- }
-}
diff --git a/mobile/android/tests/background/junit4/resources/dlc_sync_deleted_item.json b/mobile/android/tests/background/junit4/resources/dlc_sync_deleted_item.json
deleted file mode 100644
index 50b04f0e2..000000000
--- a/mobile/android/tests/background/junit4/resources/dlc_sync_deleted_item.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "data":[
- {
- "id":"c906275c-3747-fe27-426f-6187526a6f06",
- "deleted": true
- }
- ]
-}
diff --git a/mobile/android/tests/background/junit4/resources/dlc_sync_old_format.json b/mobile/android/tests/background/junit4/resources/dlc_sync_old_format.json
deleted file mode 100644
index 378bc64c6..000000000
--- a/mobile/android/tests/background/junit4/resources/dlc_sync_old_format.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "data":[
- {
- "kind":"font",
- "original": {
- "mimetype":"application/x-font-ttf",
- "filename":"CharisSILCompact-R.ttf",
- "hash":"4ed509317f1bb441b185ea13bf1c9d19d1a0b396962efa3b5dc3190ad88f2067",
- "size":1727656
- },
- "last_modified":1455710632607,
- "attachment": {
- "mimetype":"application/x-gzip",
- "size":548720,
- "hash":"960be4fc5a92c1dc488582b215d5d75429fd4ffbee463105d29992cd792a912e",
- "location":"/attachments/0d28a72d-a51f-46f8-9e5a-f95c61de904e.gz",
- "filename":"CharisSILCompact-R.ttf.gz"
- },
- "type":"asset-archive",
- "id":"c906275c-3747-fe27-426f-6187526a6f06"
- }
- ]
-}
diff --git a/mobile/android/tests/background/junit4/resources/dlc_sync_single_font.json b/mobile/android/tests/background/junit4/resources/dlc_sync_single_font.json
deleted file mode 100644
index 0de84b85d..000000000
--- a/mobile/android/tests/background/junit4/resources/dlc_sync_single_font.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "data":[
- {
- "kind":"font",
- "last_modified":1455710632607,
- "attachment": {
- "mimetype":"application/x-gzip",
- "size":548720,
- "hash":"960be4fc5a92c1dc488582b215d5d75429fd4ffbee463105d29992cd792a912e",
- "location":"/attachments/0d28a72d-a51f-46f8-9e5a-f95c61de904e.gz",
- "filename":"CharisSILCompact-R.ttf.gz",
- "original": {
- "mimetype":"application/x-font-ttf",
- "filename":"CharisSILCompact-R.ttf",
- "hash":"4ed509317f1bb441b185ea13bf1c9d19d1a0b396962efa3b5dc3190ad88f2067",
- "size":1727656
- }
- },
- "type":"asset-archive",
- "id":"c906275c-3747-fe27-426f-6187526a6f06"
- }
- ]
-}
diff --git a/mobile/android/tests/background/junit4/resources/experiments.json b/mobile/android/tests/background/junit4/resources/experiments.json
deleted file mode 100644
index 870a57778..000000000
--- a/mobile/android/tests/background/junit4/resources/experiments.json
+++ /dev/null
@@ -1,99 +0,0 @@
-
-{
- "data": [
- {
- "name": "active-experiment",
- "match": {
- },
- "buckets": {
- "min": "0",
- "max": "100"
- },
- "values": {
- "foo": true
- }
- },
-
- {
- "name": "inactive-experiment",
- "match": {
- "appId": "^NOPE$"
- },
- "buckets": {
- "min": "0",
- "max": "0"
- }
- },
- {
- "name": "bookmark-history-menu",
- "match": {
- },
- "buckets": {
- "min": "0",
- "max": "100"
- }
- },
- {
- "name": "is-matching",
- "match": {
- "appId": "^org.mozilla.gecko$"
- },
- "buckets": {
- "min": "0",
- "max": "100"
- }
- },
- {
- "name": "is-not-matching",
- "match": {
- "appId": "^org.mozilla.fennec|^org.mozilla.firefox_beta$"
- },
- "buckets": {
- "min": "0",
- "max": "100"
- }
- },
- {
- "name": "promote-add-to-homescreen",
- "buckets": {
- "max": "100",
- "min": "50"
- },
- "last_modified": 1467705654772,
- "values": {
- "lastVisitMaximumAgeMs": 600000,
- "minimumTotalVisits": 5,
- "lastVisitMinimumAgeMs": 30000
- },
- "id": "20d278d7-0d35-4811-8f01-bf24e31ba51b",
- "match": {
- "appId": "^org.mozilla.fennec|^org.mozilla.firefox_beta$"
- },
- "schema": 1467705310595
- },
- {
- "name": "offline-cache",
- "buckets": {
- "max": "100",
- "min": "0"
- },
- "last_modified": 1467705429859,
- "id": "9f1ea043-c1d8-48ba-802d-aeabaf667afe",
- "match": {
- "appId": "^org.mozilla.fennec|^org.mozilla.firefox_beta$"
- },
- "schema": 1467705310595
- },
- {
- "name": "bookmark-history-menu",
- "buckets": {
- "max": "100",
- "min": "0"
- },
- "last_modified": 1467705381971,
- "id": "29988035-1a59-4671-b679-2c717a68bd12",
- "match": {},
- "schema": 1467705310595
- }
- ]
-}
diff --git a/mobile/android/tests/background/junit4/resources/feed_atom_blogger.xml b/mobile/android/tests/background/junit4/resources/feed_atom_blogger.xml
deleted file mode 100644
index 994876d76..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_atom_blogger.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-18929277</id><updated>2016-02-18T09:07:17.583-08:00</updated><category term="jetpack"/><title type='text'>mykzilla</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default?start-index=26&amp;max-results=25'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>114</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-18929277.post-3538029308224239292</id><published>2016-01-11T08:57:00.001-08:00</published><updated>2016-01-11T08:57:31.366-08:00</updated><title type='text'>URL Has Been Changed</title><content type='html'>&lt;dl&gt;&lt;dd&gt;The URL you have reached, &lt;a href=&quot;http://mykzilla.blogspot.com/&quot;&gt;http://mykzilla.blogspot.com/&lt;/a&gt;, has been changed. The new URL is &lt;a href=&quot;https://mykzilla.org/&quot;&gt;https://mykzilla.org/&lt;/a&gt;. Please make a note of it.&lt;/dd&gt;&lt;/dl&gt;</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/3538029308224239292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=3538029308224239292' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/3538029308224239292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/3538029308224239292'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2016/01/url-has-been-changed.html' title='URL Has Been Changed'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/08518329693863067865</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-7658939959003799797</id><published>2015-06-23T16:05:00.000-07:00</published><updated>2015-06-23T16:07:06.667-07:00</updated><title type='text'>Introducing PluotSorbet</title><content type='html'>&lt;a href=&quot;https://github.com/mozilla/pluotsorbet&quot;&gt;PluotSorbet&lt;/a&gt; is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Java_Platform,_Micro_Edition&quot;&gt;J2ME&lt;/a&gt;-compatible virtual machine written in JavaScript. Its goal is to enable users you run J2ME apps (i.e. &lt;a href=&quot;https://en.wikipedia.org/wiki/MIDlet&quot;&gt;MIDlets&lt;/a&gt;) in web apps without a native plugin. It does this by interpreting Java bytecode and compiling it to JavaScript code. It also provides a virtual filesystem (via &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API&quot;&gt;IndexedDB&lt;/a&gt;), network sockets (through the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/TCPSocket&quot;&gt;TCPSocket API&lt;/a&gt;), and other common J2ME APIs, like &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Contacts_API&quot;&gt;Contacts&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The project reuses as much existing code as possible, to minimize its surface area and maximize its compatibility with other J2ME implementations. It incorporates the &lt;a href=&quot;https://java.net/projects/phoneme&quot;&gt;PhoneME&lt;/a&gt; reference implementation, numerous tests from &lt;a href=&quot;https://www.sourceware.org/mauve/&quot;&gt;Mauve&lt;/a&gt;, and a variety of JavaScript libraries (including &lt;a href=&quot;http://www-cs-students.stanford.edu/%7Etjw/jsbn/&quot;&gt;jsbn&lt;/a&gt;, &lt;a href=&quot;https://github.com/digitalbazaar/forge&quot;&gt;Forge&lt;/a&gt;, and &lt;a href=&quot;https://github.com/eligrey/FileSaver.js&quot;&gt;FileSaver.js&lt;/a&gt;). The virtual machine is originally based on &lt;a href=&quot;https://github.com/YaroslavGaponov/node-jvm&quot;&gt;node-jvm&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;PluotSorbet makes it possible to bring J2ME apps to Firefox OS. J2ME may be a moribund platform, but it still has &lt;a href=&quot;http://netmarketshare.com/operating-system-market-share.aspx?qprid=9&amp;amp;qpcustom=Java+ME&amp;amp;qpcustomb=1&quot;&gt;non-negligible market share&lt;/a&gt;, not to mention a number of useful apps. So it retains residual value, which PluotSorbet can extend to Firefox OS devices.&lt;br /&gt;&lt;br /&gt;PluotSorbet is also still under development, with a variety of issues to address. To learn more about PluotSorbet, check out its &lt;a href=&quot;https://github.com/mozilla/pluotsorbet/blob/master/README.md&quot;&gt;README&lt;/a&gt;, clone its &lt;a href=&quot;https://github.com/mozilla/pluotsorbet&quot;&gt;Git repository&lt;/a&gt;, peruse its &lt;a href=&quot;https://github.com/mozilla/pluotsorbet/issues&quot;&gt;issue tracker&lt;/a&gt;, and say hello to its developers in &lt;a href=&quot;irc://irc.mozilla.org/pluotsorbet&quot;&gt;irc.mozilla.org#pluotsorbet&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/7658939959003799797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=7658939959003799797' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7658939959003799797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7658939959003799797'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2015/06/introducing-pluotsorbet.html' title='Introducing PluotSorbet'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/08518329693863067865</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-2146007198307190404</id><published>2014-03-28T16:58:00.002-07:00</published><updated>2014-03-28T16:58:42.947-07:00</updated><title type='text'>simplify asynchronous method declarations with Task.async()</title><content type='html'>In Mozilla code, &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;Task.spawn()&lt;/span&gt; is becoming a common way to implement asynchronous operations, especially methods like the &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;greet&lt;/span&gt; method in this &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;greeter&lt;/span&gt; object:&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;background: #202020; border-width: .1em .1em .1em .8em; border: solid gray; overflow: auto; padding: .2em .6em; width: auto;&quot;&gt;&lt;pre style=&quot;line-height: 125%; margin: 0;&quot;&gt;&lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;greeter&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;message:&lt;/span&gt; &lt;span style=&quot;color: #ed9d13;&quot;&gt;&quot;Hello, NAME!&quot;&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;greet:&lt;/span&gt; &lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;(name)&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;Task.spawn((&lt;/span&gt;&lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;*()&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;yield&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;sendGreeting(&lt;/span&gt;&lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;.message.replace(&lt;/span&gt;&lt;span style=&quot;color: #ed9d13;&quot;&gt;/NAME/&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;name));&lt;/span&gt;&lt;br /&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;}).bind(&lt;/span&gt;&lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;);&lt;/span&gt;&lt;br /&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;})&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;Task.spawn()&lt;/span&gt; makes the operation logic simple, but the wrapper function and &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;bind()&lt;/span&gt; call required to start the task on method invocation and bind its &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;this&lt;/span&gt; reference make the overall implementation complex.&lt;br /&gt;&lt;br /&gt;Enter &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;Task.async()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Like &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;Task.spawn()&lt;/span&gt;, it creates a task, but it doesn&#39;t immediately start it. Instead, it returns an &quot;async function&quot; whose invocation starts the task, and the async function binds the task to its own &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;this&lt;/span&gt; reference at invocation time. That makes it simpler to declare the method:&lt;br /&gt;&lt;br /&gt;&lt;!-- HTML generated using hilite.me --&gt; &lt;div style=&quot;background: #202020; border-width: .1em .1em .1em .8em; border: solid gray; overflow: auto; padding: .2em .6em; width: auto;&quot;&gt;&lt;pre style=&quot;line-height: 125%; margin: 0;&quot;&gt;&lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;greeter&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;message:&lt;/span&gt; &lt;span style=&quot;color: #ed9d13;&quot;&gt;&quot;Hello, NAME!&quot;&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;greet:&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;Task.async(&lt;/span&gt;&lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;*(name)&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;yield&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;sendGreeting(&lt;/span&gt;&lt;span style=&quot;color: #6ab825; font-weight: bold;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;.message.replace(&lt;/span&gt;&lt;span style=&quot;color: #ed9d13;&quot;&gt;/NAME/&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;name));&lt;/span&gt;&lt;br /&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;})&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;With identical semantics:&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;background: #202020; border-width: .1em .1em .1em .8em; border: solid gray; overflow: auto; padding: .2em .6em; width: auto;&quot;&gt;&lt;pre style=&quot;line-height: 125%; margin: 0;&quot;&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;greeter.greet(&lt;/span&gt;&lt;span style=&quot;color: #ed9d13;&quot;&gt;&quot;Mitchell&quot;&lt;/span&gt;&lt;span style=&quot;color: #d0d0d0;&quot;&gt;).then((reply)&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;{&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;...&lt;/span&gt; &lt;span style=&quot;color: #d0d0d0;&quot;&gt;});&lt;/span&gt; &lt;span style=&quot;color: #999999; font-style: italic;&quot;&gt;// behaves the same&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;(And it avoids a couple anti-patterns in the process.)&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;&quot;&gt;Task.async()&lt;/span&gt; is inspired by ECMAScript&#39;s &lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=strawman:async_functions&quot;&gt;Async Functions strawman proposal&lt;/a&gt; and &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/hh191443.aspx&quot;&gt;C#&#39;s Async modifier&lt;/a&gt; and was implemented in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=966182&quot;&gt;bug 966182&lt;/a&gt;. It isn&#39;t limited to use in method declarations, although it&#39;s particularly helpful for them.&lt;br /&gt;&lt;br /&gt;Use it to implement your next asynchronous operation!&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/2146007198307190404/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=2146007198307190404' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/2146007198307190404'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/2146007198307190404'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2014/03/simplify-asynchronous-method.html' title='simplify asynchronous method declarations with Task.async()'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/08518329693863067865</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-7603765594353319606</id><published>2014-03-27T13:14:00.000-07:00</published><updated>2014-03-27T13:14:20.326-07:00</updated><title type='text'>qualifications for leadership</title><content type='html'>I&#39;ve been surprised by the negative reaction to Brendan&#39;s promotion by some of my fellow supporters of marriage equality. Perhaps I take it too much for granted that Mozillians recognize the diversity of their community in every possible respect, including politically and religiously, and that the &lt;span style=&quot;font-style: italic;&quot;&gt;only&lt;/span&gt; thing we share in common is our commitment to Mozilla&#39;s mission and the principles for participation.&lt;br /&gt;&lt;br /&gt;Those principles are reflected in our &lt;a href=&quot;http://www.mozilla.org/en-US/about/governance/policies/participation/&quot;&gt;Community Participation Agreement&lt;/a&gt;, to which Brendan has always shown fealty (since long before it was formalized, in my 15-year experience with him), and which could not possibly be clearer about the welcoming nature of Mozilla to all constructive contributors.&lt;br /&gt; &lt;br /&gt;I know that marriage equality has been a long, difficult, and painful battle, the kind that rubs nerves raw and makes it challenging to show any charity to its opponents. But they aren&#39;t all bigots, and I take Brendan at his &lt;a href=&quot;https://brendaneich.com/2014/03/inclusiveness-at-mozilla/&quot;&gt;word and deed&lt;/a&gt; that he&#39;s as committed as I am to the community&#39;s inclusive ideals (and the organization&#39;s employment policies).&lt;br /&gt; &lt;br /&gt;As Andrew Sullivan eloquently states in his recent blog post on &lt;a href=&quot;http://dish.andrewsullivan.com/2014/03/24/religious-belief-and-bigotry/&quot;&gt;Religious Belief and Bigotry&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;margin-left: 40px;&quot;&gt;&quot;Twenty years ago, I was confidently told by my leftist gay friends that Americans were all anti-gay bigots and would never, ever back marriage rights so I should stop trying to reason them out of their opposition. My friends were wrong. Americans are not all bigots. Not even close. They can be persuaded rather than attacked. And if we behave magnanimously and give maximal space for those who sincerely oppose us, then eventual persuasion will be more likely. And our victory more moral and more enduring.&quot; &lt;/div&gt;&lt;br /&gt;I&#39;m chastened to admit that I substantially shared his friends&#39; opinion twenty years ago. But I&#39;m happy to realize I was wrong. And perhaps Brendan will one day do the same. Either way, he qualifies to be a leader at any level in the Mozilla community (and organization), as do the many other Mozilla leaders whose beliefs undoubtedly differ sharply from my own.&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/7603765594353319606/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=7603765594353319606' title='21 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7603765594353319606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7603765594353319606'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2014/03/qualifications-for-leadership.html' title='qualifications for leadership'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/08518329693863067865</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>21</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-4907835732389141704</id><published>2013-10-15T17:05:00.003-07:00</published><updated>2013-10-15T17:05:53.226-07:00</updated><title type='text'>from Webapp SDK to r2d2b2g, Firefox OS Simulator, and the App Manager</title><content type='html'>A little over a year ago, on August 31, 2012, I brainstormed the outline of a &quot;Webapp SDK&quot;:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-qFEN48-NFBI/Ul2-QToFUkI/AAAAAAAAAEY/Pah7FtanWfo/s1600/2012-08-31+10.57.00.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;300&quot; src=&quot;http://2.bp.blogspot.com/-qFEN48-NFBI/Ul2-QToFUkI/AAAAAAAAAEY/Pah7FtanWfo/s400/2012-08-31+10.57.00.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;That outline was the genesis for the &lt;a href=&quot;https://hacks.mozilla.org/2012/10/r2d2b2g-an-experimental-prototype-firefox-os-test-environment/&quot;&gt;r2d2b2g experiment&lt;/a&gt;, which built the &lt;a href=&quot;http://www.blueskyonmars.com/2012/11/08/r2d2b2g-is-becoming-the-firefox-os-simulator/&quot;&gt;Firefox OS Simulator&lt;/a&gt;, whose initial version hit the web on September 14, 2012 and which has gone through numerous iterations since then as we evaluated various features to enhance app development.&lt;br /&gt;&lt;br /&gt;And that experiment spurred Mozilla&#39;s &lt;a href=&quot;https://wiki.mozilla.org/DevTools&quot;&gt;Developer Tools group&lt;/a&gt;, particularly its nascent &lt;a href=&quot;https://wiki.mozilla.org/DevTools/AppTools&quot;&gt;App Tools team&lt;/a&gt;, to build Firefox&#39;s new App Manager, which landed last month and was &lt;a href=&quot;https://hacks.mozilla.org/2013/10/introducing-the-firefox-os-app-manager/&quot;&gt;introduced today on Hacks&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;Despite the twisty passage from experiment to product, that initial outline bears a surprising resemblance to the App Manager feature set. The Manager checks off three of the four features on the outline&#39;s primary list—&quot;start Gaia in B2G,&quot; &quot;package app,&quot; and &quot;test app in Gaia/B2G&quot;—plus a few on its secondary list, like &quot;debug from Firefox&quot; and &quot;test on mobile device,&quot; with &quot;edit manifest in GUI&quot; well underway over in &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=912912&quot;&gt;bug 912912&lt;/a&gt;. And the Simulator continues to provide B2G/Gaia via an easy-to-install addon that integrates with the Manager.&lt;br /&gt;&lt;br /&gt;Like any good product of a successful experiment, however, the Manager&#39;s reach has exceeded its progenitor&#39;s grasp! So it also gives you access to pre-installed apps, lets you take screenshots of device/Simulator screens, and will doubtless continue to sprout handy features to make app development great.&lt;br /&gt;&lt;br /&gt;So kudos to the folks who built it, and long live the App Manager!&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/4907835732389141704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=4907835732389141704' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/4907835732389141704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/4907835732389141704'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2013/10/from-webapp-sdk-to-r2d2b2g-firefox-os.html' title='from Webapp SDK to r2d2b2g, Firefox OS Simulator, and the App Manager'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-qFEN48-NFBI/Ul2-QToFUkI/AAAAAAAAAEY/Pah7FtanWfo/s72-c/2012-08-31+10.57.00.jpg" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-4775473125409851813</id><published>2013-08-23T10:55:00.001-07:00</published><updated>2013-08-23T10:55:06.641-07:00</updated><title type='text'>fixing this morning&#39;s mach OS X psutil bustage</title><content type='html'>If mach is broken in your mozilla-central clone on Mac OS X this morning:&lt;br&gt; &lt;blockquote&gt;&lt;tt&gt;08-23 10:20 &amp;gt; ./mach build&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;Error running mach:&lt;/tt&gt;&lt;br&gt; &lt;br&gt; &lt;tt&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&#39;build&#39;]&lt;/tt&gt;&lt;br&gt; &lt;br&gt; &lt;tt&gt;The error occurred in code that was called by the mach command. This is either&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;a bug in the called code itself or in the way that mach is calling it.&lt;/tt&gt;&lt;br&gt; &lt;br&gt; &lt;tt&gt;You should consider filing a bug for this issue.&lt;/tt&gt;&lt;br&gt; &lt;br&gt; &lt;tt&gt;If filing a bug, please include the full output of mach, including this error&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;message.&lt;/tt&gt;&lt;br&gt; &lt;br&gt; &lt;tt&gt;The details of the failure are as follows:&lt;/tt&gt;&lt;br&gt; &lt;br&gt; &lt;tt&gt;AttributeError: &#39;module&#39; object has no attribute &#39;TCPS_ESTABLISHED&#39;&lt;/tt&gt;&lt;br&gt; &lt;br&gt; &lt;tt&gt;&amp;nbsp; File &quot;/Users/myk/Mozilla/central/python/mozbuild/mozbuild/mach_commands.py&quot;, line 293, in build&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; from mozbuild.controller.building import BuildMonitor&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;&amp;nbsp; File &quot;/Users/myk/Mozilla/central/python/mozbuild/mozbuild/controller/building.py&quot;, line 22, in &amp;lt;module&amp;gt;&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; import psutil&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;&amp;nbsp; File &quot;/Users/myk/Mozilla/central/python/psutil/psutil/__init__.py&quot;, line 95, in &amp;lt;module&amp;gt;&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; import psutil._psosx as _psplatform&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;&amp;nbsp; File &quot;/Users/myk/Mozilla/central/python/psutil/psutil/_psosx.py&quot;, line 48, in &amp;lt;module&amp;gt;&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _TCP_STATES_TABLE = {_psutil_osx.TCPS_ESTABLISHED : CONN_ESTABLISHED,&lt;/tt&gt;&lt;br&gt; &lt;/blockquote&gt; &lt;br&gt; Then you&#39;ve been bit by the fix for &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=908296&quot;&gt;bug 908296&lt;/a&gt;. To resolve the bustage, run this command in your Hg clone:&lt;br&gt; &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt; &lt;blockquote&gt;hg status -in python/psutil | xargs rm&lt;br&gt; &lt;/blockquote&gt; &lt;br&gt; Or, if you&#39;ve cloned the &lt;a href=&quot;https://github.com/mozilla/mozilla-central&quot;&gt;Git mirror&lt;/a&gt;, run this instead:&lt;br&gt; &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt; &lt;blockquote&gt;git clean -xf python/psutil&lt;br&gt; &lt;/blockquote&gt; &lt;br&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/4775473125409851813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=4775473125409851813' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/4775473125409851813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/4775473125409851813'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2013/08/fixing-this-mornings-mach-os-x-psutil.html' title='fixing this morning&#39;s mach OS X psutil bustage'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-7658176042227879683</id><published>2013-06-07T16:04:00.000-07:00</published><updated>2013-06-07T16:04:04.952-07:00</updated><title type='text'>64-bit Linux ADB for Simulator</title><content type='html'>Thanks to the efforts of new Mozilla intern &lt;a href=&quot;https://github.com/bkase&quot;&gt;Brandon Kase&lt;/a&gt;, the &lt;a href=&quot;https://ftp.mozilla.org/pub/mozilla.org/labs/r2d2b2g/r2d2b2g-linux.xpi&quot;&gt;latest preview build of Firefox OS Simulator for Linux&lt;/a&gt; includes a 64-bit version of ADB, so you can push an app to an FxOS device from 64-bit Linux installations without any extra packages!&lt;br /&gt; &lt;br /&gt; Building it was tricky, because the Android SDK build scripts don&#39;t support that target. Brandon first tried simply specifying the target, which worked on an older version of ADB (1.0.24). But it failed on the latest version (1.0.31), which links with a bundled copy of libcrypto that includes 32-bit assembly.&lt;br /&gt; &lt;br /&gt; Ubuntu 13.04 (Raring) ships a 64-bit &lt;a href=&quot;http://packages.ubuntu.com/raring/android-tools-adb&quot;&gt;android-tools-adb package&lt;/a&gt;, though, so we knew it could be done. And its &lt;a href=&quot;http://packages.ubuntu.com/source/raring/android-tools&quot;&gt;source package&lt;/a&gt;&#39;s build system is much simpler than the SDK&#39;s. We just needed a binary that works on distributions with older versions of glibc than Raring&#39;s 2.17. And one that doesn&#39;t depend on a specific version of libcrypto, which varies around the Linux world; whereas Raring&#39;s ADB executable appears to need the specific version that comes with that distribution.&lt;br /&gt; &lt;br /&gt; So Brandon modified the source package&#39;s Makefile to link libcrypto statically (note the absolute path to libcrypto.a, which may vary):&lt;br /&gt;&lt;blockquote class=&quot;tr_bq&quot;&gt; &lt;tt&gt;--- debian/makefiles/adb.mk&amp;nbsp;&amp;nbsp;&amp;nbsp; 2013-03-26 14:15:41.000000000 -0700&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;+++ adb-static-crypto.mk&amp;nbsp;&amp;nbsp;&amp;nbsp; 2013-06-06 16:51:52.794521267 -0700&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;@@ -40,15 +40,16 @@&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;CPPFLAGS+= -I.&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;CPPFLAGS+= -I../include&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;CPPFLAGS+= -I../../../external/zlib&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;+CPPFLAGS+= -I/usr/include/openssl&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;-LIBS+= -lc -lpthread -lz -lcrypto&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;+LIBS+= -lc -lpthread -lz -ldl&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;OBJS= $(SRCS:.c=.o)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;all: adb&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;adb: $(OBJS)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp; $(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp; $(CC) -o $@ $(LDFLAGS) $(OBJS) /usr/lib/x86_64-linux-gnu/libcrypto.a $(LIBS)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;clean:&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt; &lt;/tt&gt;&lt;tt&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rm -rf $(OBJS) adb&lt;/tt&gt;&lt;/blockquote&gt;&lt;br /&gt; Then I copied the source package to my CentOS 16 build machine (which has glibc 2.12) and built it there. After which the resultant executable worked on all the distributions we tested: Ubuntu 13.04, Ubuntu 10.04, CentOS 16, and Arch Linux (kernel 3.9.3-1-ARCH).&lt;br /&gt; &lt;br /&gt; Presumably it will work on others too. But if it still doesn&#39;t work for you, &lt;a href=&quot;https://github.com/mozilla/r2d2b2g/issues&quot;&gt;let us know&lt;/a&gt;!&lt;br /&gt; &lt;br /&gt; And if you just want the ADB executable, sans Simulator, &lt;a href=&quot;https://ftp.mozilla.org/pub/mozilla.org/labs/r2d2b2g/adb-1.0.31-linux64.zip&quot;&gt;here it is&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/7658176042227879683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=7658176042227879683' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7658176042227879683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7658176042227879683'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2013/06/64-bit-linux-adb-for-simulator.html' title='64-bit Linux ADB for Simulator'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-2950140535922521480</id><published>2012-10-02T12:08:00.001-07:00</published><updated>2012-10-02T12:13:24.657-07:00</updated><title type='text'>r2d2b2g implementation details</title><content type='html'>Over at Mozilla Hacks, I just &lt;a href=&quot;https://hacks.mozilla.org/2012/10/r2d2b2g-an-experimental-prototype-firefox-os-test-environment/&quot;&gt;blogged about r2d2b2g&lt;/a&gt; (ratta-datta-batta-ga), an experimental prototype test environment for Firefox OS that makes it drop-dead simple to test your app in &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Boot_to_Gecko/Using_the_B2G_desktop_client&quot;&gt;B2G Desktop&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;r2d2b2g is an addon, but it bundles &lt;a href=&quot;https://ftp.mozilla.org/pub/mozilla.org/b2g/nightly/latest-mozilla-central/&quot;&gt;B2G Desktop nightly builds&lt;/a&gt;, which are native executables, and thus the addon is platform-specific, with packages available for &lt;a href=&quot;https://ftp.mozilla.org/pub/mozilla.org/labs/r2d2b2g/r2d2b2g-mac.xpi&quot;&gt;Mac&lt;/a&gt;, &lt;a href=&quot;https://ftp.mozilla.org/pub/mozilla.org/labs/r2d2b2g/r2d2b2g-linux.xpi&quot;&gt;Linux 32-bit&lt;/a&gt;, and &lt;a href=&quot;https://ftp.mozilla.org/pub/mozilla.org/labs/r2d2b2g/r2d2b2g-windows.xpi&quot;&gt;Windows&lt;/a&gt; (caveat: B2G Desktop for Windows currently crashes on startup due to bug &lt;strike&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=794662&quot;&gt;794662&lt;/a&gt;&lt;/strike&gt; &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=795484&quot;&gt;795484&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;The packages are large, 50-60MB each, partly because of the executables, but mostly because they also bundle &lt;a href=&quot;https://wiki.mozilla.org/Gaia&quot;&gt;Gaia&lt;/a&gt; profiles, including all default apps. (It&#39;s probably worth bundling a few of these, for demonstration purposes, but we could make the packages much smaller by removing the rest.)&lt;br /&gt;&lt;br /&gt;r2d2b2g uses the &lt;a href=&quot;https://addons.mozilla.org/en-US/developers/builder&quot;&gt;Add-on SDK&lt;/a&gt; as its addon framework and relies on several third-party addon modules (&lt;a href=&quot;https://github.com/ochameau/jetpack-subprocess&quot;&gt;subprocess&lt;/a&gt;, &lt;a href=&quot;https://github.com/voldsoftware/menuitems-jplib&quot;&gt;menuitems&lt;/a&gt;) along with some Python utilities (&lt;a href=&quot;https://github.com/mozilla/mozdownload&quot;&gt;mozdownload&lt;/a&gt;, &lt;a href=&quot;https://github.com/mozilla/mozbase&quot;&gt;mozbase&lt;/a&gt;) to download and unpack B2G Desktop builds. Plus Gaia, although recent work to bundle Gaia profiles with B2G Desktop builds may break that dependency.&lt;br /&gt;&lt;br /&gt;I&#39;ve demoed the project to a variety of folks over the last couple weeks, and I&#39;ve received a bunch of positive feedback about it. B2G Desktop combines approachability with phoneliness and is the best existing test environment for Firefox OS. But its configuration is a challenge, and it provides no obvious affordances for installing and testing your own app. r2d2b2g shows that these problems are tractable (even if it doesn&#39;t yet solve them all) and demonstrates a promising product path.&lt;br /&gt;&lt;br /&gt;After seeing r2d2b2g, Kevin Dangoor drafted a &lt;a href=&quot;https://docs.google.com/document/d/1OptOCWO4b_b1aa4Gtwr82_q-mW5ybteoWNpPAJUIFNk/edit&quot;&gt;PRD for a Firefox OS Simulator&lt;/a&gt; that I&#39;ll use to guide further development. Interested in participating? Clone the code from its &lt;a href=&quot;https://github.com/mozilla/r2d2b2g&quot;&gt;GitHub repository&lt;/a&gt; and contribute your improvements!&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/2950140535922521480/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=2950140535922521480' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/2950140535922521480'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/2950140535922521480'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2012/10/r2d2b2g-implementation-details.html' title='r2d2b2g implementation details'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-704490864096897779</id><published>2012-03-07T18:04:00.001-08:00</published><updated>2012-03-07T18:04:16.546-08:00</updated><title type='text'>Next/Previous Tab on Mac Consistent At Last</title><content type='html'>After blogging about the &lt;a href=&quot;http://mykzilla.blogspot.com/2011/09/nextprevious-tab-keyboard-shortcuts-on.html&quot;&gt;inconsistency of keyboard shortcuts for Next/Previous Tab on Mac&lt;/a&gt; last year, I found out that Firefox, Thunderbird, and Komodo also support Command + Option + LeftArrow|RightArrow, and Adium has a General &amp;gt; &quot;Switch tabs with&quot; pref that I can set to the same chord.&lt;br&gt; &lt;br&gt; (Later, I switched IM clients from Adium to InstantBird, which also supports that combination.)&lt;br&gt; &lt;br&gt; That left Terminal, which I couldn&#39;t figure out how to configure to support the same shortcut. Until now.&lt;br&gt; &lt;br&gt; I&#39;m not sure if it&#39;s because I have since upgraded to Mac OS X 10.7 (Lion). I could&#39;ve sworn I tried something like this back when I wrote that previous blog post, and it didn&#39;t work.&lt;br&gt; &lt;ol&gt; &lt;li&gt;Go to System Preferences &amp;gt; Keyboard &amp;gt; Keyboard Shortcuts &amp;gt; Application Shortcuts.&lt;/li&gt; &lt;li&gt;Press the + (plus) button.&lt;/li&gt; &lt;li&gt;Select &quot;Other...&quot; from the Application menu and select Utilities &amp;gt; Terminal from the file picker dialog.&lt;/li&gt; &lt;li&gt;Enter &quot;Select Next Tab&quot; (without the quotes) into the Menu Title field.&lt;/li&gt; &lt;li&gt;Focus the Keyboard Shortcut field and press Command + Option + RightArrow to set the keyboard shortcut, which will appear as &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt; &amp;#8997;&amp;#8984;&amp;#8594;.&lt;/li&gt; &lt;li&gt;Press the Add button.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;Repeat steps 4-6 with &quot;Select Previous Tab&quot; and Command + Option + LeftArrow, which will appear as &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt; &amp;#8997;&amp;#8984;&amp;#8592;.&lt;br&gt; &lt;/p&gt; &lt;p&gt;Those shortcuts should now work in Terminal.&lt;br&gt; &lt;/p&gt; &lt;p&gt;With this change, all five of my current primary productivity applications on Mac (Firefox, Thunderbird, Instantbird, Komodo, and Terminal) support a consistent pair of keyboard shortcuts for Next/Previous Tab, which are two of the most common commands I issue in all of those apps.&lt;br&gt; &lt;/p&gt; &lt;p&gt;Woot!&lt;br&gt; &lt;br&gt; &lt;/p&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/704490864096897779/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=704490864096897779' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/704490864096897779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/704490864096897779'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2012/03/nextprevious-tab-on-mac-consistent-at.html' title='Next/Previous Tab on Mac Consistent At Last'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-4717272844287397408</id><published>2012-03-07T13:46:00.001-08:00</published><updated>2012-03-07T13:46:45.454-08:00</updated><title type='text'>generating a fingerprint for an SSH key</title><content type='html'>After recently &lt;a href=&quot;https://github.com/blog/1068-public-key-security-vulnerability-and-mitigation&quot;&gt;discovering a security vulnerability&lt;/a&gt; that allows an attacker to add an SSH key to a GitHub user account, GitHub is requiring all users to audit their SSH keys. Its &lt;a href=&quot;https://github.com/settings/ssh/audit&quot;&gt;audit page&lt;/a&gt; lists one&#39;s keys by type and fingerprint, but it doesn&#39;t say how it generated the fingerprint or how to generate one for your local copy of a key to compare it with. Nor does it let you see the whole key.&lt;br&gt; &lt;br&gt; And since I don&#39;t generate such fingerprints very often, I didn&#39;t know how to do it. So I tried &lt;tt&gt;cksum&lt;/tt&gt;, &lt;tt&gt;md5&lt;/tt&gt;, and &lt;tt&gt;shasum&lt;/tt&gt; on my Mac, but none of their checksums matched. Turns out the tool to use is &lt;tt&gt;ssh-keygen&lt;/tt&gt;:&lt;br&gt; &lt;br&gt; &lt;tt&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; ssh-keygen -l -f path/to/keyfile&lt;/tt&gt;&lt;br&gt; &lt;br&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/4717272844287397408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=4717272844287397408' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/4717272844287397408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/4717272844287397408'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2012/03/generating-fingerprint-for-ssh-key.html' title='generating a fingerprint for an SSH key'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-3538011216013400890</id><published>2011-10-17T10:38:00.001-07:00</published><updated>2011-10-17T10:38:52.345-07:00</updated><title type='text'>Mozilla Status Board Text is Markdown</title><content type='html'>It isn&#39;t documented anywhere that I can find, but Benjamin Smedberg&#39;s handy &lt;a href=&quot;http://benjamin.smedbergs.us/weekly-updates.fcgi/&quot;&gt;Mozilla Status Board&lt;/a&gt; tool parses status text as &lt;a href=&quot;http://daringfireball.net/projects/markdown/&quot;&gt;Markdown&lt;/a&gt;, which is how I added a &lt;b&gt;Didn&#39;t&lt;/b&gt; header to the &lt;b&gt;Done&lt;/b&gt; section of my &lt;a href=&quot;http://benjamin.smedbergs.us/weekly-updates.fcgi/user/mykmelez&quot;&gt;status update&lt;/a&gt; with all the things I planned to do last week but didn&#39;t make happen. (The &lt;b&gt;Done&lt;/b&gt;, &lt;b&gt;Next&lt;/b&gt;, and &lt;b&gt;Coordination&lt;/b&gt; headers are all &lt;b&gt;H4&lt;/b&gt;s, so I prepended four hash marks to &lt;tt&gt;#### &lt;b&gt;Didn&#39;t&lt;/b&gt;&lt;/tt&gt; to make it the same size).&lt;br&gt; &lt;br&gt; (Note that &lt;tt&gt;[&lt;a href=&quot;http://daringfireball.net/projects/markdown/basics&quot;&gt;Markdown-style links&lt;/a&gt;](&lt;a class=&quot;moz-txt-link-freetext&quot; href=&quot;http://daringfireball.net/projects/markdown/basics&quot;&gt;http://daringfireball.net/projects/markdown/basics&lt;/a&gt;)&lt;/tt&gt; don&#39;t work and cause the entire section in which they appear to remain unparsed. However angle-bracketed URLs, as recommended by &lt;tt&gt;&lt;a href=&quot;http://labs.apache.org/webarch/uri/rfc/rfc3986.html#delimiting&quot;&gt;RFC 3986&lt;/a&gt; &lt;a class=&quot;moz-txt-link-rfc2396E&quot; href=&quot;http://labs.apache.org/webarch/uri/rfc/rfc3986.html#delimiting&quot;&gt;&amp;lt;http://labs.apache.org/webarch/uri/rfc/rfc3986.html#delimiting&amp;gt;&lt;/a&gt;&lt;/tt&gt;, work when added to the ends of lines. And &quot;&lt;tt&gt;bug ###&lt;/tt&gt;&quot; references are auto-linkified.)&lt;br&gt; &lt;br&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/3538011216013400890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=3538011216013400890' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/3538011216013400890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/3538011216013400890'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2011/10/mozilla-status-board-text-is-markdown.html' title='Mozilla Status Board Text is Markdown'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-3002229182794927051</id><published>2011-09-16T08:32:00.001-07:00</published><updated>2011-09-16T08:32:13.528-07:00</updated><title type='text'>to all the bugs I&#39;ve filed before</title><content type='html'>The &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=20142&quot;&gt;first bug I filed&lt;/a&gt; was marked as &lt;i&gt;duplicate&lt;/i&gt;; the &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=20187&quot;&gt;second&lt;/a&gt; was &lt;i&gt;worksforme&lt;/i&gt; (although Chris Petersen could reproduce it before he couldn&#39;t anymore); and the &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=24840&quot;&gt;third&lt;/a&gt; was &lt;i&gt;invalid&lt;/i&gt; (it was the spec, not the code, that was errant). The &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=25082&quot;&gt;fourth&lt;/a&gt; is the first that was &lt;i&gt;fixed&lt;/i&gt;.&lt;br&gt; &lt;br&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/3002229182794927051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=3002229182794927051' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/3002229182794927051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/3002229182794927051'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2011/09/to-all-bugs-ive-filed-before.html' title='to all the bugs I&#39;ve filed before'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-2481752447493541518</id><published>2011-09-09T17:01:00.000-07:00</published><updated>2011-09-09T17:00:36.580-07:00</updated><title type='text'>&quot;Next/Previous Tab&quot; Keyboard Shortcuts on Windows</title><content type='html'>On my Windows laptop, I use the following four programs with tabbed interfaces on a regular basis:&lt;br&gt; &lt;ul&gt; &lt;li&gt;Firefox&lt;/li&gt; &lt;li&gt;Thunderbird&lt;/li&gt; &lt;li&gt;Instantbird&lt;/li&gt; &lt;li&gt;Komodo IDE&lt;/li&gt; &lt;/ul&gt; (I&#39;d love to have tabs in my Windows terminal app of choice, &lt;a href=&quot;http://code.google.com/p/mintty/&quot;&gt;Mintty&lt;/a&gt;, but its developer &lt;a href=&quot;http://code.google.com/p/mintty/issues/detail?id=8&quot;&gt;thinks tabs should be implemented at the window manager level&lt;/a&gt;.)&lt;br&gt; &lt;br&gt; Unlike &lt;a href=&quot;http://mykzilla.blogspot.com/2011/09/nextprevious-tab-keyboard-shortcuts-on.html&quot;&gt;on my Mac&lt;/a&gt;, all those programs implement the same keyboard shortcut for switching to the previous/next tab, and it&#39;s a simple one with just a two-key chord: Control + PageUp / PageDown.&lt;br&gt; &lt;br&gt; Ha!&lt;br&gt; &lt;br&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/2481752447493541518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=2481752447493541518' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/2481752447493541518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/2481752447493541518'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2011/09/nextprevious-tab-keyboard-shortcuts-on_09.html' title='&quot;Next/Previous Tab&quot; Keyboard Shortcuts on Windows'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-1639696569383368856</id><published>2011-09-08T17:03:00.001-07:00</published><updated>2011-09-08T17:03:31.723-07:00</updated><title type='text'>&quot;Next/Previous Tab&quot; Keyboard Shortcuts on Mac</title><content type='html'>On my Mac, I use the following five programs with tabbed interfaces on a regular basis:&lt;br&gt; &lt;ul&gt; &lt;li&gt;Firefox&lt;/li&gt; &lt;li&gt;Thunderbird&lt;/li&gt; &lt;li&gt;Adium&lt;/li&gt; &lt;li&gt;Terminal&lt;/li&gt; &lt;li&gt;Komodo IDE&lt;/li&gt; &lt;/ul&gt; &lt;br&gt; And those programs implement the following five different keyboard shortcuts for switching to the previous/next tab:&lt;br&gt; &lt;ul&gt; &lt;li&gt;Control + PageUp / PageDown (Firefox, Thunderbird)&lt;br&gt; &lt;/li&gt; &lt;li&gt;Command + LeftArrow / RightArrow (Adium)&lt;/li&gt; &lt;li&gt;Command + PageUp / PageDown (Komodo IDE)&lt;/li&gt; &lt;li&gt;Command + Shift + [ / ] (Terminal)&lt;/li&gt; &lt;li&gt;Command + Shift + LeftArrow / RightArrow (Terminal)&lt;/li&gt; &lt;/ul&gt; Hrm.&lt;br&gt; &lt;br&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/1639696569383368856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=1639696569383368856' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/1639696569383368856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/1639696569383368856'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2011/09/nextprevious-tab-keyboard-shortcuts-on.html' title='&quot;Next/Previous Tab&quot; Keyboard Shortcuts on Mac'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-4435398397928021957</id><published>2011-09-07T14:25:00.000-07:00</published><updated>2011-09-20T11:37:47.397-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jetpack"/><title type='text'>gitflow vs. the SDK</title><content type='html'>&lt;a href=&quot;http://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;gitflow&lt;/a&gt; is a model for developing and shipping software using &lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt;. &lt;a href=&quot;https://addons.mozilla.org/en-US/developers/builder&quot;&gt;Add-on SDK&lt;/a&gt; uses Git, and &lt;a href=&quot;https://wiki.mozilla.org/Jetpack/Development_Process&quot;&gt;it too has a model&lt;/a&gt;, which is similar to gitflow in some ways and different in others. Here&#39;s a comparison of the two and some thoughts on why they vary.&lt;br /&gt;&lt;br /&gt;First, some similarities: both models use multiple branches, including an ongoing branch for general development and another ongoing branch that is always ready for release (their names vary, but that&#39;s a trivial difference). Both also permit development on temporary feature (topic) branches and utilize a branch for stabilization of the codebase leading up to a release. And both accommodate the occasional hotfix release in similar ways.&lt;br /&gt;&lt;br /&gt;(Aside: gitflow appears to encourage feature branches, but I tend to agree with &lt;a href=&quot;http://martinfowler.com/bliki/FeatureBranch.html&quot;&gt;Martin Fowler&lt;/a&gt; through &lt;a href=&quot;http://pauljulius.com/blog/2009/09/03/feature-branches-are-poor-mans-modular-architecture/&quot;&gt;Paul Julius&lt;/a&gt; that continuously integrating with a central development branch is preferable.)&lt;br /&gt;&lt;br /&gt;Second, some differences: the SDK uses a single ongoing stabilization branch, while gitflow uses multiple short-lived stabilization branches, one per release. And in the SDK, stabilization fixes land on the development branch and then get cherry-picked to the stabilization branch; whereas in gitflow, stabilization fixes land on the stabilization branch and then get merged to the development branch.&lt;br /&gt;&lt;br /&gt;(Also, the SDK releases on a regular time/quality-driven &quot;train&quot; schedule similar to &lt;a href=&quot;http://mozilla.github.com/process-releases/draft/development_overview/&quot;&gt;Firefox&#39;s&lt;/a&gt;, while gitflow may anticipate an irregular feature/quality-driven release schedule, although it can be applied to projects with train schedules, like &lt;a href=&quot;http://lloyd.io/applying-gitflow&quot;&gt;BrowserID&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;A benefit of gitflow&#39;s approach to stabilization is that its change graph includes only distinct changes, whereas cherry-picking adds duplicate, semi-associated changes to the SDK&#39;s graph. However, a downside of gitflow&#39;s approach is that developers must attend to where they land changes, whereas SDK developers always land changes on its development branch, and its release manager takes on the chore of getting those changes onto the stabilization branch.&lt;br /&gt;&lt;br /&gt;(It isn&#39;t clear what happens in gitflow if a change lands on the development branch while a release is being stabilized and afterward is identified as being wanted for the release. Perhaps it gets cherry-picked?)&lt;br /&gt;&lt;br /&gt;Overall, these models seem fairly similar, and it wouldn&#39;t be too hard to make the SDK&#39;s be essentially gitflow. We would just need to stipulate that developers land stabilization fixes on the stabilization branch, and the release manager&#39;s job would then be to merge that branch back to the development branch periodically instead of cherry-picking in the other direction.&lt;br /&gt;&lt;br /&gt;However, it isn&#39;t clear to me that such a change would be preferable. What do you think?</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/4435398397928021957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=4435398397928021957' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/4435398397928021957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/4435398397928021957'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2011/09/gitflow-vs-sdk.html' title='gitflow vs. the SDK'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-8020854027593557159</id><published>2011-08-21T22:51:00.000-07:00</published><updated>2011-09-20T11:38:43.594-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jetpack"/><title type='text'>Administer Git? Get a job!</title><content type='html'>As I &lt;a href=&quot;http://mykzilla.blogspot.com/2011/08/why-add-on-sdk-doesnt-land-in-mozilla.html&quot;&gt;mentioned recently&lt;/a&gt;, &lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt; (on &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;) has become a popular VCS for Mozilla-related projects.&lt;br&gt; &lt;br&gt; GitHub is a fantastic tool for collaboration, and the site does a great job running a Git server, but given the importance of the VCS, and because Mozilla&#39;s automated test machines don&#39;t have access to servers outside the Mozilla firewall, Mozilla should &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=528360&quot;&gt;run its own Git server&lt;/a&gt; (that syncs with GitHub, so developers can continue to use that site for collaboration).&lt;br&gt; &lt;br&gt; Unfortunately, the organization doesn&#39;t have a great deal of in-house Git server administration experience, but we&#39;re &lt;a href=&quot;http://hire.jobvite.com/CompanyJobs/Careers.aspx?c=qpX9Vfwa&amp;amp;cs=9Kt9Vfw1&amp;amp;page=Job%20Description&amp;amp;j=oIfPVfwr&quot;&gt;hiring systems administrators&lt;/a&gt;, so if you grok Git hosting and meet the other requirements, &lt;a href=&quot;http://hire.jobvite.com/CompanyJobs/Careers.aspx?c=qpX9Vfwa&amp;amp;page=Apply&amp;amp;j=oIfPVfwr&quot;&gt;send in your resume&lt;/a&gt;!&lt;br&gt; &lt;br&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/8020854027593557159/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=8020854027593557159' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/8020854027593557159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/8020854027593557159'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2011/08/administer-git-get-job.html' title='Administer Git? Get a job!'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-1307851753993957811</id><published>2011-08-11T13:33:00.000-07:00</published><updated>2011-09-20T11:38:43.545-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jetpack"/><title type='text'>Why the Add-on SDK Doesn&#39;t &quot;Land in mozilla-central&quot;</title><content type='html'>Various Mozillians sometimes suggest that the Add-on SDK should &quot;land in mozilla-central&quot; and wonder why it doesn&#39;t. Here&#39;s why.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The Add-on SDK depends on features of Firefox (and Gecko), and the SDK&#39;s development process synchronizes its release schedule with Firefox&#39;s. Nevertheless, the SDK isn&#39;t a component of Firefox, it&#39;s a distinct product with its own codebase, development process, and release schedule.&lt;br /&gt;&lt;br /&gt;Mozilla makes multiple products that interact with Firefox (addons.mozilla.org, a.k.a. AMO, is another), and distinct product development efforts should generally utilize separate code repositories, to avoid contention between the projects regarding tree management, the stages of the software development lifecycle (i.e. when which branch is in alpha, beta, etc.), and the schedules for merging between branches.&lt;br /&gt;&lt;br /&gt;There can be exceptions to that principle, for products that share a bunch of code, use the same development process, and have the same release schedule (cf. the Firefoxes for desktop and mobile). But the SDK is not one of those exceptions.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It shares no code with Firefox. Its process utilizes one fewer branch and six fewer weeks of development than the Firefox development process, to minimize the burden of branch management and stabilization build testing on its much smaller development team and testing community. And it merges its branches and ships its releases two weeks before Firefox, to give AMO and addon developers time to update addons for each new version of the browser.&lt;br /&gt;&lt;br /&gt;Living in its own repository makes it possible for the SDK to have these differences in its process, and it also makes it possible for us to change the process in the future, for example to move up the branch/release dates one week, if we discover that AMO and addon developers would benefit from three weeks of lead time; or to ship twice as frequently, if we determine that doing so would get APIs for new Firefox features into developers&#39; hands faster.&lt;br /&gt;&lt;br /&gt;Finally, the Jetpack project has a vibrant community of contributors (including both organization staff and volunteers) who strongly prefer contributing via Git and &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;, because they find it easier, more efficient, and more enjoyable, and for whom working in mozilla-central would mean taking too great a hit on their productivity, passion, and participation.&lt;br /&gt;&lt;br /&gt;Mozilla Labs innovates not only on features and user experience but also on development process and tools, and while Jetpack didn&#39;t lead the way to GitHub, we were a fast follower once early experiments validated its benefits. And our experience since then has only confirmed our decision, as GitHub has proven to be a fantastic tool for branch management, code review/integration, and other software development tasks.&lt;br /&gt;&lt;br /&gt;Other Mozillians agree: there are now almost two hundred members and over one hundred repositories (not counting forks) in the Mozilla organization on GitHub, with major initiatives like &lt;a href=&quot;https://github.com/mozilla/openwebapps&quot;&gt;Open Web Apps&lt;/a&gt; and &lt;a href=&quot;https://github.com/mozilla/browserid&quot;&gt;BrowserID&lt;/a&gt; being hosted there, not to mention all the Mozilla projects in user repositories, including &lt;a href=&quot;https://github.com/graydon/rust&quot;&gt;Rust&lt;/a&gt; and &lt;a href=&quot;https://github.com/jbalogh/zamboni&quot;&gt;Zamboni&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Even if we don&#39;t make mozilla-central the canonical repository for SDK development, however, we could still periodically drop a copy of the SDK source against which Firefox changes should be tested into mozilla-central. And doing so would theoretically make it easier for Firefox developers to run SDK tests when they discover that a Firefox change breaks the SDK, because they wouldn&#39;t have to get the SDK first.&lt;br /&gt;&lt;br /&gt;But the benefit to Firefox developers is minimal. Currently, we periodically drop a reference to the SDK revision against which Firefox changes should be tested, and developers have to do the following to initiate testing:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp; wget -i testing/jetpack/jetpack-location.txt -O addon-sdk.tar.bz2
- &lt;br /&gt;&amp;nbsp; tar xjf addon-sdk.tar.bz2
- &lt;br /&gt;&amp;nbsp; cd addon-sdk-[revision]
- &lt;br /&gt;&amp;nbsp; source bin/activate
- &lt;br /&gt;&amp;nbsp; cfx testall --binary path/to/Firefox/build
- &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We can simplify this to:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp; testing/jetpack/clone
- &lt;br /&gt;&amp;nbsp; cd addon-sdk
- &lt;br /&gt;&amp;nbsp; source bin/activate
- &lt;br /&gt;&amp;nbsp; cfx testall --binary path/to/Firefox/build
- &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Whereas if we dropped the source instead of just a reference to it, it would instead be the only slightly simpler: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp; cd testing/jetpack/addon-sdk
- &lt;br /&gt;&amp;nbsp; source bin/activate
- &lt;br /&gt;&amp;nbsp; cfx testall --binary path/to/Firefox/build
- &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Either of which can be abstracted to a single make target.&lt;br /&gt;&lt;br /&gt;But if we were to drop source instead of a reference thereto, the drops would be larger and riskier changes. And test automation would still need to be updated to support Git (or at least continue to use brittle Git -&amp;gt; Mercurial mirroring), in order to run tests on SDK changes, which periodic source drops do not address.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now, this doesn&#39;t mean that no SDK code will ever land in mozilla-central.&lt;br /&gt;&lt;br /&gt;Various folks have discussed integrating parts of the SDK into core Firefox&lt;span class=&quot;st&quot;&gt;—&lt;/span&gt;including stable API implementations, the module loader, and possibly the bootstrapper&lt;span class=&quot;st&quot;&gt;—&lt;/span&gt;to reduce the size of addon packages, improve addon startup times, and decrease addon memory consumption. I have written a very preliminary draft of a &lt;a href=&quot;https://wiki.mozilla.org/Features/Jetpack/Land_Parts_of_Add-on_SDK_In_Core&quot;&gt;feature page describing this work&lt;/a&gt;, although I do not think it is a high priority at the moment, relative to the other priorities identified in the &lt;a href=&quot;https://wiki.mozilla.org/Jetpack/Roadmap&quot;&gt;Jetpack roadmap&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;And Dietrich Ayala recently suggested &lt;a href=&quot;http://groups.google.com/group/mozilla.dev.planning/browse_frm/thread/2b57ebe15aad4130&quot;&gt;integrating the SDK into core Firefox for use by core features&lt;/a&gt;, by which he presumably also means the API implementations/module loader/bootstrapper rather than the command-line tool for testing and packaging addons.&lt;br /&gt;&lt;br /&gt;Nevertheless, I am (and, I suspect, the whole Jetpack team is) even open to discussing integration of the command-line tool (or its replacement by a graphical equivalent), merging together the two products, and erasing the distinction between them, just as Firefox ships with core features for web development.&amp;nbsp; We&#39;ve even drafted a &lt;a href=&quot;https://wiki.mozilla.org/Features/Jetpack/Add-on_SDK_as_an_Addon&quot;&gt;feature page for converting the SDK into an addon&lt;/a&gt;, which is a big step in that direction.&lt;br /&gt;&lt;br /&gt;But until that happens, farther on up the road, the SDK is its own product that we develop with its own process and ship on its own schedule. And it has good reason to live in its own repository, and a Git one at that, as do the many (and growing number of) other Mozilla projects using similar processes and tools, which our community-wide development, collaboration, and testing infrastructure must evolve to accommodate.</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/1307851753993957811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=1307851753993957811' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/1307851753993957811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/1307851753993957811'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2011/08/why-add-on-sdk-doesnt-land-in-mozilla.html' title='Why the Add-on SDK Doesn&#39;t &quot;Land in mozilla-central&quot;'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-6715608859512848344</id><published>2010-12-02T11:07:00.001-08:00</published><updated>2011-09-20T11:38:43.568-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jetpack"/><title type='text'>SDK Training and More at Add-on-Con</title><content type='html'>&lt;div class=&quot;moz-text-html&quot; lang=&quot;x-western&quot;&gt;Next Wednesday, December 8, I&#39;ll be at &lt;a href=&quot;http://addoncon.com/&quot;&gt;Add-on-Con&lt;/a&gt;.&lt;br&gt; &lt;br&gt; In the morning, I&#39;ll conduct a training session introducing Mozilla&#39;s new Add-on SDK, which makes it faster and easier to build Firefox add-ons. Afterwards, I&#39;ll be around and about to discuss add-ons and answer questions about the SDK and add-on development generally.&lt;br&gt; &lt;br&gt; Lots of other Mozilla folks will also be on hand over the course of the two-day conference, including &lt;a href=&quot;http://www.oxymoronical.com/&quot;&gt;Dave Townsend&lt;/a&gt;, Jorge Villalobos, &lt;a href=&quot;http://jboriss.wordpress.com/&quot;&gt;Jeniffer Boriss&lt;/a&gt;, &lt;a href=&quot;http://starkravingfinkle.org/blog/&quot;&gt;Mark Finkle&lt;/a&gt;, and &lt;a href=&quot;http://blog.fligtar.com/&quot;&gt;Justin Scott&lt;/a&gt;. A rockin&#39; time should be had by all. Join us!&lt;br&gt; &lt;br&gt; &lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/6715608859512848344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=6715608859512848344' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/6715608859512848344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/6715608859512848344'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2010/12/sdk-training-and-more-at-add-on-con.html' title='SDK Training and More at Add-on-Con'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-1323551422046235302</id><published>2010-11-27T20:47:00.001-08:00</published><updated>2011-09-20T11:38:43.550-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jetpack"/><title type='text'>Further Adventures In Git(/Hub)ery</title><content type='html'>&lt;div class=&quot;moz-text-html&quot; lang=&quot;x-western&quot;&gt; This evening I decided to check if there were any outstanding pull requests for the SDK repository (to which I haven&#39;t been paying attention).&lt;br&gt; &lt;br&gt; There were! The oldest was &lt;a href=&quot;https://github.com/mozilla/addon-sdk/pull/29&quot;&gt;pull request 29&lt;/a&gt; from Thomas Bassetto, which contains two small fixes (&lt;a href=&quot;https://github.com/tbassetto/addon-sdk/commit/8268334070d03a896d5c006d1b4db94d4cb44b17&quot;&gt;first&lt;/a&gt;, &lt;a href=&quot;https://github.com/tbassetto/addon-sdk/commit/666ad7a99e05e338348dfc579d5b1f75e8d3bb1b&quot;&gt;second&lt;/a&gt;) to the docs.&lt;br&gt; &lt;br&gt; So I fetched the branch of his fork in which the changes reside:&lt;br&gt; &lt;br&gt; &lt;blockquote&gt;&lt;tt&gt;$ git fetch &lt;a class=&quot;moz-txt-link-freetext&quot; href=&quot;https://github.com/tbassetto/addon-sdk.git&quot;&gt;https://github.com/tbassetto/addon-sdk.git&lt;/a&gt; master&lt;/tt&gt;&lt;br&gt; &lt;/blockquote&gt; &lt;br&gt; But that branch (and the fork in general) is a few weeks out-of-date, so &quot;&lt;tt&gt;git diff HEAD FETCH_HEAD&lt;/tt&gt;&quot; showed a bunch of changes, and it was unclear how painful the merge would be.&lt;br&gt; &lt;br&gt; Thus I decided to try cherry-picking the changes, my first time using &quot;&lt;tt&gt;git cherry-pick&lt;/tt&gt;&quot;.&lt;br&gt; &lt;br&gt; The first one went great:&lt;br&gt; &lt;br&gt; &lt;blockquote&gt;&lt;tt&gt;$ git cherry-pick 8268334070d03a896d5c006d1b4db94d4cb44b17&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;Finished one cherry-pick.&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;[master ceadb1f] Fixed an internal link in the widget doc&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;&amp;nbsp;1 files changed, 1 insertions(+), 1 deletions(-)&lt;/tt&gt;&lt;br&gt; &lt;/blockquote&gt; &lt;br&gt; Except that I realized afterward I hadn&#39;t added &quot;r,a=myk&quot; to the commit message. So I tried &quot;&lt;tt&gt;git commit --amend&lt;/tt&gt;&quot; for the first time, which worked just fine:&lt;br&gt; &lt;br&gt; &lt;blockquote&gt;&lt;tt&gt;$ git commit --amend&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;[master 2d674a6] Fixed an internal link in the widget doc; r,a=myk&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;&amp;nbsp;1 files changed, 1 insertions(+), 1 deletions(-)&lt;/tt&gt;&lt;br&gt; &lt;/blockquote&gt; &lt;br&gt; Next time I&#39;ll remember to use the &quot;&lt;tt&gt;--edit&lt;/tt&gt;&quot; flag to &quot;&lt;tt&gt;git cherry-pick&lt;/tt&gt;&quot;, which lets one &quot;edit the commit message prior to committing.&quot;&lt;br&gt; &lt;br&gt; The second cherry-pick was more complicated, because I only wanted one of the two changes in the commit (in &lt;a href=&quot;https://github.com/tbassetto/addon-sdk/commit/666ad7a99e05e338348dfc579d5b1f75e8d3bb1b#commitcomment-204023&quot;&gt;my review&lt;/a&gt;, I had identified the second change as unnecessary); and, as it turned out, also because there was a merge conflict with other commits.&lt;br&gt; &lt;br&gt; I started by cherry-picking the commit with the &quot;&lt;tt&gt;--no-commit&lt;/tt&gt;&quot; option (so I could remove the second change):&lt;br&gt; &lt;br&gt; &lt;blockquote&gt;&lt;tt&gt;$ git cherry-pick --no-commit 666ad7a99e05e338348dfc579d5b1f75e8d3bb1b&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;Automatic cherry-pick failed.&amp;nbsp; After resolving the conflicts,&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;mark the corrected paths with &#39;git add &amp;lt;paths&amp;gt;&#39; or &#39;git rm &amp;lt;paths&amp;gt;&#39; and commit the result.&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;When commiting, use the option &#39;-c 666ad7a&#39; to retain authorship and message.&lt;/tt&gt;&lt;br&gt; &lt;/blockquote&gt; &lt;br&gt; The conflict was trivial, and I knew where it was, so I resolved it manually (instead of trying &quot;&lt;tt&gt;git mergetool&lt;/tt&gt;&quot; for the first time), removed the second change, added the merged file, and committed the result, using the &quot;&lt;tt&gt;-c&lt;/tt&gt;&quot; option to preserve the original author and commit message while allowing me to edit the message to add &quot;r,a=myk&quot;:&lt;br&gt; &lt;br&gt; &lt;blockquote&gt;&lt;tt&gt;$ git add packages/addon-kit/docs/request.md&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;$ git commit -c 666ad7a&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;[master 774d1cb] Completed the example in the Request module documentation; r,a=myk&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;&amp;nbsp;1 files changed, 1 insertions(+), 0 deletions(-)&lt;/tt&gt;&lt;br&gt; &lt;/blockquote&gt; &lt;br&gt; Then I used &quot;&lt;tt&gt;gitg&lt;/tt&gt;&quot; and &quot;&lt;tt&gt;git log master ^upstream/master&lt;/tt&gt;&quot; to verify that the commits looked good to go, after which I pushed them:&lt;br&gt; &lt;br&gt; &lt;blockquote&gt;&lt;tt&gt;$ git push upstream master&lt;/tt&gt;&lt;br&gt; &lt;tt&gt;[git&#39;s standard obscure and disconcerting gobbledygook]&lt;/tt&gt;&lt;br&gt; &lt;/blockquote&gt; &lt;br&gt; Finally, I closed the pull request with &lt;a href=&quot;https://github.com/mozilla/addon-sdk/pull/29#issuecomment-570630&quot;&gt;this comment&lt;/a&gt; that summarized what I did and provided links to the cherry-picked commits.&lt;br&gt; &lt;br&gt; It would have been nice if the cherry-picked commit that didn&#39;t have merge conflicts (and which I didn&#39;t change in the process of merging) had kept its original commit ID, but I sense that that is somehow a fundamental violation of the model.&lt;br&gt; &lt;br&gt; It would also have been nice if the cherry-picked commit messages had been automatically annotated with references to the original commits.&lt;br&gt; &lt;br&gt; But overall the process seemed pretty reasonable, it was fairly easy to do what I wanted and recover from mistakes, and the author, committer, reviewer, and approver are clearly indicated in the cherry-picked commits (&lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/2d674a6ea84d3be88b5365b2d24b994297a60d7a&quot;&gt;first&lt;/a&gt;, &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/774d1cbf49e152a030a0bf6cbde7b4139c8c3f49&quot;&gt;second&lt;/a&gt;).&lt;br&gt; &lt;br&gt; [Also &lt;a href=&quot;http://groups.google.com/group/mozilla-labs-jetpack/browse_thread/thread/430750c65fe80231&quot;&gt;posted to the discussion group&lt;/a&gt;.]&lt;br&gt; &lt;br&gt; &lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/1323551422046235302/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=1323551422046235302' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/1323551422046235302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/1323551422046235302'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2010/11/further-adventures-in-githubery.html' title='Further Adventures In Git(/Hub)ery'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-7960433840999647174</id><published>2010-11-27T20:39:00.001-08:00</published><updated>2011-09-20T11:38:43.583-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jetpack"/><title type='text'>More Git/Hub Workflow Experiences</title><content type='html'>After posting about my &lt;a href=&quot;http://mykzilla.blogspot.com/2010/11/github-workflow-experiences.html&quot;&gt;first Git/Hub workflow experiences&lt;/a&gt;, I got lots of helpful input from various folks, particularly Erik Vold, Irakli Gozalishvili, and Brian Warner, which led me to refine my process for handling pull requests:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;From the &quot;how to merge this pull request&quot; section of the pull request page (f.e. &lt;a href=&quot;https://github.com/mozilla/addon-sdk/pull/43&quot;&gt;pull request 34&lt;/a&gt;), copy the command from step two, but change the word &quot;pull&quot; to &quot;fetch&quot; to fetch the remote branch containing the changes without also merging it:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;git fetch &lt;a class=&quot;moz-txt-link-freetext&quot; href=&quot;https://github.com/toolness/jetpack-sdk.git&quot;&gt;https://github.com/toolness/jetpack-sdk.git&lt;/a&gt; bug-610507&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Use the magic FETCH_HEAD reference to the last fetched branch to verify that the set of changes is what you expect:&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;git diff &lt;/tt&gt;&lt;tt&gt;HEAD &lt;/tt&gt;&lt;tt&gt;FETCH_HEAD&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;(The exact syntax here may need some work; HEAD..FETCH_HEAD? three dots?)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Merge the remote branch into your local branch with a custom commit message:&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;git merge FETCH_HEAD --no-ff -m&quot;bug 610507: get rid of the nsjetpack package; r=myk&quot;&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Push the changes upstream:&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;git push upstream master&lt;/tt&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;I like this set of commands because it doesn&#39;t require me to add a remote, I can copy/paste the fetch command from GitHub (being careful not to issue the pull before I change it to a fetch), and I always type the same FETCH_HEAD reference to the remote branch in step three.&lt;br /&gt;&lt;br /&gt;However, I wish the &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/0e23d1c1555d5de228ed7ad62c8715e2775d2390&quot;&gt;merge commit page&lt;/a&gt; explicitly referenced the &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/68b6e306dfeccef103b071e0812dc3a375830ac0&quot;&gt;specific&lt;/a&gt; &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/715cb47c720bcdd11846cae6c6cab325bb1a982b&quot;&gt;commits&lt;/a&gt; that were merged. It does mention that it&#39;s a branch merge, it isn&#39;t obvious how to get from that page to the pages for the commits I merged from the branch.&lt;br /&gt;&lt;br /&gt;&quot;&lt;tt&gt;git log --oneline --graph&lt;/tt&gt;&quot;, &lt;tt&gt;gitg&lt;/tt&gt;, and &lt;tt&gt;gitk&lt;/tt&gt; do give me that information, though, so I&#39;m ok on the command line, anyway.&lt;br /&gt;&lt;br /&gt;[More discussion can be found in the &lt;a href=&quot;http://groups.google.com/group/mozilla-labs-jetpack/browse_thread/thread/2c6cb3e7f3bec468&quot;&gt;discussion group thread&lt;/a&gt;.]</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/7960433840999647174/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=7960433840999647174' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7960433840999647174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7960433840999647174'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2010/11/more-github-workflow-experiences.html' title='More Git/Hub Workflow Experiences'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-7037189428773681360</id><published>2010-11-12T18:55:00.000-08:00</published><updated>2011-09-20T11:38:43.577-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jetpack"/><title type='text'>Git/Hub Workflow Experiences</title><content type='html'>&lt;div class=&quot;moz-text-html&quot; lang=&quot;x-western&quot;&gt;The Jetpack project recently migrated its SDK repository to Git (hosted on GitHub), and we&#39;ve been working out changes to the bug/review/commit workflow that GitHub&#39;s tools enable (specifically, pull requests).&lt;/div&gt;&lt;div class=&quot;moz-text-html&quot; lang=&quot;x-western&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;moz-text-html&quot; lang=&quot;x-western&quot;&gt;Here are some of my initial experiences and my thoughts on them (which I&#39;ve also &lt;a href=&quot;http://groups.google.com/group/mozilla-labs-jetpack/browse_thread/thread/2c6cb3e7f3bec468&quot;&gt;posted to the Jetpack discussion group&lt;/a&gt;).&lt;/div&gt;&lt;div class=&quot;moz-text-html&quot; lang=&quot;x-western&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;moz-text-html&quot; lang=&quot;x-western&quot;&gt; &lt;/div&gt;&lt;div class=&quot;moz-text-html&quot; lang=&quot;x-western&quot;&gt; Warning: Git wonkery ahead, with excruciating details. I would not want to read this post. I recommend you skip it. ;-)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt; Part 1: Wherein I Handle My First Pull Request&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To fix some test failures, Atul submitted &lt;a href=&quot;https://github.com/mozilla/addon-sdk/pull/33&quot;&gt;GitHub pull request 33&lt;/a&gt;, I reviewed the changes (comprising &lt;a href=&quot;https://github.com/toolness/jetpack-sdk/commit/97619b0b25554712756827de883883c9b810319d&quot;&gt;two&lt;/a&gt; &lt;a href=&quot;https://github.com/toolness/jetpack-sdk/commit/405390a586f6c09bad2b26183fe2925d09bcd52b&quot;&gt;commits&lt;/a&gt;) on GitHub, and then I pushed them to the canonical repository via the following set of commands:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;git checkout -b toolness-&lt;span class=&quot;commit-ref from&quot;&gt;4.0b7-bustage-fixes&lt;/span&gt; master&lt;/li&gt;&lt;li&gt;git pull &lt;a class=&quot;moz-txt-link-freetext&quot; href=&quot;https://github.com/toolness/jetpack-sdk.git&quot;&gt;https://github.com/toolness/jetpack-sdk.git&lt;/a&gt; &lt;span class=&quot;commit-ref from&quot;&gt;4.0b7-bustage-fixes&lt;/span&gt;&lt;/li&gt;&lt;li&gt;git checkout master&lt;/li&gt;&lt;li&gt;git merge toolness-&lt;span class=&quot;commit-ref from&quot;&gt;4.0b7-bustage-fixes&lt;/span&gt;&lt;/li&gt;&lt;li&gt;git push upstream master&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;That landed the &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/97619b0b25554712756827de883883c9b810319d&quot;&gt;two&lt;/a&gt; &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/405390a586f6c09bad2b26183fe2925d09bcd52b&quot;&gt;commits&lt;/a&gt; in the canonical repository, but it isn&#39;t obvious that they were related (i.e. part of the same pull request), that I was the one who reviewed them, or that I was the one who pushed them.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Part 2: Wherein I Handle My Second Pull Request&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Thus, for the fix for &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=611042&quot;&gt;bug 611042&lt;/a&gt;, for which Atul submitted &lt;a href=&quot;https://github.com/mozilla/addon-sdk/pull/34&quot;&gt;GitHub pull request 34&lt;/a&gt;, I again reviewed the changes (also comprising &lt;a href=&quot;https://github.com/toolness/jetpack-sdk/commit/5e6ca0e1834e65623f6ac87d3828965da420847c&quot;&gt;two&lt;/a&gt; &lt;a href=&quot;https://github.com/toolness/jetpack-sdk/commit/1ab9c78c94fb08610460ad19fd763a7402fc233c&quot;&gt;commits&lt;/a&gt;) on GitHub, but then I pushed them to the &lt;a href=&quot;https://github.com/mozilla/addon-sdk&quot;&gt;canonical repository&lt;/a&gt; via this different set of commands (after discussion with Atul and Patrick Walton of the Rust team):&lt;br /&gt;&lt;ol&gt;&lt;li&gt;git checkout -b toolness-bug-611042 master&lt;/li&gt;&lt;li&gt;git pull &lt;a class=&quot;moz-txt-link-freetext&quot; href=&quot;https://github.com/toolness/jetpack-sdk.git&quot;&gt;https://github.com/toolness/jetpack-sdk.git&lt;/a&gt; bug-611042&lt;/li&gt;&lt;li&gt;(There might have been something else here, since the pull request resulted in a merge; I don&#39;t quite remember.)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;git checkout master&lt;/li&gt;&lt;li&gt;git merge --no-ff --no-commit toolness-bug-611042&lt;/li&gt;&lt;li&gt;git commit --signoff -m &quot;bug 611042: remove request.response.xml for e10s compatibility; r=myk&quot; --author &quot;atul&quot;&lt;/li&gt;&lt;li&gt;git push upstream master&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Because Atul&#39;s pull request was no longer against the tip (since I had just merged those previous changes), when I pulled the remote bug-611042 branch into my local toolness-bug-611042 branch (step 2), I had to merge his changes, which resulted in a &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/6a3c9e2a614f29b61e580a7a7619f91dd1306eea&quot;&gt;merge commit&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Merging the changes to my local master with &quot;--no-ff&quot; and &quot;--no-commit&quot; (step 5) then allowed me to commit the merge to my master branch manually (step 6), resulting in another &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/9f202a3003cddace040bc695ab7137d4a31051ec&quot;&gt;merge commit&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For the second merge commit, I specified &quot;--signoff&quot;, which added &quot;Signed-off-by: Myk Melez &lt;a class=&quot;moz-txt-link-rfc2396E&quot; href=&quot;mailto:myk@mozilla.org&quot;&gt;&lt;myk@mozilla.org&gt;&lt;/myk@mozilla.org&gt;&lt;/a&gt;&quot; to the commit message; crafted a custom commit message that included &quot;r=myk&quot;; and specified &#39;--author &quot;atul&quot;&#39;, which made Atul the author of the merge.&lt;br /&gt;&lt;br /&gt;I dislike having the former merge commit in history, since it&#39;s extraneous, unuseful details about how I did the merging locally before I pushed to the canonical repository. I&#39;m not sure how to avoid it, though.&lt;br /&gt;&lt;br /&gt;On the other hand, I like having the latter merge commit in history, since it provides context for Atul&#39;s &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/5e6ca0e1834e65623f6ac87d3828965da420847c&quot;&gt;two&lt;/a&gt; &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/1ab9c78c94fb08610460ad19fd763a7402fc233c&quot;&gt;commits&lt;/a&gt;: the bug number, the fact that the changes were reviewed, and a commit message that describes the changes as a whole.&lt;br /&gt;&lt;br /&gt;I&#39;m ambivalent about --signoff vs. adding &quot;r=myk&quot; to the commit message, as they seem equivalentish, with --signoff being more explicit (so in theory it might form part of an enlightened workflow in the future), while &quot;r=myk&quot; is simpler.&lt;br /&gt;&lt;br /&gt;And I dislike having made Atul the author of the merge, since it&#39;s incorrect: he wasn&#39;t the author of the merge, he was only the author of the changes (for which he is correctly credited). And if the merge itself caused problems (f.e. I accidentally backed out other recent changes in the process), I would be the one responsible for fixing those problems, not Atul.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Part 3: Pushing Patches&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In addition to pull requests, one can also contribute via patches. I&#39;ve pushed a few of these via something like the following set of commands:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;git apply patch.diff&lt;/li&gt;&lt;li&gt;git commit -a -m &quot;bug &lt;number&gt;: &lt;description changes=&quot;&quot; of=&quot;&quot;&gt;; r=myk&quot; --author &quot;&lt;author name=&quot;&quot;&gt;&quot;&lt;br /&gt;&lt;/author&gt;&lt;/description&gt;&lt;/number&gt;&lt;/li&gt;&lt;li&gt;git push upstream master&lt;/li&gt;&lt;/ol&gt;That results in a commit like &lt;a href=&quot;https://github.com/mozilla/addon-sdk/commit/026b4e8e78336c2dbbf30edb14e5db78ca4afb21&quot;&gt;this one&lt;/a&gt;, which shows me as the committer and the patch author as the author. And that seems like a fine record of what happened.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Part 4: To Bug or Not To Bug?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One of the questions GitHub raises is whether or not every change deserves a bug report. And if not, how do we differentiate those that do from the rest?&lt;br /&gt;&lt;br /&gt;I don&#39;t have the definitive answers to these questions, but my sense, from my experience so far, is that we shouldn&#39;t require all changes to be accompanied by bug reports, but larger, riskier, time-consuming, and/or controversial changes should have reports to capture history, provide a forum for discussion, and permit project planning; while bug reports should be optional for smaller, safer, quickly-resolved, and/or non-controversial changes.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/7037189428773681360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=7037189428773681360' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7037189428773681360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7037189428773681360'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2010/11/github-workflow-experiences.html' title='Git/Hub Workflow Experiences'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-236254320002589931</id><published>2010-07-15T14:22:00.000-07:00</published><updated>2011-09-20T11:38:43.557-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jetpack"/><title type='text'>My Recent Jetpack Presentations</title><content type='html'>The last few weeks have been presentation-heavy.&lt;br /&gt;&lt;br /&gt;First, I gave a presentation about the Jetpack project (past accomplishments, present status, future plans) at the &lt;a href=&quot;https://wiki.mozilla.org/MAOW:2010:London&quot;&gt;2010 London Mozilla Add-ons Workshop&lt;/a&gt; (MAOW), including a demo of using &lt;a href=&quot;https://builder.mozillalabs.com/&quot;&gt;Add-on Builder&lt;/a&gt; to build an add-on in five minutes.&lt;br /&gt;&lt;br /&gt;Then I reprised the Add-on Builder demo as part of the opening day keynote at the &lt;a href=&quot;https://wiki.mozilla.org/Summit2010&quot;&gt;Mozilla Summit&lt;/a&gt;, where it got a great reception. You can watch it in &lt;a href=&quot;http://www.youtube.com/watch?v=lKN4_fOKEWQ&quot;&gt;this Youtube video&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Finally, I gave an updated version of the MAOW presentation on the third day of the summit. The slides are available in &lt;a href=&quot;https://people.mozilla.com/%7Emyk/presentations/Prepare%20for%20Liftoff%20-%20Summit%202010.odp&quot;&gt;OpenDocument&lt;/a&gt; and &lt;a href=&quot;https://people.mozilla.com/%7Emyk/presentations/Prepare%20for%20Liftoff%20-%20Summit%202010.pdf&quot;&gt;PDF&lt;/a&gt; formats, and Jetpack presentation materials generally are all available from the &lt;a href=&quot;https://wiki.mozilla.org/Labs/Jetpack/Presentations&quot;&gt;Jetpack Presentations wiki page&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/236254320002589931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=236254320002589931' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/236254320002589931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/236254320002589931'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2010/07/my-recent-jetpack-presentations.html' title='My Recent Jetpack Presentations'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-6583468542975089893</id><published>2010-03-05T23:03:00.001-08:00</published><updated>2010-04-18T23:58:52.841-07:00</updated><title type='text'>This blog has moved</title><content type='html'>&lt;br /&gt; This blog is now located at http://mykzilla.blogspot.com/.&lt;br /&gt; You will be automatically redirected in 30 seconds, or you may click &lt;a href=&#39;http://mykzilla.blogspot.com/&#39;&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt; For feed subscribers, please update your feed subscriptions to&lt;br /&gt; http://mykzilla.blogspot.com/feeds/posts/default.&lt;br /&gt; </content><link rel="related" href="http://mykzilla.blogspot.com/" title="This blog has moved"/><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/6583468542975089893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=6583468542975089893' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/6583468542975089893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/6583468542975089893'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2010/03/this-blog-has-moved.html' title='This blog has moved'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-7015776887411907934</id><published>2009-11-17T17:26:00.000-08:00</published><updated>2009-11-17T17:26:50.807-08:00</updated><title type='text'>The Skinny on Raindrop&#39;s Mailing List Extensions</title><content type='html'>Raindrop is an exploration of messaging innovation that strives to intelligently assist people in managing their flood of incoming messages. And mailing lists are a common source of messages you need to manage. So, with assistance from the Raindrop hackers, I wrote extensions that make it easier to deal with messages from mailing lists.&lt;br /&gt;&lt;br /&gt;Their goal is to soothe two particular pain points when dealing with mailing lists: grouping their messages together by list and unsubscribing from them once you&#39;re no longer interested in their subject matter.&lt;br /&gt;&lt;br /&gt;This post explains how the extensions do this; touches on some aspects of Raindrop&#39;s message processing and data storage models; and speculates about possible future directions for the extensions.&lt;br /&gt;&lt;h3&gt;Raindrop Extensibility&lt;/h3&gt;Raindrop is being built with the explicit goal of being broadly and deeply extensible, and it includes a number of APIs for adding and modifying functionality. The mailing list enhancements comprise two related extensions, one in the backend and one in the user interface.&lt;br /&gt;&lt;br /&gt;The backend extension plugs into Raindrop&#39;s incoming message processor, intercepting incoming email messages and extracting info about the mailing lists to which they belong. It also handles much of the work of unsubscribing from a list.&lt;br /&gt;&lt;br /&gt;The frontend extension plugs into Raindrop&#39;s Inflow application, modifying its interface to show you the most recent mailing list messages at a glance, group mailing list conversations together by list, and provide a button you can press to easily unsubscribe from a mailing list.&lt;br /&gt;&lt;h3&gt;Message Processing and Data Storage&lt;br /&gt;&lt;/h3&gt;Before getting into how the extensions work, it&#39;s useful to know a bit about how Raindrop processes and stores messages.&lt;br /&gt;&lt;br /&gt;Raindrop stores information using &lt;a href=&quot;http://couchdb.apache.org/&quot;&gt;CouchDB&lt;/a&gt;, a document-centric database whose principal unit of information storage and retrieval is the document (the equivalent of a record in SQL databases). Documents are just JSON blobs that can contain arbitrary name -&gt; value pairs (unlike SQL records, which can only contain values for predeclared columns).&lt;br /&gt;&lt;br /&gt;To distinguish between different kinds of documents, Raindrop assigns each a schema (similar to a table in SQL parlance) that describes (and may one day constrain) its properties. The &lt;tt&gt;rd.msg.email&lt;/tt&gt; schema is the primary schema representing an email message, while the &lt;tt&gt;rd.mailing-list&lt;/tt&gt; is the schema representing a mailing list, and the &lt;tt&gt;rd.msg.email.mailing-list&lt;/tt&gt; is a simple schema that associates messages with their lists.&lt;br /&gt;&lt;br /&gt;(In an SQL database, &lt;tt&gt;rd.msg.email&lt;/tt&gt; and &lt;tt&gt;rd.mailing-list&lt;/tt&gt; would be tables whose rows represent email messages and mailing lists, while &lt;tt&gt;rd.msg.email.mailing-list&lt;/tt&gt; would be a table whose rows map one to the other.)&lt;br /&gt;&lt;br /&gt;Note that there&#39;s a many-to-one relationship between messages and lists, since messages belong to a single list, although lists contain many messages, so &lt;tt&gt;rd.msg.email.mailing-list&lt;/tt&gt; isn&#39;t strictly necessary. Its &lt;tt&gt;list-id&lt;/tt&gt; property (which identifies the list to which the message belongs) could simply be a property of &lt;tt&gt;rd.msg.email&lt;/tt&gt; docs (or, in SQL terms, a foreign key in the &lt;tt&gt;rd.msg.email&lt;/tt&gt; table).&lt;br /&gt;&lt;br /&gt;But putting it into its own document has several advantages. First, it improves robustness, as it reduces the possibility of conflicts between extensions and core code writing to the same documents.&lt;br /&gt;&lt;br /&gt;It also improves write performance, as it&#39;s faster to add a document than to modify an existing one (although index generation and read performance can be an issue).&lt;br /&gt;&lt;br /&gt;Finally, it improves extensibility, because it makes it possible to write an extension that extends the backend mailing list extension.&lt;br /&gt;&lt;br /&gt;That&#39;s because Raindrop&#39;s incoming message processing model allows extensions to observe the creation of any kind of document, including those created by other extensions.&lt;br /&gt;&lt;br /&gt;So just as the mailing list extension observes the creation of &lt;tt&gt;rd.msg.email&lt;/tt&gt; documents, another extension can observe the creation of &lt;tt&gt;rd.msg.email.mailing-list&lt;/tt&gt; documents and process them further in some useful way. If the mailing list extension simply modified the original document instead of creating its own, that would require some additional and more complicated API.&lt;br /&gt;&lt;h3&gt;The Backend Extension&lt;/h3&gt;The primary function of the backend extension is to examine every incoming message and dress the ones from mailing lists with some additional structured information that the frontend can use to organize them.&lt;br /&gt;&lt;br /&gt;Backend extensions are accompanied by a JSON manifest that tells Raindrop what kinds of incoming documents it wants to intercept. The mailing list extension&#39;s manifest registers it as an observer of incoming &lt;tt&gt;rd.msg.email&lt;/tt&gt; documents, which get created when Raindrop retrieves an email message:&lt;br /&gt;&lt;pre style=&quot;background-color: rgb(238, 238, 238); border: 1px solid rgb(187, 187, 187); color: black; padding: 10px;&quot;&gt;&quot;schemas&quot; : {&lt;br /&gt; &quot;rd.ext.workqueue&quot; : {&lt;br /&gt; &quot;source_schemas&quot; : [&quot;rd.msg.email&quot;],&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;The extension itself is a Python script with a &lt;tt&gt;handler&lt;/tt&gt; function that gets passed the &lt;tt&gt;rd.msg.email&lt;/tt&gt; document and looks to see if it contains a &lt;tt&gt;List-ID&lt;/tt&gt; header (or, in certain cases, another identifier) identifying the mailing list from which the message comes:&lt;br /&gt;&lt;pre style=&quot;background-color: rgb(238, 238, 238); border: 1px solid rgb(187, 187, 187); color: black; padding: 10px;&quot;&gt;def handler(message):&lt;br /&gt; ...&lt;br /&gt; if &#39;list-id&#39; in message[&#39;headers&#39;]:&lt;br /&gt; # Extract the ID and name of the mailing list from the list-id header.&lt;br /&gt; # Some mailing lists give only the ID, but others (Google Groups,&lt;br /&gt; # Mailman) provide both using the format &#39;NAME &amp;lt;id&amp;gt;&#39;, so we extract them&lt;br /&gt; # separately if we detect that format.&lt;br /&gt; list_id = message[&#39;headers&#39;][&#39;list-id&#39;][0]&lt;br /&gt; ...&lt;/pre&gt;&lt;br /&gt;If it doesn&#39;t find a list identifier, it simply returns, and Raindrop continues processing the message:&lt;br /&gt;&lt;pre style=&quot;background-color: rgb(238, 238, 238); border: 1px solid rgb(187, 187, 187); color: black; padding: 10px;&quot;&gt;if not list_id:&lt;br /&gt; logger.debug(&quot;NO LIST ID; ignoring message %s&quot;, message_id)&lt;br /&gt; return&lt;/pre&gt;&lt;br /&gt;Otherwise, it calls Raindrop&#39;s &lt;tt&gt;emit_schema&lt;/tt&gt; function to create an &lt;tt&gt;rd.msg.email.mailing-list&lt;/tt&gt; document linking the message document to an &lt;tt&gt;rd.mailing-list&lt;/tt&gt; document representing the mailing list:&lt;br /&gt;&lt;pre style=&quot;background-color: rgb(238, 238, 238); border: 1px solid rgb(187, 187, 187); color: black; padding: 10px;&quot;&gt;emit_schema(&#39;rd.msg.email.mailing-list&#39;, { &#39;list_id&#39;: list_id })&lt;/pre&gt;&lt;br /&gt;In this function call, &lt;tt&gt;rd.msg.email.mailing-list&lt;/tt&gt; is the type of document to create, while &lt;tt&gt;{ &#39;list_id&#39;: list_id }&lt;/tt&gt; is the document itself, written as Python that will get serialized to JSON.&lt;br /&gt;&lt;br /&gt;A document created inside a backend extension like this automatically gets a reference to the document the extension is processing (i.e. the &lt;tt&gt;rd.msg.email&lt;/tt&gt; document), so the only thing it has to explicitly include is a reference to the list document, in the form of a &lt;tt&gt;list_id&lt;/tt&gt; property whose value is the list identifier.&lt;br /&gt;&lt;br /&gt;The extension also checks if there&#39;s an &lt;tt&gt;rd.mailing-list&lt;/tt&gt; document in the database for the mailing list itself, and if not, it creates one, populating it with information from the message&#39;s &lt;tt&gt;List-*&lt;/tt&gt; headers, like how to unsubscribe from the list. Otherwise, it updates the existing mailing list document if the message&#39;s &lt;tt&gt;List-*&lt;/tt&gt; headers contain updates.&lt;br /&gt;&lt;h3&gt;The Frontend Extension&lt;/h3&gt;The frontend extension uses the information extracted by the backend to help users manage mailing lists in the Inflow application.&lt;br /&gt;&lt;br /&gt;It adds a widget to the Home view that shows you the last few messages from your lists at the bottom of the page, so you can keep an eye on those messages without having to give them your full attention:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://www.melez.com/mykzilla/uploaded_images/latest-list-messages-714113.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img src=&quot;http://www.melez.com/mykzilla/uploaded_images/latest-list-messages-714111.png&quot; height=&quot;176&quot; width=&quot;320&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;It adds a list of your mailing lists to the Organizer widget:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://www.melez.com/mykzilla/uploaded_images/mailing-list-list-722772.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img src=&quot;http://www.melez.com/mykzilla/uploaded_images/mailing-list-list-722768.png&quot; height=&quot;320&quot; width=&quot;190&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And when you click on the name of a list, it shows you its conversations in the conversation pane:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://www.melez.com/mykzilla/uploaded_images/list-conversations-763392.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img src=&quot;http://www.melez.com/mykzilla/uploaded_images/list-conversations-763369.png&quot; height=&quot;201&quot; width=&quot;320&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In traditional mail clients, users who want to break out their list messages into separate buckets like this typically have to create a folder for each list to contain its messages and then a filter for each list to move incoming list messages into the appropriate folders. The extension does this for you automatically!&lt;br /&gt;&lt;br /&gt;Finally, while viewing list conversations, if the extension knows how to unsubscribe you from the list, it displays an Unsubscribe button:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://www.melez.com/mykzilla/uploaded_images/unsubscribe-button-794151.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img src=&quot;http://www.melez.com/mykzilla/uploaded_images/unsubscribe-button-794149.png&quot; height=&quot;201&quot; width=&quot;320&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Pressing the button (and then confirming your decision) unsubscribes you from the list. You don&#39;t have to do anything else, like remembering your username/password for some web page, sending an email, or confirming your request with the list admin. The extensions handle all those details for you so you don&#39;t have to know about them!&lt;br /&gt;&lt;h3&gt;List Unsubscription&lt;/h3&gt;In case you do want to know the details, however, it goes like this...&lt;br /&gt;&lt;br /&gt;First, the frontend extension sends a message to the list&#39;s admin address requesting unsubscription, with a certain command (like &quot;unsubscribe&quot;) in the subject or body of the message (lists often specify exactly what command to send in the &lt;tt&gt;mailto:&lt;/tt&gt; link they include in the &lt;tt&gt;List-Unsubscribe&lt;/tt&gt; header):&lt;br /&gt;&lt;pre style=&quot;background-color: rgb(238, 238, 238); border: 1px solid rgb(187, 187, 187); color: black; padding: 10px;&quot;&gt;From: Jan Reilly &lt;jan@example.com&gt;&lt;br /&gt;To: wasbigtalk-admin@example.com&lt;br /&gt;Subject: unsubscribe&lt;/jan@example.com&gt;&lt;/pre&gt;&lt;br /&gt;Then the server responds with a message requesting confirmation of the request, often putting a unique token into the Subject or Reply-To header to track the request:&lt;br /&gt;&lt;pre style=&quot;background-color: rgb(238, 238, 238); border: 1px solid rgb(187, 187, 187); color: black; padding: 10px;&quot;&gt;From: wasbigtalk-admin@example.com&lt;br /&gt;To: jan@example.com&lt;br /&gt;Subject: please confirm unsubscribe from wasbigtalk (4bc3b7e439fd)&lt;br /&gt;&lt;br /&gt;Hello jan@example.com,&lt;br /&gt;&lt;br /&gt;We have received a request to unsubscribe you from wasbigtalk.&lt;br /&gt;Please confirm this request to unsubscribe by replying to this email.&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;Then the backend extension responds with a message confirming the request that includes the unique token:&lt;br /&gt;&lt;pre style=&quot;background-color: rgb(238, 238, 238); border: 1px solid rgb(187, 187, 187); color: black; padding: 10px;&quot;&gt;From: jan@example.com&lt;br /&gt;To: wasbigtalk-admin@example.com&lt;br /&gt;Subject: Re: please confirm unsubscribe from wasbigtalk (4bc3b7e439fd)&lt;/pre&gt;&lt;br /&gt;Finally, the server responds with a message confirming that the subscriber has, indeed, been unsubscribed:&lt;br /&gt;&lt;pre style=&quot;background-color: rgb(238, 238, 238); border: 1px solid rgb(187, 187, 187); color: black; padding: 10px;&quot;&gt;From: wasbigtalk-admin@example.com&lt;br /&gt;To: jan@example.com&lt;br /&gt;Subject: you have been unsubscribed from wasbigtalk&lt;br /&gt;&lt;br /&gt;Hello jan@example.com,&lt;br /&gt;&lt;br /&gt;Your unsubscription from wasbigtalk was successful.&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;At this point, the backend extension marks the list unsubscribed in the database, and the frontend extension marks it unsubscribed in the user interface.&lt;br /&gt;&lt;br /&gt;This process matches the way much mailing list server software works, although there are daemons in the details, so the extensions have to be programmed to support each server individually.&lt;br /&gt;&lt;br /&gt;Currently, they know how to handle &lt;a href=&quot;http://groups.google.com/&quot;&gt;Google Groups&lt;/a&gt; and &lt;a href=&quot;http://www.gnu.org/software/mailman/&quot;&gt;Mailman&lt;/a&gt; lists. &lt;a href=&quot;http://www.mj2.org/&quot;&gt;Majordomo2&lt;/a&gt; (used by the &lt;a href=&quot;http://www.bugzilla.org/&quot;&gt;Bugzilla&lt;/a&gt; and &lt;a href=&quot;http://www.openbsd.org/&quot;&gt;OpenBSD&lt;/a&gt; projects, among others) is not supported, because it doesn&#39;t send &lt;tt&gt;List-*&lt;/tt&gt; headers (alhough supposedly it can be configured to do so). The &lt;a href=&quot;http://www.w3.org/&quot;&gt;W3C&lt;/a&gt;&#39;s list server is not yet supported, although it does send &lt;tt&gt;List-*&lt;/tt&gt; headers, and support should be fairly easy to add.&lt;br /&gt;&lt;br /&gt;Note that some of the processing the extension does is (locale-dependent) &quot;screen&quot;-scraping, as Google Groups and Mailman don&#39;t consistently identify the list ID and message type in some of their correspondence. In the long run, hopefully server software will improve in that regard. Perhaps someone can spearhead an effort to make it so?&lt;br /&gt;&lt;h3&gt;The Future&lt;/h3&gt;The extensions&#39; current features fit in well with Raindrop&#39;s goal of helping people better handle their flood of incoming messages. But there is surely much more they could do to help in this regard.&lt;br /&gt;&lt;br /&gt;Besides general improvements to reliability and robustness--like support for additional list servers and handling of localized admin messages--they could let you resubscribe to a mailing list from which you&#39;ve unsubscribed. And perhaps they could automatically fetch the messages you missed while you were away. Or even retrieve the entire archive of a list to which you&#39;re subscribed, so you can browse the archive in Raindrop!&lt;br /&gt;&lt;br /&gt;What bugs you about mailing lists? And how might Raindrop&#39;s mailing list extensions make them easier (and even funner) to use?</content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/7015776887411907934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=7015776887411907934' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7015776887411907934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7015776887411907934'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2009/11/skinny-on-raindrops-mailing-list.html' title='The Skinny on Raindrop&#39;s Mailing List Extensions'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18929277.post-7740719470656815276</id><published>2009-11-04T15:58:00.001-08:00</published><updated>2009-11-04T15:58:03.687-08:00</updated><title type='text'>Building/Releasing Personas</title><content type='html'>Want to know how a popular extension like Personas gets built and released? Neither do I! Yet I know anyway. And I&#39;ve written it down for your edification! So &lt;a href=&quot;https://wiki.mozilla.org/Labs/Personas/Build&quot;&gt;check it out&lt;/a&gt;.&lt;br&gt; &lt;br&gt; </content><link rel='replies' type='application/atom+xml' href='http://mykzilla.blogspot.com/feeds/7740719470656815276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18929277&amp;postID=7740719470656815276' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7740719470656815276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18929277/posts/default/7740719470656815276'/><link rel='alternate' type='text/html' href='http://mykzilla.blogspot.com/2009/11/buildingreleasing-personas.html' title='Building/Releasing Personas'/><author><name>Myk Melez</name><uri>http://www.blogger.com/profile/01837818348188071923</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-_YZppM5V97U/VedxzrpG9BI/AAAAAAAAAGA/wHrKKAgCoH0/s220/headshot-2014.jpg'/></author><thr:total>0</thr:total></entry></feed> \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/resources/feed_atom_feedburner.xml b/mobile/android/tests/background/junit4/resources/feed_atom_feedburner.xml
deleted file mode 100644
index 85c4aaddf..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_atom_feedburner.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><id>tag:blogger.com,1999:blog-1531829516427013333</id><updated>2016-01-21T16:20:29.143+01:00</updated><category term="Instant Mustache" /><category term="Intent" /><category term="ViewPager" /><category term="camera" /><category term="BlinkLayout" /><category term="CameraFragment" /><category term="Layout" /><category term="ViewGroup" /><category term="glass" /><category term="google glass" /><category term="picture" /><category term="API" /><category term="Animation" /><category term="Boolean" /><category term="Clean Code" /><category term="Discovery" /><category term="External storage" /><category term="Fragment" /><category term="FragmentPagerAdapter" /><category term="FragmentStatePagerAdapter" /><category term="Framework" /><category term="Handler" /><category term="Integer" /><category term="IntentService" /><category term="Library" /><category term="Looper" /><category term="MediaScanner" /><category term="Minimal marketable app" /><category term="Network" /><category term="Offscreen pages" /><category term="OnClickListener" /><category term="OnPageChangeListener" /><category term="OrientationEventListener" /><category term="PagerAdapter" /><category term="Resources" /><category term="SeekBar" /><category term="Service" /><category term="Sharing" /><category term="String" /><category term="SurfaceView" /><category term="TextUtils" /><category term="UI" /><category term="Uri" /><category term="bezel swipe" /><category term="fake dragging" /><category term="firefox" /><category term="gdk" /><category term="immersion" /><category term="margin" /><category term="mirror api" /><category term="mockup" /><category term="mozilla" /><category term="orientation" /><category term="restricted profiles" /><category term="roadmap" /><category term="rotation" /><category term="scrolling" /><category term="sketch" /><category term="support library" /><category term="voice input" /><title type="text">Android Zeitgeist</title><subtitle type="html" /><link rel="alternate" type="text/html" href="http://www.androidzeitgeist.com/" /><author><name>Sebastian Kaspari</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>23</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/AndroidZeitgeist" /><feedburner:info uri="androidzeitgeist" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-4435702616301783869</id><published>2015-09-17T19:46:00.000+02:00</published><updated>2015-09-17T19:46:08.239+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="firefox" /><category scheme="http://www.blogger.com/atom/ns#" term="mozilla" /><category scheme="http://www.blogger.com/atom/ns#" term="restricted profiles" /><title type="text">Support for restricted profiles in Firefox 42</title><content type="html">One of our goals for &lt;a href="https://www.mozilla.org/en-US/firefox/android/"&gt;Firefox for Android&lt;/a&gt; 42.0 was to create a kid and parent-friendly web experience (Project &lt;i&gt;KinderFox / KidFox&lt;/i&gt;): The browser should be easy to use for a kid and at the same time parents want to be in control and decide what the kid can do with it.&lt;br /&gt;&lt;br /&gt;There are a lot of things you can do to create a kid-friendly browsing experience. In this first version we focused on making the browser simpler by hiding complex or kid-unfriendly features and utilizing the parental controls of the Android system: &lt;i&gt;Restricted profiles&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What are restricted profiles?&lt;/h3&gt;&lt;br /&gt;Restricted Profiles have been introduced in Android 4.3. The device administrator can create these profiles and restrict access to apps and features on the device. In addition to that restrictions inside an app can be configured if supported by the app.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-2nsGZS3PMBQ/VeSXR42xZcI/AAAAAAAAluA/eXr4RUP6QQs/s1600/restricted-profiles-settings.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" src="http://4.bp.blogspot.com/-2nsGZS3PMBQ/VeSXR42xZcI/AAAAAAAAluA/eXr4RUP6QQs/s640/restricted-profiles-settings.png" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Configuring which apps the restricted profile can acccess.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;A unique feature of restricted profiles is that they share the Google account of the device owner. It does not allow full-access to everything connected to the account but it allows the restricted user to watch content (e.g. movies and music) bought with that account or use paid applications. Of course only if the device owner explicitly allowed this. &lt;br /&gt;&lt;br /&gt;Unfortunately Restricted Profiles are only supported on tablets so far. It is a pity because in the meantime Google allowed to create full-featured and guest profiles on phones too.&lt;br /&gt;&lt;br /&gt;The following DevBytes episodes gives a good overview about the Restricted Profiles APIs:&lt;br /&gt;&lt;br /&gt;&lt;iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/pdUcANNm72o" width="560"&gt;&lt;/iframe&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Being in control&lt;/h3&gt;&lt;br /&gt;Our final list of restrictable features for Firefox 42 contains 10 items:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;Disable add-on installation &lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Disable 'Import from Android' (Bookmark import) &lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Disable developer tools &lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Disable Home customization (&lt;a href="https://hacks.mozilla.org/2014/07/building-firefox-hub-add-ons-for-firefox-for-android/"&gt;Home panels&lt;/a&gt;) &lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Disable Private Browsing &lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Disable Location Services (Contributing to &lt;a href="https://location.services.mozilla.com/"&gt;Mozilla's Location Service&lt;/a&gt;) &lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Disable Display settings &lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Disable 'Clear browsing history' &lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Disable master password &lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Disable Guest Browsing &lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;br /&gt;Limiting access to features is a very personal decision. Not every parent wants to control every aspect of the browsing experience. That's why we decided to make these restrictions configurable by the parent. By implementing a broadcast receiver that listens to &lt;a href="https://developer.android.com/reference/android/content/Intent.html#ACTION_GET_RESTRICTION_ENTRIES"&gt;ACTION_GET_RESTRICTION_ENTRIES&lt;/a&gt; actions it's possible to send a list of restrictions to the system and so they will show up in the admin interface:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-9loC85f7nwM/VfrYo9ck7lI/AAAAAAAAmXo/ffox2Np3nZk/s1600/app-restrictions.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/-9loC85f7nwM/VfrYo9ck7lI/AAAAAAAAmXo/ffox2Np3nZk/s640/app-restrictions.png" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Configuring restrictions of an application.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Later the application can query the &lt;a href="http://developer.android.com/reference/android/os/UserManager.html"&gt;UserManager&lt;/a&gt; to ask which restrictions have been enabled or disabled.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Technical details&lt;/h3&gt;&lt;br /&gt;&lt;b&gt;User restrictions vs. application restrictions&lt;/b&gt;&lt;br /&gt;There are two kinds of restrictions. &lt;a href="http://developer.android.com/reference/android/os/UserManager.html#getUserRestrictions%28%29"&gt;User restrictions&lt;/a&gt; are imposed on the user by the system and &lt;a href="http://developer.android.com/reference/android/os/UserManager.html#getApplicationRestrictions%28java.lang.String%29"&gt;application restrictions&lt;/a&gt; are added by an application via the broadcast mechanism mentioned above. An application can query the &lt;a href="http://developer.android.com/reference/android/os/UserManager.html"&gt;UserManager&lt;/a&gt; only for its own and global user restrictions.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Detecting restricted profiles&lt;/b&gt;&lt;br /&gt;One of the first things you might want to do in your app is to detect if the current user is using a restricted or a normal profile. There's no API method to do that and the video linked above suggests to query the user restrictions from the &lt;a href="http://developer.android.com/reference/android/os/UserManager.html"&gt;UserManager&lt;/a&gt; and if the returned bundle is not empty then you are in a restricted profile.&lt;br /&gt;&lt;br /&gt;This worked fine until we deployed the application to a phone running an Android M preview build. On this phone - that doesn't even support restricted profiles - the &lt;a href="http://developer.android.com/reference/android/os/UserManager.html"&gt;UserManager&lt;/a&gt; always returned a restriction. Whoops, suddenly everyone with Android M on their phones had a very limited &lt;a href="https://nightly.mozilla.org/"&gt;Firefox Nightly&lt;/a&gt;. We then switched to iterating over the returned Bundles (for application and user restrictions) and only assuming we are in a restricted profile if at least one restriction in those bundles is enabled (&lt;i&gt;getBoolean()&lt;/i&gt; returns true).&lt;br /&gt;&lt;br /&gt;In general it is a better approach to never detect whether you are in a restricted profile or not but instead always check whether a specific (application) restriction is enabled or not.&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A resource qualifier would be nice&lt;/b&gt;&lt;br /&gt;Hiding features and UI in restricted profiles will add a lot of &lt;i&gt;if&lt;/i&gt; statements to the code base. It would have been nice to have a &lt;a href="http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources"&gt;resource qualifier&lt;/a&gt; for restricted profiles to load different layouts, drawables and other configurations. Besides that this would also solve the "detect restricted profile" problem quite elegant.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Strict mode: Disk read violation&lt;/b&gt;&lt;br /&gt;At runtime we noticed that we have been triggering a lot of disk read violations. Looking at &lt;a href="http://androidxref.com/5.1.1_r6/xref/frameworks/base/services/core/java/com/android/server/pm/UserManagerService.java#readApplicationRestrictionsLocked"&gt;Android's source code&lt;/a&gt; it turns out that &lt;a href="http://developer.android.com/reference/android/os/UserManager.html#getApplicationRestrictions%28java.lang.String%29"&gt;UserManager.getApplicationRestrictions()&lt;/a&gt; reads and parses an XML file on every call. Without caching anything like &lt;a href="http://developer.android.com/reference/android/content/SharedPreferences.html"&gt;SharedPreferences&lt;/a&gt; do. We worked around that by implementing our own memory cache and refreshing the list of restrictions whenever the application is resumed. To update restrictions the user will always have to switch to the admin profile and therefore leave (and later resume) the application.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;No Fun&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Android Marshmallow (6.0) introduced a new &lt;i&gt;Easter egg&lt;/i&gt; system restriction: &lt;a href="http://developer.android.com/reference/android/os/UserManager.html#DISALLOW_FUN"&gt;UserManager.DISALLOW_FUN&lt;/a&gt; - &lt;i&gt;Specifies if the user is not allowed to have fun. In some cases, the device owner may wish to prevent the user from experiencing amusement or joy while using the device. The default value is false&lt;/i&gt;.&amp;nbsp;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;What's next?&lt;/h3&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-8hdHsE2sf6Q/Vfr6lwJChxI/AAAAAAAAmZA/lSpXgbzrKsQ/s1600/kidbrowser.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" src="http://3.bp.blogspot.com/-8hdHsE2sf6Q/Vfr6lwJChxI/AAAAAAAAmZA/lSpXgbzrKsQ/s640/kidbrowser.png" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Simplified browser UI with custom theme using a restricted profile (Firefox 42).&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;With the current set of restrictions parents can create a kid-friendly and simplified browsing experience. Of course there are a lot of more possible features around parental controls that come to mind like block lists and restricting Web APIs (Microphone, Webcam). Some of these ideas have already been filed (&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1125710"&gt;Bug 1125710&lt;/a&gt;) and in addition to that we just started planning features for the next version (&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1205615"&gt;Bug 1205615&lt;/a&gt;). More ideas are definitely welcome!&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Testing and feedback&lt;/h3&gt;&lt;br /&gt;At the time of this writing support for restricted profiles is available in &lt;a href="https://ftp.mozilla.org/pub/mozilla.org/mobile/nightly/latest-mozilla-aurora-android-api-11/"&gt;Aurora&lt;/a&gt; (42.0) and &lt;a href="https://nightly.mozilla.org/"&gt;Nightly&lt;/a&gt; (43.0) builds of Firefox. Restricted Profiles serve a very specific use case and therefore do not get as much usage coverage like other browser features. If you do have a tablet and are interested in restricted profiles then help us testing it! :)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Contributing &lt;/h3&gt;&lt;br /&gt;Firefox for Android is open-source software and contributors are very welcome!&amp;nbsp;You can find me on IRC (irc.mozilla.org) in #mobile (my nickname is "sebastian"), on &lt;a href="https://twitter.com/Anti_Hype"&gt;Twitter&lt;/a&gt; and &lt;a href="http://plus.google.com/+SebastianKaspari"&gt;Google+&lt;/a&gt;. &lt;a href="https://wiki.mozilla.org/Mobile/Get_Involved"&gt;Get involved with Firefox for Android&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;More resources about Project &lt;i&gt;KidFox&lt;/i&gt;&lt;/h3&gt;&lt;ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://wiki.mozilla.org/Mobile/Projects/Kinderfox"&gt;Mozilla Wiki: Project KinderFox&lt;/a&gt; &lt;/li&gt;&lt;li&gt;&lt;a href="https://wiki.mozilla.org/Mobile/Projects/Kid_browsing"&gt;Mozilla Wiki: KidFox proposal&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://wiki.mozilla.org/Mobile/Briefs/Kidfox"&gt;Mozilla wiki: KidFox brief&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1125710"&gt;Generic meta bug &lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1125984"&gt;Bugzilla meta bug for v1&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1205615"&gt;Bugzilla meta bug for v2&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/xaSicfGuwOU" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/4435702616301783869/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2015/09/support-restricted-profiles-firefox.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/4435702616301783869" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/4435702616301783869" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/xaSicfGuwOU/support-restricted-profiles-firefox.html" title="Support for restricted profiles in Firefox 42" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-2nsGZS3PMBQ/VeSXR42xZcI/AAAAAAAAluA/eXr4RUP6QQs/s72-c/restricted-profiles-settings.png" height="72" width="72" /><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2015/09/support-restricted-profiles-firefox.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-1833936883751020212</id><published>2014-11-20T08:30:00.001+01:00</published><updated>2014-11-20T08:32:09.334+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Discovery" /><category scheme="http://www.blogger.com/atom/ns#" term="Intent" /><category scheme="http://www.blogger.com/atom/ns#" term="Library" /><category scheme="http://www.blogger.com/atom/ns#" term="Network" /><title type="text">Introducing Android Network Intents</title><content type="html">&lt;a href="https://github.com/pocmo/Android-Network-Intents"&gt;Android Network Intents&lt;/a&gt; is a library that I wrote for &lt;a href="http://landsofruin.com/"&gt;Lands of Ruin&lt;/a&gt; - a game that two friends and I are developing. To avoid a complicated network setup to play the game against a friend, we needed a way to discover games running on the local network. Android offers a &lt;a href="http://developer.android.com/training/connect-devices-wirelessly/nsd.html"&gt;Network Service Discovery (NSD)&lt;/a&gt; since API level 16 (Android 4.1) but we kept running into problems using it. This lead to writing this library.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;What does the library do?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;The library allows you to send &lt;a href="http://developer.android.com/reference/android/content/Intent.html"&gt;Intents&lt;/a&gt; to listening clients on the local network (WiFi) without knowing who these clients are. Sender and receiver do not need to connect to each other. Therefore the library can be used to write custom discovery protocols.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Sending Intents (Transmitter)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;An &lt;i&gt;Intent&lt;/i&gt; is sent by using the&amp;nbsp;&lt;i&gt;Transmitter&lt;/i&gt;&amp;nbsp;class. A&amp;nbsp;&lt;i&gt;TransmitterException&lt;/i&gt;&amp;nbsp;is thrown in case of error.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-r6N5E7HFdJc/VGyPPqvem4I/AAAAAAAAbn8/aJ_XtPS7lkU/s1600/Screen%2BShot%2B2014-11-19%2Bat%2B13.33.29.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-r6N5E7HFdJc/VGyPPqvem4I/AAAAAAAAbn8/aJ_XtPS7lkU/s1600/Screen%2BShot%2B2014-11-19%2Bat%2B13.33.29.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Network-Intents/wiki/Sending-Intents"&gt;Sending an Intent&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Receiving Intents (Receiver)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Intents are received using the&amp;nbsp;&lt;i&gt;Discovery&lt;/i&gt;&amp;nbsp;class. Once started by calling&amp;nbsp;&lt;i&gt;enable()&lt;/i&gt;&amp;nbsp;the&amp;nbsp;&lt;i&gt;Discovery&lt;/i&gt;&amp;nbsp;class will spawn a background thread that will wait for incoming&amp;nbsp;&lt;i&gt;Intent&lt;/i&gt;&amp;nbsp;objects. A&amp;nbsp;&lt;i&gt;DiscoveryListener&lt;/i&gt;&amp;nbsp;instance will be notified about every incoming&amp;nbsp;&lt;i&gt;Intent&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-fNRqCrKBhbg/VGyPnT00VdI/AAAAAAAAboE/XnejMaKLuyw/s1600/Screen%2BShot%2B2014-11-19%2Bat%2B13.37.46.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-fNRqCrKBhbg/VGyPnT00VdI/AAAAAAAAboE/XnejMaKLuyw/s1600/Screen%2BShot%2B2014-11-19%2Bat%2B13.37.46.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Network-Intents/wiki/Receiving-Intents"&gt;Writing a DiscoveryListener to receive events.&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-_GOcgSh-4qY/VGyPpC2sA-I/AAAAAAAAboM/TVMtxnj-zKk/s1600/Screen%2BShot%2B2014-11-19%2Bat%2B13.37.55.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-_GOcgSh-4qY/VGyPpC2sA-I/AAAAAAAAboM/TVMtxnj-zKk/s1600/Screen%2BShot%2B2014-11-19%2Bat%2B13.37.55.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Network-Intents/wiki/Receiving-Intents"&gt;Starting and stoping the discovery.&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Things you should know&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;The Intents are sent as &lt;a href="http://en.wikipedia.org/wiki/Multicast"&gt;UDP multicast&lt;/a&gt; packets. Unlike TCP the UDP protocol does not guarantee that a sent packet will be received and there is no confirmation or retry mechanism. Even though losing a packet only happens rarely in a stable WiFi, the library is not intended for using as a stable &lt;i&gt;communication&lt;/i&gt; protocol. Instead you can use it to find other clients (by sending an Intent in a periodic interval) and then establish a stable TCP connection for communication.&lt;br /&gt;&lt;br /&gt;On GitHub you can find a &lt;a href="https://github.com/pocmo/Android-Network-Intents/tree/master/samples"&gt;chat sample application&lt;/a&gt; using the library. While this is a convenient example, it is not a good use of the library for the reasons state above. You obviously do not want to lose chat messages.&lt;br /&gt;&lt;br /&gt;We are using the library for almost two years in Lands of Ruin and didn't observe any problems. However the game only runs on tablets so far. In theory the library should run on all Android versions back to API level 3 (Android 1.5) but this has obviously never been tested.&lt;br /&gt;&lt;br /&gt;You can find &lt;a href="https://github.com/pocmo/Android-Network-Intents"&gt;Android Network Intents on GitHub&lt;/a&gt;.&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/frg0Ba2z4H0" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/1833936883751020212/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2014/11/introducing-android-network-intents17.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/1833936883751020212" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/1833936883751020212" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/frg0Ba2z4H0/introducing-android-network-intents17.html" title="Introducing Android Network Intents" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-r6N5E7HFdJc/VGyPPqvem4I/AAAAAAAAbn8/aJ_XtPS7lkU/s72-c/Screen%2BShot%2B2014-11-19%2Bat%2B13.33.29.png" height="72" width="72" /><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2014/11/introducing-android-network-intents17.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-8654031246499256112</id><published>2013-12-24T15:24:00.001+01:00</published><updated>2013-12-24T15:24:38.598+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="glass" /><category scheme="http://www.blogger.com/atom/ns#" term="google glass" /><category scheme="http://www.blogger.com/atom/ns#" term="immersion" /><category scheme="http://www.blogger.com/atom/ns#" term="voice input" /><title type="text">Hello World Immersion - Developing for Google Glass #2</title><content type="html">This article describes how to create a simple hello world application for Google Glass using the&amp;nbsp;Glass Development Kit (GDK). As described in the &lt;a href="http://www.androidzeitgeist.com/2013/12/mirror-api-gdk-developing-google-glass.html"&gt;previous article&lt;/a&gt; you have two options how your Glassware should show up on the device: As a &lt;i&gt;live card&lt;/i&gt; that is part of the timeline or as an &lt;i&gt;immersion&lt;/i&gt;&amp;nbsp;that is displayed outside of the context of the timeline. This article focuses on how to write an immersion.&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;What is an immersion?&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;An immersion is basically an Android activity. The name immersion implies that it is not part of the normal Glass timeline. Instead it takes full control of the device - except for the back gesture (Swipe down). To go back to the timeline you need to leave the immersion.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-75TfF3lNoWs/UrhgTb9OPZI/AAAAAAAASH4/wESuu-yTUy4/s1600/glass_timeline_immersion.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-75TfF3lNoWs/UrhgTb9OPZI/AAAAAAAASH4/wESuu-yTUy4/s1600/glass_timeline_immersion.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Once started an immersion takes full control of the screen.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Project setup&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Create a normal Android project with the following settings:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Set &lt;i&gt;minSdkVersion&lt;/i&gt; and &lt;i&gt;targetSdkVersion&lt;/i&gt; to 15 (Android 4.0.3)&lt;/li&gt;&lt;li&gt;Set &lt;i&gt;compileSdkVersion&lt;/i&gt; to&amp;nbsp;&lt;i&gt;"Google Inc.:Glass Development Kit Sneak Peek:15"&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Do not assign a theme to your application or derive your own theme from&amp;nbsp;&lt;i&gt;Theme.DeviceDefault&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Creating the immersion&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Let's create a simple activity. The &lt;a href="https://developers.google.com/glass/develop/gdk/reference/com/google/android/glass/app/Card"&gt;Card&lt;/a&gt; class helps us to create a layout that looks like a timeline card.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Fj2t5BJi7yk/Urlo4Z4_FYI/AAAAAAAASI0/4qv2fF4ElX8/s1600/helloworldactivity.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-Fj2t5BJi7yk/Urlo4Z4_FYI/AAAAAAAASI0/4qv2fF4ElX8/s1600/helloworldactivity.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/blob/master/Glass/HelloWorldImmersion/HelloWorld/src/main/java/de/androidzeitgeist/glass/helloworld/immersion/HelloWorldActivity.java"&gt;HelloWorldActivity.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Launching the Glassware - Voice commands&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;After creating the activity we need a way to start our Glassware. A common way to launch Glassware is to use a voice trigger. Let's add a simple voice trigger to start our &lt;i&gt;hello world&lt;/i&gt; activity.&lt;br /&gt;&lt;br /&gt;First we need to declare a string resource for our voice command.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-MnJseZKHYxY/Url83ImZEZI/AAAAAAAASJc/Lrxu_J2gZ8w/s1600/resource_hello_world.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-MnJseZKHYxY/Url83ImZEZI/AAAAAAAASJc/Lrxu_J2gZ8w/s1600/resource_hello_world.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/blob/master/Glass/HelloWorldImmersion/HelloWorld/src/main/res/values/strings.xml"&gt;strings.xml&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The next step is to create an XML resource file for the voice trigger using the previously created string value.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-8y21kaJD3fI/Url839921yI/AAAAAAAASJw/HUZ4Po3-lr4/s1600/trigger_hello_world.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-8y21kaJD3fI/Url839921yI/AAAAAAAASJw/HUZ4Po3-lr4/s1600/trigger_hello_world.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/blob/master/Glass/HelloWorldImmersion/HelloWorld/src/main/res/xml/voice_trigger.xml"&gt;voice_trigger.xml&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Now we can add an intent filter for the VOICE_TRIGGER action to our activity. A meta-data tag links it to the XML file we wrote above.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-GfHAXMZTDas/Url83illC8I/AAAAAAAASJs/oBmo7h4_Tuk/s1600/hello_world_activity.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-GfHAXMZTDas/Url83illC8I/AAAAAAAASJs/oBmo7h4_Tuk/s1600/hello_world_activity.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/blob/master/Glass/HelloWorldImmersion/HelloWorld/src/main/AndroidManifest.xml"&gt;AndroidManifest.xml&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The developer guide requires you to add an icon for the touch menu to the activity (white in color on transparent background, 50x50 pixels). The&amp;nbsp;&lt;a href="http://glass-asset-utils.appspot.com/icons-submission.html"&gt;Glass Asset Studio&lt;/a&gt;&amp;nbsp;is a helpful tool to generate these icons.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-MWCSEYXWpUQ/UrmYIdPJp6I/AAAAAAAASKE/h2c7egiWuNs/s1600/50x50_icon.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-MWCSEYXWpUQ/UrmYIdPJp6I/AAAAAAAASKE/h2c7egiWuNs/s1600/50x50_icon.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;The final Glassware&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Now we can start our Glassware by saying "&lt;i&gt;ok glass, show hello world&lt;/i&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-R3N3nwLXIIg/UrlsMbHPgkI/AAAAAAAASJA/9P6foH55OUc/s1600/hello_world_glassware.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="340" src="http://4.bp.blogspot.com/-R3N3nwLXIIg/UrlsMbHPgkI/AAAAAAAASJA/9P6foH55OUc/s400/hello_world_glassware.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Another option to start our Glassware is to use the touch menu and scroll to the "&lt;i&gt;show hello world&lt;/i&gt;" command:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-5KjJBjb5qn4/UrlupI3MTuI/AAAAAAAASJM/j6-nNCKgWJM/s1600/hello_world_glassware_menu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="340" src="http://2.bp.blogspot.com/-5KjJBjb5qn4/UrlupI3MTuI/AAAAAAAASJM/j6-nNCKgWJM/s400/hello_world_glassware_menu.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The source code for this &lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/tree/master/Glass/HelloWorldImmersion"&gt;Hello World Glassware is available on GitHub&lt;/a&gt;.&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/fr-WO1v1SIU" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/8654031246499256112/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2013/12/google-glass-immersion-hello-world.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8654031246499256112" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8654031246499256112" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/fr-WO1v1SIU/google-glass-immersion-hello-world.html" title="Hello World Immersion - Developing for Google Glass #2" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-75TfF3lNoWs/UrhgTb9OPZI/AAAAAAAASH4/wESuu-yTUy4/s72-c/glass_timeline_immersion.png" height="72" width="72" /><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2013/12/google-glass-immersion-hello-world.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-5605536583111663735</id><published>2013-12-22T13:03:00.001+01:00</published><updated>2013-12-22T13:03:25.308+01:00</updated><title type="text">Android 2013</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-swoL-7rAksk/UrbIgrRXS0I/AAAAAAAASEk/FuB-KSnuxuU/s1600/android_2013.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-swoL-7rAksk/UrbIgrRXS0I/AAAAAAAASEk/FuB-KSnuxuU/s1600/android_2013.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;It's the end of the year - &lt;a href="http://www.youtube.com/watch?v=H7jtC8vjXw8"&gt;YouTube&lt;/a&gt; and &lt;a href="http://www.youtube.com/watch?v=Lv-sY_z8MNs"&gt;Google Zeitgeist&lt;/a&gt; have posted their reviews. Let's have a look on what happened in the Android world in 2013.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-S2ecXdl66_I/UrbQgaKZPxI/AAAAAAAASFE/qChEPdoly-w/s1600/nexus4.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="200" src="http://4.bp.blogspot.com/-S2ecXdl66_I/UrbQgaKZPxI/AAAAAAAASFE/qChEPdoly-w/s200/nexus4.png" width="200" /&gt;&lt;/a&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;January&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;2012 is over and the Nexus 4 is the current flagship phone made by Google and LG.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;February&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://android-developers.blogspot.de/2013/02/google-sign-in-now-part-of-google-play.html"&gt;Google+ Sign-In is integrated&lt;/a&gt; into the Google Play Services and Google starts accepting &lt;a href="http://www.nytimes.com/2013/02/21/technology/google-looks-to-make-its-computer-glasses-stylish.html?_r=0"&gt;applications for the Google Glass Explorer program&lt;/a&gt;.&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;March&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;The new &lt;a href="http://android-developers.blogspot.de/2013/03/now-is-time-to-switch-to-new-google.html"&gt;Android developer console is out of preview&lt;/a&gt;. While &lt;a href="http://officialandroid.blogspot.de/2013/03/celebrating-google-plays-first-birthday.html"&gt;Google Play celebrates it first birthday&lt;/a&gt;, the &lt;a href="http://techcrunch.com/2013/07/01/android-led-by-samsung-continues-to-storm-the-smartphone-market-pushing-a-global-70-market-share/?ncid=tcdaily"&gt;market share of Android hits 64%&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;April&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;The &lt;a href="http://android-developers.blogspot.de/2013/04/update-on-tablet-app-guidelines-and.html"&gt;tablet guidelines are updated&lt;/a&gt; and the Android developer console starts to &lt;a href="http://android-developers.blogspot.de/2013_04_01_archive.html"&gt;show tablet optimization tips&lt;/a&gt;. Google pushes a &lt;a href="http://android-developers.blogspot.de/2013/04/new-look-new-purchase-flow-in-google.html"&gt;Google Play app update&lt;/a&gt; that features a redesigned UI. Samsung releases it new flaship phone - &lt;a href="http://en.wikipedia.org/wiki/Samsung_Galaxy_S4"&gt;the Samsung Galaxy S4&lt;/a&gt;.&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;May&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-wZeaMyx7VUs/UrbPAzv69mI/AAAAAAAASE4/-VEbnrV9MF4/s1600/io2013.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-wZeaMyx7VUs/UrbPAzv69mI/AAAAAAAASE4/-VEbnrV9MF4/s1600/io2013.png" /&gt;&lt;/a&gt;The &lt;a href="https://developers.google.com/events/io/"&gt;Google I/O&lt;/a&gt;&amp;nbsp;takes place for three days from May 15th to 17th. This time there won't be a new Android release. Instead Google releases &lt;a href="http://android-developers.blogspot.de/2013/05/social-gaming-location-and-more-in.html"&gt;new game services and a new location API&lt;/a&gt;. At the Google I/O a new IDE for Android development is introduced: &lt;a href="http://android-developers.blogspot.de/2013/05/android-studio-ide-built-for-android.html"&gt;Android Studio&lt;/a&gt;. Since then every couple of weeks a new Android Studio update is pushed to the developer community.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt; &lt;span style="font-size: large;"&gt;&lt;b&gt;July&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;A new flavor of Android Jelly Bean is released: &lt;a href="http://android-developers.blogspot.de/2013/07/android-43-and-updated-developer-tools.html"&gt;Android 4.3&lt;/a&gt;. Open GL ES 3.0 and support for&amp;nbsp;low-power Bluetooth Smart devices are some of the new features. Furthermore a new version of the Nexus 7 is released. Together with the new tablet Google &lt;a href="http://officialandroid.blogspot.de/2013/07/from-tvs-to-tablets-everything-you-love.html"&gt;releases the Chromecast dongle&lt;/a&gt; and the &lt;a href="http://googledevelopers.blogspot.de/2013/07/cast-content-from-your-apps-to-tv-with.html"&gt;Google Cast SDK preview&lt;/a&gt;.&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;August&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Google releases &lt;a href="http://android-developers.blogspot.de/2013/08/google-play-services-32.html"&gt;version 3.2 of the Google Play Services&lt;/a&gt;. The update&amp;nbsp;includes several enhancements to the Location Based Services. With the r18 release of the support library Google&amp;nbsp;released a new backward-compatible &lt;a href="http://android-developers.blogspot.de/2013/08/actionbarcompat-and-io-2013-app-source.html"&gt;Action Bar implementation called ActionBarCompat&lt;/a&gt;. Motorola is releasing the &lt;a href="http://en.wikipedia.org/wiki/Moto_X"&gt;Moto X&lt;/a&gt; - its first phone since the company has been acquired by Google. The same month &lt;a href="https://plus.google.com/u/0/+HugoBarra/posts/BzZMqRht1xQ"&gt;Hugo Barra announces to leave Google&lt;/a&gt; after 5½ years to join the Xiaomi team in China.&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;September&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://android-developers.blogspot.de/2013/09/renderscript-in-android-support-library.html"&gt;RenderScript is now part of the support library&lt;/a&gt; and can be used&amp;nbsp;on plaform versions all the way back to Android 2.2 (Froyo). Jean-Baptiste Queru, who worked on the Android Open Source Project at Google, &lt;a href="http://www.androidpolice.com/2013/09/17/jean-baptiste-queru-now-at-yahoo-as-senior-principal-engineer-working-on-mobile-apps/"&gt;starts a new job at Yahoo&lt;/a&gt;. Google launches the &lt;a href="http://officialandroid.blogspot.de/2013/08/find-your-lost-phone-with-android.html"&gt;Android device manager website&lt;/a&gt; to&amp;nbsp;locate, lock and ring misplaced devices.&lt;br /&gt;&lt;br /&gt; &lt;a href="http://1.bp.blogspot.com/-qksojJjcafk/UrbQ_JNFI_I/AAAAAAAASFM/mOaNvKPz2d0/s1600/nexus5.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="200" src="http://1.bp.blogspot.com/-qksojJjcafk/UrbQ_JNFI_I/AAAAAAAASFM/mOaNvKPz2d0/s200/nexus5.png" width="200" /&gt;&lt;/a&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;October&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;After a lot of leaks and rumors &lt;a href="https://www.google.com/nexus/5/"&gt;a new Nexus phone is released&lt;/a&gt; on Halloween. Together with the Nexus 5 a new Android version - &lt;a href="http://www.android.com/kitkat/"&gt;Android 4.4 KitKat&lt;/a&gt; - is published.&amp;nbsp;Full-screen immersive mode, a new transitions framework, a printing framework and a storage access framework are some of the many new features. In addition to that he &lt;a href="http://android-developers.blogspot.de/2013/10/google-play-services-40.html"&gt;Google Play Services are updated to version 4.0&lt;/a&gt;. With &lt;a href="https://plus.google.com/+RomainGuy/posts/faCzPs6GKtg"&gt;Romain Guy another popular Android team member is leaving&lt;/a&gt; - but remaining at Google.&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;November&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;The &lt;a href="http://android-developers.blogspot.de/2013/11/app-translation-service-now-available.html"&gt;App Translation Service&lt;/a&gt;, announced at Google I/O, is now available for every developer. Motorola releases a second phone - the &lt;a href="http://en.wikipedia.org/wiki/Moto_G"&gt;Moto G&lt;/a&gt;. Android hits a new record with &lt;a href="http://www.highlightpress.com/android-tops-80-global-smartphone-market-share-windows-phone-up-156-year-on-year/6708/tharper"&gt;80% market share&lt;/a&gt;. The Google Glass team releases a first sneak peek version of the &lt;a href="https://developers.google.com/glass/develop/gdk/"&gt;Glass development kit (GDK)&lt;/a&gt;.&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;December&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Two small updates for Android KitKat are released: &lt;a href="http://en.wikipedia.org/wiki/Android_version_history#Android_4.4_KitKat_.28API_level_19.29"&gt;Android 4.4.1 and 4.4.2&lt;/a&gt;. The Android device manager &lt;a href="http://techcrunch.com/2013/12/11/google-android-device-manager-play-store/"&gt;is now available as an app&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;i&gt;Android Design in Action&lt;/i&gt; team releases its 2013 Recap:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/ajO2zFEtEYs" width="560"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;2014?&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;What has been your Android highlight in 2013 and what are your wishes for 2014?&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/f-NE_F-73GY" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/5605536583111663735/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2013/12/android-2013.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/5605536583111663735" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/5605536583111663735" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/f-NE_F-73GY/android-2013.html" title="Android 2013" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-swoL-7rAksk/UrbIgrRXS0I/AAAAAAAASEk/FuB-KSnuxuU/s72-c/android_2013.png" height="72" width="72" /><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2013/12/android-2013.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-3139284173480483099</id><published>2013-12-16T21:21:00.004+01:00</published><updated>2013-12-16T21:21:56.392+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="gdk" /><category scheme="http://www.blogger.com/atom/ns#" term="glass" /><category scheme="http://www.blogger.com/atom/ns#" term="google glass" /><category scheme="http://www.blogger.com/atom/ns#" term="mirror api" /><title type="text">Mirror API and GDK - Developing for Google Glass #1</title><content type="html">I recently got my hands on&lt;a href="http://www.google.com/glass/start/"&gt; Google Glass&lt;/a&gt; and decided to write some articles about developing applications for Glass. After all it's Android that is running on Glass.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;What is Glass?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;It's very complicated to explain Google Glass just using text. Only wearing and using it will give you this aha moment. However the following video, made by Google, gives you a good impression about how it feels like.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/v1uyQZNg2vE" width="560"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;What is Glass from a developer's point of view?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Google Glass is an Android device running Android 4.0.3. What you see through Glass is basically a customized &lt;i&gt;Launcher&lt;/i&gt; / &lt;i&gt;Home screen&lt;/i&gt; application (a timeline of cards about current and past events) and a slightly different theme. This makes it really interesting for Android developers to develop for Glass: You can use almost all the familiar Android framework APIs. However wearing Glass feels totally different than using a mobile phone. So there's a big difference in designing applications. But not only the UI is different: You can't just port an existing application to Glass. Use cases have to be designed especially for Glass. Some features of your app might not make sense on Glass. Some other interesting features might only be possible on Glass. It's almost impossible to get a feeling for that without using Glass for some days.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Back to writing code.. Currently we can decide between two ways to develop for Glass: The Mirror API or an early preview of the Glass Development Kit (GDK). Let's have a look at both and see what they are capable of.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;The Mirror API&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;The Mirror API has been the first API that has been introduced by the Glass team. It's a server-side API meaning the applications don't run on Glass itself but on your server and it's your server that interacts with Glass.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Mirror API is great for pushing cards to the timeline of Glass and sharing content from Glass with your server application.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some examples of applications that could use the Mirror API:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Twitter client&lt;/b&gt;: The server pushes interesting tweets to the timeline of the Glass owner. The user can share photos and messages with the application and they will be posted to the Twitter timeline.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Context-aware notifications&lt;/b&gt;: Your server subscribes to the user's location. Every now and then your server will receive the latest user location. You use this location to post interesting and related cards to the timeline of the user.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;b&gt;More about the Mirror API&lt;/b&gt;:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://developers.google.com/glass/develop/mirror/quickstart/"&gt;Google Developers: Mirror API Quick Start&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=CxB1DuwGRqk"&gt;YouTube: Google I/O 2013 - Building Glass Services with the Google Mirror API&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;The Glass Development Kit (GDK)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;With the GDK you can build Android applications that run directly on Glass. Think of the GDK as Android 4.0.3 SDK with some extra APIs for Google Glass. It's worth mentioning that the GDK is currently in an early preview state. The API is not complete and some important parts are missing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When developing Glass you have two options how your application should show up on Glass:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Live Cards&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-wpH3qxEjT_Y/Uq9XLpCVIJI/AAAAAAAAR4A/my3NMMsA1SQ/s1600/glass_timeline_livecard.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-wpH3qxEjT_Y/Uq9XLpCVIJI/AAAAAAAAR4A/my3NMMsA1SQ/s1600/glass_timeline_livecard.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;How a live card shows up in the Glass timeline.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Your application shows up as a card in the timeline (left of the Glass clock). You have again two options how to render these cards:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Low-Frequency Rendering&lt;/b&gt;: Your card is rendered using &lt;a href="https://developer.android.com/reference/android/widget/RemoteViews.html"&gt;Remote Views&lt;/a&gt;. Think of it as a Home screen widget on Android phones. A background service is responsible for updating these views. You only update the views every now and then.&lt;/li&gt;&lt;li&gt;&lt;b&gt;High Frequency Rendering&lt;/b&gt;: Your background service renders directly on the live card's surface. You can draw anything and are not limited to Android views. Furthermore you can update the card many times a second.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;b&gt;Immersion&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-9Wv_J7QV5AM/Uq9XdQLAvuI/AAAAAAAAR4I/AwZ0p8RzYPM/s1600/glass_timeline_immersion.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-9Wv_J7QV5AM/Uq9XdQLAvuI/AAAAAAAAR4I/AwZ0p8RzYPM/s1600/glass_timeline_immersion.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;An Immersion is not part of the timeline but "replaces" it.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;An immersion is at the bottom a regular Android activity. For your activity to look like a timeline card:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Don't assign a theme to your activity or use the DeviceDefault theme as base for your customization.&lt;/li&gt;&lt;li&gt;Even though you can use the touch pad of Glass almost like a d-pad: Try to avoid most input-related Android widgets. They don't make much sense on Glass because you are not using a touch screen. Instead try to use gestures with the &lt;a href="https://developers.google.com/glass/develop/gdk/reference/com/google/android/glass/touchpad/GestureDetector"&gt;GestureDetector&lt;/a&gt;&amp;nbsp;class or &lt;a href="https://developers.google.com/glass/develop/gdk/input/voice"&gt;voice input&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Use the &lt;a href="https://developers.google.com/glass/develop/gdk/reference/com/google/android/glass/app/Card"&gt;Card class&lt;/a&gt; and its &lt;a href="https://developers.google.com/glass/develop/gdk/reference/com/google/android/glass/app/Card#toView()"&gt;toView()&lt;/a&gt; method to create a view that looks like regular Glass card.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;b&gt;More about the GDK&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://developers.google.com/glass/develop/gdk/quick-start"&gt;Google Developers: GDK Quick Start&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=oZSLKtpgQkc"&gt;YouTube: Glass Development Kit Sneak Peek&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/JXGHhmdRusw" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/3139284173480483099/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2013/12/mirror-api-gdk-developing-google-glass.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/3139284173480483099" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/3139284173480483099" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/JXGHhmdRusw/mirror-api-gdk-developing-google-glass.html" title="Mirror API and GDK - Developing for Google Glass #1" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-wpH3qxEjT_Y/Uq9XLpCVIJI/AAAAAAAAR4A/my3NMMsA1SQ/s72-c/glass_timeline_livecard.png" height="72" width="72" /><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2013/12/mirror-api-gdk-developing-google-glass.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-3096175864289654512</id><published>2013-08-22T12:43:00.002+02:00</published><updated>2013-08-22T12:43:53.597+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Framework" /><category scheme="http://www.blogger.com/atom/ns#" term="Handler" /><category scheme="http://www.blogger.com/atom/ns#" term="Intent" /><category scheme="http://www.blogger.com/atom/ns#" term="IntentService" /><category scheme="http://www.blogger.com/atom/ns#" term="Looper" /><category scheme="http://www.blogger.com/atom/ns#" term="Service" /><title type="text">Read the code: IntentService</title><content type="html">&lt;span style="font-size: x-small;"&gt;In the new category &lt;b&gt;Read the code&lt;/b&gt; I’m going to show the internals of the Android framework. Reading the code of the framework can give you a good impression about what’s going on under the hood. In addition to that knowing how the framework developers solved common problems can help you to find the best solutions when facing problems in your own app code.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;What is the IntentService class good for?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;This article is about the &lt;a href="https://developer.android.com/reference/android/app/IntentService.html"&gt;IntentService&lt;/a&gt; class of Android. Extending the IntentService class is the best solution for implementing a background service that is going to process something in a queue-like fashion. You can pass data via &lt;a href="https://developer.android.com/reference/android/content/Intent.html"&gt;Intents&lt;/a&gt; to the IntentService and it will take care of queuing and processing the Intents on a worker thread one at a time. When writing your IntentService implementation you are required to override the &lt;a href="https://developer.android.com/reference/android/app/IntentService.html#onHandleIntent(android.content.Intent)"&gt;onHandleIntent()&lt;/a&gt; method to process the data of the supplied Intents.&lt;br /&gt;&lt;br /&gt;Let’s take a look at a simple example: This DownloadService class receives Uris to download data from. It will download only one thing at a time with the other requests waiting in a queue.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-VJ13VmPcpx4/UhXgpEhsitI/AAAAAAAANSk/ZLzJYR-7ypE/s1600/DownloadService.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-VJ13VmPcpx4/UhXgpEhsitI/AAAAAAAANSk/ZLzJYR-7ypE/s1600/DownloadService.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/blob/master/IntentService/DownloadService.java"&gt;DownloadService&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;The components&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Before we dip into the source code of the IntentService class, let's first take a look at the different components that we need to know in order to understand the source code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Handler&lt;/b&gt;&amp;nbsp;(&lt;a href="https://developer.android.com/reference/android/os/Handler.html"&gt;documentation&lt;/a&gt;) (&lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/os/Handler.java"&gt;source code&lt;/a&gt;)&lt;br /&gt;You may already have used Handler objects. When a Handler is created on the UI thread, messages can be posted to it and these messages will be processed on the UI thread.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ServiceHandler&lt;/b&gt;&amp;nbsp;(&lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/app/IntentService.java#58"&gt;source code&lt;/a&gt;)&lt;br /&gt;The ServiceHandler inner-class is a helper class extending the Handler class to delegate the Intent wrapped inside a Message object to the IntentService for processing.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/--OVWzXz_dlQ/UhXZNL7nZII/AAAAAAAANR0/3pWwyp_Iw3g/s1600/ServiceHandler.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/--OVWzXz_dlQ/UhXZNL7nZII/AAAAAAAANR0/3pWwyp_Iw3g/s1600/ServiceHandler.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/app/IntentService.java#58"&gt;ServiceHandler inner class of&amp;nbsp;android.app.IntentService&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;Looper&lt;/b&gt;&amp;nbsp;(&lt;a href="https://developer.android.com/reference/android/os/Looper.html"&gt;documentation&lt;/a&gt;) (&lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/os/Looper.java#Looper"&gt;source code&lt;/a&gt;)&lt;br /&gt;The Looper class has a MessageQueue object attached to it and blocks the current thread until a Message is received. This message will be passed to the assigned Handler. After that the Looper processes the next message in the queue or blocks again until a message is received.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;HandlerThread&lt;/b&gt;&amp;nbsp;(&lt;a href="https://developer.android.com/reference/android/os/HandlerThread.html"&gt;documentation&lt;/a&gt;) (&lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/os/HandlerThread.java#HandlerThread"&gt;source code&lt;/a&gt;)&lt;br /&gt;A HandlerThread is a Thread implementation that does all the Looper setup for you. By creating and starting a HandlerThread instance you will have a running thread with a Looper attached to it waiting for messages to process.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Read the code!&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now we know enough about all the components to understand the &lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/app/IntentService.java"&gt;IntentService code&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;onCreate()&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-YHAG_7OKKhI/UhXazQgkmkI/AAAAAAAANSA/57KqOScdP9k/s1600/IntentService_oncreate.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-YHAG_7OKKhI/UhXazQgkmkI/AAAAAAAANSA/57KqOScdP9k/s1600/IntentService_oncreate.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/app/IntentService.java#101"&gt;IntentService.onCreate()&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;At first a HandlerThread is created and started. We now have a background thread running that already has a Looper assigned. This Looper is waiting on the background thread for messages to process.&lt;br /&gt;&lt;br /&gt;Next a ServiceHandler is created for this Looper. The Handler’s &lt;a href="https://developer.android.com/reference/android/os/Handler.html#handleMessage(android.os.Message)"&gt;handleMessage&lt;/a&gt;() method will be called for every message received by the Looper. The ServiceHandler obtains the Intent object from the Message and passes it to the onHandleIntent() method of the IntentService.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;onStart()&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-C91WSSI62cw/UhXbfPQsAJI/AAAAAAAANSI/k5Hyb0QB9qI/s1600/IntentService_onstart.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-C91WSSI62cw/UhXbfPQsAJI/AAAAAAAANSI/k5Hyb0QB9qI/s1600/IntentService_onstart.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/app/IntentService.java#115"&gt;IntentService.onStart()&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The onStart() method is called every time &lt;a href="https://developer.android.com/reference/android/content/Context.html#startService(android.content.Intent)"&gt;startService()&lt;/a&gt; is called. We wrap the Intent in a Message object and post it to the Handler. The Handler will enqueue it in the message queue of the Looper. The onStart() method is deprecated since API level 5 (Android 2.0). Instead onStartCommand() should be implemented.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;onStartCommand()&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-HB0fPJbsY8A/UhXcBOrAYAI/AAAAAAAANSQ/pfU3UUXUmE8/s1600/IntentService_onstartcommand.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-HB0fPJbsY8A/UhXcBOrAYAI/AAAAAAAANSQ/pfU3UUXUmE8/s1600/IntentService_onstartcommand.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/app/IntentService.java#129"&gt;IntentService.onStartCommand()&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;In onStartCommand() we call onStart() to enqueue the Intent. We return &lt;a href="https://developer.android.com/reference/android/app/Service.html#START_REDELIVER_INTENT"&gt;START_REDELIVER_INTENT&lt;/a&gt; or &lt;a href="https://developer.android.com/reference/android/app/Service.html#START_NOT_STICKY"&gt;START_NOT_STICK&lt;/a&gt; depending on what the child class has set via&amp;nbsp;&lt;a href="https://developer.android.com/reference/android/app/IntentService.html#setIntentRedelivery(boolean)"&gt;setIntentRedelivery()&lt;/a&gt;. Depending on this setting an Intent will be redelivered to the service if the process dies before onHandleIntent() returns or the Intent will die as well.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;onDestroy()&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-GkK4xWmOWu0/UhXcmqOLkQI/AAAAAAAANSY/M8oZn2GF5FY/s1600/IntentService_ondestroy.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-GkK4xWmOWu0/UhXcmqOLkQI/AAAAAAAANSY/M8oZn2GF5FY/s1600/IntentService_ondestroy.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/app/IntentService.java#134"&gt;IntentService.onDestroy()&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;In onDestroy() we just need to stop the Looper.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The IntentService code is quite short and simple, yet a powerful pattern. With the &lt;a href="https://developer.android.com/reference/android/os/Handler.html"&gt;Handler&lt;/a&gt;, &lt;a href="https://developer.android.com/reference/android/os/Looper.html"&gt;Looper&lt;/a&gt; and &lt;a href="https://developer.android.com/reference/java/lang/Thread.html"&gt;Thread&lt;/a&gt; class you can easily build your own simple processing queues.&lt;br /&gt;&lt;br /&gt;Oh, and if you are looking for an exercise. The code of the onCreate() method contains a TODO comment that I omitted above:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-QlS7sJHfj1I/UhXp96c9r_I/AAAAAAAANS0/iRXyCb9E7NI/s1600/oncreate_todo.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-QlS7sJHfj1I/UhXp96c9r_I/AAAAAAAANS0/iRXyCb9E7NI/s1600/oncreate_todo.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/app/IntentService.java#101"&gt;TODO in onCreate()&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/ohV1Ybma6A4" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/3096175864289654512/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2013/08/read-code-intentservice.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/3096175864289654512" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/3096175864289654512" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/ohV1Ybma6A4/read-code-intentservice.html" title="Read the code: IntentService" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-VJ13VmPcpx4/UhXgpEhsitI/AAAAAAAANSk/ZLzJYR-7ypE/s72-c/DownloadService.png" height="72" width="72" /><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2013/08/read-code-intentservice.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-5050374432842781763</id><published>2013-05-27T19:31:00.001+02:00</published><updated>2013-05-27T19:31:31.801+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Instant Mustache" /><category scheme="http://www.blogger.com/atom/ns#" term="Intent" /><category scheme="http://www.blogger.com/atom/ns#" term="picture" /><category scheme="http://www.blogger.com/atom/ns#" term="Sharing" /><title type="text">Sharing the taken picture - Instant Mustache #9</title><content type="html">&lt;div&gt;&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the development process of Instant Mustache, a fun camera app that adds mustaches to all faces using face detection.&amp;nbsp;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html"&gt;Click here&lt;/a&gt;&amp;nbsp;to get a chronological list of all published&amp;nbsp;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html"&gt;articles about Instant Mustache&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html"&gt;Up to now&lt;/a&gt; our app can take and view pictures. The next step is to share the taken picture with other Android apps. This is done via &lt;a href="https://developer.android.com/guide/components/intents-filters.html"&gt;Intents&lt;/a&gt;. The Intent system is one of the most powerful features of Android. It allows us to interact with any app that accepts images with almost no extra afford.&lt;br /&gt;&lt;br /&gt;We could create an &lt;a href="https://developer.android.com/guide/topics/ui/actionbar.html"&gt;ActionBar&lt;/a&gt; item and when clicked launch an &lt;a href="https://developer.android.com/reference/android/content/Intent.html"&gt;Intent&lt;/a&gt;&amp;nbsp;to share the image but instead we are going to use a &lt;a href="http://developer.android.com/training/sharing/shareaction.html"&gt;ShareActionProvider&lt;/a&gt;. The ShareActionProvider adds a share icon to the ActionBar as well as the icon of the app that the user has shared pictures the most with. By clicking this icon the user can share directly with this app. In addition to that the ShareActionProvider shows a sub menu with more apps that the given picture can be shared with.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-pDiZ5iw7DMw/UaOT6GqMHuI/AAAAAAAALjk/oLbP5J6_nok/s1600/shareactionprovider.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-pDiZ5iw7DMw/UaOT6GqMHuI/AAAAAAAALjk/oLbP5J6_nok/s1600/shareactionprovider.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;A ShareActionProvider with Google+ as default share action.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-L_-glPQZGF8/UaOXqTIYImI/AAAAAAAALkE/ofFypChT2Ew/s1600/shareactionprovider_menu.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="285" src="http://4.bp.blogspot.com/-L_-glPQZGF8/UaOXqTIYImI/AAAAAAAALkE/ofFypChT2Ew/s320/shareactionprovider_menu.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Sub menu of a ShareActionProvider.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;If sharing is a key feature of your activity, you should consider using the ShareActionProvider.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;We start by creating an XML menu file for adding the share action. For legacy reasons the ActionBar uses the same approach for creating action items as the menu in Android 2.x.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-KWMveO6nNuo/UaOTQWFlM1I/AAAAAAAALjc/OXqcUuxPmhg/s1600/activity_photo_menu.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-KWMveO6nNuo/UaOTQWFlM1I/AAAAAAAALjc/OXqcUuxPmhg/s1600/activity_photo_menu.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-09/res/menu/activity_photo.xml"&gt;activity_photo.xml&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Once we inflated the menu in &lt;a href="https://developer.android.com/reference/android/app/Activity.html#onCreateOptionsMenu(android.view.Menu)"&gt;onCreateOptionsMenu()&lt;/a&gt; we need to set the Intent used to share the photo.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-0eTGVnhBo_0/UaOVjb4aX-I/AAAAAAAALj0/mXc2KKjxi0k/s1600/initialize_share_action.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-0eTGVnhBo_0/UaOVjb4aX-I/AAAAAAAALj0/mXc2KKjxi0k/s1600/initialize_share_action.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-09/src/com/androidzeitgeist/mustache/activity/PhotoActivity.java#L45"&gt;PhotoActivity.initializeShareAction()&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Let's take a look at the different components of the Intent:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;ACTION_SEND&lt;/b&gt;: The default action used for “sending†data to an other unspecified activity.&lt;/li&gt;&lt;li&gt;&lt;b&gt;MIME&lt;/b&gt; type: The MIME type of the data being sent. Other apps can define multiple MIME types they accept. We are sending a JPEG image and therefore we are using the MIME type “image/jpegâ€. To learn more about MIME types start with the &lt;a href="https://en.wikipedia.org/wiki/Internet_media_type"&gt;"Internet media type" Wikipedia article&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;b&gt;EXTRA_STREAM&lt;/b&gt;: &lt;a href="https://developer.android.com/reference/android/net/Uri.html"&gt;Uri&lt;/a&gt; that points to the data that should be sent. In our case the Uri is pointing to the image file on the external storage.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;That's it already. For all changes done to the code base, see the &lt;a href="https://github.com/pocmo/Instant-Mustache/commit/4bded2002dfd56f63245d59e07a44e71deb04172"&gt;repository on GitHub&lt;/a&gt;. In the next article we'll polish some aspects of the app before we start implementing the Face detection feature.&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/APLuQCN5xxA" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/5050374432842781763/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2013/05/sharing-taken-picture-instant-mustache-9.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/5050374432842781763" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/5050374432842781763" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/APLuQCN5xxA/sharing-taken-picture-instant-mustache-9.html" title="Sharing the taken picture - Instant Mustache #9" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-pDiZ5iw7DMw/UaOT6GqMHuI/AAAAAAAALjk/oLbP5J6_nok/s72-c/shareactionprovider.png" height="72" width="72" /><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2013/05/sharing-taken-picture-instant-mustache-9.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-8353658165969956441</id><published>2013-01-14T20:47:00.000+01:00</published><updated>2013-01-14T20:47:04.700+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="camera" /><category scheme="http://www.blogger.com/atom/ns#" term="Instant Mustache" /><category scheme="http://www.blogger.com/atom/ns#" term="orientation" /><category scheme="http://www.blogger.com/atom/ns#" term="OrientationEventListener" /><category scheme="http://www.blogger.com/atom/ns#" term="rotation" /><title type="text">Fixing the rotation - Instant Mustache #8</title><content type="html">&lt;div&gt;&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the development process of Instant Mustache, a fun camera app that adds mustaches to all faces using face detection.&amp;nbsp;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html"&gt;Click here&lt;/a&gt;&amp;nbsp;to get a chronological list of all published&amp;nbsp;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html"&gt;articles about Instant Mustache&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Wrong orientation&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;If you run the current version of Instant Mustache and take some pictures you'll notice something odd: The orientation of the taken pictures is sometimes wrong. This may depend on the device you are using. When using a Galaxy Nexus the picture will be rotated 90° to the left when taking a picture in portrait mode but will be rotated correctly when taking a picture in landscape mode.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-RDkIH8Iw8VY/UPRZTnyZA2I/AAAAAAAAH0Q/BU7sRAlQQOw/s1600/rotation_error.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="239" src="http://1.bp.blogspot.com/-RDkIH8Iw8VY/UPRZTnyZA2I/AAAAAAAAH0Q/BU7sRAlQQOw/s320/rotation_error.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Wrong orientation of photo that has been taken in portrait mode&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;How does this happen? You may remember that we've used &lt;a href="https://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int)"&gt;Camera.setDisplayOrientation()&lt;/a&gt; in one of the &lt;a href="http://www.androidzeitgeist.com/2012/10/displaying-camera-preview-instant.html"&gt;previous articles&lt;/a&gt; to explicitly set the display rotation. First, this setting only affects the preview picture. The picture passed to the &lt;a href="https://developer.android.com/reference/android/hardware/Camera.ShutterCallback.html"&gt;Camera.ShutterCallback&lt;/a&gt; isn't affected by this setting. And second, we still have to account into how the device is rotated in the moment of taking the picture.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Detecting and remembering the orientation&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;What we need to do in our code is to register an &lt;a href="https://developer.android.com/reference/android/view/OrientationEventListener.html"&gt;OrientationEventListener&lt;/a&gt; to get notified whenever the orientation changes. We'll remember this orientation and use this to rotate the taken image once the callback returns.&lt;br /&gt;&lt;br /&gt;Whenever the orientation changes &lt;a href="https://developer.android.com/reference/android/view/OrientationEventListener.html#onOrientationChanged(int)"&gt;onOrientationChanged(int)&lt;/a&gt; of the listener will be called. The orientation will be passed to the method in degrees, ranging from 0 to 359. We need to normalize this value as we are only interested in 90° steps for rotating the picture.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-JQ2Rm-uZ0gQ/UPRahx8kf2I/AAAAAAAAH0c/v7NIwzqReBM/s1600/cameraorientationlistener_normalize.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-JQ2Rm-uZ0gQ/UPRahx8kf2I/AAAAAAAAH0c/v7NIwzqReBM/s1600/cameraorientationlistener_normalize.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-08/src/com/androidzeitgeist/mustache/listener/CameraOrientationListener.java#L31"&gt;CameraOrientationListener.normalize()&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Another method called &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-08/src/com/androidzeitgeist/mustache/listener/CameraOrientationListener.java#L51"&gt;rememberOrientation()&lt;/a&gt; will be used to save the orientation of the device in the moment of the user pressing the shutter button.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-rqdv0tzl52Y/UPRbbrb1vBI/AAAAAAAAH00/2Ldj2OrPXBM/s1600/camerafragment_takepicture.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-rqdv0tzl52Y/UPRbbrb1vBI/AAAAAAAAH00/2Ldj2OrPXBM/s1600/camerafragment_takepicture.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-08/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java#L231"&gt;CameraFragment.takePicture()&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Rotating the picture&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now we just need to rotate the Bitmap. We do this by creating a new Bitmap object and applying a rotated &lt;a href="http://developer.android.com/reference/android/graphics/Matrix.html"&gt;Matrix&lt;/a&gt; to the pixels. The rotation angle is calculated by summing the remembered orientation, the display orientation and the natural rotation of the device.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-Kp9GQ7CSHik/UPRcKSjRiBI/AAAAAAAAH1I/cTRdA_NYgjI/s1600/camerafragment_onpicturetaken.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-Kp9GQ7CSHik/UPRcKSjRiBI/AAAAAAAAH1I/cTRdA_NYgjI/s1600/camerafragment_onpicturetaken.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-08/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java#L241"&gt;CameraFragment.onPictureTaken()&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Result&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-3lBP-pDo5cQ/UPRd8jZp-LI/AAAAAAAAH14/kJaLh3-Mdak/s1600/result_rotation.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="242" src="http://3.bp.blogspot.com/-3lBP-pDo5cQ/UPRd8jZp-LI/AAAAAAAAH14/kJaLh3-Mdak/s320/result_rotation.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Photos rotated correctly in portrait and landscape mode&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/17oriJk6I8w" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/8353658165969956441/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8353658165969956441" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8353658165969956441" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/17oriJk6I8w/fixing-rotation-camera-picture.html" title="Fixing the rotation - Instant Mustache #8" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-RDkIH8Iw8VY/UPRZTnyZA2I/AAAAAAAAH0Q/BU7sRAlQQOw/s72-c/rotation_error.png" height="72" width="72" /><thr:total>1</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-1598031232613876637</id><published>2012-12-22T14:21:00.000+01:00</published><updated>2012-12-22T14:27:19.476+01:00</updated><title type="text">Android 2012</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-dKfHvBySVQk/UNWsnfVSK6I/AAAAAAAAHR8/FYWEUfw0yeU/s1600/android2012.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-dKfHvBySVQk/UNWsnfVSK6I/AAAAAAAAHR8/FYWEUfw0yeU/s1600/android2012.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;After &lt;a href="http://www.youtube.com/watch?v=xY_MUB8adEQ"&gt;Google Zeitgeist&lt;/a&gt; and&amp;nbsp;&lt;a href="http://www.youtube.com/watch?v=iCkYw3cRwLo"&gt;YouTube&lt;/a&gt;&amp;nbsp;looked back on 2012 it’s time to do the same for Android.&lt;span id="goog_2128203782"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;January&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://4.bp.blogspot.com/-4cV7er0VgPI/UNWw0GXYL5I/AAAAAAAAHSQ/nDFaspNqWns/s1600/androiddesign.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="157" src="http://4.bp.blogspot.com/-4cV7er0VgPI/UNWw0GXYL5I/AAAAAAAAHSQ/nDFaspNqWns/s200/androiddesign.png" width="200" /&gt;&lt;/a&gt;The year 2011 has just ended and the &lt;b&gt;Galaxy Nexus&lt;/b&gt; is the current flagship phone. 12 days later on January 12th the &lt;b&gt;&lt;a href="http://developer.android.com/design/index.html"&gt;Android Design&lt;/a&gt;&lt;/b&gt; website launched. Followed by the &lt;b&gt;&lt;a href="https://plus.google.com/u/0/+AndroidDevelopers/posts"&gt;Android developers Google+ page&lt;/a&gt;&lt;/b&gt; on January 30th.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;February&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first numbers of the year are published. &lt;b&gt;850,000&lt;/b&gt; Android phones are activated every day. &lt;b&gt;300 million &lt;/b&gt;devices have been activated so far.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;March&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;On March 5th &lt;b&gt;&lt;a href="http://android-developers.blogspot.de/2012/03/android-apps-break-50mb-barrier.html"&gt;expansion files&lt;/a&gt;&lt;/b&gt; are introduced and &lt;b&gt;Android apps break the 50MB barrier&lt;/b&gt; expanding the size limit to &lt;b&gt;4GB&lt;/b&gt;. The Android market retires and is reborn as &lt;b&gt;Google play&lt;/b&gt; on March 6th. The same month on March 21st the &lt;b&gt;SDK tools and ADT revision 17&lt;/b&gt; are released, adding an emulator that supports running x86 system images on Windows and Mac OS X. An update to the Android Developer Console on March 29th allows &lt;b&gt;multiple users&lt;/b&gt; to manage published Android apps.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-qPqhAtg_PVg/UNWxPkos_2I/AAAAAAAAHSY/ivgQD4D4Nmo/s1600/appclinic.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="150" src="http://1.bp.blogspot.com/-qPqhAtg_PVg/UNWxPkos_2I/AAAAAAAAHSY/ivgQD4D4Nmo/s200/appclinic.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;April&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The emulator gets even more faster on April 9th by adding &lt;b&gt;GPU support&lt;/b&gt;. On April 20th the first episode of &lt;b&gt;&lt;a href="http://www.youtube.com/playlist?list=PLB7B9B23D864A55C3"&gt;Friday App Review&lt;/a&gt;&lt;/b&gt; airs and is later called &lt;b&gt;&lt;a href="http://www.youtube.com/playlist?list=PLB7B9B23D864A55C3"&gt;The app clinic&lt;/a&gt;&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;May&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;On May 4th Wolfram Rittmeyer publishes the first posting on his blog &lt;b&gt;&lt;a href="http://www.grokkingandroid.com/"&gt;Grokking Android&lt;/a&gt;&lt;/b&gt;. Followed by the first article published on &lt;a href="http://www.androidzeitgeist.com/"&gt;&lt;b&gt;Android Zeitgeist&lt;/b&gt;&lt;/a&gt; on May 27th. 3 days before on May 24th &lt;b&gt;&lt;a href="http://android-developers.blogspot.de/2012/05/in-app-subscriptions-in-google-play.html"&gt;In-app Subscriptions&lt;/a&gt;&lt;/b&gt; are launched on Google Play.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;June&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-HvAwcdnUaq4/UNWxlZCN7XI/AAAAAAAAHSg/jM3slhIq--k/s1600/google-io-logo.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="40" src="http://1.bp.blogspot.com/-HvAwcdnUaq4/UNWxlZCN7XI/AAAAAAAAHSg/jM3slhIq--k/s200/google-io-logo.png" width="200" /&gt;&lt;/a&gt;&lt;br /&gt;The &lt;b&gt;&lt;a href="https://developers.google.com/events/io/"&gt;Google I/O&lt;/a&gt;&lt;/b&gt; takes place for three days from June 27th to 29th. There are now &lt;b&gt;900,000&lt;/b&gt; Android devices activated every day and &lt;b&gt;400 million&lt;/b&gt; devices have been activated up to now. &lt;b&gt;Android 4.1 (Jelly Bean)&lt;/b&gt; is publicly shown for the first time on June 27th. The same day the &lt;b&gt;Android 4.1 SDK&lt;/b&gt; is released. In addition to that the first tablet by Google is unveiled: The &lt;b&gt;Nexus 7&lt;/b&gt;. On the second day of the Google I/O the &lt;b&gt;Android SDK tools&lt;/b&gt; are updated to &lt;b&gt;revision 20&lt;/b&gt;. At the end of the Google I/O there have been 3.5 million live streams seen from 170 countries.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;July&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-iu-C9xVT-_U/UNWyPKppPJI/AAAAAAAAHS4/JfRWJvOp7dg/s1600/ouya.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="200" src="http://3.bp.blogspot.com/-iu-C9xVT-_U/UNWyPKppPJI/AAAAAAAAHS4/JfRWJvOp7dg/s200/ouya.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;On July 3rd the &lt;b&gt;&lt;a href="http://www.ouya.tv/"&gt;Ouya&lt;/a&gt;&lt;/b&gt;, an Android based console, is unveiled and a Kickstarter campaign is started on July 10th. On July 9th the &lt;b&gt;Android 4.1 source code&lt;/b&gt; is published as part of the Android Open Source Project (AOSP).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;August&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The funding phase for the &lt;b&gt;Ouya&lt;/b&gt; is completed. The campaign collected $8,596,475. That’s 904% more than the initial campaign goal.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;September&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;New numbers are released. There are now &lt;b&gt;1.3 million devices&lt;/b&gt; activated every a day. About &lt;b&gt;70,000&lt;/b&gt; of these devices are tablets. &lt;b&gt;480 million&lt;/b&gt; devices have been activated up to now. On September 9th the first episode of &lt;b&gt;&lt;a href="http://www.youtube.com/playlist?list=PLWz5rJ2EKKc9Wam5jE-9oY8l6RpeAx-XM"&gt;This week in Android development&lt;/a&gt;&lt;/b&gt; airs. A day later the first episode of &lt;b&gt;&lt;a href="http://www.youtube.com/playlist?list=PLWz5rJ2EKKc8j2B95zGMb8muZvrIy-wcF"&gt;Android Design in Action&lt;/a&gt;&lt;/b&gt; is uploaded to YouTube.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;October&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-iMCBRXK31yE/UNWx_vXgIjI/AAAAAAAAHSw/9PXrh3tQBs4/s1600/nexus4.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="167" src="http://3.bp.blogspot.com/-iMCBRXK31yE/UNWx_vXgIjI/AAAAAAAAHSw/9PXrh3tQBs4/s200/nexus4.png" width="200" /&gt;&lt;/a&gt;Till mid October &lt;b&gt;3 million Nexus 7&lt;/b&gt; units have been sold. Starting from October 15th the &lt;b&gt;new Google Play Developer Console&lt;/b&gt; is available to everyone. Google planned a &lt;b&gt;launch event&lt;/b&gt; on October 29th in New York but it has been cancelled due to Hurricane Sandy. Nevertheless the &lt;b&gt;Nexus 4&lt;/b&gt; and &lt;b&gt;Nexus 10&lt;/b&gt; are introduced online this day. These are the first devices to run &lt;b&gt;Android 4.2&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;November&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first episode of &lt;a href="http://www.youtube.com/playlist?list=PLWz5rJ2EKKc9loen4OjS03gdjI0JhF4cW"&gt;(╯°□°)╯︵ â”»â”â”»&lt;/a&gt; airs on November 8th. On November 13th the &lt;b&gt;Nexus 4&lt;/b&gt; and &lt;b&gt;Nexus 10&lt;/b&gt; went on sale and are sold out in minutes. Later that day the &lt;b&gt;Android 4.2 SDK platform&lt;/b&gt; is released. Another day later the &lt;b&gt;Android SDK tools revision 21&lt;/b&gt; are released.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;December&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Google releases a new &lt;b&gt;&lt;a href="http://android-developers.blogspot.de/2012/12/new-google-maps-android-api-now-part-of.html"&gt;Google Maps API&lt;/a&gt;&lt;/b&gt; for Android on December 3rd. On December 10th a new version of the&lt;b&gt; &lt;a href="http://android-developers.blogspot.de/2012/12/in-app-billing-version-3.html"&gt;In-App billing API&lt;/a&gt;&lt;/b&gt; is released.&lt;br /&gt;&lt;br /&gt;The Android team releases their &lt;b&gt;Happy Holidays&lt;/b&gt; video:&lt;br /&gt;&lt;br /&gt;&lt;iframe allowfullscreen="allowfullscreen" frameborder="0" height="315" src="http://www.youtube.com/embed/967nio2LF7s" width="560"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;2013?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What has been your Android highlight in 2012 and what are your wishes for 2013?&lt;/b&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/6_wXwDjJRdc" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/1598031232613876637/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/12/android-2012.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/1598031232613876637" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/1598031232613876637" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/6_wXwDjJRdc/android-2012.html" title="Android 2012" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-dKfHvBySVQk/UNWsnfVSK6I/AAAAAAAAHR8/FYWEUfw0yeU/s72-c/android2012.png" height="72" width="72" /><thr:total>1</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/12/android-2012.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-8734004828090755204</id><published>2012-12-11T20:41:00.000+01:00</published><updated>2012-12-11T20:41:51.969+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="API" /><category scheme="http://www.blogger.com/atom/ns#" term="Clean Code" /><category scheme="http://www.blogger.com/atom/ns#" term="String" /><category scheme="http://www.blogger.com/atom/ns#" term="TextUtils" /><title type="text">Mind the gap: String.isEmpty()</title><content type="html">&lt;span style="font-size: x-small;"&gt;Articles labeled "Mind the gap" are short articles mostly about simple problems that arise from using different API levels of Android. They are more short trivia postings than big teachings about Android development.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I try to write code as readable as possible. That's the reason why I don't want to compare a String to an other empty String object or check its length when I want to know if a String is empty.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-FWLirpvHLAM/UMbfKHp3tUI/AAAAAAAAHCI/NPnjM4Qx5Pk/s1600/isemptyvariants.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-FWLirpvHLAM/UMbfKHp3tUI/AAAAAAAAHCI/NPnjM4Qx5Pk/s1600/isemptyvariants.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;In the book "&lt;a href="http://books.google.de/books?id=dwSfGQAACAAJ&amp;amp;dq=isbn:0132350882y"&gt;Clean code&lt;/a&gt;" by &lt;a href="http://en.wikipedia.org/wiki/Robert_Cecil_Martin"&gt;Robert C. Martin&lt;/a&gt; you can read&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Grady_Booch"&gt;Grady Booch&lt;/a&gt; saying: "Clean code reads like well-written prose". So I try to use &lt;a href="http://developer.android.com/reference/java/lang/String.html#isEmpty()"&gt;String.isEmpty()&lt;/a&gt; for that reason. Internally it may do a length check as well (I stopped my investigation at the &lt;i&gt;native&lt;/i&gt; keyword)&amp;nbsp;but when reading the following snippet it is absolutely obvious what I intend to do.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-fPosAzNzRYc/UMbecA_7d3I/AAAAAAAAHB4/K6lPAMAkrIs/s1600/isEmptyMethod.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-fPosAzNzRYc/UMbecA_7d3I/AAAAAAAAHB4/K6lPAMAkrIs/s1600/isEmptyMethod.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Even though &lt;a href="http://developer.android.com/reference/java/lang/String.html#isEmpty()"&gt;isEmpty()&lt;/a&gt; has been introduced in Java 1.6 it hasn't been available in Android until API level 9 (Android 2.3) so I accidentally caused some crashes on earlier versions of Android. Nowadays &lt;a href="http://tools.android.com/tips/lint"&gt;lint&lt;/a&gt;&amp;nbsp;thankfully&amp;nbsp;saves me from doing this error.&lt;br /&gt;&lt;br /&gt;So what to do now? I don't know if someone at Google felt the same but there is a class in the Android framework that solves that problem: &lt;a href="http://developer.android.com/reference/android/text/TextUtils.html"&gt;TextUtils&lt;/a&gt;. This class also has a lot of other helpful methods like &lt;a href="http://developer.android.com/reference/android/text/TextUtils.html#join(java.lang.CharSequence, java.lang.Object[])"&gt;join()&lt;/a&gt; to join an array of elements to a String using a&amp;nbsp;delimiter&amp;nbsp;or &lt;a href="http://developer.android.com/reference/android/text/TextUtils.html#getReverse(java.lang.CharSequence, int, int)"&gt;getReverse() &lt;/a&gt;to reverse a String (Take that interview question!).&lt;br /&gt;&lt;br /&gt;In addition to that the TextUtils class has a method &lt;a href="http://developer.android.com/reference/android/text/TextUtils.html#isEmpty(java.lang.CharSequence)"&gt;isEmpty()&lt;/a&gt; that is available since API level 1.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-nzyWV2TAHaM/UMbelfdSHCI/AAAAAAAAHCA/Z2lLIH_YddU/s1600/TextUtils.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-nzyWV2TAHaM/UMbelfdSHCI/AAAAAAAAHCA/Z2lLIH_YddU/s1600/TextUtils.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Phew! By the way: &lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/text/TextUtils.java#TextUtils.isEmpty%28java.lang.CharSequence%29"&gt;Internally&lt;/a&gt; isEmpty() checks if the length of the String is 0 (and does a null check).&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/jbePXNFlMnA" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/8734004828090755204/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/12/string-is-empty.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8734004828090755204" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8734004828090755204" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/jbePXNFlMnA/string-is-empty.html" title="Mind the gap: String.isEmpty()" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-FWLirpvHLAM/UMbfKHp3tUI/AAAAAAAAHCI/NPnjM4Qx5Pk/s72-c/isemptyvariants.png" height="72" width="72" /><thr:total>5</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/12/string-is-empty.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-4510260145421419236</id><published>2012-11-05T20:40:00.000+01:00</published><updated>2012-11-05T20:40:10.181+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bezel swipe" /><category scheme="http://www.blogger.com/atom/ns#" term="fake dragging" /><category scheme="http://www.blogger.com/atom/ns#" term="scrolling" /><category scheme="http://www.blogger.com/atom/ns#" term="SeekBar" /><category scheme="http://www.blogger.com/atom/ns#" term="support library" /><category scheme="http://www.blogger.com/atom/ns#" term="ViewPager" /><title type="text">Examining the ViewPager #3</title><content type="html">&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the ViewPager component.&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/viewpager.html" style="font-size: small;"&gt;Click here&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;&amp;nbsp;to see a list of&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/viewpager.html" style="font-size: small;"&gt;all articles of this series&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Horizontal scrolling pages&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Have you ever tried putting horizontal scrolling components inside a &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html"&gt;ViewPager&lt;/a&gt;? Well, since revision 9 of the &lt;a href="http://developer.android.com/tools/extras/support-library.html"&gt;support library&lt;/a&gt; this is supported by the ViewPager. As long as the inner component can scroll horizontally this component will be scrolled. Whenever the component can't be further scrolled the ViewPager will handle the touch events and you start to switch to the next page. This works out-of-the-box for scrolling view components of Android like the &lt;a href="http://developer.android.com/reference/android/webkit/WebView.html"&gt;WebView&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Internally the ViewPager uses &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewCompat.html#canScrollHorizontally(android.view.View, int)"&gt;ViewCompat.canScrollHorizontally(View v, int direction)&lt;/a&gt;&amp;nbsp;to determine if a child view can be scrolled horizontally and should receive the according touch events. Unfortunately this method is only implemented for Android 4.0 (API level 14) and above. For all earlier versions this method will always return false and therefore never scroll the components inside the ViewPager.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Bezel swipe&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Allowing horizontal scrolling components introduces a new problem: What if you want to switch pages but not scroll every component to its horizontal end? When you start the swipe at the phone's bezel (or actually from the edge of the ViewPager) you'll switch pages instead of scrolling the page's content. This gesture is called &lt;i&gt;bezel swipe&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;For reading more about the bezel swipe gesture from a UI point of view read "&lt;a href="http://www.androiduipatterns.com/2012/02/bezel-swipe-solution-to-pan-and-swipe.html"&gt;Bezel swipe, a Solution to Pan and Swipe Confusion?&lt;/a&gt;" on &lt;a href="http://www.androiduipatterns.com/"&gt;Android UI Patterns&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The good news is again: The ViewPager supports bezel swipe out of the box. But as you can't horizontally scroll inside pages on devices running an Android version lower than 4.0 (API level 14) bezel swipe isn't of any use on these as well.&lt;br /&gt;&lt;br /&gt;The area to start a bezel swipe has a width of either 16dp or a 10th of the total width of the ViewPager depending on which one is smaller.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-dNYV1OuZvdQ/UJgLXTptXHI/AAAAAAAAGS4/Zt0OXlBwbaM/s1600/viewpager_bezel_swipe.png" imageanchor="1"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-dNYV1OuZvdQ/UJgLXTptXHI/AAAAAAAAGS4/Zt0OXlBwbaM/s1600/viewpager_bezel_swipe.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Fake dragging&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The ViewPager supports fake dragging. Fake dragging can be used to simulate a dragging event/animation, e.g. for detecting drag events on a different component and delegating these to the ViewPager.&lt;br /&gt;&lt;br /&gt;You have to signal the ViewPager when to start or end a fake drag by calling &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html#beginFakeDrag()"&gt;beginFakeDrag()&lt;/a&gt; and &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html#endFakeDrag()"&gt;endFakeDrag()&lt;/a&gt; on it. After starting a fake drag you can use &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html#fakeDragBy(float)"&gt;fakeDragBy(float)&lt;/a&gt; to drag the ViewPager by the given amount of pixels along the x axis (negative values to the left and positive values to the right).&lt;br /&gt;&lt;br /&gt;The following example uses a &lt;a href="http://developer.android.com/reference/android/widget/SeekBar.html"&gt;SeekBar&lt;/a&gt;&amp;nbsp;whose current progress state is used to fake drag a ViewPager by the given percentage.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-SFr1EyEfN4Q/UJgNTawCuSI/AAAAAAAAGTA/Pq_75XpuIes/s1600/SeekBarPagerListener.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-SFr1EyEfN4Q/UJgNTawCuSI/AAAAAAAAGTA/Pq_75XpuIes/s1600/SeekBarPagerListener.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/blob/master/ViewPager/03/SeekBarPagerListener.java"&gt;SeekBarPagerListener.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;This video shows the fake drag in action:&lt;br /&gt;&lt;br /&gt;&lt;iframe allowfullscreen="allowfullscreen" frameborder="0" height="360" src="http://www.youtube.com/embed/us8w2g9YXC4?rel=0" width="480"&gt;&lt;/iframe&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/GsNXoeK7N6Y" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/4510260145421419236/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/11/examining-viewpager-3.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/4510260145421419236" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/4510260145421419236" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/GsNXoeK7N6Y/examining-viewpager-3.html" title="Examining the ViewPager #3" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-dNYV1OuZvdQ/UJgLXTptXHI/AAAAAAAAGS4/Zt0OXlBwbaM/s72-c/viewpager_bezel_swipe.png" height="72" width="72" /><thr:total>1</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/11/examining-viewpager-3.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-5361828375857120954</id><published>2012-10-30T23:35:00.000+01:00</published><updated>2012-10-30T23:35:59.679+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Instant Mustache" /><category scheme="http://www.blogger.com/atom/ns#" term="Intent" /><category scheme="http://www.blogger.com/atom/ns#" term="Uri" /><title type="text">Displaying the taken picture – Instant Mustache #7</title><content type="html">&lt;div&gt;&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the development process of Instant Mustache, a fun camera app that adds mustaches to all faces using face detection. &lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html"&gt;Click here&lt;/a&gt; to get a chronological list of all published &lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html"&gt;articles about Instant Mustache&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Writing the PhotoActivity&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;In the &lt;a href="http://www.androidzeitgeist.com/2012/10/taking-picture-instant-mustache-6.html"&gt;last article&lt;/a&gt; we wrote the code to take a camera picture and save it on the external storage. After saving the file the activity will be finished and a Toast will show up. This is not really user-friendly so now we'll write our next activity which will display the taken picture and later offer the option to share this picture.&lt;br /&gt;&lt;br /&gt;We'll start by creating an empty activity called &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-07/src/com/androidzeitgeist/mustache/activity/PhotoActivity.java"&gt;PhotoActivity&lt;/a&gt; and add it to the &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-07/AndroidManifest.xml#L30"&gt;manifest&lt;/a&gt; of our application. For now the layout will only contain an &lt;a href="http://developer.android.com/reference/android/widget/ImageView.html"&gt;ImageView&lt;/a&gt; to display the picture:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-KnA5sDjgZds/UJBOSqCkiZI/AAAAAAAAF2k/q3_2TKxMJ8I/s1600/layout_activity_photo.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-KnA5sDjgZds/UJBOSqCkiZI/AAAAAAAAF2k/q3_2TKxMJ8I/s1600/layout_activity_photo.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-07/res/layout/activity_photo.xml"&gt;activity_photo.xml&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Instead of showing a toast in our &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-07/src/com/androidzeitgeist/mustache/activity/CameraActivity.java"&gt;CameraActivity&lt;/a&gt; we create an Intent to start the PhotoActivity and use &lt;a href="http://developer.android.com/reference/android/content/Intent.html#setData(android.net.Uri)"&gt;setData(Uri)&lt;/a&gt; on the Intent object to pass a &lt;a href="http://developer.android.com/reference/android/net/Uri.html"&gt;Uri&lt;/a&gt; pointing to the picture file:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-VSkxvSyGYTU/UJBOjJYq-aI/AAAAAAAAF2s/q1DBQt-Ib9A/s1600/intent_start_photo_activity.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-VSkxvSyGYTU/UJBOjJYq-aI/AAAAAAAAF2s/q1DBQt-Ib9A/s1600/intent_start_photo_activity.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-07/src/com/androidzeitgeist/mustache/activity/CameraActivity.java#L116"&gt;onPictureTaken() - CameraActivity.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;In &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-07/src/com/androidzeitgeist/mustache/activity/PhotoActivity.java#L19"&gt;onCreate(Bundle)&lt;/a&gt; of the PhotoActivity we'll retrieve the Uri from the Intent and pass it to the ImageView. The ImageView will take care of loading the picture from the external storage and displaying it.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-tE-1b0nu5Ic/UJBO0nSip_I/AAAAAAAAF20/Thmkq7JwsmM/s1600/photo_activity_on_create.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-tE-1b0nu5Ic/UJBO0nSip_I/AAAAAAAAF20/Thmkq7JwsmM/s1600/photo_activity_on_create.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-07/src/com/androidzeitgeist/mustache/activity/PhotoActivity.java#L19"&gt;onCreate() - PhotoActivity.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;And that's already all the code we need for the first version of the &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-07/src/com/androidzeitgeist/mustache/activity/PhotoActivity.java"&gt;PhotoActivity&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-sX-QuJWGZtQ/UJBVljLcABI/AAAAAAAAF3I/XEL1UJHnjiI/s1600/camera_and_photo_screenshot.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-sX-QuJWGZtQ/UJBVljLcABI/AAAAAAAAF3I/XEL1UJHnjiI/s1600/camera_and_photo_screenshot.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;CameraActivity (left) and PhotoActivity (right)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/bA7tWUcBxoc" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/5361828375857120954/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/10/displaying-taken-picture-instant.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/5361828375857120954" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/5361828375857120954" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/bA7tWUcBxoc/displaying-taken-picture-instant.html" title="Displaying the taken picture – Instant Mustache #7" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-KnA5sDjgZds/UJBOSqCkiZI/AAAAAAAAF2k/q3_2TKxMJ8I/s72-c/layout_activity_photo.png" height="72" width="72" /><thr:total>3</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/10/displaying-taken-picture-instant.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-73829038323965617</id><published>2012-10-26T20:59:00.000+02:00</published><updated>2012-10-30T23:17:25.534+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="camera" /><category scheme="http://www.blogger.com/atom/ns#" term="CameraFragment" /><category scheme="http://www.blogger.com/atom/ns#" term="External storage" /><category scheme="http://www.blogger.com/atom/ns#" term="Instant Mustache" /><category scheme="http://www.blogger.com/atom/ns#" term="MediaScanner" /><category scheme="http://www.blogger.com/atom/ns#" term="OnClickListener" /><category scheme="http://www.blogger.com/atom/ns#" term="picture" /><title type="text">Taking a picture – Instant Mustache #6</title><content type="html">&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the development process of Instant Mustache, a fun camera app that adds mustaches to all faces using face detection.&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-size: small;"&gt;Click here&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;&amp;nbsp;to get a chronological list of all published&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-size: small;"&gt;articles about Instant Mustache&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After writing the necessary code to display a camera preview in &lt;a href="http://www.androidzeitgeist.com/2012/10/displaying-camera-preview-instant.html"&gt;the last article&lt;/a&gt; it's now time to actually take a picture and save it on the external storage of the device.&lt;br /&gt;&lt;br /&gt;We start by extending the layout of the &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-06/src/com/androidzeitgeist/mustache/activity/CameraActivity.java"&gt;CameraActivity&lt;/a&gt; to include a button for taking a picture. We assign a method to it to be called when the user clicks on the button via the attribute &lt;a href="http://developer.android.com/reference/android/view/View.html#attr_android:onClick"&gt;android:onClick&lt;/a&gt;. Another option would be to assign an &lt;a href="http://developer.android.com/reference/android/view/View.OnClickListener.html"&gt;OnClickListener&lt;/a&gt; to the view in code. Defining the method in the XML results in less code but has the disadvantage of not being checked by the compiler. Since one of the last releases of the Android SDK the &lt;a href="http://tools.android.com/tips/lint"&gt;lint&lt;/a&gt; tool is able to check the onClick attributes for correctness. So we will use the XML attribute here.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-hmHriQ9ppUo/UIqjpzAIkZI/AAAAAAAAFpQ/PJZvXOEn5XE/s1600/activity_camera.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-hmHriQ9ppUo/UIqjpzAIkZI/AAAAAAAAFpQ/PJZvXOEn5XE/s1600/activity_camera.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-06/res/layout/activity_camera.xml"&gt;activity_camera.xml&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;As we encapsulated the code handling the &lt;a href="http://developer.android.com/reference/android/hardware/Camera.html"&gt;Camera&lt;/a&gt; object inside the &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-06/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java"&gt;CameraFragment&lt;/a&gt; class the activity just calls takePicture() on the fragment when the user presses the button.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-FE7ro562XUI/UIqkAHnPvzI/AAAAAAAAFpY/-IZ0ncr7CbU/s1600/CameraActivity_takePicture.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-FE7ro562XUI/UIqkAHnPvzI/AAAAAAAAFpY/-IZ0ncr7CbU/s1600/CameraActivity_takePicture.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-06/src/com/androidzeitgeist/mustache/activity/CameraActivity.java#L64"&gt;takePicutre() - CameraActivity.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The fragment calls &lt;a href="http://developer.android.com/reference/android/hardware/Camera.html#takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback)"&gt;takePicture()&lt;/a&gt; on the Camera object. It's possible to pass up to four callbacks to this method: A shutter callback, a raw callback, a postview callback and a jpeg callback. According to the documentation their usage is:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The shutter callback occurs after the image is captured. This can be used to trigger a sound to let the user know that image has been captured.&lt;/li&gt;&lt;li&gt;The raw callback occurs when the raw image data is available.&lt;/li&gt;&lt;li&gt;The postview callback occurs when a scaled, fully processed postview image is available.&lt;/li&gt;&lt;li&gt;The jpeg callback occurs when the compressed image is available.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;We are only interested in the JPEG image. The fragment itself is also the callback so we'll implement the Camera.PictureCallback interface.&lt;br /&gt;&lt;br /&gt;Once the picture is taken &lt;a href="http://developer.android.com/reference/android/hardware/Camera.PictureCallback.html#onPictureTaken(byte[], android.hardware.Camera)"&gt;onPictureTaken()&lt;/a&gt; will be called with a byte array. We decode the given byte array and create a &lt;a href="http://developer.android.com/reference/android/graphics/Bitmap.html"&gt;Bitmap&lt;/a&gt; object and pass it via the &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-06/src/com/androidzeitgeist/mustache/listener/CameraFragmentListener.java"&gt;CameraFragmentListener&lt;/a&gt; interface to our CameraActivity. Later we will use this bitmap to draw the mustaches on it.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-HmhBl2pWTlo/UIqkdSoODnI/AAAAAAAAFpg/cJ69yQZOIeg/s1600/CameraFragment_onPictureTaken.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-HmhBl2pWTlo/UIqkdSoODnI/AAAAAAAAFpg/cJ69yQZOIeg/s1600/CameraFragment_onPictureTaken.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-06/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java#L224"&gt;onPictureTaken() - CameraFragment.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Saving the picture to the external storage&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Once the activity receives the bitmap object it needs to do a bunch of things:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Determine the directory to save the picture to and create it if necessary&lt;/li&gt;&lt;li&gt;Create a unique file for the picture inside the directory and save the image data to it&lt;/li&gt;&lt;li&gt;Notify the MediaScanner that we created a new file&lt;/li&gt;&lt;li&gt;Show a toast that the picture has been saved successfully (For now until we've written the activity to display the taken picture).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Determining the directory&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We want to save the picture into a directory on the external storage that is visible for all other applications. By calling &lt;a href="http://developer.android.com/reference/android/os/Environment.html#getExternalStoragePublicDirectory(java.lang.String)"&gt;Environment.getExternalStoragePublicDirectory()&lt;/a&gt; and passing &lt;a href="http://developer.android.com/reference/android/os/Environment.html#DIRECTORY_PICTURES"&gt;Environment.DIRECTORY_PICTURES&lt;/a&gt; we get the public directory for pictures (Available since API Level 8). Inside this directory we'll create a directory with the name of our application (if it doesn't exist already).&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-etMHinejAMU/UIqlvdRKOlI/AAAAAAAAFpo/QlH_Lu4dUOY/s1600/determining_directory.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-etMHinejAMU/UIqlvdRKOlI/AAAAAAAAFpo/QlH_Lu4dUOY/s1600/determining_directory.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-06/src/com/androidzeitgeist/mustache/activity/CameraActivity.java#L77"&gt;onPictureTaken() - CameraActivity.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&amp;nbsp;&lt;span style="font-size: large;"&gt;Saving the file&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We'll create a file with a unique file name containing a timestamp, e.g.: MUSTACHE_20121031_235959.jpg. The &lt;a href="http://developer.android.com/reference/android/graphics/Bitmap.html#compress(android.graphics.Bitmap.CompressFormat, int, java.io.OutputStream)"&gt;compress()&lt;/a&gt; method of the bitmap object is used to save the picture into the file.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-yNhLaUTQOs8/UIqlxhiP9tI/AAAAAAAAFp0/HlPPxj7_L9w/s1600/saving_picture.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-yNhLaUTQOs8/UIqlxhiP9tI/AAAAAAAAFp0/HlPPxj7_L9w/s1600/saving_picture.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-06/src/com/androidzeitgeist/mustache/activity/CameraActivity.java#L92"&gt;onPictureTaken() - CameraActivity.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Notifying the MediaScanner&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Scanning the SD card for changes is costly. Therefore most Android versions only scan the whole card if the card is re-inserted or was mounted by another device. This seems to be different in different vendor versions of Android but nevertheless you can't assume a file to be seen by other applications (for example the gallery) until it has been scanned by the &lt;a href="http://developer.android.com/reference/android/media/MediaScannerConnection.html"&gt;MediaScanner&lt;/a&gt;. For that reason we'll notify the MediaScanner about the file we've created.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-BKiT4GJmj8s/UIqlw9LsiFI/AAAAAAAAFpw/K1_jEkvhX98/s1600/notify_mediascanner.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-BKiT4GJmj8s/UIqlw9LsiFI/AAAAAAAAFpw/K1_jEkvhX98/s1600/notify_mediascanner.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-06/src/com/androidzeitgeist/mustache/activity/CameraActivity.java#L107"&gt;onPictureTaken() - CameraActivity.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;By now we've already created a simple camera application. We can take pictures and they show up in the gallery of the device. Pretty cool so far, huh?&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/c-K683UuF5g" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/73829038323965617/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/10/taking-picture-instant-mustache-6.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/73829038323965617" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/73829038323965617" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/c-K683UuF5g/taking-picture-instant-mustache-6.html" title="Taking a picture – Instant Mustache #6" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-hmHriQ9ppUo/UIqjpzAIkZI/AAAAAAAAFpQ/PJZvXOEn5XE/s72-c/activity_camera.png" height="72" width="72" /><thr:total>1</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/10/taking-picture-instant-mustache-6.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-8727545494996059717</id><published>2012-10-25T21:24:00.000+02:00</published><updated>2012-11-05T19:31:06.680+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="margin" /><category scheme="http://www.blogger.com/atom/ns#" term="Offscreen pages" /><category scheme="http://www.blogger.com/atom/ns#" term="OnPageChangeListener" /><category scheme="http://www.blogger.com/atom/ns#" term="ViewPager" /><title type="text">Examining the ViewPager #2</title><content type="html">&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the ViewPager component.&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/viewpager.html" style="font-size: small;"&gt;Click here&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;&amp;nbsp;to see a list of&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/viewpager.html" style="font-size: small;"&gt;all articles of this series&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Offscreen pages&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html"&gt;ViewPager&lt;/a&gt; doesn't create all its pages at once. When using a lot of pages this would be horribly slow and even unnecessary if the user would never swipe through all these pages. By default the ViewPager only creates the current page as well as the offscreen pages to the left and right of the current page.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-HzlJvCZIyQc/UIkzJpr1neI/AAAAAAAAFls/jfMZCwnu30I/s1600/offscreen_pages.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-HzlJvCZIyQc/UIkzJpr1neI/AAAAAAAAFls/jfMZCwnu30I/s1600/offscreen_pages.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;If you only use a small amount of pages you may get a better performance by creating them all at once. You can use &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)"&gt;setOffscreenPageLimit(int limit)&lt;/a&gt; to set the number of pages that will be created and retained. Note that the limit applies to both sides of the current page. So if you set the offscreen page limit to 2 the ViewPager will retain 5 pages: The current page plus 2 pages to the left and right.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Responding to changing states&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;You can get notified whenever the displayed page changes or is incrementally scrolled. To listen to these state changes you can implement the &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.OnPageChangeListener.html"&gt;OnPageChangeListener&lt;/a&gt; interface or extend the &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.SimpleOnPageChangeListener.html"&gt;SimpleOnPageChangeListener&lt;/a&gt; class if you do not intent to override every method of the interfacce.&lt;br /&gt;&lt;br /&gt;The following example listener updates the title of the activity according to the title of the currently selected page:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-xgUfOiVWc_g/UIkzQ_OCF8I/AAAAAAAAFl0/Fp_eXNYlt4g/s1600/UpdateTitleListener.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-xgUfOiVWc_g/UIkzQ_OCF8I/AAAAAAAAFl0/Fp_eXNYlt4g/s1600/UpdateTitleListener.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/blob/master/ViewPager/02/UpdateTitleListener.java"&gt;UpdateTitleListener.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Margin between pages&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;When scrolling through pages they all look like glued together. You can use &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setPageMargin(int)"&gt;setPageMargin(int pixels)&lt;/a&gt; to define a margin between pages. The gap is filled with the background color of the ViewPager.&lt;br /&gt;&lt;br /&gt;The following screenshots are showing the same ViewPager during switching pages. The left screenshot shows the ViewPager with no page margin set. In the right screenshot the margin has been set to 20 pixels. Notice that the method expects the margin to be defined in pixels. To use the same physical margin on all kind of screens independent from their pixel density define the margin in density independent pixels (dp) and &lt;a href="http://stackoverflow.com/a/6327095/234908"&gt;convert them to the actual number of pixels&lt;/a&gt; for the current screen.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-fS9q-7IO-Uc/UIkzWvgeSoI/AAAAAAAAFl8/GESmB7vau7c/s1600/page_margin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-fS9q-7IO-Uc/UIkzWvgeSoI/AAAAAAAAFl8/GESmB7vau7c/s1600/page_margin.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;It's also possible to define a drawable that will be used to fill the margin between two pages using &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setPageMarginDrawable(int)"&gt;setPageMarginDrawable(int resId)&lt;/a&gt; or &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setPageMarginDrawable(android.graphics.drawable.Drawable)"&gt;setPageMarginDrawable(Drawable d)&lt;/a&gt;. The best approach is to use a &lt;a href="http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch"&gt;Nine-patch&lt;/a&gt; that be scaled dynamically by the system to fill the space between the pages.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Switching pages programmatically&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;You can also switch between pages programmatically. Using &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setCurrentItem(int, boolean)"&gt;setCurrentItem(int position, boolean smoothScroll)&lt;/a&gt; you can switch to the given position. If the second parameter is &lt;span style="color: #660000;"&gt;true&lt;/span&gt; a smooth animated transition is being performed. Using &lt;span style="color: #660000;"&gt;false&lt;/span&gt; the ViewPager will switch to the given page without any animation. If you always want to switch pages with an animation you can also leave the second parameter and use &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setCurrentItem(int)"&gt;setCurrentItem(int position)&lt;/a&gt;.&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/EUMG4ssJLOA" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/8727545494996059717/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/10/examining-viewpager-2.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8727545494996059717" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8727545494996059717" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/EUMG4ssJLOA/examining-viewpager-2.html" title="Examining the ViewPager #2" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-HzlJvCZIyQc/UIkzJpr1neI/AAAAAAAAFls/jfMZCwnu30I/s72-c/offscreen_pages.png" height="72" width="72" /><thr:total>1</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/10/examining-viewpager-2.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-1618586447717593615</id><published>2012-10-22T18:30:00.000+02:00</published><updated>2012-10-30T23:18:43.358+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="FragmentPagerAdapter" /><category scheme="http://www.blogger.com/atom/ns#" term="FragmentStatePagerAdapter" /><category scheme="http://www.blogger.com/atom/ns#" term="PagerAdapter" /><category scheme="http://www.blogger.com/atom/ns#" term="ViewPager" /><title type="text">Examining the ViewPager #1</title><content type="html">&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the ViewPager component. &lt;a href="http://www.androidzeitgeist.com/p/viewpager.html"&gt;Click here&lt;/a&gt; to see a list of &lt;a href="http://www.androidzeitgeist.com/p/viewpager.html"&gt;all articles of this series&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://developer.android.com/tools/extras/support-library.html"&gt;Android support library&lt;/a&gt; offers a great UI component for horizontal scrolling pages: &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html"&gt;The ViewPager&lt;/a&gt;. Over the last iterations of the support library more and more functionality has been added to the ViewPager silently. For that reason I decided to study the various features of the ViewPager more closely. This will be a series of articles covering several of these features.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Disclaimer upfront&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;According to the &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html"&gt;documentation of the ViewPager&lt;/a&gt; the implementation and API of the class may change in future releases. Therefore also this blog posting may not be up-to-date if you are reading this a long time after the published date. Check the &lt;a href="http://developer.android.com/reference/android/support/v4/view/ViewPager.html"&gt;documentation&lt;/a&gt; if some of the examples may not work anymore as I described them here.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;The basics&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The ViewPager is a &lt;a href="http://developer.android.com/reference/android/view/ViewGroup.html"&gt;ViewGroup&lt;/a&gt; that displays by default one page at a time. The user can switch between these pages by swiping horizontally. A &lt;a href="http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html"&gt;PagerAdapter&lt;/a&gt; dynamically provides these pages which can be just views or fragments. However the ViewPager is not an AdapterView like the ListView or the GridView. Therefore you need to implement a specific adapter class in order to use the ViewPager class.&lt;br /&gt;&lt;br /&gt;The following video shows a ViewPager with different colored pages:&lt;br /&gt;&lt;br /&gt;&lt;iframe allowfullscreen="allowfullscreen" frameborder="0" height="360" src="http://www.youtube.com/embed/tcnGyRc9t0M?rel=0" width="480"&gt;&lt;/iframe&gt; &lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Adapter using fragments&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The easiest way to write an adapter for a ViewPager is to use fragments and let your adapter implementation extend the &lt;a href="http://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter.html"&gt;FragmentPagerAdapter&lt;/a&gt; class. You only need to implement &lt;a href="http://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter.html#getItem(int)"&gt;getItem(int position)&lt;/a&gt; to return a fragment for the page at the given position and &lt;a href="http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html#getCount()"&gt;getCount()&lt;/a&gt; to return the number of pages to display.&lt;br /&gt;&lt;br /&gt;The following implementation shows the FragmentPagerAdapter used for the video above:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-CkknYiuF5vQ/UIQMY-pOFOI/AAAAAAAAFjY/es0HrjuPA0U/s1600/SampleFragmentPagerAdapter.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-CkknYiuF5vQ/UIQMY-pOFOI/AAAAAAAAFjY/es0HrjuPA0U/s1600/SampleFragmentPagerAdapter.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/blob/master/ViewPager/01/SampleFragmentPagerAdapter.java"&gt;SampleFragmentPagerAdapter.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Saving fragment states&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When using a &lt;a href="http://developer.android.com/reference/android/support/v13/app/FragmentPagerAdapter.html"&gt;FragmentPagerAdapter&lt;/a&gt; and swiping through the pages the ViewPager may eventually have created fragments for all the pages. Depending on the number of pages this may need a large amount of memory just for holding all the offscreen pages. To solve this problem the support library offers the &lt;a href="http://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html"&gt;FragmentStatePagerAdapter&lt;/a&gt; class. This adapter will destroy fragments not visible to the user when needed. Whenever this happens the adapter saves the fragment's current state using &lt;a href="http://developer.android.com/reference/android/app/Fragment.html#onSaveInstanceState(android.os.Bundle)"&gt;onSaveInstanceState(Bundle outState) &lt;/a&gt;of the fragment class to restore it when the fragment for this page gets recreated.&lt;br /&gt;&lt;br /&gt;Implementing an adapter extending the FragmentStatePagerAdapter is exactly the same as when using the FragmentPagerAdapter class. Just your fragment needs to take care of saving its state when getting destroyed. Take a look at the &lt;a href="http://developer.android.com/reference/android/app/Fragment.html#onSaveInstanceState(android.os.Bundle)"&gt;documentation&lt;/a&gt; for an example on how to retain the state of a fragment.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Adapter using views&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can also use the ViewPager with only View objects as pages if using fragments isn't an option for you. It's a bit more tricky to implement the adapter as you'll have to directly extend the &lt;a href="http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html"&gt;PagerAdapter&lt;/a&gt; class.&lt;br /&gt;&lt;br /&gt;The following example creates an adapter that shows a number of different colored pages like the FragmentPagerAdapter implementation above.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-mxaO0n1cYhQ/UIQNo43ZszI/AAAAAAAAFjw/FQ5bbhdhrMU/s1600/SamplePagerAdapter.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-mxaO0n1cYhQ/UIQNo43ZszI/AAAAAAAAFjw/FQ5bbhdhrMU/s1600/SamplePagerAdapter.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/blob/master/ViewPager/01/SamplePagerAdapter.java"&gt;SamplePagerAdaper.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;As you can see you need to write some boilerplate code to add and remove the views to the pager. I published a simple&amp;nbsp;&lt;a href="https://gist.github.com/3927202"&gt;ViewPagerAdapter&lt;/a&gt; class on GitHub that does all this for you so that you don't need to write much more code than when using fragments:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-RG1Pybe0Qko/UIQNEZ0emlI/AAAAAAAAFjo/wiW86E8k3lY/s1600/SamplePagerAdapter2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-RG1Pybe0Qko/UIQNEZ0emlI/AAAAAAAAFjo/wiW86E8k3lY/s1600/SamplePagerAdapter2.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Android-Zeitgeist-Samples/blob/master/ViewPager/01/SamplePagerAdapter2.java"&gt;SamplePagerAdapter2.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/Xd7oNSltXJE" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/1618586447717593615/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/10/examining-viewpager-14.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/1618586447717593615" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/1618586447717593615" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/Xd7oNSltXJE/examining-viewpager-14.html" title="Examining the ViewPager #1" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://img.youtube.com/vi/tcnGyRc9t0M/default.jpg" height="72" width="72" /><thr:total>4</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/10/examining-viewpager-14.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-2935160722418880762</id><published>2012-10-18T19:28:00.003+02:00</published><updated>2012-10-30T23:19:15.647+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="camera" /><category scheme="http://www.blogger.com/atom/ns#" term="CameraFragment" /><category scheme="http://www.blogger.com/atom/ns#" term="Instant Mustache" /><category scheme="http://www.blogger.com/atom/ns#" term="SurfaceView" /><title type="text">Displaying the camera preview - Instant Mustache #5</title><content type="html">&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the development process of Instant Mustache, a fun camera app that adds mustaches to all faces using face detection.&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-size: small;"&gt;Click here&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;&amp;nbsp;to get a chronological list of all published&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-size: small;"&gt;articles about Instant Mustache&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;From &lt;a href="http://www.androidzeitgeist.com/2012/10/using-fragment-for-camera-preview.html"&gt;the last article&lt;/a&gt; we already have three components: A &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-04/src/com/androidzeitgeist/mustache/activity/CameraActivity.java"&gt;CameraActivity&lt;/a&gt; with not much code, an empty &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-04/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java"&gt;CameraFragment&lt;/a&gt; and a &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-04/src/com/androidzeitgeist/mustache/listener/CameraFragmentListener.java"&gt;CameraFragmentListener&lt;/a&gt; interface for the communication between fragment and activity. Now we need to write the actual CameraFragment code to display the camera preview.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;The CameraPreview component&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For displaying the preview we need an instance of &lt;a href="http://developer.android.com/reference/android/view/SurfaceView.html"&gt;SurfaceView&lt;/a&gt; to draw the actual camera picture on. We'll extend the SurfaceView to create our own view component called &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-05/src/com/androidzeitgeist/mustache/view/CameraPreview.java"&gt;CameraPreview&lt;/a&gt;.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.androidzeitgeist.com/2012/08/lets-start-coding-not-instant-mustache-3.html"&gt;In the first articles&lt;/a&gt; we decided to use a square ratio for the preview. After some testing around it seems the emulator is the only "device" that supports a square sized camera preview and picture size out of the box. To work around this issue we would need to use a widely supported ratio (4:3) and crop the preview picture as well as the taken photo ourselves. To keep the code and the first version of the app small (and to follow the &lt;a href="http://www.androidzeitgeist.com/2012/07/minimal-marketable-app-instant-mustache.html"&gt;Minimal Marketable App&lt;/a&gt; principle) I decided to change this requirement. We will use the commonly supported ratio of 4:3.&lt;br /&gt;&lt;br /&gt;We implement onMeasure() to set the dimension of the view to a 4:3 ratio:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-NJ3UtjTFli4/UIA4oX9FTuI/AAAAAAAAFhg/AMivOOGn94Y/s1600/onmeasure.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-NJ3UtjTFli4/UIA4oX9FTuI/AAAAAAAAFhg/AMivOOGn94Y/s1600/onmeasure.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-05/src/com/androidzeitgeist/mustache/view/CameraPreview.java#L32"&gt;onMeasure() - CameraPreview.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Setting up the camera&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Even though we know our desired ratio we can't just set a size via &lt;a href="http://developer.android.com/reference/android/hardware/Camera.html#setParameters(android.hardware.Camera.Parameters)"&gt;camera.setParameters(Camera.Parameters)&lt;/a&gt;. Instead we have to query the &lt;a href="http://developer.android.com/reference/android/hardware/Camera.Parameters.html"&gt;Camera.Parameters&lt;/a&gt; object we get from getParameters() to retrieve a list of supported preview and picture sizes. Then we have to scan this list for a size that has our desired ratio. This is what determineBestSize() does:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-9EpZpQQQk_g/UH2o5PQn4kI/AAAAAAAAFgk/Ip5ecGrvDSU/s1600/determine_size.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-9EpZpQQQk_g/UH2o5PQn4kI/AAAAAAAAFgk/Ip5ecGrvDSU/s1600/determine_size.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-05/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java#L190"&gt;determineBestSize() - CameraFragment.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;We are using a threshold for the preview and picture size to save some heap space for the bitmap transformations we'll do later. For now these limits are 640x480 for the preview size and 1280x960 for the &amp;nbsp;picture size.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Finally the determined values are used to setup the camera object:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-aeWvWYDnT2s/UH2uJVZkAFI/AAAAAAAAFg4/puouCbK7VOQ/s1600/setup_camera.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-aeWvWYDnT2s/UH2uJVZkAFI/AAAAAAAAFg4/puouCbK7VOQ/s1600/setup_camera.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-05/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java#L166"&gt;setupCamera() - CameraFragment.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The CameraPreview component will be used as view of our CameraFragment by returning it in &lt;a href="http://developer.android.com/reference/android/app/Fragment.html#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)"&gt;onCreateView()&lt;/a&gt;. In addition to that our CameraFragment needs to implement &lt;a href="http://developer.android.com/reference/android/view/SurfaceHolder.Callback.html"&gt;SurfaceHolder.Callback&lt;/a&gt; in order to get notified when the surface is created or destroyed.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Accessing the camera&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To access the camera of the device we need to call &lt;a href="http://developer.android.com/reference/android/hardware/Camera.html#open(int)"&gt;Camera.open(int cameraId)&lt;/a&gt; to obtain a &lt;a href="http://developer.android.com/reference/android/hardware/Camera.html"&gt;Camera&lt;/a&gt; object. The camera ids are numbered starting with 0. As we currently don't want to support multiple cameras we will just call Camera.open(0).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Unfortunately using the camera can cause undefined exceptions to be thrown. Therefore we need to wrap some code accessing the camera object into try-catch blocks and catch the generic Exception object. This is usually &lt;a href="http://source.android.com/source/code-style.html#dont-catch-generic-exception"&gt;considered bad practice&lt;/a&gt; but in this case &lt;a href="http://developer.android.com/guide/topics/media/camera.html#access-camera"&gt;encouraged to do by the documentation&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Sharing the camera resource&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The camera can only be used by one application at a time so we need to release the camera every time the activity gets paused. Otherwise the user would not be able to use other camera applications while our activity is in the background. In some cases not releasing the camera can lead to the CameraService crashing. If this happens no camera application can be used until the user reboots his phone. We never want this to happen.&lt;br /&gt;&lt;br /&gt;To be safe we will open the camera by calling Camera.open() in the &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-05/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java#L70"&gt;onResume()&lt;/a&gt; method of the CameraFragment and releasing it again in &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-05/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java#L87"&gt;onPause()&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Once we have a Camera object and our surface is created we can assign the surface to the camera object and start the preview. We wrap the call to startPreview() in our own method called &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-05/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java#L97"&gt;startCameraPreview()&lt;/a&gt; inside our fragment. This way we can setup the camera object before actually starting the preview.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-KFpfQOjQJY4/UIA567dmV6I/AAAAAAAAFho/fv7wu7wsUYg/s1600/startpreview.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-KFpfQOjQJY4/UIA567dmV6I/AAAAAAAAFho/fv7wu7wsUYg/s1600/startpreview.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-05/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java#L97"&gt;startCameraPreview() - CameraFragment.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Determining the display orientation&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The screen can be rotated in four different angles (0°, 90°, 180°, 270°). In addition to that the camera can also be built into the device in four different angles by the manufacturer. Finally the camera can be on the front or on the back of the device. We will need to get all these angles and tell the camera object the display orientation so that the preview will be drawn on the surface using the right rotation.&lt;br /&gt;&lt;br /&gt;This sounds tricky but fortunately there's a &lt;a href="http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int)"&gt;code snippet for that in the Android documentation&lt;/a&gt;. We'll use &lt;a href="http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int)"&gt;this code snippet&lt;/a&gt; to implement &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-05/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java#L126"&gt;determineDisplayOrientation()&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Screenshot&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;And that's how our app looks like so far:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-YuVQvTJ3OU0/UIA00sECLRI/AAAAAAAAFhM/R8mHYZhRnIE/s1600/mustache_screen.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-YuVQvTJ3OU0/UIA00sECLRI/AAAAAAAAFhM/R8mHYZhRnIE/s1600/mustache_screen.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;As always the&amp;nbsp;&lt;a href="https://github.com/pocmo/Instant-Mustache/tree/article-05"&gt;source code&amp;nbsp;of the current version&lt;/a&gt; of the app is available at Github.&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/C01oUsX3kSI" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/2935160722418880762/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/10/displaying-camera-preview-instant.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/2935160722418880762" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/2935160722418880762" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/C01oUsX3kSI/displaying-camera-preview-instant.html" title="Displaying the camera preview - Instant Mustache #5" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-NJ3UtjTFli4/UIA4oX9FTuI/AAAAAAAAFhg/AMivOOGn94Y/s72-c/onmeasure.png" height="72" width="72" /><thr:total>1</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/10/displaying-camera-preview-instant.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-7757019473292818494</id><published>2012-10-15T19:28:00.002+02:00</published><updated>2012-10-30T23:19:35.663+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Fragment" /><category scheme="http://www.blogger.com/atom/ns#" term="Instant Mustache" /><title type="text">Using a fragment for the camera preview - Instant Mustache #4</title><content type="html">&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the development process of Instant Mustache, a fun camera app that adds mustaches to all faces using face detection.&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-size: small;"&gt;Click here&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;&amp;nbsp;to get a chronological list of all published&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-size: small;"&gt;articles about Instant Mustache&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This article will be the first one about writing the CameraActivity for &lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html"&gt;Instant Mustache&lt;/a&gt;. From &lt;a href="http://www.androidzeitgeist.com/2012/08/lets-start-coding-not-instant-mustache-3.html"&gt;the last article&lt;/a&gt; we already know how the layout of the activity should look like. Now it's time to start the coding part.&lt;br /&gt;&lt;br /&gt;I won't cover all the lines of code in this and the following blog articles but you can always get the complete &lt;a href="https://github.com/pocmo/Instant-Mustache"&gt;source code of Instant Mustache at GitHub&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Using a fragment&lt;/b&gt;&lt;br /&gt;We'll move the actual code (and layout) that handles the camera preview to a &lt;a href="http://developer.android.com/guide/components/fragments.html"&gt;fragment&lt;/a&gt;. Using fragments has several advantages:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Fragments can be reused in different activities and layouts. Therefore they are perfect building blocks for composing UIs for different screen sizes.&lt;/li&gt;&lt;li&gt;They encapsulate the code for a specific component including the layout of the component. This makes the activity code and layout much more simpler and cleaner. By using a bunch of fragments the activity basically only has to handle events and delegate them to the appropriate fragments. This leads to the activity becoming some kind of light meta controller instead of an unreadable dumping ground for handling everything on the current screen.&lt;/li&gt;&lt;li&gt;Fragments can be dynamically added, removed, replaced, added to the back stack, animated and other cool things that can be painful to do yourself.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;Activity layout&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="margin-bottom: 0in;"&gt;As said before we are moving the camera preview code and layout to a fragment. Therefore our activity's layout is really quite simple:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="margin-left: auto; margin-right: auto;"&gt;&lt;a href="http://www.blogger.com/goog_154278281"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-9A5F03FauP0/UHxDx3aMDcI/AAAAAAAAFfE/x245XxDRKJk/s1600/camera_activity_layout_2.png" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-04/res/layout/activity_camera.xml"&gt;activity_camera.xml&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;b&gt;Communication between activity and fragment&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;There are situations where the fragment needs to notify the activity about events. In our case the fragment needs to tell the activity when it's unable to instantiate a camera preview so that the activity can handle this error case. Of course we could just access the activity inside the fragment using &lt;a href="http://developer.android.com/reference/android/app/Fragment.html#getActivity()"&gt;getActivity()&lt;/a&gt; and cast it to a CameraActivity object to get access to a method like onCameraError() but then our fragment would only be usable with this particular activity:&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="color: #444444; font-family: Courier New, Courier, monospace;"&gt;CameraActivity activity = (CameraActivity) getActivity();&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="color: #444444; font-family: Courier New, Courier, monospace;"&gt;activity.onCameraError();&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;We work around this issue by defining an interface that has to be implemented by the CameraActivity and every other component that wants to use the CameraFragment:&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/--DMu6Y45ciU/UHxBNXetSII/AAAAAAAAFe0/YrGtXiPkUXE/s1600/fragment_listener.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;span style="color: black;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/--DMu6Y45ciU/UHxBNXetSII/AAAAAAAAFe0/YrGtXiPkUXE/s1600/fragment_listener.png" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-04/src/com/androidzeitgeist/mustache/listener/CameraFragmentListener.java"&gt;&lt;span style="color: black; font-size: small;"&gt;CameraFragmentListener.java&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Every time our fragment gets attached to an activity &lt;a href="http://developer.android.com/reference/android/app/Fragment.html#onAttach(android.app.Activity)"&gt;onAttach()&lt;/a&gt; will be called with the activity as parameter. We use this method to enforce that the activity implements our defined interface:&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="margin-left: auto; margin-right: auto;"&gt;&lt;a href="http://www.blogger.com/goog_154278245"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-hGixG23tyHc/UHxBneeyqOI/AAAAAAAAFe8/VF7FmuzO8Jk/s1600/fragment_on_attach.png" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-04/src/com/androidzeitgeist/mustache/fragment/CameraFragment.java"&gt;CameraFragment.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Finally take a look at the &lt;a href="https://github.com/pocmo/Instant-Mustache/blob/article-04/src/com/androidzeitgeist/mustache/activity/CameraActivity.java"&gt;CameraActivity source code on GitHub&lt;/a&gt;. It just sets the layout in onCreate() and shows a &lt;a href="http://developer.android.com/guide/topics/ui/notifiers/toasts.html"&gt;toast&lt;/a&gt; in case of the fragment calling onCameraError(). As this method will be called in case of non-recoverable errors we'll also finish the activity.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/BCc8E5OcNig" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/7757019473292818494/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/10/using-fragment-for-camera-preview.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/7757019473292818494" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/7757019473292818494" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/BCc8E5OcNig/using-fragment-for-camera-preview.html" title="Using a fragment for the camera preview - Instant Mustache #4" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-9A5F03FauP0/UHxDx3aMDcI/AAAAAAAAFfE/x245XxDRKJk/s72-c/camera_activity_layout_2.png" height="72" width="72" /><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/10/using-fragment-for-camera-preview.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-8978580997544983984</id><published>2012-08-20T19:02:00.001+02:00</published><updated>2012-10-30T23:19:51.789+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Boolean" /><category scheme="http://www.blogger.com/atom/ns#" term="Integer" /><category scheme="http://www.blogger.com/atom/ns#" term="Resources" /><title type="text">Know your resources: Integers and Booleans</title><content type="html">An Android application isn't only code but comes with a bunch of &lt;a href="http://developer.android.com/guide/topics/resources/index.html"&gt;resources&lt;/a&gt;. Probably the most important resources (besides layouts and drawables) are the string resources. In conjunction with the &lt;a href="http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources"&gt;resource qualifiers&lt;/a&gt; they are not only perfect to externalize strings for localization but also for defining different internal configurations of your app.&lt;br /&gt;&lt;br /&gt;However sometimes string resources are overused. Especially when they are used to define boolean or integer values. Let's look at the following example. Code lines like the next ones can be found in several Android projects. For example you can find &lt;a href="https://github.com/pocmo/Yaaic/blob/master/application/src/org/yaaic/model/Settings.java#L74"&gt;some of these in Yaaic&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-XLbaLF9yRos/UDJrT8HzfaI/AAAAAAAAFMk/6_ctbD-1rQ8/s1600/resources_example01.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-XLbaLF9yRos/UDJrT8HzfaI/AAAAAAAAFMk/6_ctbD-1rQ8/s1600/resources_example01.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Loading string resources and parsing as boolean or integer&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Or even worse in a condition without casting, doing a string comparison:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-IfOUvr3e9og/UDJrri2Gu3I/AAAAAAAAFMs/qB5wMlRTBzI/s1600/resources_example02.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-IfOUvr3e9og/UDJrri2Gu3I/AAAAAAAAFMs/qB5wMlRTBzI/s1600/resources_example02.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Loading boolean as string resource and doing string comparison&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The code above is not wrong but instead of using string resources and parsing or comparing them it would be easier to use resources of the appropriate type. Fortunately Android allows to&amp;nbsp;define &lt;a href="http://developer.android.com/guide/topics/resources/more-resources.html#Bool"&gt;boolean&lt;/a&gt; and &lt;a href="http://developer.android.com/guide/topics/resources/more-resources.html#Integer"&gt;integer&lt;/a&gt; resources too (since API level 1). It's basically the same process as defining a string resource in XML just use the bool and integer tags:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-BIkUDBXNXFU/UDJr4uQMhTI/AAAAAAAAFM0/39d0Vj3jIKo/s1600/xml_resources.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-BIkUDBXNXFU/UDJr4uQMhTI/AAAAAAAAFM0/39d0Vj3jIKo/s1600/xml_resources.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Defining boolean and integer resources in XML&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;After that you can access these resources in code. However there are no &lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/content/Context.java#304"&gt;alias methods&lt;/a&gt; on the &lt;a href="http://developer.android.com/reference/android/content/Context.html"&gt;Context&lt;/a&gt; object like for string resources. Therefore you need to get a &lt;a href="http://developer.android.com/reference/android/content/res/Resources.html"&gt;Resources&lt;/a&gt; instance first and then ask it for the defined resources.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-bLP5ceuA0xY/UDOhAxoQunI/AAAAAAAAFNM/ONwuHscnEDw/s1600/accessing_resources.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-bLP5ceuA0xY/UDOhAxoQunI/AAAAAAAAFNM/ONwuHscnEDw/s1600/accessing_resources.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Accessing integer and boolean resources from code&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/SH5Bn82Meao" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/8978580997544983984/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/08/know-your-resources-integers-and.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8978580997544983984" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8978580997544983984" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/SH5Bn82Meao/know-your-resources-integers-and.html" title="Know your resources: Integers and Booleans" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-XLbaLF9yRos/UDJrT8HzfaI/AAAAAAAAFMk/6_ctbD-1rQ8/s72-c/resources_example01.png" height="72" width="72" /><thr:total>1</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/08/know-your-resources-integers-and.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-7567694303001801787</id><published>2012-08-01T21:01:00.002+02:00</published><updated>2012-10-30T23:20:51.695+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Instant Mustache" /><category scheme="http://www.blogger.com/atom/ns#" term="mockup" /><category scheme="http://www.blogger.com/atom/ns#" term="sketch" /><category scheme="http://www.blogger.com/atom/ns#" term="UI" /><title type="text">Let's start coding ... NOT! - Instant Mustache #3</title><content type="html">&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the development process of Instant Mustache, a fun camera app that adds mustaches to all faces using face detection.&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-size: small;"&gt;Click here&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;&amp;nbsp;to get a chronological list of all published&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-size: small;"&gt;articles about Instant Mustache&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the &lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html"&gt;last two articles&lt;/a&gt; about Instant Mustache we've talked a lot and it's about time to start coding! Yet I’ve to disappoint you for now. There still will be no code in this article. Before we’ll start coding we’ve to define what we actually need or want. From the last article we already know there will be two screens. But what we don’t know yet is how they should look like. So how will we figure out how the (very simple) UI will look like? Of course we can fire up our code editor or visual editor but there’s a much faster way to get results: Good old paper.&lt;br /&gt;&lt;br /&gt;I won’t talk about paper prototypes or UI development and user testing here. But there’s a better resource for that. The &lt;a href="http://www.androiduipatterns.com/"&gt;Android UI Patterns blog&lt;/a&gt; has a lot of articles published covering a variety of Android UI topics. Here we are going to just sketch some screens, play around and hopefully come up with an idea of how the app will feel like when it’s finally developed. As said before I'll use paper for that. Other people may like to use software for creating mockups (&lt;a href="http://www.fluidui.com/"&gt;Fluid UI&lt;/a&gt; seems to be a nice online tool for that). It's up to you what works the best for you. For me paper is the easiest way to try different ideas without the limitations of a software tool. But the important thing is: We won't write a lot of code that we need to throw away again after we realize that our initial idea may not be as good as we thought.&lt;br /&gt;&lt;br /&gt;The following photo shows a bunch of discarded drawings I came up with during brainstorming the UI:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-vLyg3OA870M/UBlqUI8HXhI/AAAAAAAAEeA/E3oDqTCMi9o/s1600/screens.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="176" src="http://2.bp.blogspot.com/-vLyg3OA870M/UBlqUI8HXhI/AAAAAAAAEeA/E3oDqTCMi9o/s400/screens.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;b&gt;The camera screen (CameraActivity)&lt;/b&gt;&lt;br /&gt;The first screen the user will see after launching the app will be the camera screen. There are two main components we need: A camera preview and a button to take a photo. In addition to that we may want to reserve some space for future features like switching between cameras and mustaches.&lt;br /&gt;&lt;br /&gt;Let's take a look at the the final version of the camera screen as I've drawn it:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ACfaRYTWXiQ/UBlrUkZlmPI/AAAAAAAAEe4/c5nw7R2I3EM/s1600/final_camera_activity.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-ACfaRYTWXiQ/UBlrUkZlmPI/AAAAAAAAEe4/c5nw7R2I3EM/s1600/final_camera_activity.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;CameraActivity&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;The following decisions I've made during drawing and experimenting:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I want the app to have an &lt;a href="http://developer.android.com/design/patterns/actionbar.html"&gt;ActionBar&lt;/a&gt;. To be consistent I also want the ActionBar in the camera screen. I don't know yet if it's useful to show the app title "Instant Mustache" in the ActionBar as I've drawn it. It's quite long and may take up too much space. Furthermore the overflow menu drawn here may not be visible as we have no menu entries defined yet.&lt;/li&gt;&lt;li&gt;The camera picture will be a square. We'll have to define a picture ratio and a square may fit quite nice into the screen. The darker areas on the screen will grow or shrink depending on the screen size of the device and always center the camera preview.&lt;/li&gt;&lt;li&gt;There will be a bar at the bottom of the screen which will house the button for taking a picture. Here we will have enough space for adding more functionality in later releases.&lt;/li&gt;&lt;li&gt;Almost all activities showing a camera preview are fixed in their orientation. While moving the phone around to take a photo you don't want the phone to destroy the current activity, do the rotation and re-create the activity. Especially because the camera picture will be oriented correctly anyways because you are rotating the camera inside the phone as well. To satisfy the previous points we will fixate the orientation to portrait mode.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;The photo screen (PhotoActivity)&lt;/b&gt;&lt;br /&gt;After taking a photo you will see another screen showing the photo you've taken and you'll have the option to share the photo with other apps on your phone.&lt;br /&gt;&lt;br /&gt;That's how my final version of the photo screen looks like:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-ZkXDFTYoBTs/UBlv6nT4mRI/AAAAAAAAEfI/RGFW1HHcngE/s1600/final_share_activity.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-ZkXDFTYoBTs/UBlv6nT4mRI/AAAAAAAAEfI/RGFW1HHcngE/s1600/final_share_activity.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;PhotoActivtiy&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;The first version of this screen will be really simple:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;At the top we'll have the ActionBar again. To share the photo we'll add a &lt;a href="http://developer.android.com/guide/topics/ui/actionbar.html#ActionProvider"&gt;ShareActionProvider&lt;/a&gt; that shows a list of available share targets as well as the most used app as an icon right beside it.&lt;/li&gt;&lt;li&gt;Below the ActionBar we'll show the taken photo and that's everything for now.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;b&gt;What's next?&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Now we've defined how our two screens will look like. In the next article we are going to launch our IDE and start writing the CameraActivity. I am curious to know what you think about the UI as described here and if you have other ideas. Let me know in the comments or on Google+.&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/xRHDRu4wROY" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/7567694303001801787/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/08/lets-start-coding-not-instant-mustache-3.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/7567694303001801787" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/7567694303001801787" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/xRHDRu4wROY/lets-start-coding-not-instant-mustache-3.html" title="Let's start coding ... NOT! - Instant Mustache #3" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-vLyg3OA870M/UBlqUI8HXhI/AAAAAAAAEeA/E3oDqTCMi9o/s72-c/screens.png" height="72" width="72" /><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/08/lets-start-coding-not-instant-mustache-3.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-2631040260680088231</id><published>2012-07-03T20:08:00.003+02:00</published><updated>2012-10-30T23:21:12.300+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Instant Mustache" /><category scheme="http://www.blogger.com/atom/ns#" term="Minimal marketable app" /><category scheme="http://www.blogger.com/atom/ns#" term="roadmap" /><title type="text">Minimal marketable app - Instant Mustache #2</title><content type="html">&lt;span style="font-size: x-small;"&gt;This article is part of a series of articles about the development process of Instant Mustache, a fun camera app that adds mustaches to all faces using face detection.&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-size: small;"&gt;Click here&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;&amp;nbsp;to get a chronological list of all published&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-size: small;"&gt;articles about Instant Mustache&lt;/a&gt;&lt;span style="font-size: x-small;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b id="internal-source-marker_0.039026354206725955"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;In &lt;a href="http://www.androidzeitgeist.com/2012/06/instant-mustache-1-idea.html"&gt;the last article&lt;/a&gt; I described roughly the idea behind Instant Mustache. Now it's time to get more concrete. While doing so we try to follow the principle of the minimal marketable feature (MMF).&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;Minimal marketable feature&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span id="internal-source-marker_0.039026354206725955"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;The idea behind the minimal marketable feature is to strip all aspects of a feature that are not necessarily needed to end up with a useful (or marketable) feature. After that you'll end up with smaller features that are easier and faster to develop. This is only a very rough explanation of MMF. You can find a way better &lt;a href="http://www.upstarthq.com/2010/04/introduction-to-minimum-marketable-features-mmf/"&gt;Introduction to Minimum marketable feature&lt;/a&gt; at the upstart blog.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b style="background-color: white; font-family: Arial; font-size: 15px; white-space: pre-wrap;"&gt;Minimal marketable app&lt;/b&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;In this case we are slightly modifying this idea to end up with something like a &lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;"&gt;minimal marketable app&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;. This means we are going one level higher and strip all features that are not essentially required for a first releasable app. This does not mean that we won't develop these features at all but our first version will be without them enabling us to ship the app as early as possible. &lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; font-family: Arial; font-size: 15px; white-space: pre-wrap;"&gt;Let's continue with an example. When you think about the app (&lt;a href="http://www.androidzeitgeist.com/2012/06/instant-mustache-1-idea.html"&gt;see first article&lt;/a&gt;) you will very fast come up with an idea like: The user should be able to select between a bunch of mustaches - more mustaches = more fun. But do we really need this feature when we launch the app? No, we don't. Our fun app will still be fun with one single mustache. Of course this is one of the first features we should have in the next release after the initial one.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;Another feature that's easy to come up with is switching between the cameras of a device. In most cases this means switching between back and front camera. Again for our basic app it's totally acceptable to strip this feature in the first release. The users of our app won't be able to take pictures of themselves easily and therefore they won't have much fun when there's no mustache-less friend to photograph around. Therefore we should rank this feature high as well to implement it right after the first release.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;In our case the minimal marketable feature set is an app that has two screens: A camera screen - with a camera preview and a button to take a picture - and a second screen that shows the picture you took and has an option to share this picture. The camera preview will show a live preview. Every detected face on the live preview will automatically have a mustache overlayed. If you take a picture the second screen will show the composed picture including the added mustaches. The user will be able to share the picture via the &lt;a href="http://android-developers.blogspot.co.uk/2012/02/share-with-intents.html"&gt;Android intent system&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;Roadmap and Milestones&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b id="internal-source-marker_0.039026354206725955"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;Nothing is more motivating than playing around with what you have created. In contrast nothing is more killing motivation than programming for ages without coming up with something that runs at all.&lt;/span&gt;&lt;span style="vertical-align: baseline;"&gt; &lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;This leads us to the goal to always have a running prototype that step by step gets features added until it's ready to ship. So let's break the functionality into parts that can be implemented in order and always leave us with a working prototype that we can deploy on our phone and use at the next party.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: Arial;"&gt;&lt;span style="font-size: 15px; white-space: pre-wrap;"&gt;&lt;b&gt;Milestone #1&lt;/b&gt;: &lt;/span&gt;&lt;/span&gt;&lt;b id="internal-source-marker_0.039026354206725955"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;A camera screen that shows the camera preview and has a button to take a photo. The photos will be saved on the SD card. After that we will end up with a basic camera app that we can use to take photos on the go. Goodbye native camera app!&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;Milestone #2&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;: &lt;/span&gt;&lt;/b&gt;&lt;b id="internal-source-marker_0.039026354206725955"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;We add the second screen. After taking a photo we’ll switch to this second screen which shows the taken photo and has an option to share the photo.&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;Milestone #3&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;: &lt;/span&gt;&lt;/b&gt;&lt;b id="internal-source-marker_0.039026354206725955"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;It’s time to add the face tracking. We’ll use the face tracking and display mustaches for every face on top of the camera preview.&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;Milestone #4&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;: &lt;/span&gt;&lt;/b&gt;&lt;b id="internal-source-marker_0.039026354206725955"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;When taking a photo we’ll compose the final photo using the information of the face tracking. The composed photo will contain mustaches like the preview screen before. The composed photo will be saved on the SD card and shown in the second screen. We are ready to release!&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/D7VVl5yQcUE" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/2631040260680088231/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/07/minimal-marketable-app-instant-mustache.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/2631040260680088231" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/2631040260680088231" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/D7VVl5yQcUE/minimal-marketable-app-instant-mustache.html" title="Minimal marketable app - Instant Mustache #2" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/07/minimal-marketable-app-instant-mustache.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-2571392770508842451</id><published>2012-06-08T12:14:00.002+02:00</published><updated>2012-10-30T23:21:30.173+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Animation" /><category scheme="http://www.blogger.com/atom/ns#" term="BlinkLayout" /><category scheme="http://www.blogger.com/atom/ns#" term="Layout" /><category scheme="http://www.blogger.com/atom/ns#" term="ViewGroup" /><title type="text">Creating a MarqueeLayout with the Android Animation System</title><content type="html">When I posted the article about &lt;a href="http://www.androidzeitgeist.com/2012/05/curious-blinklayout.html"&gt;the hidden BlinkLayout&lt;/a&gt; inside Android’s LayoutInflater &lt;a href="https://plus.google.com/105344175486242358933/posts"&gt;Thierry-Dimitri Roy&lt;/a&gt; wrote on Google+:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-kpn1WJrtNRw/T9CZQxI269I/AAAAAAAADnM/Pxbd7NWhWkM/s1600/gpluscomment.png" imageanchor="1" style="clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em; text-align: center;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-kpn1WJrtNRw/T9CZQxI269I/AAAAAAAADnM/Pxbd7NWhWkM/s1600/gpluscomment.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That’s a challenge I accept! Back in the days when I worked at Jimdo we developed “&lt;a href="http://www.youtube.com/watch?v=RDNhra-6dQo"&gt;a lifeboat for GeoCities&lt;/a&gt;†which allowed users to migrate their GeoCities website to Jimdo before GeoCities finally shut down in 2009. So I’ve some kind of heart for&amp;nbsp;GeoCities&amp;nbsp;users.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://developer.android.com/guide/topics/graphics/view-animation.html"&gt;view animation system&lt;/a&gt; of Android makes it quite easy to develop something like a MarqueeLayout. All we need to do is to extend an existing ViewGroup and attach a marquee-like animation to every instance.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://developer.android.com/reference/android/view/animation/TranslateAnimation.html"&gt;TranslateAnimation&lt;/a&gt; does already exactly what we need: It moves a view from a starting position to an ending position. The two positions can either be declared absolute (position on the screen) or relative to the view or its parent. After that we only need to define the duration of the animation and Android will do the rest for us.&lt;br /&gt;&lt;br /&gt;We'll define the start and end positions of the animation by using coordinates relative to the view. When using relative coordinates you can think of our view having a size of 1x1 and it's top left corner placed at (0,0).&lt;br /&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-002il9hIkbs/T9CiYixSw3I/AAAAAAAADnY/-04SitxZqVg/s1600/view.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-002il9hIkbs/T9CiYixSw3I/AAAAAAAADnY/-04SitxZqVg/s1600/view.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;View of size 1x1 at position (0,0)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;If our view's width stretches to the whole width of the screen we can consider the screen's size also 1 (relative to the view's width).&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-a8TAfL-nbQs/T9ClZz9tuxI/AAAAAAAADnk/qwDhuGD7DRU/s1600/view_on_screen.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-a8TAfL-nbQs/T9ClZz9tuxI/AAAAAAAADnk/qwDhuGD7DRU/s1600/view_on_screen.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;View (green) filling full width of screen (grey)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Assuming a screen size of 1 and a starting position on the right side outside of the screen gives us a relative starting position of (1,0). This will place our view exactly outside the screen (or it's parent).&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-wuSTX1TEt88/T9Cl3Z4JaxI/AAAAAAAADns/orVD4QJqXMg/s1600/start_at_1_0.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="231" src="http://2.bp.blogspot.com/-wuSTX1TEt88/T9Cl3Z4JaxI/AAAAAAAADns/orVD4QJqXMg/s320/start_at_1_0.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;View animation starting at (1,0)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;The view should move from the starting position to the left until it's outside of the screen at (-1, 0).&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-NOoImxh16nw/T9CmIXQJRqI/AAAAAAAADn0/OF_7nGDw9Pw/s1600/end_-1_0_1.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="231" src="http://4.bp.blogspot.com/-NOoImxh16nw/T9CmIXQJRqI/AAAAAAAADn0/OF_7nGDw9Pw/s320/end_-1_0_1.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;View animation stopping at (-1,0)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;The animation system will generate all transient positions needed for the animation. Given all the information above we can write a simple MarqueeLayout in a few lines:&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;a href="http://www.blogger.com/goog_1690609543"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-OaTBb9uyHZ4/T9Cox5IvbMI/AAAAAAAADoA/bD9eXxmXu-Y/s1600/marquee_layout_code.png" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://source.androidzeitgeist.com/raw/marquee_layout_code.txt"&gt;MarqueeLayout.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;That's what our MarqueeLayout looks like when adding a TextView to it:&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;iframe allowfullscreen="" frameborder="0" height="360" src="http://www.youtube.com/embed/r1LT2EpIB0s" width="480"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;The following code was used to set up an activity using our MarqueeLayout:&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;a href="http://www.blogger.com/goog_1690609550"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-VzGJqlPup70/T9CpDx20HUI/AAAAAAAADoI/iw61M_02ZuQ/s1600/marquee_activity.png" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://source.androidzeitgeist.com/raw/marquee_layout_activity.txt"&gt;MarqueeLayoutActivity.java&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/5ogW6KCmbFc" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/2571392770508842451/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/06/creating-marqueelayout-with-android.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/2571392770508842451" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/2571392770508842451" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/5ogW6KCmbFc/creating-marqueelayout-with-android.html" title="Creating a MarqueeLayout with the Android Animation System" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-kpn1WJrtNRw/T9CZQxI269I/AAAAAAAADnM/Pxbd7NWhWkM/s72-c/gpluscomment.png" height="72" width="72" /><thr:total>1</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/06/creating-marqueelayout-with-android.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-8985540882459629006</id><published>2012-06-05T20:33:00.000+02:00</published><updated>2012-10-30T23:21:46.957+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Instant Mustache" /><title type="text">Instant Mustache #1 - The idea</title><content type="html">&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;span style="font-family: 'Times New Roman'; font-size: x-small; white-space: normal;"&gt;This article is part of a series of articles about the development process of Instant Mustache, a fun camera app that adds mustaches to all faces using face detection.&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-family: 'Times New Roman'; font-size: small; white-space: normal;"&gt;Click here&lt;/a&gt;&lt;span style="font-family: 'Times New Roman'; font-size: x-small; white-space: normal;"&gt;&amp;nbsp;to get a chronological list of all published&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.androidzeitgeist.com/p/instant-mustache.html" style="font-family: 'Times New Roman'; font-size: small; white-space: normal;"&gt;articles about Instant Mustache&lt;/a&gt;&lt;span style="font-family: 'Times New Roman'; font-size: x-small; white-space: normal;"&gt;.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;b&gt;The idea&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="internal-source-marker_0.8338896373752505"&gt;&lt;span style="font-family: Arial; vertical-align: baseline;"&gt;&lt;span style="font-size: 15px; white-space: pre-wrap;"&gt;Instant Mustache is the name of an app that I'm going to develop. The idea is to show the development process of an app starting from a rough idea to a full featured app in the Android market. I'll demonstrate the process of developing the app as well as the thoughts and decisions involved. The source code will be publicly available on &lt;/span&gt;&lt;a href="http://github.com/pocmo/Instant-Mustache" style="font-size: 15px; font-weight: normal; white-space: pre-wrap;"&gt;GitHub&lt;/a&gt;&lt;span style="font-size: 15px; white-space: pre-wrap;"&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="internal-source-marker_0.8338896373752505"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;Later versions of this series of articles are expected to be about topics like &lt;i&gt;refactoring&lt;/i&gt;, adding &lt;i&gt;features&lt;/i&gt;, &lt;i&gt;testing&lt;/i&gt; and maybe &lt;i&gt;monetization&lt;/i&gt;. I'll try to make everything as transparent as possible including user statistics of the Android market.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;The app&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b id="internal-source-marker_0.8338896373752505"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;Instant Mustache is a fun app that utilizes the face tracking feature of Android 4.x to add mustaches to all detected faces currently visible to the camera. Users will be able to take funny pictures and share them with their friends on social networks or other apps on their mobile phone. The user shouldn't need to place the mustaches herself. Instead the placing should be done automatically for every detected face.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;div&gt;&lt;span id="internal-source-marker_0.8338896373752505"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;This is a rough idea every developer can come up with. In the following postings we will refine the idea, plan the app with some basic wireframes and develop an elementary version that can be extended to match our planned full-featured app later.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family: Arial;"&gt;&lt;span style="font-size: 15px; white-space: pre-wrap;"&gt;&lt;b&gt;Do not forget the napkin&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b id="internal-source-marker_0.8338896373752505"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;Of course as a good entrepreneur we had this world-changing idea on the go and had only time to sketch it on a napkin to not forget it later.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;So here is the napkin we came up with:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://1.bp.blogspot.com/-fF1hf6-tlzA/T8ZmAQiTOzI/AAAAAAAADb4/ADS5E1ODlLU/s1600/instant_mustache_tissue.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://1.bp.blogspot.com/-fF1hf6-tlzA/T8ZmAQiTOzI/AAAAAAAADb4/ADS5E1ODlLU/s200/instant_mustache_tissue.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/QNOIAC4E51A" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/8985540882459629006/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/06/instant-mustache-1-idea.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8985540882459629006" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/8985540882459629006" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/QNOIAC4E51A/instant-mustache-1-idea.html" title="Instant Mustache #1 - The idea" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-fF1hf6-tlzA/T8ZmAQiTOzI/AAAAAAAADb4/ADS5E1ODlLU/s72-c/instant_mustache_tissue.jpg" height="72" width="72" /><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/06/instant-mustache-1-idea.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-1531829516427013333.post-9065086572488467738</id><published>2012-05-27T19:01:00.002+02:00</published><updated>2012-10-30T23:22:02.346+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="BlinkLayout" /><category scheme="http://www.blogger.com/atom/ns#" term="Layout" /><category scheme="http://www.blogger.com/atom/ns#" term="ViewGroup" /><title type="text">The curious BlinkLayout</title><content type="html">&lt;span id="internal-source-marker_0.19517051335424185"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;While reading the source code of Android's &lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/view/LayoutInflater.java#LayoutInflater"&gt;LayoutInflater class&lt;/a&gt; I found a hidden gem that seems to be quite unnoticed yet. Ladies and gentlemen I present you the mighty &lt;a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/view/LayoutInflater.java#LayoutInflater.BlinkLayout"&gt;BlinkLayout&lt;/a&gt;. Views that are placed inside this ViewGroup blink at a rate of 500ms.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;The BlinkLayout is an inner class of the LayoutInflater and can therefore only be used in a XML layout that will be parsed by a LayoutInflater instance. Due to the implementation it's only possible to use it as root node using the &amp;lt;blink&amp;gt; tag inside a XML layout.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;It seems like the BlinkLayout is available since Android 4.0 and isn't used in the Android source code I observed. Maybe it was added for debugging reasons and was forgotten later.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial;"&gt;&lt;span style="font-size: 15px; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/o_EX1mH5ZvM/0.jpg" height="266" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/o_EX1mH5ZvM?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt; &lt;param name="bgcolor" value="#FFFFFF" /&gt; &lt;embed width="320" height="266" src="http://www.youtube.com/v/o_EX1mH5ZvM?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;span style="font-family: Arial;"&gt;&lt;span style="font-size: 15px; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;T&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;he video above shows the BlinkLayout in action using the following layout XML:&lt;/span&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-2PBd4Bdwjr8/T8I-BukTXnI/AAAAAAAADZs/_z-Ajl7hOlo/s1600/blinklayout_xml.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img alt="" border="0" src="http://1.bp.blogspot.com/-2PBd4Bdwjr8/T8I-BukTXnI/AAAAAAAADZs/_z-Ajl7hOlo/s1600/blinklayout_xml.png" title="" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://source.androidzeitgeist.com/raw/blinklayout_view_xml.txt"&gt;main_layout.xml&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;T&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;he following snippet was used to inflate the layout and pass it to the activity:&lt;/span&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;a href="http://www.blogger.com/goog_899898043"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-zgP0dePQwzw/T8JIp8nqZ0I/AAAAAAAADaY/ZP7LER-JmM0/s1600/blinklayout_code.png" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="http://source.androidzeitgeist.com/raw/blinklayout_activity_code.txt"&gt;BlinkLayoutActivity.java&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: Arial;"&gt;&lt;span style="font-size: 15px; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;&lt;span style="font-size: 15px; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial;"&gt;&lt;span style="font-size: 15px; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/AndroidZeitgeist/~4/1MleyCfQAow" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.androidzeitgeist.com/feeds/9065086572488467738/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.androidzeitgeist.com/2012/05/curious-blinklayout.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/9065086572488467738" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1531829516427013333/posts/default/9065086572488467738" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AndroidZeitgeist/~3/1MleyCfQAow/curious-blinklayout.html" title="The curious BlinkLayout" /><author><name>Sebastian Kaspari</name><uri>https://plus.google.com/112283223674539938062</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-20YfT7gfh08/AAAAAAAAAAI/AAAAAAAArYw/l6jF4JnmC2E/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-2PBd4Bdwjr8/T8I-BukTXnI/AAAAAAAADZs/_z-Ajl7hOlo/s72-c/blinklayout_xml.png" height="72" width="72" /><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://www.androidzeitgeist.com/2012/05/curious-blinklayout.html</feedburner:origLink></entry></feed>
diff --git a/mobile/android/tests/background/junit4/resources/feed_atom_planetmozilla.xml b/mobile/android/tests/background/junit4/resources/feed_atom_planetmozilla.xml
deleted file mode 100644
index 1638ed9b1..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_atom_planetmozilla.xml
+++ /dev/null
@@ -1,4996 +0,0 @@
-<?xml version="1.0"?>
-<!--
- Snapshot from http://planet.mozilla.org/atom.xml
--->
-<feed xmlns="http://www.w3.org/2005/Atom" xmlns:planet="http://planet.intertwingly.net/" xmlns:indexing="urn:atom-extension:indexing" indexing:index="no"><access:restriction xmlns:access="http://www.bloglines.com/about/specs/fac-1.0" relationship="deny"/>
- <title>Planet Mozilla</title>
- <updated>2016-01-26T19:01:54Z</updated>
- <generator uri="http://intertwingly.net/code/venus/">Venus</generator>
- <author>
- <name>Planet Mozilla Module Team</name>
- <email>planet@mozilla.org</email>
- </author>
- <id>http://planet.mozilla.org/atom.xml</id>
- <link href="http://planet.mozilla.org/atom.xml" rel="self" type="application/atom+xml"/>
- <link href="http://planet.mozilla.org/" rel="alternate"/>
-
- <entry xml:lang="en-US">
- <id>https://quality.mozilla.org/?p=49454</id>
- <link href="https://quality.mozilla.org/2016/01/firefox-45-0-beta-3-testday-february-5th/" rel="alternate" type="text/html"/>
- <title>Firefox 45.0 Beta 3 Testday, February 5th</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Hello Mozillians, We are happy to announce that Friday, February 5th, we are organizing Firefox 45.0 Beta 3 Testday. We will be focusing our testing on the following features: Search Refactoring, Synced Tabs Menu, Text to Speech and Grouped Tabs Migration. Check out the … <a class="go" href="https://quality.mozilla.org/2016/01/firefox-45-0-beta-3-testday-february-5th/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Hello Mozillians,</p>
- <p>We are happy to announce that <strong>Friday, February 5th</strong>, we are organizing <strong>Firefox 45.0 Beta 3 Testday</strong>. We will be focusing our testing on the following features: <em>Search Refactoring, Synced Tabs Menu, Text to Speech and Grouped Tabs Migration</em>. Check out the detailed instructions via <a href="https://public.etherpad-mozilla.org/p/testday-20160205" target="_blank">this etherpad</a>.</p>
- <p>No previous testing experience is required, so feel free to join us on <strong><a href="http://widget01.mibbit.com/?server=irc.mozilla.org&amp;channel=%23qa">#qa IRC channel</a></strong> where our moderators will offer you guidance and answer your questions.</p>
- <p>Join us and help us make Firefox better! See you on <strong>Friday</strong>!</p></div>
- </content>
- <updated>2016-01-26T14:40:55Z</updated>
- <category term="Community"/>
- <category term="Firefox Team"/>
- <category term="QMO News"/>
- <author>
- <name>vasilica.mihasca</name>
- </author>
- <source>
- <id>https://quality.mozilla.org</id>
- <link href="https://quality.mozilla.org/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://quality.mozilla.org" rel="alternate" type="text/html"/>
- <subtitle>Driving quality across Mozilla with data, metrics and a strong community focus</subtitle>
- <title>Mozilla Quality Assurance</title>
- <updated>2016-01-26T14:46:40Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en">
- <id>http://dlawrence.wordpress.com/?p=29</id>
- <link href="https://dlawrence.wordpress.com/2016/01/26/happy-bmo-push-day-4/" rel="alternate" type="text/html"/>
- <title>Happy BMO Push Day!</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">the following changes have been pushed to bugzilla.mozilla.org: [1240575] Update form.reps.budget [1226028] API for batching MozReview requests discuss these changes on mozilla.tools.bmo.<img alt="" border="0" height="1" src="https://pixel.wp.com/b.gif?host=dlawrence.wordpress.com&amp;blog=58816&amp;post=29&amp;subd=dlawrence&amp;ref=&amp;feed=1" width="1"/></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>the following changes have been pushed to bugzilla.mozilla.org:</p>
- <ul>
- <li>[<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1240575" target="_blank">1240575</a>] Update form.reps.budget</li>
- <li>[<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1226028" target="_blank">1226028</a>] API for batching MozReview requests</li>
- </ul>
- <p>discuss these changes on <a href="https://lists.mozilla.org/listinfo/tools-bmo" target="_blank">mozilla.tools.bmo</a>.</p><br/> <a href="http://feeds.wordpress.com/1.0/gocomments/dlawrence.wordpress.com/29/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/dlawrence.wordpress.com/29/"/></a> <img alt="" border="0" height="1" src="https://pixel.wp.com/b.gif?host=dlawrence.wordpress.com&amp;blog=58816&amp;post=29&amp;subd=dlawrence&amp;ref=&amp;feed=1" width="1"/></div>
- </content>
- <updated>2016-01-26T14:27:50Z</updated>
- <category term="Uncategorized"/>
- <author>
- <name>dlawrence</name>
- </author>
- <source>
- <id>https://dlawrence.wordpress.com</id>
- <logo>https://s2.wp.com/i/buttonw-com.png</logo>
- <link href="https://dlawrence.wordpress.com/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://dlawrence.wordpress.com" rel="alternate" type="text/html"/>
- <link href="https://dlawrence.wordpress.com/osd.xml" rel="search" title="Dave's Ramblings" type="application/opensearchdescription+xml"/>
- <link href="https://dlawrence.wordpress.com/?pushpress=hub" rel="hub" type="text/html"/>
- <subtitle>Thoughts somehow related to web, linux, mobile and other things I am interested in</subtitle>
- <title>Dave's Ramblings</title>
- <updated>2016-01-26T14:31:40Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://blog.mozilla.org/tanvi/?p=198</id>
- <link href="https://blog.mozilla.org/tanvi/2016/01/26/updated-firefox-security-indicators/" rel="alternate" type="text/html"/>
- <title>Updated Firefox Security Indicators</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">This article has been coauthored by Aislinn Grigas, Senior Interaction Designer, Firefox Desktop Cross posting with Mozilla’s Security Blog November 3, 2015 Over the past few months, Mozilla has been improving the user experience of our privacy and security features in Firefox. One specific initiative has focused on the feedback shown in our address bar… <a class="more-link" href="https://blog.mozilla.org/tanvi/2016/01/26/updated-firefox-security-indicators/" title="Read the rest of &#x201C;Updated Firefox Security Indicators&#x201D;">Read more</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>This article has been coauthored by Aislinn Grigas, Senior Interaction Designer, Firefox Desktop</em><br/>
- <em>Cross posting with <a href="https://blog.mozilla.org/security/2015/11/03/updated-firefox-security-indicators-2/">Mozilla’s Security Blog</a></em></p>
- <p>November 3, 2015</p>
- <p>Over the past few months, Mozilla has been improving the user experience of our privacy and security features in Firefox. One specific initiative has focused on the feedback shown in our address bar around a site’s security. The major changes are highlighted below along with the rationale behind each change.</p>
- <p><a href="https://blog.mozilla.org/security/files/2015/10/combo-graph21.png"><img alt="" class="alignnone wp-image-2045 size-full" height="914" src="https://blog.mozilla.org/security/files/2015/10/combo-graph21.png" width="1518"/></a></p>
- <h3>Change to DV Certificate treatment in the address bar</h3>
- <p>Color and iconography is commonly used today to communicate to users when a site is secure. The most widely used patterns are coloring a lock icon and parts of the address bar green. This treatment has a straightforward rationale given green = good in most cultures. Firefox has historically used two different color treatments for the lock icon – a gray lock for <a href="https://en.wikipedia.org/wiki/Domain-validated_certificate">Domain-validated (DV) certificates</a> and a green lock for <a href="https://en.wikipedia.org/wiki/Extended_Validation_Certificate">Extended Validation (EV) certificates</a>. The average user is likely not going to understand this color distinction between EV and DV certificates. The overarching message we want users to take from both certificate states is that their connection to the site is secure. We’re therefore updating the color of the lock when a DV certificate is used to match that of an EV certificate.</p>
- <p>Although the same green icon will be used, the UI for a site using EV certificates will continue to differ from a site using a DV certificate. Specifically, EV certificates are used when <a href="https://en.wikipedia.org/wiki/Certificate_authority">Certificate Authorities (CA)</a> verify the owner of a domain. Hence, we will continue to include the organization name verified by the CA in the address bar.</p>
- <h3>Changes to Mixed Content Blocker UI on HTTPS sites</h3>
- <p>A second change we’re introducing addresses what happens when a page served over a secure connection contains <a href="https://developer.mozilla.org/en-US/docs/Security/MixedContent">Mixed Content</a>. Firefox’s Mixed Content Blocker proactively blocks <a href="https://developer.mozilla.org/en-US/docs/Security/MixedContent#Mixed_active_content">Mixed Active Content</a> by default. Users historically saw a <a href="https://people.mozilla.org/~tvyas/FigureA.jpg">shield icon</a> when Mixed Active Content was blocked and were given the option to disable the protection.</p>
- <p>Since the Mixed Content state is closely tied to site security, the information should be communicated in one place instead of having two separate icons. Moreover, we have seen that the <a href="https://telemetry.mozilla.org/new-pipeline/dist.html#!cumulative=0&amp;end_date=2015-09-17&amp;keys=__none__!__none__!__none__&amp;max_channel_version=beta%252F41&amp;measure=MIXED_CONTENT_UNBLOCK_COUNTER&amp;min_channel_version=null&amp;product=Firefox&amp;sanitize=1&amp;sort_keys=submissions&amp;start_date=2015-08-11&amp;table=0&amp;trim=1&amp;use_submission_date=0">number of times users override mixed content protection</a> is slim, and hence the need for dedicated mixed content iconography is diminishing. Firefox is also using the shield icon for another feature in <a href="https://support.mozilla.org/en-US/kb/private-browsing-use-firefox-without-history">Private Browsing Mode</a> and we want to avoid making the iconography ambiguous.</p>
- <p>The updated design that ships with Firefox 42 combines the lock icon with a warning sign which represents Mixed Content. When Firefox blocks Mixed Active Content, we retain the green lock since the HTTP content is blocked and hence the site remains secure.</p>
- <p>For users who want to learn more about a site’s security state, we have added an informational panel to further explain differences in page security. This panel appears anytime a user clicks on the lock icon in the address bar.</p>
- <p>Previously users could <a href="https://people.mozilla.org/~tvyas/FigureB.jpg">click on the shield icon</a> in the rare case they needed to override mixed content protection. With this new UI, users can still do this by clicking the arrow icon to expose more information about the site security, along with a disable protection button.</p>
- <div class="wp-caption alignnone" id="attachment_2034" style="width: 557px;"><a href="https://blog.mozilla.org/security/files/2015/10/mixed-active-content-click-and-subpanel.png"><img alt="mixed active content click and subpanel" class="wp-image-2034 " height="176" src="https://blog.mozilla.org/security/files/2015/10/mixed-active-content-click-and-subpanel.png" width="547"/></a><p class="wp-caption-text">Users can click the lock with warning icon and proceed to disable Mixed Content Protection.</p></div>
- <h3/>
- <h3>Loading Mixed Passive Content on HTTPS sites</h3>
- <p>There is a second category of Mixed Content called <a href="https://developer.mozilla.org/en-US/docs/Security/MixedContent#Mixed_passivedisplay_content">Mixed Passive Content</a>. Firefox does not block Mixed Passive Content by default. However, when it is loaded on an HTTPS page, we let the user know with iconography and text. In previous versions of Firefox, we used a gray warning sign to reflect this case.</p>
- <p>We have updated this iconography in Firefox 42 to a gray lock with a yellow warning sign. We degrade the lock from green to gray to emphasize that the site is no longer completely secure. In addition, we use a vibrant color for the warning icon to amplify that there is something wrong with the security state of the page.</p>
- <p><a href="https://blog.mozilla.org/security/files/2015/10/mixed-passive-click1.png"><img alt="" class="alignnone wp-image-2042 " height="100" src="https://blog.mozilla.org/security/files/2015/10/mixed-passive-click1-600x221.png" width="268"/></a></p>
- <p>We also use this iconography when the certificate or TLS connection used by the website relies on deprecated cryptographic algorithms.</p>
- <p>The above changes will be rolled out in Firefox 42. Overall, the design improvements make it simpler for our users to understand whether or not their interactions with a site are secure.</p>
- <h3>Firefox Mobile</h3>
- <p>We have made similar changes to the site security indicators in Firefox for Android, which you can learn more about <a href="https://support.mozilla.org/en-US/kb/mixed-content-blocker-firefox-android#w_how-do-i-know-if-a-page-has-mixed-content">here</a>.</p></div>
- </content>
- <updated>2016-01-26T05:58:29Z</updated>
- <category term="Browser Security"/>
- <author>
- <name>Tanvi Vyas</name>
- </author>
- <source>
- <id>https://blog.mozilla.org/tanvi</id>
- <link href="https://blog.mozilla.org/tanvi/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://blog.mozilla.org/tanvi" rel="alternate" type="text/html"/>
- <subtitle>Security Engineering - @TanviHacks</subtitle>
- <title>Tanvi's Blog</title>
- <updated>2016-01-26T06:16:19Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://blog.mozilla.org/?p=9166</id>
- <link href="https://blog.mozilla.org/blog/2016/01/25/firefox-can-now-get-push-notifications-from-your-favorite-sites/" rel="alternate" type="text/html"/>
- <title>Firefox Can Now Get Push Notifications From Your Favorite Sites</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Firefox for Windows, Mac and Linux now lets you choose to receive push notifications from websites if you give them permission. This is similar to Web notifications, except now you can receive notifications for websites even when they’re not loaded … <a class="go" href="https://blog.mozilla.org/blog/2016/01/25/firefox-can-now-get-push-notifications-from-your-favorite-sites/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Firefox for Windows, Mac and Linux now lets you choose to receive push notifications from websites if you give them permission. This is similar to Web notifications, except now you can receive notifications for websites even when they’re not loaded in a tab. This is super useful for websites like email, weather, social networks and shopping, which you might check frequently for updates.</p>
- <p>You can manage your notifications in the Control Center by clicking the <img alt="'I' Icon" class="alignnone wp-image-9170" height="10" src="https://blog.mozilla.org/wp-content/uploads/2016/01/IIcon.png" width="10"/> icon on the left side of the address bar.</p>
- <p><b>Push Notifications for Web Developers</b><br/>
- To make this functionality possible, Mozilla helped establish the Web Push W3C standard that’s gaining momentum across the Web. We also continue to explore the new design pattern known as<a href="https://blog.mozilla.org/futurereleases/2015/11/17/extending-the-webs-capabilities-in-firefox-and-beyond/"> Progressive Web Apps</a>. If you’re a developer who wants to implement push notifications on your site, you can learn more in this<a href="https://hacks.mozilla.org/2016/01/web-push-arrives-in-firefox-44/"> Hacks blog post</a>.</p>
- <p><b>More information:</b></p>
- <ul>
- <li>Download<a href="https://www.mozilla.org/firefox/new/"> Firefox for Windows, Mac, Linux</a></li>
- <li>Release Notes for<a href="https://www.mozilla.org/firefox/44.0/releasenotes/"> Firefox for Windows, Mac, Linux</a></li>
- <li>Download<a href="https://play.google.com/store/apps/details?id=org.mozilla.firefox&amp;referrer=utm_source%3Dmozilla%26utm_medium"> Firefox for Android</a></li>
- <li>Release Notes for<a href="https://www.mozilla.org/firefox/android/44.0/releasenotes/"> Firefox for Android</a></li>
- </ul></div>
- </content>
- <updated>2016-01-26T01:56:50Z</updated>
- <category term="Firefox"/>
- <author>
- <name>Mozilla</name>
- </author>
- <source>
- <id>https://blog.mozilla.org</id>
- <link href="https://blog.mozilla.org/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://blog.mozilla.org" rel="alternate" type="text/html"/>
- <subtitle>News, notes and ramblings from the Mozilla project</subtitle>
- <title>The Mozilla Blog</title>
- <updated>2016-01-26T16:01:47Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en">
- <id>http://benoitgirard.wordpress.com/?p=651</id>
- <link href="https://benoitgirard.wordpress.com/2016/01/25/using-recordreplay-to-investigate-intermittent-oranges/" rel="alternate" type="text/html"/>
- <title>Using RecordReplay to investigate intermittent oranges</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">This is a quick write up to summarize my, and Jeff’s, experience, using RR to debug a fairly rare intermittent reftest failure. There’s still a lot of be learned about how to use RR effectively so I’m hoping sharing this will help others. Finding the root of the bad pixel First given a offending pixel […]<img alt="" border="0" height="1" src="https://pixel.wp.com/b.gif?host=benoitgirard.wordpress.com&amp;blog=12112851&amp;post=651&amp;subd=benoitgirard&amp;ref=&amp;feed=1" width="1"/></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This is a quick write up to summarize my, and Jeff’s, experience, using RR to debug a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1226748">fairly rare intermittent reftest failure</a>. There’s still a lot of be learned about how to use RR effectively so I’m hoping sharing this will help others.</p>
- <h3>Finding the root of the bad pixel</h3>
- <p>First given a offending pixel I was able to set a breakpoint on it using <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Hacking_Tips#rr_with_reftest">these instructions</a>. Next using <a href="https://github.com/jrmuizel/rr-dataflow">rr-dataflow</a> I was able to step from the offending bad pixel to the display item responsible for this pixel. Let me emphasize this for a second since it’s incredibly impressive. rr + rr-dataflow allows you to go from a buffer, through an intermediate surface, to the compositor on another thread, through another intermediate surface, back to the main thread and eventually back to the relevant display item. All of this was automated except for when the two pixels are blended together which is logically ambiguous. The speed at which rr was able to reverse continue through this execution was very impressive!</p>
- <p>Here’s the trace of this part: <a href="https://gist.github.com/bgirard/e707e9b97556b500d9ae">rr-trace-reftest-pixel-origin</a></p>
- <h3>Understanding the decoding step</h3>
- <p>From here I started comparing a replay of a failing test and a non failing step and it was clear that the DisplayList was different. In one we have a nsDisplayBackgroundColor in the other we don’t. From here I was able to step through the decoder and compare the sequence. This was very useful in ruling out possible theories. It was easy to step forward and backwards in the good and bad replay debugging sessions to test out various theories about race conditions and understanding at which part of the decode process the image was rejected. It turned out that we sent two decodes, one for the metadata that is used to sized the frame tree and the other one for the image data itself.</p>
- <h3>Comparing the frame tree</h3>
- <p>In hindsight, it would have been more effective to start debugging this test by looking at the frame tree (and I imagine for other tests looking at the display list and layer tree) first would have been a quicker start. It works even better if you have a good and a bad trace to compare the difference in the frame tree. From here, I found that the difference in the layer tree came from a change hint that wasn’t guaranteed to come in before the draw.</p>
- <p>The problem is now well understood: When we do a sync decode on reftest draw, if there’s an image error we wont flush the style hints since we’re already too deep in the painting pipeline.</p>
- <h3>Take away</h3>
- <ul>
- <li>Finding the root cause of a bad pixel is very easy, and fast, to do using rr-dataflow.</li>
- <li>However it might be better to look for obvious frame tree/display list/layer tree difference(s) first.</li>
- <li>Debugging a replay is a lot simpler then debugging against non-determinist re-runs and a lot less frustrating too.</li>
- <li>rr is really useful for race conditions, especially rare ones.</li>
- </ul><br/> <a href="http://feeds.wordpress.com/1.0/gocomments/benoitgirard.wordpress.com/651/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/benoitgirard.wordpress.com/651/"/></a> <img alt="" border="0" height="1" src="https://pixel.wp.com/b.gif?host=benoitgirard.wordpress.com&amp;blog=12112851&amp;post=651&amp;subd=benoitgirard&amp;ref=&amp;feed=1" width="1"/></div>
- </content>
- <updated>2016-01-25T22:16:01Z</updated>
- <category term="Graphics"/>
- <category term="Mozilla"/>
- <author>
- <name>benoitgirard</name>
- </author>
- <source>
- <id>https://benoitgirard.wordpress.com</id>
- <logo>https://s2.wp.com/i/buttonw-com.png</logo>
- <link href="https://benoitgirard.wordpress.com/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://benoitgirard.wordpress.com" rel="alternate" type="text/html"/>
- <link href="https://benoitgirard.wordpress.com/osd.xml" rel="search" title="Benoit Girard's Blog" type="application/opensearchdescription+xml"/>
- <link href="https://benoitgirard.wordpress.com/?pushpress=hub" rel="hub" type="text/html"/>
- <subtitle>My Programming Experiences</subtitle>
- <title>Benoit Girard's Blog</title>
- <updated>2016-01-25T22:30:59Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://blog.servo.org/2016/01/25/twis-48/</id>
- <link href="http://blog.servo.org/2016/01/25/twis-48/" rel="alternate" type="text/html"/>
- <title>These Weeks In Servo 48</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>In the <a href="https://github.com/pulls?page=1&amp;q=is%3Apr+is%3Amerged+closed%3A2016-01-11..2016-01-25+user%3Aservo">last two weeks</a>, we landed 130 PRs in the Servo organization’s repositories.</p>
-
- <p>After months of work by vlad and many others, Windows support <a href="https://github.com/servo/servo/pull/9385">landed</a>! Thanks to everyone who contributed fixes, tests, reviews, and even encouragement (or impatience!) to help us make this happen.</p>
-
- <h3 id="notable-additions">Notable Additions</h3>
-
- <ul>
- <li>nikki <a href="https://github.com/servo/servo/pull/9391">added</a> tests and support for checking the Fetch redirect count</li>
- <li>glennw <a href="https://github.com/servo/servo/pull/9359">implemented</a> horizontal scrolling with arrow keys</li>
- <li>simon <a href="https://github.com/servo/servo/pull/9333">created</a> a script that parses all of the CSS properties parsed by Servo</li>
- <li>ms2ger <a href="https://github.com/servo/servo/pull/9293">removed</a> the legacy reftest framework</li>
- <li>fernando <a href="https://github.com/servo/crowbot/pull/33">made</a> crowbot able to rejoin IRC after it accidentally floods the channel</li>
- <li>jack <a href="https://github.com/servo/saltfs/pull/193">added</a> testing the <code>geckolib</code> target to our CI</li>
- <li>antrik <a href="https://github.com/servo/ipc-channel/pull/25">fixed</a> transfer corruption in ipc-channel on 32-bit</li>
- <li>valentin <a href="https://github.com/servo/rust-url/pull/119">added</a> and simon <a href="https://github.com/servo/rust-url/pull/152">extended</a> IDNA support in rust-url, which is required for both web and Gecko compatibility</li>
- </ul>
-
- <h3 id="new-contributors">New Contributors</h3>
-
- <ul>
- <li><a href="https://github.com/Chandler">Chandler Abraham</a></li>
- <li><a href="https://github.com/DarinM223">Darin Minamoto</a></li>
- <li><a href="https://github.com/coder543">Josh Leverette</a></li>
- <li><a href="https://github.com/shssoichiro">Joshua Holmer</a></li>
- <li><a href="https://github.com/therealkbhat">Kishor Bhat</a></li>
- <li><a href="https://github.com/MonsieurLanza">Lanza</a></li>
- <li><a href="https://github.com/mattkuo">Matthew Kuo</a></li>
- <li><a href="https://github.com/waterlink">Oleksii Fedorov</a></li>
- <li><a href="https://github.com/stspyder">St.Spyder</a></li>
- <li><a href="https://github.com/vvuk">Vladimir Vukicevic</a></li>
- <li><a href="https://github.com/apopiak">apopiak</a></li>
- <li><a href="https://github.com/askalski">askalski</a></li>
- </ul>
-
- <h3 id="screenshot">Screenshot</h3>
-
- <p>Screencast of this post being upvoted on reddit… from Windows!</p>
-
- <p><img alt="(screencast)" src="http://blog.servo.org/images/upvote-windows.gif" title="Screencast of upvoting on Reddit on Windows."/></p>
-
- <h3 id="meetings">Meetings</h3>
-
- <p>We had a <a href="https://github.com/servo/servo/wiki/Meeting-2016-01-11">meeting</a> on some CI-related woes, documenting tags and mentoring, and dependencies for the style subsystem.</p></div>
- </summary>
- <updated>2016-01-25T20:30:00Z</updated>
- <source>
- <id>http://blog.servo.org/</id>
- <author>
- <name>The Servo Blog</name>
- </author>
- <link href="http://blog.servo.org/" rel="alternate" type="text/html"/>
- <link href="http://blog.servo.org/feed.xml" rel="self" type="application/rss+xml"/>
- <title>Servo Blog</title>
- <updated>2016-01-26T02:01:45Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://air.mozilla.org/mozilla-weekly-project-meeting-20160125/</id>
- <link href="https://air.mozilla.org/mozilla-weekly-project-meeting-20160125/" rel="alternate" type="text/html"/>
- <title>Mozilla Weekly Project Meeting, 25 Jan 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
- <img alt="Mozilla Weekly Project Meeting" class="wp-post-image" height="90" src="https://air.cdn.mozilla.net/media/cache/e9/4f/e94fbd7f8df916c75a60e63a85b9168c.png" width="160"/>
- The Monday Project Meeting
- </p></div>
- </summary>
- <updated>2016-01-25T19:00:00Z</updated>
- <author>
- <name>Air Mozilla</name>
- </author>
- <source>
- <id>https://air.mozilla.org/</id>
- <link href="https://air.mozilla.org/" rel="alternate" type="text/html"/>
- <link href="https://air.mozilla.org/" rel="self" type="application/rss+xml"/>
- <rights>Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.</rights>
- <subtitle>Air Mozilla is the Internet multimedia presence of Mozilla, with live and pre-recorded shows, interviews, news snippets, tutorial videos, and features about the Mozilla community.</subtitle>
- <title>Air Mozilla</title>
- <updated>2016-01-25T20:31:50Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://blog.mozilla.org/community/?p=2292</id>
- <link href="http://blog.mozilla.org/community/2016/01/25/firefox-44-new-contributors/" rel="alternate" type="text/html"/>
- <title>Firefox 44 new contributors</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">With the release of Firefox 44, we are pleased to welcome the 28 developers who contributed their first code change to Firefox in this release, 23 of whom were brand new volunteers! Please join us in thanking each of these … <a class="go" href="http://blog.mozilla.org/community/2016/01/25/firefox-44-new-contributors/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>With the release of Firefox 44, we are pleased to welcome the <strong>28 developers</strong> who contributed their first code change to Firefox in this release, <strong>23</strong> of whom were brand new volunteers! Please join us in thanking each of these diligent and enthusiastic individuals, and take a look at their contributions:</p>
- <ul>
- <li>mkm: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1208124">1208124</a></li>
- <li>Aditya Motwani: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1209087">1209087</a></li>
- <li>Aniket Vyas: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1197309">1197309</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1197315">1197315</a></li>
- <li>Chirath R: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1216941">1216941</a></li>
- <li>Christiane Ruetten: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1209091">1209091</a></li>
- <li>Fernando Campo: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1199815">1199815</a></li>
- <li>Grisha Pushkov: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=994555">994555</a></li>
- <li>Guang-De Lin: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1150305">1150305</a></li>
- <li>Hassen ben tanfous: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1074804">1074804</a></li>
- <li>Helen V. Holmes: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1205046">1205046</a></li>
- <li>Henrik Tjäder: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1161698">1161698</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1209912">1209912</a></li>
- <li>Johann Hofmann: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1192432">1192432</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1198405">1198405</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1204072">1204072</a></li>
- <li>Kapeel Sable: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1212171">1212171</a></li>
- <li>Manav Batra: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1202618">1202618</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1212280">1212280</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1214626">1214626</a></li>
- <li>Manuel Casas Barrado: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1172662">1172662</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1193674">1193674</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1200693">1200693</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1203298">1203298</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1205684">1205684</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1212331">1212331</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1212338">1212338</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1214582">1214582</a></li>
- <li>Matt Howell: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1208626">1208626</a></li>
- <li>Matthew Turnbull: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1213620">1213620</a></li>
- <li>Olivier Yiptong: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1210936">1210936</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1210940">1210940</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1213078">1213078</a></li>
- <li>Piotr Tworek: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1209446">1209446</a></li>
- <li>Rocik: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1070719">1070719</a></li>
- <li>Roland Sako: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1207733">1207733</a></li>
- <li>Ronald Claveau: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1207266">1207266</a></li>
- <li>Sanchit Nevgi: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1205181">1205181</a></li>
- <li>Shaif Chowdhury: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1185606">1185606</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1208121">1208121</a></li>
- <li>Shubham Jain: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1208470">1208470</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1208705">1208705</a></li>
- <li>Stanislas Daniel Claude Dolcini: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1147197">1147197</a></li>
- <li>Stephanie Ouillon: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1178533">1178533</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1201626">1201626</a></li>
- <li>Tim Huang: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1181489">1181489</a></li>
- <li>simplyblue24: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1218204">1218204</a></li>
- </ul></div>
- </content>
- <updated>2016-01-25T16:21:33Z</updated>
- <category term="Spotlight"/>
- <author>
- <name>Josh Matthews</name>
- </author>
- <source>
- <id>http://blog.mozilla.org/community</id>
- <link href="http://blog.mozilla.org/community/feed/" rel="self" type="application/rss+xml"/>
- <link href="http://blog.mozilla.org/community" rel="alternate" type="text/html"/>
- <subtitle>News and notes from and for the Mozilla community.</subtitle>
- <title>about:community</title>
- <updated>2016-01-25T16:31:42Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>tag:literaci.es,2014:Post/digital-skills-curriculum</id>
- <link href="http://literaci.es/digital-skills-curriculum" rel="alternate" type="text/html"/>
- <title xml:lang="en-US">3 things to consider when designing a digital skills framework</title>
- <content type="xhtml" xml:lang="en-US"><div xmlns="http://www.w3.org/1999/xhtml"><p><img alt="Learning to credential" src="http://bryanmmathers.com/wp-content/uploads/2016/01/learning-to-credential.png"/></p>
-
- <p>The image above was created by <a href="http://bryanmmathers.com/learning-to-credential" rel="nofollow">Bryan Mathers</a> for our <a href="https://goo.gl/QqwUKP" rel="nofollow">presentation</a> at <a href="http://bettshow.com" rel="nofollow">BETT</a> last week. It shows the way that, in broad brushstrokes, learning design <em>should</em> happen. Before microcredentials such as <a href="http://openbadges.org" rel="nofollow">Open Badges</a> this was a difficult thing to do as both the credential and the assessment are usually given to educators. The flow tends to go <em>backwards</em> from credentials instead of forwards from what we want people to learn.</p>
-
- <p>But what if you really <em>were</em> starting from scratch? How could you design a digital skills framework that contains knowledge, skills, and behaviours worth learning? Having written my <a href="http://neverendingthesis.com" rel="nofollow">thesis</a> on digital literacies and led Mozilla’s <a href="https://teach.mozilla.org/activities/web-literacy/" rel="nofollow">Web Literacy Map</a> for a couple of years, I’ve got some suggestions. </p>
- <h3>
- <a class="head_anchor" href="http://literaci.es/feed#1-define-your-audience" name="1-define-your-audience" rel="nofollow"> </a>1. Define your audience</h3>
- <p>One of the most important things to define is who your audience is for your digital skills framework. Is it for learners to read? Who are they? How old are they? Are you excluding anyone on purpose? Why / why not?</p>
-
- <p>You might want to do some research and work around <a href="https://en.wikipedia.org/wiki/Persona_(user_experience)" rel="nofollow">user personas</a> as part of a user-centred design approach. This ensures you’re designing for real people instead of figments of your imagination (or, worse still, in line with your prejudices).</p>
-
- <p>It’s also good practice to make the language used in the skills framework as precise as possible. Jargon is technical language used for the sake of it. There may be times when it’s impossible not to use a word (e.g. ’<a href="https://en.wikipedia.org/wiki/Meme" rel="nofollow">meme</a>’). If you do this then link to a definition or include a glossary. It’s also useful to check the ‘reading level’ of your framework and, if you really want a challenge, try using <a href="http://splasho.com/upgoer5/" rel="nofollow">Up-Goer Five</a> language.</p>
- <h3>
- <a class="head_anchor" href="http://literaci.es/feed#2-focus-on-verbs" name="2-focus-on-verbs" rel="nofollow"> </a>2. Focus on verbs</h3>
- <p>It’s extremely easy, when creating a framework for learning, to fall into the 'knowledge trap’. Our aim when creating the raw materials from which someone can build a curriculum is to focus on <em>action</em>. Knowledge should make a difference in practice.</p>
-
- <p>One straightforward way to ensure that you’re focusing on action rather than head knowledge is to use <strong>verbs</strong> when constructing your digital skills framework. If you’re familiar with <a href="https://en.wikipedia.org/wiki/Bloom%27s_taxonomy" rel="nofollow">Bloom’s Taxonomy</a>, then you may find <a href="http://byrdseed.com/differentiator/" rel="nofollow">The Differentiator</a> useful. This pairs verbs with the various levels of Bloom’s.</p>
- <h3>
- <a class="head_anchor" href="http://literaci.es/feed#3-add-version-numbers" name="3-add-version-numbers" rel="nofollow"> </a>3. Add version numbers</h3>
- <p>A framework needs to be a living, breathing thing. It should be subject to revision and updated often. For this reason, you should add version numbers to your documentation. Ideally, the latest version should be at a canonical URL and you should archive previous versions to static URLs. </p>
-
- <p>I would also advise releasing the first version of your framework not as 'version 1.0’ but as 'v0.1’. This shows that you’re willing for others to provide input, that there will be further versions, and that you know you haven’t got it right first time (and forevermore). </p>
-
- <hr/>
-
- <p><strong>Questions? Comments?</strong> Ask me on Twitter (<a href="http://twitter.com/dajbelshaw" rel="nofollow">@dajbelshaw</a>). I also consult around this kind of thing, so hit me up on <a href="http://literaci.es/hello@dynamicskillset.com" rel="nofollow">hello@dynamicskillset.com</a></p></div>
- </content>
- <updated>2016-01-25T14:46:34Z</updated>
- <published>2016-01-25T14:46:34Z</published>
- <source>
- <id>tag:literaci.es,2014:/feed</id>
- <author>
- <name>Doug Belshaw</name>
- <email>mail@dougbelshaw.com</email>
- <uri>http://literaci.es</uri>
- </author>
- <link href="http://literaci.es" rel="alternate" type="text/html"/>
- <link href="http://literaci.es/feed" rel="self" type="application/atom+xml"/>
- <title xml:lang="en-US">Literacies</title>
- <updated>2016-01-25T14:46:34Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://fundraising.mozilla.org/?p=800</id>
- <link href="https://fundraising.mozilla.org/why-did-you-decide-to-donate-today/" rel="alternate" type="text/html"/>
- <title>Why did you decide to donate today?</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">This year, we asked some of our donors why they decided to donate to our end of year fundraising campaign. The Survey The Audience The survey was shown to a random sample of donors whose browser language was set to … <a class="go" href="https://fundraising.mozilla.org/why-did-you-decide-to-donate-today/">Continue reading</a></div>
- </summary>
- <updated>2016-01-25T13:31:34Z</updated>
- <category term="metrics"/>
- <category term="mozilla"/>
- <author>
- <name>Adam Lofting</name>
- </author>
- <source>
- <id>https://fundraising.mozilla.org</id>
- <link href="https://fundraising.mozilla.org/category/mozilla/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://fundraising.mozilla.org" rel="alternate" type="text/html"/>
- <subtitle>We work in the open, we fundraise in the open. This site shows you how we work, shares what we know, and challenges you to help us do it better.</subtitle>
- <title>Mozilla: View Source Fundraising » mozilla</title>
- <updated>2016-01-25T13:31:34Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-us">
- <id>http://www.agmweb.ca/robbie-burns</id>
- <link href="http://www.agmweb.ca/2016-01-25-robbie-burns/" rel="alternate" type="text/html"/>
- <title xml:lang="en-us">Robbie Burns</title>
- <content type="xhtml" xml:lang="en-us"><div xmlns="http://www.w3.org/1999/xhtml"><p>Tonight is Robbie Burns night, in honour of that great Scottish poet. But tonight had me thinking about another night in my past.</p>
-
- <p>It was about 5 years ago, maybe less, I struggle to remember now. I was in the UK visiting family and my Dad was sick. Cancer and it's treatment is tough, you have good weeks, you have bad weeks and you have really fucking bad weeks. This was a good week and for some reason I was in the UK.</p>
-
- <p>Myself, my brother and my sister-in-law went down to see him that night. It was Robbie Burns night and that meant an excuse for haggis, really, truly terrible scotch, Scottish dancing and all that. There are many times when I look back at time with my Dad in those last few years. This was definitely one of those times. He was my Dad at his best, cracking jokes and having fun. Living life to the absolute fullest, while you still have that chance.</p>
-
- <p>We had a great night. That ended way too soon.</p>
-
- <p>Not long after that the cancer came back and that was that.</p>
-
- <p>But suddenly tonight, in a bar in Portland I had these memories of my Dad in a waistcoat cracking jokes and having fun on Robbie Burns night. No-one else in the bar seemed to know what night it was. You'd think Robbie Burns night might get a little bit more appreciation, but hey.</p>
-
- <p>In the many years I've been running this blog I've never written about my Dad passing away. Here's the first time. I miss him.</p>
-
- <p>Hey Robbie Burns? Thanks for making me remember that night.</p></div>
- </content>
- <updated>2016-01-25T08:00:00Z</updated>
- <source>
- <id>http://www.agmweb.ca/blog/andy</id>
- <author>
- <name>Andy McKay</name>
- <email>andy@clearwind.ca</email>
- </author>
- <link href="http://www.agmweb.ca/blog/andy" rel="alternate" type="text/html"/>
- <link href="http://www.agmweb.ca/blog/rss/latest/andy/" rel="self" type="application/atom+xml"/>
- <title xml:lang="en-us">Andy McKay</title>
- <updated>2016-01-26T06:33:30Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>tag:this-week-in-rust.org,2016-01-25:blog/2016/01/25/this-week-in-rust-115/</id>
- <link href="http://this-week-in-rust.org/blog/2016/01/25/this-week-in-rust-115/" rel="alternate" type="text/html"/>
- <title>This Week in Rust 115</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Hello and welcome to another issue of <em>This Week in Rust</em>!
- <a href="http://rust-lang.org">Rust</a> is a systems language pursuing the trifecta:
- safety, concurrency, and speed. This is a weekly summary of its progress and
- community. Want something mentioned? Tweet us at <a href="https://twitter.com/ThisWeekInRust">@ThisWeekInRust</a> or <a href="mailto:corey@octayn.net?subject=This%20Week%20in%20Rust%20Suggestion">send us an
- email</a>!
- Want to get involved? <a href="https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md">We love
- contributions</a>.</p>
- <p><em>This Week in Rust</em> is openly developed <a href="https://github.com/cmr/this-week-in-rust">on GitHub</a>.
- If you find any errors in this week's issue, <a href="https://github.com/cmr/this-week-in-rust/pulls">please submit a PR</a>.</p>
- <p>This week's edition was edited by: <a href="https://github.com/nasa42">nasa42</a>, <a href="https://github.com/brson">brson</a>, and <a href="https://github.com/llogiq">llogiq</a>.</p>
- <h3>Updates from Rust Community</h3>
- <h4>News &amp; Blog Posts</h4>
- <ul>
- <li><img alt="balloon" class="emoji" src="https://cdn.discourse.org/business/images/emoji/emoji_one/balloon.png?v=0" title=":balloon:"/><img alt="tada" class="emoji" src="https://cdn.discourse.org/business/images/emoji/emoji_one/tada.png?v=0" title=":tada:"/> <a href="http://blog.rust-lang.org/2016/01/21/Rust-1.6.html">Announcing Rust 1.6</a>. <img alt="tada" class="emoji" src="https://cdn.discourse.org/business/images/emoji/emoji_one/tada.png?v=0" title=":tada:"/><img alt="balloon" class="emoji" src="https://cdn.discourse.org/business/images/emoji/emoji_one/balloon.png?v=0" title=":balloon:"/></li>
- <li><a href="http://www.poumeyrol.fr/2016/01/15/Awkward-zone/">Rust, BigData and my laptop</a>.</li>
- <li>[pdf]<a href="https://cdn.rawgit.com/Gankro/thesis/master/thesis.pdf">You can't spell trust without Rust</a>. Analysis of the semantics and expressiveness of Rust’s type system.</li>
- <li><a href="http://www.ncameron.org/blog/libmacro/">Libmacro - an API for procedural macros to interact with the compiler</a>.</li>
- <li><a href="http://www.jonathanturner.org/2016/01/rust-and-blub-paradox.html">Rust and the Blub Paradox</a>. And the <a href="http://www.jonathanturner.org/2016/01/rethinking-the-blub-paradox.html">follow-up</a>.</li>
- <li>[video] <a href="https://www.youtube.com/channel/UC4mpLlHn0FOekNg05yCnkzQ/videos">Ferris Makes Emulators</a>. Live stream of Ferris developing a N64 emulator in Rust (also on <a href="http://www.twitch.tv/ferrisstreamsstuff/profile">Twitch</a>).</li>
- </ul>
- <h4>Notable New Crates &amp; Project Updates</h4>
- <ul>
- <li><a href="http://areweconcurrentyet.com/">Are we concurrent yet</a>?</li>
- <li><a href="https://github.com/gfx-rs/gfx">GFX</a> epic rewrite for the Pipeline State Objects paradigm has <a href="https://github.com/gfx-rs/gfx/pull/828">landed</a>, described <a href="http://gfx-rs.github.io/2016/01/22/pso.html">on the blog</a>.</li>
- <li><a href="https://github.com/mcarton/rust-herbie-lint">Herbie</a>. A rustc plugin to check for numerical instability.</li>
- <li><a href="http://blog.piston.rs/2016/01/23/dynamo/">Dynamo</a>. A rusty dynamically typed scripting language.</li>
- <li><a href="https://github.com/whitequark/rust-vnc">rust-vnc</a>. An implementation of VNC protocol, client state machine and a client.</li>
- </ul>
- <h3>Updates from Rust Core</h3>
- <p>129 pull requests were <a href="https://github.com/issues?q=is%3Apr+org%3Arust-lang+is%3Amerged+merged%3A2016-01-18..2016-01-25">merged in the last week</a>.</p>
- <p>See the <a href="https://internals.rust-lang.org/t/triage-digest-mon-jan-25-2016/3111">triage digest</a> and <a href="https://internals.rust-lang.org/t/subteam-reports-2016-01-22/3106">subteam reports</a> for more details.</p>
- <h4>Notable changes</h4>
- <ul>
- <li><a href="https://github.com/rust-lang/rust/pull/30872">Implement RFC 1252 expanding the OpenOptions structure</a>.</li>
- <li><a href="https://github.com/rust-lang/book/pull/58">Book: First draft of 'ownership'</a>.</li>
- <li><a href="https://github.com/rust-lang/cargo/pull/2205">Cargo: Add convenience syntax to install current crate</a>.</li>
- <li><a href="https://github.com/rust-lang/cargo/pull/2196">Cargo: Introduce cargo metadata subcommand</a>.</li>
- <li><a href="https://github.com/rust-lang/cargo/pull/2081">Cargo: Implement <code>cargo init</code></a>.</li>
- <li><a href="https://github.com/rust-lang/cargo/pull/2270">Cargo: Emit a warning when manifest specifies empty dependency constraints</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/29520">Change name when outputting staticlibs on Windows</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30998">Make <code>btree_set::{IntoIter, Iter, Range}</code> covariant</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30917">Avoid bounds checking at <code>slice::binary_search</code></a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30894"><code>std::sync::mpsc</code>: Add <code>fmt::Debug</code> stubs</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30882">resolve: Fix variant namespacing</a>.</li>
- </ul>
- <h4>New Contributors</h4>
- <ul>
- <li>Adrian Heine</li>
- <li>Andrea Bedini</li>
- <li>Guillaume Bonnet</li>
- <li>Kamal Marhubi</li>
- <li>Keith Yeung</li>
- <li>Marc Bowes</li>
- <li>Martin</li>
- <li>mopp</li>
- <li>Olaf Buddenhagen</li>
- <li>Paul Dicker</li>
- <li>Peter Kolloch</li>
- <li>Stephen (Ziyun) Li</li>
- </ul>
- <h4>Approved RFCs</h4>
- <p>Changes to Rust follow the Rust <a href="https://github.com/rust-lang/rfcs#rust-rfcs">RFC (request for comments)
- process</a>. These
- are the RFCs that were approved for implementation this week:</p>
- <ul>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1462">Amendment to RFC 550: Add <code>[</code> to the FOLLOW(ty) in macro future-proofing rules</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1320">Amendment to RFC 1192: Amend <code>RangeInclusive</code> to use an enum</a>.</li>
- </ul>
- <h4>Final Comment Period</h4>
- <p>Every week <a href="https://rust-lang.org/team.html">the team</a> announces the
- 'final comment period' for RFCs and key PRs which are reaching a
- decision. Express your opinions now. <a href="https://github.com/rust-lang/rfcs/labels/final-comment-period">This week's FCPs</a> are:</p>
- <ul>
- <li><a href="https://github.com/rust-lang/rfcs/pull/243">Trait-based exception handling</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1361">Improve Cargo target-specific dependencies</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1129">Add a <code>IndexAssign</code> trait that allows overloading "indexed assignment" expressions like <code>a[b] = c</code></a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1196">Allow eliding more type parameters</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1296">Add an <code>alias</code> attribute to <code>#[link]</code> and <code>-l</code></a>.</li>
- </ul>
- <h4>New RFCs</h4>
- <ul>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1477">Add compiler support for generic atomic operations</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1478">Translate undefined generic intrinsics to an LLVM <code>unreachable</code> and a lint</a>.</li>
- </ul>
- <h3>Upcoming Events</h3>
- <ul>
- <li><a href="http://www.meetup.com/opentechschool-berlin/">1/27. OpenTechSchool Berlin: Rust Hack and Learn</a>.</li>
- <li><a href="http://www.meetup.com/Tokyo-Rust-Meetup/events/227871840/">1/28. Tokyo Rust Meetup #2</a>.</li>
- <li><a href="http://www.meetup.com/Rust-Berlin/events/227321071/">2/3. Rust Berlin: Leaf and Collenchyma</a>.</li>
- <li><a href="http://www.meetup.com/de/Rust-Cologne-Bonn/events/227534456/">2/3. Rust Meetup in Cologne / Germany</a>.</li>
- <li><a href="https://www.eventbrite.com/e/mozilla-rust-seattle-meetup-tickets-12222326307?aff=erelexporg">2/8. Seattle Rust Meetup</a>.</li>
- </ul>
- <p>If you are running a Rust event please add it to the <a href="https://www.google.com/calendar/embed?src=apd9vmbc22egenmtu5l6c5jbfc%40group.calendar.google.com">calendar</a> to get
- it mentioned here. Email <a href="mailto:erick.tryzelaar@gmail.com">Erick Tryzelaar</a> or <a href="mailto:banderson@mozilla.com">Brian
- Anderson</a> for access.</p>
- <h3>fn work(on: RustProject) -&gt; Money</h3>
- <ul>
- <li><a href="http://maidsafe.net/rust_engineer.html">Rust Engineer</a> at MaidSafe.</li>
- <li><a href="https://careers.mozilla.org/en-US/position/ozy21fwU">Research Engineer - Servo</a> at Mozilla.</li>
- <li><a href="https://careers.mozilla.org/en-US/position/o0H41fww">Senior Research Engineer - Rust</a> at Mozilla.</li>
- <li><a href="http://plv.mpi-sws.org/rustbelt/">PhD and postdoc positions</a> at MPI-SWS.</li>
- </ul>
- <p><em>Tweet us at <a href="https://twitter.com/ThisWeekInRust">@ThisWeekInRust</a> to get your job offers listed here!</em></p>
- <h3>Crate of the Week</h3>
- <p>This week's Crate of the Week is <a href="https://github.com/phildawes/racer">racer</a> which powers code completion in all Rust development environments.</p>
- <p>Thanks to <a href="https://users.rust-lang.org/users/stebalien">Steven Allen</a> for the suggestion.</p>
- <p><a href="https://users.rust-lang.org/t/crate-of-the-week/2704">Submit your suggestions for next week</a>!</p>
- <h3>Quote of the Week</h3>
- <blockquote>
- <p>Memory errors are fundamentally state errors, and Rust's move semantics, borrowing, and aliasing XOR mutating help enormously for me to reason about how my program changes state as it executes, to avoid accidental shared state and side effects at a distance. Rust more than any other language I know enables me to do compiler driven design. And internalizing its rules has helped me design better systems, even in other languages.</p>
- </blockquote>
- <p>— <a href="https://www.reddit.com/r/rust/comments/4275gz/rust_and_the_blub_paradox/cz8akv9">desiringmachines on /r/rust</a>.</p>
- <p>Thanks to <a href="https://users.rust-lang.org/users/dikaiosune">dikaiosune</a> for the suggestion.</p>
- <p><a href="http://users.rust-lang.org/t/twir-quote-of-the-week/328">Submit your quotes for next week</a>!</p></div>
- </summary>
- <updated>2016-01-25T05:00:00Z</updated>
- <author>
- <name>Corey Richardson</name>
- </author>
- <source>
- <id>http://this-week-in-rust.org/</id>
- <link href="http://this-week-in-rust.org/" rel="alternate" type="text/html"/>
- <link href="http://this-week-in-rust.org/atom.xml" rel="self" type="application/atom+xml"/>
- <title>This Week in Rust</title>
- <updated>2016-01-25T05:00:00Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>tag:blogger.com,1999:blog-1015214236289077798.post-7056349209464984020</id>
- <link href="http://tenfourfox.blogspot.com/2016/01/3860-available.html" rel="alternate" type="text/html"/>
- <title>38.6.0 available</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">TenFourFox 38.6.0 is available for testing (<a href="https://sourceforge.net/projects/tenfourfox/files/38.6.0/">downloads</a>, <a href="https://github.com/classilla/tenfourfox/wiki/Hashes">hashes</a>, <a href="https://github.com/classilla/tenfourfox/wiki/ZZReleaseNotes3860">release notes</a>). I'm sorry it's been so quiet around here; I'm in the middle of a backbreaking Master's course, my last one before I'm finally done with the lousy thing, and I haven't had any time to start on 45 so far. 38.6 does have some other fixes in it, though: I think I found the last place where bookmark backups were being mistakenly saved in LZ4 based on Chris Trusch's report, and the problematic fonts on the iCloud login page are now blacklisted, so you should be able to login again. I can't do much more testing than that, however, since I don't use iCloud personally, so other lapses in font functionality will require the font URL and I'll add them to the blacklist in 38.7. The browser will go live Monday Pacific time as usual. (The temporary workaround is to set <tt>gfx.downloadable_fonts.enabled</tt> to <tt>false</tt>, and switch the setting back when you don't need it anymore.) <p>Speaking of, downloadable fonts were exactly the same problem on the Sun Ultra-3 laptop I've been refurbishing; Oracle still provides a free Solaris 10 build of 38ESR, but it crashes on web fonts for reasons I have yet to diagnose, so I just have them turned off. Yes, it really is a SPARC laptop, a rebranded Tadpole Viper, and I think the fastest one ever made in this form factor (a 1.2GHz UltraSPARC IIIi). It's pretty much what I expected the PowerBook G5 would have been -- hot, overthrottled and power-hungry -- but Tadpole actually built the thing and it's not a disaster, relatively speaking. There's no JIT in this Firefox build, the brand new battery gets only 70 minutes of runtime even with the CPU clock-skewed to hell, it stands a very good chance of rendering me sterile and/or medium rare if I actually use it in my lap and it had at least one sudden overtemp shutdown and pooped all over the filesystem, but between Firefox, Star Office and <tt>pkgsrc</tt> I can actually use it. More on that for laughs in a future post. </p><p>It has been pointed out to me that Leopard Webkit has not made an update in over three months, so hopefully Tobias is still doing okay with his port.</p></div>
- </summary>
- <updated>2016-01-23T06:02:00Z</updated>
- <author>
- <name>ClassicHasClass</name>
- <email>noreply@blogger.com</email>
- </author>
- <source>
- <id>tag:blogger.com,1999:blog-1015214236289077798</id>
- <category term="security"/>
- <category term="mozilla"/>
- <category term="anfscd"/>
- <category term="qte"/>
- <category term="transition"/>
- <category term="PowerPC"/>
- <category term="shame"/>
- <category term="mte"/>
- <category term="ppc970"/>
- <category term="applesnark"/>
- <category term="judgment day"/>
- <category term="shoutout"/>
- <category term="parity"/>
- <category term="tenfourfoxbox"/>
- <category term="68k"/>
- <category term="classilla"/>
- <category term="intel"/>
- <category term="kubrick"/>
- <category term="sluggo"/>
- <category term="statistics"/>
- <category term="thereisnoxulonlywebextensions"/>
- <author>
- <name>ClassicHasClass</name>
- <email>noreply@blogger.com</email>
- </author>
- <link href="http://tenfourfox.blogspot.com/" rel="alternate" type="text/html"/>
- <link href="http://tenfourfox.blogspot.com/feeds/posts/default?alt=rss" rel="self" type="application/rss+xml"/>
- <subtitle>What's new in TenFourFox, the Mozilla browser for Power Macs.</subtitle>
- <title>TenFourFox Development</title>
- <updated>2016-01-26T18:31:40Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://blog.mozilla.org/netpolicy/?p=907</id>
- <link href="https://blog.mozilla.org/netpolicy/2016/01/22/addressing-the-chilling-effect-of-patent-damages/" rel="alternate" type="text/html"/>
- <title>Addressing the Chilling Effect of Patent Damages</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Last year, we unveiled the Mozilla Open Software Patent License as part of our Initiative to help limit the negative impacts that patents have on open source software. While those were an important first step for us, we continue to … <a class="go" href="https://blog.mozilla.org/netpolicy/2016/01/22/addressing-the-chilling-effect-of-patent-damages/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Last year, we unveiled the <a href="https://www.mozilla.org/about/patents/license/">Mozilla Open Software Patent License</a> as part of our <a href="https://www.mozilla.org/about/patents/">Initiative</a> to help limit the negative impacts that patents have on open source software. While those were an important first step for us, we continue to do more. This past Wednesday, Mozilla joined several other tech and software companies in filing an <a href="https://blog.mozilla.org/netpolicy/files/2016/01/Halo-Stryker-Internet-Companies-brief.pdf">amicus brief</a> with the Supreme Court of the United States in the <i>Halo</i> and <i>Stryker</i> cases.</p>
- <p>In the brief, we urge the Court to limit the availability of treble damages. Treble damages are significant because they greatly increase the amount of money owed if a defendant is found to “willfully infringe†a patent. As a result, many open source projects and technology companies will refuse to look into or engage in discussions about patents, in order to avoid even a remote possibility of willful infringement. This makes it very hard to address the chilling effects that patents can have on open source software development, open innovation, and collaborative efforts.</p>
- <p>We hope that our brief will help the Court see how this legal standard has affected technology companies and persuade the Court to limit treble damages.</p></div>
- </content>
- <updated>2016-01-23T00:17:34Z</updated>
- <category term="Open Source"/>
- <category term="patent"/>
- <category term="United States"/>
- <author>
- <name>Elvin Lee</name>
- </author>
- <source>
- <id>https://blog.mozilla.org/netpolicy</id>
- <link href="http://blog.mozilla.org/netpolicy/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://blog.mozilla.org/netpolicy" rel="alternate" type="text/html"/>
- <subtitle>Mozilla's official blog on open Internet policy initiatives and developments</subtitle>
- <title>Open Policy &amp; Advocacy</title>
- <updated>2016-01-25T20:46:35Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://blog.mozilla.org/addons/?p=7640</id>
- <link href="https://blog.mozilla.org/addons/2016/01/22/add-on-signing-update/" rel="alternate" type="text/html"/>
- <title>Add-on Signing Update</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">In Firefox 43, we made it a default requirement for add-ons to be signed. This requirement can be disabled by toggling a preference that was originally scheduled to be removed in Firefox 44 for release and beta versions (this preference … <a class="go" href="https://blog.mozilla.org/addons/2016/01/22/add-on-signing-update/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>In Firefox 43, we made it a default requirement for add-ons to be signed. This requirement can be disabled by <a href="https://wiki.mozilla.org/Addons/Extension_Signing#FAQ">toggling a preference</a> that was originally scheduled to be removed in Firefox 44 for release and beta versions (this preference will continue to be available in the Nightly, Developer, and ESR Editions of Firefox for the foreseeable future). </p>
- <p>We are delaying the removal of this preference to Firefox 46 for a couple of reasons: We’re adding a feature in Firefox 45 that allows <a href="https://blog.mozilla.org/addons/2015/12/23/loading-temporary-add-ons/">temporarily loading unsigned restartless add-ons</a> in release, which will allow developers of those add-ons to use Firefox for testing, and we’d like this option to be available when we remove the preference. We also want to ensure that developers have adequate time to finish the transition to signed add-ons. </p>
- <p>The <a href="https://wiki.mozilla.org/Addons/Extension_Signing#Timeline">updated timeline</a> is available on the signing wiki, and you can look up <a href="https://wiki.mozilla.org/RapidRelease/Calendar">release dates for Firefox versions</a> on the releases wiki. Signing will be mandatory in the beta and release versions of Firefox from 46 onwards, at which point unbranded builds based on beta and release will be provided for testing.</p></div>
- </content>
- <updated>2016-01-22T22:40:59Z</updated>
- <category term="developers"/>
- <category term="general"/>
- <category term="releases"/>
- <author>
- <name>Kev Needham</name>
- </author>
- <source>
- <id>https://blog.mozilla.org/addons</id>
- <link href="https://blog.mozilla.org/addons/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://blog.mozilla.org/addons" rel="alternate" type="text/html"/>
- <title>Mozilla Add-ons Blog</title>
- <updated>2016-01-25T20:46:40Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://coopcoopbware.tumblr.com/post/137832199980</id>
- <link href="http://coopcoopbware.tumblr.com/post/137832199980" rel="alternate" type="text/html"/>
- <title>RelEng &amp; RelOps Weekly Highlights - January 22, 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p/><figure class="alignright"><a href="https://www.flickr.com/photos/proud2bcan8dn/1150097247/in/faves-19934681@N00/" target="_blank" title="wine-and-pies"><img alt="wine-and-pies" src="https://farm2.staticflickr.com/1216/1150097247_2f11cb4c2d_z.jpg?zz=1" width="200px"/></a>Releng: drinkin’ wine and makin’ pies.</figure>It’s encouraging to see more progress this week on both the build/release promotion and TaskCluster migration fronts, our two major efforts for this quarter.<p/>
-
- <p><b>Modernize infrastructure:</b></p>
- <p>In a continuing effort to enable faster, more reliable, and more easily-run tests for TaskCluster components, Dustin landed support for an in-memory, credential-free mock of Azure Table Storage in the <a href="https://www.npmjs.com/package/azure-entities" target="_blank">azure-entities</a> package. Together with the fake mock support he added to <a href="https://github.com/djmitche/taskcluster-lib-testing" target="_blank">taskcluster-lib-testing</a>, this allows tests for components like taskcluster-hooks to run without network access and without the need for any credentials, substantially decreasing the barrier to external contributions.</p>
-
- <p>All release promotion tasks are now signed by default. Thanks to Rail for his work here to help improve verifiability and chain-of-custody in our upcoming release process. (<a href="https://bugzil.la/1239682" target="_blank">https://bugzil.la/1239682</a>)
- Beetmover has been spotted in the wild! Jordan has been working on this new tool as part of our release promotion project. Beetmover helps move build artifacts from one place to another (generally between S3 buckets these days), but can also be extended to perform validation actions inline, e.g. checksums and anti-virus. (<a href="https://bugzil.la/1225899" target="_blank">https://bugzil.la/1225899</a>)</p>
-
- <p>Dustin configured the “desktop-test†and “desktop-build†docker images to build automatically on push. That means that you can modify the Dockerfile under `testing/docker`, push to try, and have the try job run in the resulting image, all without pushing any images. This should enable much quicker iteration on tweaks to the docker images. Note, however, that updates to the base OS images (ubuntu1204-build and centos6-build) still require manual pushes.</p>
-
- <p>Mark landed Puppet code for base windows 10 support including secrets and ssh keys management.</p>
-
- <p><b>Improve CI pipeline:</b></p>
-
- <p>Vlad and Amy repurposed 10 Windows XP machines as Windows 7 to improve the wait times in that test pool (<a href="https://bugzil.la/1239785" target="_blank">https://bugzil.la/1239785</a>)
- Armen and Joel have been working on porting the Gecko tests to run under TaskCluster, and have narrowed the failures down to the single digits. This puts us on-track to enable Linux debug builds and tests in TaskCluster as the canonical build/test process.</p>
-
- <p><b>Release:</b></p>
-
- <p>Ben finished up work on enhanced Release Blob validation in Balrog (<a href="https://bugzil.la/703040" target="_blank">https://bugzil.la/703040</a>), which makes it much more difficult to enter bad data into our update server.</p>
-
- <p>You may recall Mihai, our former intern who <a href="http://coopcoopbware.tumblr.com/post/133490693210/welcome-back-mihai" target="_blank">we just hired back in November</a>. Shortly after joining the team, he jumped into the <a href="https://wiki.mozilla.org/ReleaseEngineering/Releaseduty" target="_blank">releaseduty</a> rotation to provide much-needed extra bandwidth. The learning curve here is steep, but over the course of the Firefox 44 release cycle, he’s taken on more and more responsibility. He’s even volunteered to do releaseduty for the Firefox 45 release cycle as well. Perhaps the most impressive thing is that he’s also taken the time to update (or write) the releaseduty docs so that the next person who joins the rotation will be that much further ahead of the game. Thanks for your hard work here, Mihai!</p>
-
- <p><b>Operational:</b></p>
-
- <p>Hal did some cleanup work to remove unused mozharness configs and directories from the build mercurial repos. These resources have long-since moved into the main mozilla-central tree. Hopefully this will make it easier for contributors to find the canonical copy! (<a href="https://bugzil.la/1239003" target="_blank">https://bugzil.la/1239003</a>)</p>
-
- <p><b>Hiring:</b></p>
-
- <p>We’re still hiring for a full-time <a href="https://careers.mozilla.org/position/oi8b2fwn" target="_blank">Build &amp; Release Engineer</a>, and we are still accepting applications for <a href="https://careers.mozilla.org/position/ofA51fwF" target="_blank">interns for 2016</a>. Come join us!</p>
-
- <p>Well, I don’t know about you, but all that hard work makes me hungry for pie. See you next week!</p></div>
- </summary>
- <updated>2016-01-22T20:49:38Z</updated>
- <category term="Mozilla"/>
- <category term="releng"/>
- <category term="highlights"/>
- <source>
- <id>http://coopcoopbware.tumblr.com/</id>
- <author>
- <name>Chris Cooper</name>
- </author>
- <link href="http://coopcoopbware.tumblr.com/" rel="alternate" type="text/html"/>
- <link href="http://coopcoopbware.tumblr.com/tagged/Mozilla/rss" rel="self" type="application/rss+xml"/>
- <title>Five different types of fried cheese</title>
- <updated>2016-01-22T21:00:12Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://air.mozilla.org/foundation-demos-january-22-2016/</id>
- <link href="https://air.mozilla.org/foundation-demos-january-22-2016/" rel="alternate" type="text/html"/>
- <title>Foundation Demos January 22 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
- <img alt="Foundation Demos January 22 2016" class="wp-post-image" height="90" src="https://air.cdn.mozilla.net/media/cache/1c/a0/1ca0b9b2609cdd4e6e3577a8c3df8cfc.jpg" width="160"/>
- Mozilla Foundation Demos January 22 2016
- </p></div>
- </summary>
- <updated>2016-01-22T18:00:00Z</updated>
- <author>
- <name>Air Mozilla</name>
- </author>
- <source>
- <id>https://air.mozilla.org/</id>
- <link href="https://air.mozilla.org/" rel="alternate" type="text/html"/>
- <link href="https://air.mozilla.org/" rel="self" type="application/rss+xml"/>
- <rights>Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.</rights>
- <subtitle>Air Mozilla is the Internet multimedia presence of Mozilla, with live and pre-recorded shows, interviews, news snippets, tutorial videos, and features about the Mozilla community.</subtitle>
- <title>Air Mozilla</title>
- <updated>2016-01-25T20:31:50Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://blog.mozilla.org/sumo/?p=3667</id>
- <link href="https://blog.mozilla.org/sumo/2016/01/22/whats-up-with-sumo-22nd-january/" rel="alternate" type="text/html"/>
- <title>What’s up with SUMO – 22nd January</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Hello, SUMO Nation! The third week of the new year is already behind us. Time flies when you’re not paying attention… What are you going to do this weekend? Let us know in the comments, if you feel like sharing … <a class="go" href="https://blog.mozilla.org/sumo/2016/01/22/whats-up-with-sumo-22nd-january/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><strong>Hello, SUMO Nation!</strong></p>
- <p><a href="http://blog.mozilla.org/sumo/files/2016/01/sumo_logo.png"><img alt="sumo_logo" class="aligncenter size-full wp-image-3670" height="387" src="http://blog.mozilla.org/sumo/files/2016/01/sumo_logo.png" width="383"/></a>The third week of the new year is already behind us. Time flies when you’re not paying attention… What are you going to do this weekend? Let us know in the comments, if you feel like sharing :-) I hope to be in the mountains, getting some fresh (bracing) air, and enjoying nature.</p>
- <h3><strong class="username">Welcome, new contributors!<br/>
- </strong></h3>
- <ul>
- <li class="author">
- <div class="author"><a class="username" href="https://support.mozilla.org/user/johnmwc2" target="_blank">johnmwc2</a></div>
- </li>
- <li class="author"><a class="author-name" href="https://support.mozilla.org/user/myanesp" target="_blank">myanesp</a></li>
- <li class="author"><a class="author-name" href="https://support.mozilla.org/user/Harish.A" target="_blank">Harish.A</a></li>
- <li class="author"><a class="author-name" href="https://support.mozilla.org/user/hoolibob" target="_blank">hoolibob</a></li>
- <li class="author"><a class="author-name" href="https://support.mozilla.org/user/Meteoro890" target="_blank">Meteoro890</a></li>
- </ul>
- <div class="author">If you just joined us, don’t hesitate – come over and <a href="https://support.mozilla.org/forums/buddies" target="_blank">say “hi†in the forums!</a></div>
- <div class="author"/>
- <div class="author">
- <h3><strong>Contributors of the week<br/>
- </strong></h3>
- <ul>
- <li><span class="author-a-z74z1rz89z69z76zbz72zz69zz67z9z82zniz71z"><a href="https://support.mozilla.org/user/safwan.rahman" target="_blank">Safwan</a> for his work on the <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=619284" target="_blank">draft feature for l10n / KB editing</a> – rock on!</span></li>
- <li><a href="https://support.mozilla.org/user/artist" target="_blank">Artist</a> and <a href="https://support.mozilla.org/user/pollti" target="_blank">Pollti</a> for their the work on updating important articles for Focus with limited time – woot!</li>
- </ul>
- <div class="" id="magicdomid64">
- <p><strong><span style="text-decoration: underline;">We salute you!</span></strong></p>
- </div>
- <div class="author">Don’t forget that if you are new to SUMO and someone helped you get started in a nice way you can <a href="https://support.mozilla.org/forums/buddies/711364?last=65670" target="_blank">nominate them for the Buddy of the Month!</a></div>
- <div class="author"/>
- </div>
- <h3><strong>Most recent SUMO Community meeting</strong></h3>
- <ul>
- <li><a href="https://public.etherpad-mozilla.org/p/sumo-2016-01-18" target="_blank">You can read the notes here</a> (most of the staff members were AFK due to MLK Day in the US) and see the video on our <a href="https://www.youtube.com/channel/UCaiposaIhA7HfMqH2NIciyA/videos" target="_blank">YouTube channel</a> and <a href="https://air.mozilla.org/search/?q=sumo" target="_blank">at AirMozilla</a>.<del> </del><del><br/>
- </del></li>
- <li><strong>IMPORTANT: We are considering changing the way the meetings work. Help us figure out what’s best for you – join the discussion on the forums in this thread: <a href="https://support.mozilla.org/en-US/forums/contributors/711752?last=67873">(Monday) Community Meetings in 2016</a>.</strong></li>
- </ul>
- <h3><strong>The next SUMO Community meeting… </strong></h3>
- <ul>
- <li style="text-align: left;">is happening on <a href="https://public.etherpad-mozilla.org/p/sumo-2016-01-25" target="_blank">Monday the 25th – join us</a>!</li>
- <li style="text-align: left;"><strong>Reminder: if you want to add a discussion topic to the upcoming meeting agenda:</strong>
- <ul>
- <li style="text-align: left;">Start a thread in the <a href="https://support.mozilla.org/forums/contributors" target="_blank">Community Forums</a>, so that everyone in the community can see what will be discussed and voice their opinion here before Monday (this will make it easier to have an efficient meeting).</li>
- <li style="text-align: left;">Please do so as soon as you can before the meeting, so that people have time to read, think, and reply (and also add it to the agenda).</li>
- <li style="text-align: left;">If you can, please attend the meeting in person (or via IRC), so we can follow up on your discussion topic during the meeting with your feedback.</li>
- </ul>
- </li>
- </ul>
- <h3><strong class="author-g-ivsra51ph44x461i">Developers</strong></h3>
- <ul>
- <li><a href="http://edwin.mozilla.io/t/sumo" target="_blank">You can see the current state of the backlog our developers are working on here</a>.</li>
- <li><a href="https://public.etherpad-mozilla.org/p/sumo-p-2016-01-21" target="_blank">The latest SUMO Platform meeting notes can be found here</a>.</li>
- <li>Interested in learning how Kitsune (the engine behind SUMO) works? <a href="http://kitsune.readthedocs.org/" target="_blank">Read more about it here</a> and <a href="https://github.com/mozilla/kitsune/" target="_blank">fork it on GitHub</a>!</li>
- <li>We have a new link for promoting contributions to Kitsune’s code. Please use <strong>http://mzl.la/SUMOdev</strong> whenever you want to show interested people to see what Kitsune is all about – thanks!</li>
- </ul>
- <p><a href="http://blog.mozilla.org/sumo/files/2016/01/mission_developers.png"><img alt="mission_developers" class="aligncenter size-full wp-image-3668" height="406" src="http://blog.mozilla.org/sumo/files/2016/01/mission_developers.png" width="437"/></a></p>
- <h3><strong>Social</strong></h3>
- <ul>
- <li>Next week, there will be a kick-off meeting for the rethinking of Mozilla’s general support strategy through social networks. <a href="https://support.mozilla.org/user/Madasan" target="_blank">Are you interested in taking part? Let Madalina know!</a></li>
- </ul>
- <h3><strong>Community</strong></h3>
- <ul>
- <li>The NDA process and list is currently being reworked under the leadership of the Participation Team. Expect to see messaging on this subject in the coming days.</li>
- <li>
- <div class="title"><strong><a href="https://support.mozilla.org/forums/contributors/711729?last=67763">IMPORTANT: take a look at our Work Week Summary for Mozlando. We need your feedback for a few things there.</a></strong></div>
- </li>
- <li>Are you going to FOSDEM next week? Would you like to have a small SUMO-meetup? <a href="https://support.mozilla.org/user/vesper" target="_blank">Let me know</a>!</li>
- <li>
- <div class="title">Ongoing reminder: if you think you can benefit from getting <a href="https://wiki.mozilla.org/Community_Hardware" target="_blank">a second-hand device</a> to help you with contributing to SUMO, you know where to find us.</div>
- </li>
- </ul>
- <p><a href="http://blog.mozilla.org/sumo/files/2016/01/hero_support.png"><img alt="hero_support" class="aligncenter size-full wp-image-3669" height="383" src="http://blog.mozilla.org/sumo/files/2016/01/hero_support.png" width="367"/></a></p>
- <div class="">
- <div class="" id="magicdomid83">
- <h3><strong class="author-g-ivsra51ph44x461i">Localization</strong></h3>
- </div>
- </div>
- <div class="" id="magicdomid95">
- <ul>
- <li>You can <a href="https://support.mozilla.org/forums/l10n-forum/711781" target="_blank">read more about the recent “infrequent contributor survey†in this thread</a>. In short: the good news is that we’re doing a good job at making it easy enough for everyone to contribute. The bad news – we’re not doing enough to make sure they know what to do after their first contribution. Expect some changes in the messaging for first-time contributors to the KB :-)</li>
- <li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1012384" target="_blank">Our magical l10n dashboards keep being magical</a> ;-) Thank you for your patience. If you see any discrepancies between the number of localized articles and the percentage shown in the bar, file a bug!</li>
- </ul>
- </div>
- <div class="" id="magicdomid75">
- <h3><strong>Firefox<br/>
- </strong></h3>
- <ul>
- <li><strong>for Android</strong>
- <ul>
- <li><a href="https://support.mozilla.org/forums/contributors/711712?last=67653">Learn more about Firefox 43 for Android from the official thread with release notes / issues / discussions</a>.</li>
- <li>
- <div class="title"><a href="https://support.mozilla.org/forums/contributors/711718?last=67822">Reminder: Roland is sharing Firefox 44 for Android release notes / issues / discussions</a> with everyone in the forum.</div>
- </li>
- </ul>
- </li>
- </ul>
- <ul>
- <li><strong>for Desktop</strong>
- <ul>
- <li>Heads up – next week should be release week! Keep your eyes peeled ;-)</li>
- </ul>
- </li>
- </ul>
- <ul>
- <li><strong>for iOS</strong>
- <div class="" id="magicdomid85">
- <ul class="list-bullet1">
- <li><span class="author-a-107uz69zz81zhz78z0z78zz84zz66zz76zz82zz77zj">No news from the world of Firefox for iOS this week.</span></li>
- </ul>
- </div>
- </li>
- </ul>
- </div>
- <p>Thank you for reading all the way down here… More to come next week! You know where to find us, so see you around – keep rocking the open &amp; helpful web!</p></div>
- </content>
- <updated>2016-01-22T17:43:56Z</updated>
- <category term="General"/>
- <author>
- <name>Michał</name>
- </author>
- <source>
- <id>https://blog.mozilla.org/sumo</id>
- <link href="https://blog.mozilla.org/sumo/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://blog.mozilla.org/sumo" rel="alternate" type="text/html"/>
- <subtitle>SUpport MOzilla's official blog - rocking the helpful web since 2008!</subtitle>
- <title>SUMO Blog</title>
- <updated>2016-01-25T09:31:47Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://air.mozilla.org/bay-area-rust-meetup-january-2016/</id>
- <link href="https://air.mozilla.org/bay-area-rust-meetup-january-2016/" rel="alternate" type="text/html"/>
- <title>Bay Area Rust Meetup January 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
- <img alt="Bay Area Rust Meetup January 2016" class="wp-post-image" height="90" src="https://air.cdn.mozilla.net/media/cache/87/4f/874f4abef76f55213d50e43d6417ed99.png" width="160"/>
- Bay Area Rust meetup for January 2016. Topics TBD.
- </p></div>
- </summary>
- <updated>2016-01-22T03:00:00Z</updated>
- <author>
- <name>Air Mozilla</name>
- </author>
- <source>
- <id>https://air.mozilla.org/</id>
- <link href="https://air.mozilla.org/" rel="alternate" type="text/html"/>
- <link href="https://air.mozilla.org/" rel="self" type="application/rss+xml"/>
- <rights>Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.</rights>
- <subtitle>Air Mozilla is the Internet multimedia presence of Mozilla, with live and pre-recorded shows, interviews, news snippets, tutorial videos, and features about the Mozilla community.</subtitle>
- <title>Air Mozilla</title>
- <updated>2016-01-25T20:31:49Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://blog.lizardwrangler.com/?p=3953</id>
- <link href="http://blog.lizardwrangler.com/2016/01/22/honored-to-participate-in-new-un-panel-on-womens-economic-empowerment/" rel="alternate" type="text/html"/>
- <title>Honored to Participate in New UN Panel on Women’s Economic Empowerment</title>
- <summary>Women’s economic empowerment is necessary for many reasons. It is necessary to bring health, safety and opportunity to half of humanity. It is necessary to bring investment and health to families and communities. It is necessary to unlock economic growth and build more stable societies. Today the UN Secretary General Ban Ki-moon launched the first […]</summary>
- <updated>2016-01-22T02:45:58Z</updated>
- <category term="Mozilla"/>
- <author>
- <name>Mitchell Baker</name>
- </author>
- <source>
- <id>http://blog.lizardwrangler.com</id>
- <link href="http://blog.lizardwrangler.com/feed/" rel="self" type="application/rss+xml"/>
- <link href="http://blog.lizardwrangler.com" rel="alternate" type="text/html"/>
- <title>Mitchell's Blog</title>
- <updated>2016-01-22T03:00:15Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://blog.mozilla.org/webdev/?p=4082</id>
- <link href="https://blog.mozilla.org/webdev/2016/01/21/beer-and-tell-january-2016/" rel="alternate" type="text/html"/>
- <title>Beer and Tell – January 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Once a month, web developers from across the Mozilla Project get together to talk about our side projects and drink, an occurrence we like to call “Beer and Tellâ€. There’s a wiki page available with a list of the presenters, … <a class="go" href="https://blog.mozilla.org/webdev/2016/01/21/beer-and-tell-january-2016/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Once a month, web developers from across the Mozilla Project get together to talk about our side projects and drink, an occurrence we like to call “Beer and Tellâ€.</p>
- <p>There’s a <a href="https://wiki.mozilla.org/Webdev/Beer_And_Tell/January_2016">wiki page available</a> with a list of the presenters, as well as links to their presentation materials. There’s also a <a href="https://air.mozilla.org/webdev-beer-and-tell-january-2016/">recording available</a> courtesy of Air Mozilla.</p>
- <h3>shobson: CSS-Only Disco Ball</h3>
- <p>First up was <a href="https://mozillians.org/en-US/u/stephaniehobson/">shobson</a> with a cool demo of an <a href="http://codepen.io/stephaniehobson/pen/ZGZBVW?editors=110">animated disco ball made entirely with CSS</a>. The demo uses a repeated radial gradient for the background, and linear gradients plus a border radius for the disco ball itself. The demo was made for use in shobson’s <a href="https://www.youtube.com/watch?v=7poVasAQjos">WordCamp talk</a> about debugging CSS. A <a href="http://stephaniehobson.ca/wordpress/2015/08/15/how-to-debug-css/">blog post</a> with notes from the talk is available as well.</p>
- <h3>craigcook: Proton – A CSS Framework for Prototyping</h3>
- <p>Next was <a href="https://mozillians.org/en-US/u/craigcook/">craigcook</a>, who presented <a href="http://craigcook.github.io/proton/">Proton</a>. It’s a CSS framework that is intentionally ugly to encourage use for prototypes only. Unlike other CSS frameworks, the temptation to reuse the classes from the framework in your final page doesn’t occur, which helps avoid the presentational classes that plague sites built using a framework normally.</p>
- <p>Proton’s website includes an overview of the layout and components provided, as well as examples of prototypes made using the framework.</p>
- <hr/>
- <p>If you’re interested in attending the next Beer and Tell, sign up for the <a href="https://lists.mozilla.org/listinfo/dev-webdev">dev-webdev@lists.mozilla.org mailing list</a>. An email is sent out a week beforehand with connection details. You could even add yourself to the wiki and show off your side-project!</p>
- <p>See you next month!</p></div>
- </content>
- <updated>2016-01-21T18:56:46Z</updated>
- <category term="Beer and Tell"/>
- <author>
- <name>Michael Kelly</name>
- </author>
- <source>
- <id>https://blog.mozilla.org/webdev</id>
- <link href="https://blog.mozilla.org/webdev/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://blog.mozilla.org/webdev" rel="alternate" type="text/html"/>
- <subtitle>For make benefit of glorious tubes</subtitle>
- <title>Mozilla Web Development</title>
- <updated>2016-01-21T19:01:37Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://blog.mozilla.org/community/?p=2287</id>
- <link href="http://blog.mozilla.org/community/2016/01/21/this-month-at-mozilla/" rel="alternate" type="text/html"/>
- <title>This Month at Mozilla</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">A lot of exciting things are happening with Participation at Mozilla this month. Here’s a quick round-up of some of the things that are going on! Mozillians Profiles Got a Facelift: Since the start of this year, the Participation Infrastructure … <a class="go" href="http://blog.mozilla.org/community/2016/01/21/this-month-at-mozilla/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p style="text-align: center;"><em>A lot of exciting things are happening with Participation at Mozilla this month. Here’s a quick round-up of some of the things that are going on!</em></p>
- <h3><b>Mozillians Profiles Got a Facelift: </b></h3>
- <p>Since the start of this year, the Participation Infrastructure team has had a renewed focus on making mozillians.org a modern community directory to meet Mozilla’s growing needs.</p>
- <p>Their first target for 2016 was to improve the UX on the profile edit interface.</p>
- <p><a href="https://blog.mozilla.org/community/files/2016/01/new-profile-768x548.png"><img alt="new-profile-768x548" class="aligncenter wp-image-2288 size-large" height="428" src="https://blog.mozilla.org/community/files/2016/01/new-profile-768x548-600x428.png" width="600"/></a><br/>
- â€We chose it due to relatively self-contained nature of it, and cause many people were not happy with the current UX. After research of existing tools and applying latest best practices, we designed, coded and deployed a new profile edit interface (which by the way is renamed to Settings now) that we are happy to deliver to all Mozillians.â€</p>
- <p>Read the full blog <a href="http://pierros.papadeas.gr/?p=447">here</a>!</p>
- <h3><b>There are New Ways to Bring Your Design Skills to Mozilla: </b></h3>
- <p>Are you a passionate designer looking to contribute to Mozilla? You’ll be happy to hear there is a new way to contribute to the many design projects around Mozilla! Submit issues, find collaborators, and work on open source projects by getting involved!</p>
- <ul>
- <li>You can check out the projects looking for help, or submit your own on the <a href="https://github.com/mozilla/Community-Design/issues">GitHub Repo</a>.</li>
- <li><a href="https://docs.google.com/a/mozilla.com/forms/d/1Tw3Mw_CMiqcIQrJF7TB1yIETGYec__NiVhaSz0CAaE8/viewform">Sign-up to the mailing list</a> to be added as a contributor to the Repo, added to the regular meeting list, and to get emails about GitHub trainings and more!</li>
- <li>And read<a href="http://elioqoshi.me/en/2016/01/mozilla-community-design-kickoff/"> a blogpost</a> about the project and its first meeting.</li>
- </ul>
- <p>Learn more <a href="https://discourse.mozilla-community.org/c/community-design">here</a>.</p>
- <h3><b>136 Volunteers Are Going to Singapore: </b></h3>
- <p>This weekend 136 participation leaders from all over the world are<a href="https://twitter.com/thephoenixbird/status/690181985222926336"> heading to Singapore</a> to undergo two days of<a href="https://wiki.mozilla.org/Participation/Global_Gatherings_2015"> leadership training</a> to develop the skills, knowledge and attitude to lead Participation in 2016.</p>
- <div class="wp-caption aligncenter" id="attachment_2289" style="width: 609px;"><a href="https://blog.mozilla.org/community/files/2016/01/CZQE241WIAA6R2J.jpg"><img alt="Photo credit @thephoenixbird on Twitter" class="wp-image-2289 size-full" height="337" src="https://blog.mozilla.org/community/files/2016/01/CZQE241WIAA6R2J.jpg" width="599"/></a><p class="wp-caption-text">Photo credit @<a href="https://twitter.com/thephoenixbird/status/690181985222926336" target="_blank">thephoenixbird</a> on Twitter</p></div>
- <p>If you know someone attending don’t forget to share your questions and goals with them, and follow along over the weekend by watching the hashtag<a href="https://twitter.com/search?q=%23mozsummit"> #MozSummit</a>.</p>
- <p>Stay tuned after the event for a debrief of the weekend!</p>
- <h3><b>Friday’s Plenary from Mozlando is now public on Air Mozilla: </b></h3>
- <p>If you’re interested in learning more about all the exciting new features, projects, and plans that were presented at Mozlando look no further! You can now watch the final plenary sessions on Air Mozilla (it’s a lot of fun so I highly recommend it!) <a href="https://air.mozilla.org/channels/mozlando/">here</a>.</p>
- <p>Share your questions and comments on discourse <a href="https://discourse.mozilla-community.org/t/friday-plenary-from-mozlando-now-public-on-air-mozilla/6659">here</a>.</p>
- <p><em>Look forward to more updates like these in the coming months!</em></p></div>
- </content>
- <updated>2016-01-21T17:58:33Z</updated>
- <category term="Participation"/>
- <category term="Air Mozilla"/>
- <category term="contributor"/>
- <category term="MonthlyUpdate"/>
- <category term="MozParticipation"/>
- <author>
- <name>Lucy Harris</name>
- </author>
- <source>
- <id>http://blog.mozilla.org/community</id>
- <link href="http://blog.mozilla.org/community/feed/" rel="self" type="application/rss+xml"/>
- <link href="http://blog.mozilla.org/community" rel="alternate" type="text/html"/>
- <subtitle>News and notes from and for the Mozilla community.</subtitle>
- <title>about:community</title>
- <updated>2016-01-25T16:31:42Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://blog.mozilla.org/netpolicy/?p=912</id>
- <link href="https://blog.mozilla.org/netpolicy/2016/01/21/prioritizing-privacy-good-for-business/" rel="alternate" type="text/html"/>
- <title>Prioritizing privacy: Good for business</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">This was originally posted at StaySafeOnline.org in advance of Data Privacy Day. Data Privacy Day – which arrives in just a week – is a day designed to raise awareness and promote best practices for privacy and data protection. It … <a class="go" href="https://blog.mozilla.org/netpolicy/2016/01/21/prioritizing-privacy-good-for-business/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>This was originally posted at <a href="http://staysafeonline.org/blog/prioritizing-privacy-good-for-business/">StaySafeOnline.org</a> in advance of <a href="http://www.staysafeonline.org/data-privacy-day/events/">Data Privacy Day</a>.</em></p>
- <p>Data Privacy Day – which arrives in just a week – is a day designed to raise awareness and promote best practices for privacy and data protection. It is a day that looks to the future and recognizes that we can and should do better as an industry. It reminds us that we need to focus on the importance of having the trust of our users.</p>
- <p>We seek to build trust so we can collectively create the Web our users want – the Web we all want.</p>
- <p>That Web is based on relationships, the same way that the offline world is. When I log in to a social media account, schedule a grocery delivery online or browse the news, I’m relying on those services to respect my data. While companies are innovating their products and services, they need to be innovating on user trust as well, which means designing to address privacy concerns – and making smart choices (early!) about how to manage data.</p>
- <p>A <a href="http://www.pewinternet.org/2016/01/14/privacy-and-information-sharing/">recent survey by Pew</a> highlights the thought that each user puts into their choices – and the contextual considerations in various scenarios. They concluded that many participants were annoyed and uncertain by how their information was used, and they are choosing not to interact with those services that they don’t trust. This is a clear call to businesses to foster more trust with their users, which starts by making sure that there are people empowered within your company to ask the right questions: what do your users expect? What data do you need to collect? How can you communicate about that data collection? How should you protect their data? Is holding on to data a risk, or should you delete it?</p>
- <p>It’s crucial that users are a part of this process – consumers’ data is needed to offer cool, new experiences and a user needs to trust you in order to choose to give you their data. Pro-user innovation can’t happen in a vacuum – the system as it stands today isn’t doing a good job of aligning user interests with business incentives. Good user decisions can be good business decisions, but only if we create thoughtful user-centric products in a way that closes the feedback loop so that positive user experiences are rewarded with better business outcomes.</p>
- <p>Not prioritizing privacy in product decisions will impact the bottom line. From the many data breaches over the last few years to increasing evidence of eroding trust in online services, data practices are proving to be the dark horse in the online economy. When a company loses user trust, whether on privacy or <a href="https://medium.com/@davidamerland/the-cost-of-losing-trust-97d764a1e696">anything else</a>, it loses customers and the potential for growth.</p>
- <p>Privacy means different things to different people but what’s clear is that people make decisions about the products and services that they use based on how those companies choose to treat their users. Over this time, the Internet ecosystem has evolved, as has its relationship with users – and some aspects of this evolution threaten the trust that lies at the heart of that relationship. Treating a user as a target – whether for an ad, purchase, or service – undermines the trust and relationship that a business may have with a consumer.</p>
- <p>The solution is not to abandon the massive value that robust data can bring to users, but rather, to collect and use data leanly, productively and transparently. At Mozilla, we have created a strong set of internal data practices to ensure that data decisions align with our <a href="https://www.mozilla.org/en-US/privacy/principles/">privacy principles</a>. As an industry, we need to keep users at the center of the product vision rather than viewing them as targets of the product – it’s the only way to stay true to consumers and deliver the best, most trusted experiences possible.</p>
- <p>Want to hear more about how businesses can build relationships with their users by focusing on trust and privacy? We’re holding events in Washington, D.C., and <a href="https://www.eventbrite.com/e/january-privacy-lab-privacy-for-startups-tickets-19849219550?aff=es2">San Francisco</a> with some of our partners to talk about it. Please join us!</p></div>
- </content>
- <updated>2016-01-21T17:42:00Z</updated>
- <category term="Data Governance"/>
- <category term="privacy"/>
- <category term="Trust"/>
- <author>
- <name>Heather West</name>
- </author>
- <source>
- <id>https://blog.mozilla.org/netpolicy</id>
- <link href="http://blog.mozilla.org/netpolicy/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://blog.mozilla.org/netpolicy" rel="alternate" type="text/html"/>
- <subtitle>Mozilla's official blog on open Internet policy initiatives and developments</subtitle>
- <title>Open Policy &amp; Advocacy</title>
- <updated>2016-01-25T20:46:35Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>https://tacticalsecret.com/tag/mozilla/rss/9c39ad13-14ae-4456-a84e-13612637d832</id>
- <link href="https://tacticalsecret.com/issuance-rate-for-lets-encrypt/" rel="alternate" type="text/html"/>
- <title>Issuance Rate for Let's Encrypt</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Gathering data from <a href="https://github.com/jcjones/letsencrypt_statistics">Certificate Transparency logs</a>, here's a snapshot in time of Let's Encrypt's certificate issuance rate per minute from 7-21 January 2016. On 20 January, DreamHost launched formal support for Let's Encrypt, which coincides with a rate increase.</p>
-
- <p>Note: This is mostly an experimental post with embedding charts; I've</p></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Gathering data from <a href="https://github.com/jcjones/letsencrypt_statistics">Certificate Transparency logs</a>, here's a snapshot in time of Let's Encrypt's certificate issuance rate per minute from 7-21 January 2016. On 20 January, DreamHost launched formal support for Let's Encrypt, which coincides with a rate increase.</p>
-
- <p>Note: This is mostly an experimental post with embedding charts; I've more data in the queue.</p>
-
- <h3>Let's Encrypt Issuance Rate per Minute</h3>
-
- <div id="rate_hours"/></div>
- </content>
- <updated>2016-01-21T17:07:25Z</updated>
- <category term="letsencrypt"/>
- <category term="mozilla"/>
- <category term="charts"/>
- <author>
- <name>James 'J.C.' Jones</name>
- </author>
- <source>
- <id>https://tacticalsecret.com/</id>
- <link href="https://tacticalsecret.com/" rel="alternate" type="text/html"/>
- <link href="https://tacticalsecret.com/tag/mozilla/rss/" rel="self" type="application/rss+xml"/>
- <subtitle>On a mission to solve information security issues for the whole Internet. That, and whatever else comes up.</subtitle>
- <title>mozilla - The Internet of Secure Things</title>
- <updated>2016-01-21T17:16:43Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://air.mozilla.org/web-qa-weekly-meeting-20160121/</id>
- <link href="https://air.mozilla.org/web-qa-weekly-meeting-20160121/" rel="alternate" type="text/html"/>
- <title>Web QA Weekly Meeting, 21 Jan 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
- <img alt="Web QA Weekly Meeting" class="wp-post-image" height="90" src="https://air.cdn.mozilla.net/media/cache/f5/13/f5137857516694df0458e837c2d3a4be.png" width="160"/>
- This is our weekly gathering of Mozilla'a Web QA team filled with discussion on our current and future projects, ideas, demos, and fun facts.
- </p></div>
- </summary>
- <updated>2016-01-21T17:00:00Z</updated>
- <author>
- <name>Air Mozilla</name>
- </author>
- <source>
- <id>https://air.mozilla.org/</id>
- <link href="https://air.mozilla.org/" rel="alternate" type="text/html"/>
- <link href="https://air.mozilla.org/" rel="self" type="application/rss+xml"/>
- <rights>Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.</rights>
- <subtitle>Air Mozilla is the Internet multimedia presence of Mozilla, with live and pre-recorded shows, interviews, news snippets, tutorial videos, and features about the Mozilla community.</subtitle>
- <title>Air Mozilla</title>
- <updated>2016-01-25T20:31:49Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://soledadpenades.com/?p=6379</id>
- <link href="http://soledadpenades.com/2016/01/21/no-more-tap-tap-tap-sounds-yay/" rel="alternate" type="text/html"/>
- <link href="https://flattr.com/submit/auto?user_id=8399&amp;popout=1&amp;url=http%3A%2F%2Fsoledadpenades.com%2F2016%2F01%2F21%2Fno-more-tap-tap-tap-sounds-yay%2F&amp;language=en_GB&amp;category=text&amp;title=No+more+tap+tap+tap+sounds%3A+yay%21&amp;description=A+few+days+ago+the+fantastic+Fritz+from+the+Netherlands+told+me+that+my+Hands+On+Web+Audio+slides+had+stopping+working+and+there+was+no+sound+coming+out+from...&amp;tags=bugs%2Cfirefox%2Cjavascript%2Cmozilla%2Cweb+audio%2Cblog" rel="payment" title="Flattr this!" type="text/html"/>
- <title>No more tap tap tap sounds: yay!</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">A few days ago the fantastic Fritz from the Netherlands told me that my Hands On Web Audio slides had stopping working and there was no sound coming out from them in Firefox. @supersole oh noes! I reopened your slides: https://t.co/SO35UfljMI and it doesn't work in @firefox anymore 😱 (works in chrome though.. 😢) — … <a class="more-link" href="http://soledadpenades.com/2016/01/21/no-more-tap-tap-tap-sounds-yay/">Continue reading <span class="screen-reader-text">No more tap tap tap sounds: yay!</span> <span class="meta-nav">→</span></a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>A few days ago the fantastic Fritz from the Netherlands told me that my <a href="http://soledadpenades.com/files/t/2015_howa/">Hands On Web Audio slides</a> had stopping working and there was no sound coming out from them in Firefox.</p>
- <blockquote class="twitter-tweet" width="550"><p dir="ltr" lang="en"><a href="https://twitter.com/supersole">@supersole</a> oh noes! I reopened your slides: <a href="https://t.co/SO35UfljMI">https://t.co/SO35UfljMI</a> and it doesn't work in <a href="https://twitter.com/firefox">@firefox</a> anymore <img alt="&#x1F631;" class="wp-smiley" src="http://s.w.org/images/core/emoji/72x72/1f631.png" style="height: 1em;"/> (works in chrome though.. <img alt="&#x1F622;" class="wp-smiley" src="http://s.w.org/images/core/emoji/72x72/1f622.png" style="height: 1em;"/>)</p>
- <p>— Boring Stranger (@fritzvd) <a href="https://twitter.com/fritzvd/status/686481500611735552">January 11, 2016</a></p></blockquote>
- <p/>
- <p>Which is pretty disappointing for a slide deck that is built to teach you about Web Audio!</p>
- <p>I noticed that the issue was only on the introductory slide which uses a modified version of Stuart Memo’s <a href="https://blog.stuartmemo.com/thx-deep-note-in-javascript/">fantastic THX sound recreation</a>-the rest of slides did play sound.</p>
- <p>I built <a href="http://sole.github.io/test_cases/web_audio/thx_cutting_out/">an isolated test case</a> <small><a href="https://github.com/sole/test_cases/tree/gh-pages/web_audio/thx_cutting_out">(source)</a></small> that used a parameter-capable version of the THX sound code, just in case the issue depended on the number of oscillators, and submitted this funnily titled bug to the Web Audio component: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1240054">Entirely Web Audio generated sound cuts out after a little while, or emits random tap tap tap sounds then silence</a>.</p>
- <p>I can happily confirm that the bug has been fixed in Nightly and the fix will hopefully be “uplifted†to DevEdition very soon, as it was due to a regression.</p>
- <p><a href="https://paul.cx/">Paul Adenot</a> (who works in Web Audio and is a Web Audio spec editor, amongst a couple tons of other cool things) was really excited about the bug, saying it was very edge-casey! Yay! And he also explained what did actually happen in lay terms: “you’d have to have a frequency that goes down very very slowly so that the FFT code could not keep upâ€, which is what the THX sound is doing with the filter frequency automation.</p>
- <p>I want to thank both Fritz for spotting this out and letting me know and also Stuart for sharing his THX code. It’s amazing what happens when you put stuff on the net and lots of different people use it in different ways and configurations. Together we make everything more robust <img alt=":-)" class="wp-smiley" src="http://soledadpenades.com/wp-includes/images/smilies/simple-smile.png" style="height: 1em;"/></p>
- <p>Of course also sending thanks to Paul and Ben for identifying and fixing the issue so fast! It’s not been even a week! Woohoo!</p>
- <p>Well done everyone! <img alt="&#x1F44F;" class="wp-smiley" src="http://s.w.org/images/core/emoji/72x72/1f44f.png" style="height: 1em;"/><img alt="&#x1F3FC;" class="wp-smiley" src="http://s.w.org/images/core/emoji/72x72/1f3fc.png" style="height: 1em;"/></p>
- <p><a href="http://soledadpenades.com/?flattrss_redirect&amp;id=6379&amp;md5=57babe624711830f95e4b8fbd6e52c91" target="_blank" title="Flattr"><img alt="flattr this!" src="http://soledadpenades.com/wp-content/plugins/flattr/img/flattr-badge-large.png"/></a></p></div>
- </content>
- <updated>2016-01-21T15:49:05Z</updated>
- <category term="Software"/>
- <category term="bugs"/>
- <category term="firefox"/>
- <category term="javascript"/>
- <category term="mozilla"/>
- <category term="web audio"/>
- <author>
- <name>sole</name>
- </author>
- <source>
- <id>http://soledadpenades.com</id>
- <link href="http://soledadpenades.com/tag/mozilla/feed/" rel="self" type="application/rss+xml"/>
- <link href="http://soledadpenades.com" rel="alternate" type="text/html"/>
- <subtitle>repeat 4[fd 100 rt 90]</subtitle>
- <title>mozilla – soledad penadés</title>
- <updated>2016-01-26T02:46:28Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://pierros.papadeas.gr/?p=447</id>
- <link href="http://pierros.papadeas.gr/?p=447" rel="alternate" type="text/html"/>
- <title>Mozillians.org Profile Edit refresh</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Since the start of this year, Participation Infrastructure team has a renewed focus on making mozillians.org a modern community directory to meet Mozilla’s growing needs. This will not be an one-time effort. We need to invest technically and programmatically in … <a href="http://pierros.papadeas.gr/?p=447">Continue reading <span class="meta-nav">→</span></a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Since the start of this year, Participation Infrastructure team has a renewed focus on making mozillians.org a modern community directory to meet Mozilla’s growing needs. This will not be an one-time effort. We need to invest technically and programmatically in order to deliver a first-class product that will be the foundation for identity management across the Mozilla ecosystem.</p>
- <p>Mozillians.org is full of functionality as it is today, but is paying the debt of being developed by 5 different teams over the past 5 years. We started simple this time. Updated all core technology pieces, did privacy and security reviews, and started the process of consolidating and modernizing many of the things we do in the site.</p>
- <p>Our first target was Profile Edit. We chose it due to relatively self-contained nature of it, and cause many people were not happy with the current UX. After research of existing tools and applying latest best practices, we designed, coded and deployed a new profile edit interface (which by the way is renamed to Settings now) that we are happy to deliver to all Mozillians.</p>
- <p><a href="http://pierros.papadeas.gr/wp-content/uploads/2016/01/new-profile.png" rel="attachment wp-att-448"><img alt="new-profile" class="aligncenter size-large wp-image-448" height="417" src="http://pierros.papadeas.gr/wp-content/uploads/2016/01/new-profile-1024x731.png" width="584"/></a>Have a<a href="https://mozillians.org/en-US/user/edit/"> look for yourself </a>and don’t miss the chance to update your profile while you do it!</p>
- <p><a href="https://mozillians.org/en-US/u/comzeradd/">Nikos</a> (on the front-end), <a href="https://mozillians.org/en-US/u/akatsoulas/">Tasos</a> and <a href="https://mozillians.org/en-US/u/jgiannelos/">Nemo</a> (on the back-end) worked hard to deliver this in a speedy manner (as they are used to), and the end result is a testament to what is coming next on Mozillians.org.</p>
- <p>Our next target? Groups. Currently it is obscure and unclear what all those settings in groups are, what is the functionality and how teams within Mozilla will be using it. We will be tackling this soon. After that, search and stats will be our attention, in an ongoing effort to fortify mozillians.org functionality. Stay tuned, and as always feel free to <a href="https://bugzilla.mozilla.org/enter_bug.cgi?product=Participation%20Infrastructure&amp;component=Phonebook">file bugs</a> and <a href="https://github.com/mozilla/mozillians">contribute </a>in the process.</p></div>
- </content>
- <updated>2016-01-21T11:41:39Z</updated>
- <category term="Foss Life"/>
- <category term="Software"/>
- <category term="Weblog"/>
- <category term="computer"/>
- <category term="foss"/>
- <category term="mozilla"/>
- <category term="mozillians"/>
- <category term="partinfra"/>
- <author>
- <name>Pierros Papadeas</name>
- </author>
- <source>
- <id>http://pierros.papadeas.gr</id>
- <link href="http://pierros.papadeas.gr/?feed=rss2&amp;tag=mozilla" rel="self" type="application/rss+xml"/>
- <link href="http://pierros.papadeas.gr" rel="alternate" type="text/html"/>
- <subtitle>whereabouts of a life</subtitle>
- <title>mozilla – Pierro's Spot</title>
- <updated>2016-01-21T11:45:53Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://adamlofting.com/?p=1396</id>
- <link href="http://feedproxy.google.com/~r/adamlofting/blog/~3/DoEWpBapwiw/" rel="alternate" type="text/html"/>
- <title>Blog posts I haven’t written lately</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Last year I joked… Thinking about writing a blog post listing the blog posts I’ve been meaning to write… Maybe that will save some time — Adam Lofting (@adamlofting) November 20, 2015 Now, it has come to this. 9 blog posts I’ve not been writing Working on working on the impact of impact Designing Games … <a class="more-link" href="http://adamlofting.com/1396/blog-posts-i-havent-written-lately/">Continue reading <span class="screen-reader-text">Blog posts I haven’t written lately</span></a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Last year I joked…</p>
- <blockquote class="twitter-tweet" lang="en">
- <p dir="ltr" lang="en">Thinking about writing a blog post listing the blog posts I’ve been meaning to write… Maybe that will save some time</p>
- <p>— Adam Lofting (@adamlofting) <a href="https://twitter.com/adamlofting/status/667657889817956352">November 20, 2015</a></p></blockquote>
- <p/>
- <p>Now, it has come to this.</p>
- <h4>9 blog posts I’ve not been writing</h4>
- <ul>
- <li>Working on working on the impact of impact</li>
- <li>Designing Games in <a href="https://en.wikipedia.org/wiki/Amateur" target="_blank">my free time</a></li>
- <li>Moving Out (the board game)</li>
- <li>Mozilla Foundation 2016 KPIs</li>
- <li>Studying Network Science</li>
- <li>Learning Analytics plans for 2016</li>
- <li>Daily practice / you are what you do every day</li>
- <li>Several more A/B tests to write up from <a href="http://fundraising.mozilla.org/">the fundraising campaign</a></li>
- <li>CRM Progress in 2015</li>
- </ul>
- <p>But my most requested blog by far, is an update on the status of my shed / office that I was tagging on to the end my blog posts at this time last year. Many people at Mozfest wanted to know about the shed… so here it is.</p>
- <p>This time last year:</p>
- <blockquote class="twitter-tweet" lang="en"><p>
- Starting in the new office today. It will take time to make it *nice* but it works for now. <a href="http://t.co/sWoC4kFNLc">pic.twitter.com/sWoC4kFNLc</a></p>
- <p>— Adam Lofting (@adamlofting) <a href="https://twitter.com/adamlofting/status/560361913339899904">January 28, 2015</a>
- </p></blockquote>
- <p/>
- <p>Some pictures from this morning:</p>
- <p><img alt="office1" class="alignright size-large wp-image-1398" height="282" src="http://adamlofting.com/wp-content/uploads/2016/01/office1-750x320.jpg" width="660"/></p>
- <p><img alt="office2" class="aligncenter size-large wp-image-1399" height="237" src="http://adamlofting.com/wp-content/uploads/2016/01/office2-750x269.jpg" width="660"/></p>
- <p>It’s a pretty nice place to work now and it doubles as useful workshop on the weekends. It needs a few finishing touches, but the law of diminishing returns means those finishing touches are lower priority than work that needs to be done elsewhere in the house and garden. So it’ll stay like this a while longer.</p>
- <img alt="" height="1" src="http://feeds.feedburner.com/~r/adamlofting/blog/~4/DoEWpBapwiw" width="1"/></div>
- </content>
- <updated>2016-01-21T09:44:24Z</updated>
- <category term="Personal"/>
- <category term="Taking note"/>
- <category term="Work"/>
- <category term="life"/>
- <category term="Mozilla"/>
- <category term="Planning"/>
- <category term="shed"/><feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://adamlofting.com/1396/blog-posts-i-havent-written-lately/</feedburner:origLink>
- <author>
- <name>Adam</name>
- </author>
- <source>
- <id>http://adamlofting.com</id>
- <link href="http://adamlofting.com" rel="alternate" type="text/html"/>
- <link href="http://feeds.feedburner.com/adamlofting/blog" rel="self" type="application/rss+xml"/>
- <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
- <subtitle>Thinking out loud about metrics, systems, human experience and the web.</subtitle>
- <title>Adam Lofting</title>
- <updated>2016-01-21T09:46:30Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://blog.ziade.org/2016/01/21/a-pelican-web-editor/</id>
- <link href="http://blog.ziade.org/2016/01/21/a-pelican-web-editor/" rel="alternate" type="text/html"/>
- <title>A Pelican web editor</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>The benefit of being a father again (Freya my 3rd child, was born last week) is
- that while on paternity leave &amp; between two baby bottles, I can hack on fun stuff.</p>
- <p>A few months ago, I've built for my running club a Pelican-based website, check it out
- at : <a class="reference external" href="http://acr-dijon.org">http://acr-dijon.org</a>. Nothing's special about it, except that I am not
- the one feeding it. The content is added by people from the club that have zero
- knowledge about softwares, let alone stuff like vim or command line tools.</p>
- <p>I set up a github-based flow for them, where they add content through the
- github UI and its minimal reStructuredText preview feature - and then a few
- of my crons update the website on the server I host.
- For images and other media, they are uploading them via FTP using FireSSH in Firefox.</p>
- <p>For the comments, I've switched from Disqus to <a class="reference external" href="https://posativ.org/isso/">ISSO</a>
- after I got annoyed by the fact that it was impossible to display a simple Disqus
- UI for people to comment without having to log in.</p>
- <p>I had to make my club friends go through a minimal
- reStructuredText syntax training, and things are more of less working now.</p>
- <p>The system has a few caveats though:</p>
- <ul class="simple">
- <li>it's dependent on Github. I'd rather have everything hosted on my server.</li>
- <li>the github restTRucturedText preview will not display syntax errors and warnings
- and very often, articles get broken</li>
- <li>the resulting reST is ugly, and it's a bit hard to force my editors to be stricter
- about details like empty lines, not using tabs etc.</li>
- <li>adding folders or organizing articles from Github is a pain</li>
- <li>editing the metadata tags is prone to many mistakes</li>
- </ul>
- <p>So I've decided to build my own web editing tool with the following features:</p>
- <ul class="simple">
- <li>resTructuredText cleanup</li>
- <li>content browsing</li>
- <li>resTructuredText web editor with live preview that shows warnings &amp; errors</li>
- <li>a little bit of wsgi glue and a few forms to create articles without
- having to worry about metadata syntax.</li>
- </ul>
- <div class="section" id="restructuredtext-cleanup">
- <h3>resTructuredText cleanup</h3>
- <p>The first step was to build a reStructuredText parser that would read some
- reStructuredText and render it back into a cleaner version.</p>
- <p>We've imported almost 2000 articles in Pelican from the old blog, so I had
- a <strong>lot</strong> of samples to make my parser work well.</p>
- <p>I first tried <a class="reference external" href="https://github.com/benoitbryon/rst2rst">rst2rst</a> but that
- parser was built for a very specific use case (text wrapping) and was
- incomplete. It was not parsing all of the reStructuredText syntax.</p>
- <p>Inspired by it, I wrote my own little parser using <strong>docutils</strong>.</p>
- <p>Understanding docutils is not a small task. This project is very powerfull
- but quite complex. One thing that cruelly misses in docutils parser tools
- is the ability to get the source text from any node, including its children,
- so you can render back the same source.</p>
- <p>That's roughly what I had to add in my code. It's ugly but it does the job:
- it will parse rst files and render the same content, minus all the extraneous
- empty lines, spaces, tabs etc.</p>
- </div>
- <div class="section" id="content-browsing">
- <h3>Content browsing</h3>
- <p>Content browsing is pretty straightforward: my admin tool let you browse
- the Pelican <em>content</em> directory and lists all articles, organized by categories.</p>
- <p>In our case, each category has a top directory in <em>content</em>. The browser
- parses the articles using my parser and displays paginated lists.</p>
- <p>I had to add a cache system for the parser, because one of the directory
- contains over 1000 articles -- and browsing was kind of slow :)</p>
- <img alt="http://ziade.org/henet-browsing.png" src="http://ziade.org/henet-browsing.png"/>
- </div>
- <div class="section" id="restructuredtext-web-editor">
- <h3>resTructuredText web editor</h3>
- <p>The last big bit was the live editor. I've stumbled on a neat little tool
- called <strong>rsted</strong>, that provides a live preview of the reStructuredText
- as you are typing it. And it includes warnings !</p>
- <p>Check it out: <a class="reference external" href="http://rst.ninjs.org/">http://rst.ninjs.org/</a></p>
- <p>I've stripped it and kept what I needed, and included it in my app.</p>
- <img alt="http://ziade.org/henet.png" src="http://ziade.org/henet.png"/>
- <p>I am quite happy with the result so far. I need to add real tests and
- a bit of documentation, and I will start to train my club friends on it.</p>
- <p>The next features I'd like to add are:</p>
- <ul class="simple">
- <li>comments management, to replace Isso (working on it now)</li>
- <li>smart Pelican builds. e.g. if a comment is added I don't want to rebuild the whole
- blog (~1500 articles)</li>
- <li>media management</li>
- <li>spell checker</li>
- </ul>
- <p>The project lives here: <a class="reference external" href="https://github.com/AcrDijon/henet">https://github.com/AcrDijon/henet</a></p>
- <p>I am not going to release it, but if someone finds it useful, I could.</p>
- <p>It's built with Bottle &amp; Bootstrap as well.</p>
- </div></div>
- </summary>
- <updated>2016-01-21T09:40:00Z</updated>
- <category term="python"/>
- <category term="mozilla"/>
- <author>
- <name>Tarek Ziade</name>
- </author>
- <source>
- <id>http://blog.ziade.org</id>
- <link href="http://blog.ziade.org" rel="alternate" type="text/html"/>
- <link href="http://blog.ziade.org/tag/mozilla/feed" rel="self" type="application/rss+xml"/>
- <subtitle>Tarek Ziadé</subtitle>
- <title>Fetchez le Python</title>
- <updated>2016-01-24T20:45:46Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://www.ncameron.org/blog/rss/631106eb-e7b1-47d5-82f9-cb6ad210ea89</id>
- <link href="http://www.ncameron.org/blog/closures-and-first-class-functions/" rel="alternate" type="text/html"/>
- <title>Closures and first-class functions</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I wrote a long and probably dull chapter on closures and first-class and higher-order functions in Rust. It goes into some detail on the implementation and some of the subtleties like higher-ranked lifetime bounds.</p>
-
- <p>I was going to post it here too, but it is really too long. Instead, pop</p></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I wrote a long and probably dull chapter on closures and first-class and higher-order functions in Rust. It goes into some detail on the implementation and some of the subtleties like higher-ranked lifetime bounds.</p>
-
- <p>I was going to post it here too, but it is really too long. Instead, pop over to the 'Rust for C++ programmers' repo and read it <a href="https://github.com/nrc/r4cppp/blob/master/closures.md">there</a>.</p></div>
- </content>
- <updated>2016-01-21T08:36:21Z</updated>
- <category term="Mozilla"/>
- <category term="Rust"/>
- <category term="rust-for-c"/>
- <author>
- <name>Nick Cameron</name>
- </author>
- <source>
- <id>http://www.ncameron.org/blog/</id>
- <link href="http://www.ncameron.org/blog/" rel="alternate" type="text/html"/>
- <link href="http://www.ncameron.org/blog/rss/" rel="self" type="application/rss+xml"/>
- <subtitle>I'm a research engineer at Mozilla working on Rust: the language, compiler, and tools. @nick_r_cameron</subtitle>
- <title>featherweight musings</title>
- <updated>2016-01-21T08:46:17Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://nickdesaulniers.github.io/blog/2016/01/20/debugging-x86-64-assembly-with-lldb-and-dtrace</id>
- <link href="http://nickdesaulniers.github.io/blog/2016/01/20/debugging-x86-64-assembly-with-lldb-and-dtrace/" rel="alternate" type="text/html"/>
- <title>Intro to Debugging x86-64 Assembly</title>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I’m hacking on an assembly project, and wanted to document some of the tricks I
- was using for figuring out what was going on. This post might seem a little
- basic for folks who spend all day heads down in gdb or who do this stuff
- professionally, but I just wanted to share a quick intro to some tools that
- others may find useful.
- (<a href="https://pchiusano.github.io/2014-10-11/defensive-writing.html">oh god, I’m doing it</a>)</p>
-
- <p>If your coming from gdb to lldb, there’s a few differences in commands. LLDB
- has
- <a href="http://lldb.llvm.org/lldb-gdb.html">great documentation</a>
- on some of the differences. Everything in this post about LLDB is pretty much
- there.</p>
-
- <p>The bread and butter commands when working with gdb or lldb are:</p>
-
- <ul>
- <li>r (run the program)</li>
- <li>s (step in)</li>
- <li>n (step over)</li>
- <li>finish (step out)</li>
- <li>c (continue)</li>
- <li>q (quit the program)</li>
- </ul>
-
-
- <p>You can hit enter if you want to run the last command again, which is really
- useful if you want to keep stepping over statements repeatedly.</p>
-
- <p>I’ve been using LLDB on OSX. Let’s say I want to debug a program I can build,
- but is crashing or something:</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="nv">$ </span>sudo lldb ./asmttpd web_root
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>Setting a breakpoint on jump to label:</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- <span class="line-number">2</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="o">(</span>lldb<span class="o">)</span> b sys_write
- </span><span class="line">Breakpoint 3: <span class="nv">where</span> <span class="o">=</span> asmttpd<span class="sb">`</span>sys_write, <span class="nv">address</span> <span class="o">=</span> 0x00000000000029ae
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>Running the program until breakpoint hit:</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- <span class="line-number">2</span>
- <span class="line-number">3</span>
- <span class="line-number">4</span>
- <span class="line-number">5</span>
- <span class="line-number">6</span>
- <span class="line-number">7</span>
- <span class="line-number">8</span>
- <span class="line-number">9</span>
- <span class="line-number">10</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="o">(</span>lldb<span class="o">)</span> r
- </span><span class="line">Process 32236 launched: <span class="s1">'./asmttpd'</span> <span class="o">(</span>x86_64<span class="o">)</span>
- </span><span class="line">Process 32236 stopped
- </span><span class="line">* thread <span class="c">#1: tid = 0xe69b9, 0x00000000000029ae asmttpd`sys_write, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1</span>
- </span><span class="line"> frame <span class="c">#0: 0x00000000000029ae asmttpd`sys_write</span>
- </span><span class="line">asmttpd<span class="sb">`</span>sys_write:
- </span><span class="line">-&gt; 0x29ae &lt;+0&gt;: pushq %rdi
- </span><span class="line"> 0x29af &lt;+1&gt;: pushq %rsi
- </span><span class="line"> 0x29b0 &lt;+2&gt;: pushq %rdx
- </span><span class="line"> 0x29b1 &lt;+3&gt;: pushq %r10
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>Seeing more of the current stack frame:</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- <span class="line-number">2</span>
- <span class="line-number">3</span>
- <span class="line-number">4</span>
- <span class="line-number">5</span>
- <span class="line-number">6</span>
- <span class="line-number">7</span>
- <span class="line-number">8</span>
- <span class="line-number">9</span>
- <span class="line-number">10</span>
- <span class="line-number">11</span>
- <span class="line-number">12</span>
- <span class="line-number">13</span>
- <span class="line-number">14</span>
- <span class="line-number">15</span>
- <span class="line-number">16</span>
- <span class="line-number">17</span>
- <span class="line-number">18</span>
- <span class="line-number">19</span>
- <span class="line-number">20</span>
- <span class="line-number">21</span>
- <span class="line-number">22</span>
- <span class="line-number">23</span>
- <span class="line-number">24</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="o">(</span>lldb<span class="o">)</span> d
- </span><span class="line">asmttpd<span class="sb">`</span>sys_write:
- </span><span class="line">-&gt; 0x29ae &lt;+0&gt;: pushq %rdi
- </span><span class="line"> 0x29af &lt;+1&gt;: pushq %rsi
- </span><span class="line"> 0x29b0 &lt;+2&gt;: pushq %rdx
- </span><span class="line"> 0x29b1 &lt;+3&gt;: pushq %r10
- </span><span class="line"> 0x29b3 &lt;+5&gt;: pushq %r8
- </span><span class="line"> 0x29b5 &lt;+7&gt;: pushq %r9
- </span><span class="line"> 0x29b7 &lt;+9&gt;: pushq %rbx
- </span><span class="line"> 0x29b8 &lt;+10&gt;: pushq %rcx
- </span><span class="line"> 0x29b9 &lt;+11&gt;: movq %rsi, %rdx
- </span><span class="line"> 0x29bc &lt;+14&gt;: movq %rdi, %rsi
- </span><span class="line"> 0x29bf &lt;+17&gt;: movq <span class="nv">$0x1</span>, %rdi
- </span><span class="line"> 0x29c6 &lt;+24&gt;: movq <span class="nv">$0x2000004</span>, %rax
- </span><span class="line"> 0x29cd &lt;+31&gt;: syscall
- </span><span class="line"> 0x29cf &lt;+33&gt;: popq %rcx
- </span><span class="line"> 0x29d0 &lt;+34&gt;: popq %rbx
- </span><span class="line"> 0x29d1 &lt;+35&gt;: popq %r9
- </span><span class="line"> 0x29d3 &lt;+37&gt;: popq %r8
- </span><span class="line"> 0x29 &lt;+39&gt;: popq %r10
- </span><span class="line"> 0x29d7 &lt;+41&gt;: popq %rdx
- </span><span class="line"> 0x29d8 &lt;+42&gt;: popq %rsi
- </span><span class="line"> 0x29d9 &lt;+43&gt;: popq %rdi
- </span><span class="line"> 0x29da &lt;+44&gt;: retq
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>Getting a back trace (call stack):</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- <span class="line-number">2</span>
- <span class="line-number">3</span>
- <span class="line-number">4</span>
- <span class="line-number">5</span>
- <span class="line-number">6</span>
- <span class="line-number">7</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="o">(</span>lldb<span class="o">)</span> bt
- </span><span class="line">* thread <span class="c">#1: tid = 0xe69b9, 0x00000000000029ae asmttpd`sys_write, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1</span>
- </span><span class="line"> * frame <span class="c">#0: 0x00000000000029ae asmttpd`sys_write</span>
- </span><span class="line"> frame <span class="c">#1: 0x00000000000021b6 asmttpd`print_line + 16</span>
- </span><span class="line"> frame <span class="c">#2: 0x0000000000002ab3 asmttpd`start + 35</span>
- </span><span class="line"> frame <span class="c">#3: 0x00007fff9900c5ad libdyld.dylib`start + 1</span>
- </span><span class="line"> frame <span class="c">#4: 0x00007fff9900c5ad libdyld.dylib`start + 1</span>
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>peeking at the upper stack frame:</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- <span class="line-number">2</span>
- <span class="line-number">3</span>
- <span class="line-number">4</span>
- <span class="line-number">5</span>
- <span class="line-number">6</span>
- <span class="line-number">7</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="o">(</span>lldb<span class="o">)</span> up
- </span><span class="line">frame <span class="c">#1: 0x00000000000021b6 asmttpd`print_line + 16</span>
- </span><span class="line">asmttpd<span class="sb">`</span>print_line:
- </span><span class="line"> 0x21b6 &lt;+16&gt;: movabsq <span class="nv">$0x30cb</span>, %rdi
- </span><span class="line"> 0x21c0 &lt;+26&gt;: movq <span class="nv">$0x1</span>, %rsi
- </span><span class="line"> 0x21c7 &lt;+33&gt;: callq 0x29ae ; sys_write
- </span><span class="line"> 0x21cc &lt;+38&gt;: popq %rcx
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>back down to the breakpoint-halted stack frame:</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- <span class="line-number">2</span>
- <span class="line-number">3</span>
- <span class="line-number">4</span>
- <span class="line-number">5</span>
- <span class="line-number">6</span>
- <span class="line-number">7</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="o">(</span>lldb<span class="o">)</span> down
- </span><span class="line">frame <span class="c">#0: 0x00000000000029ae asmttpd`sys_write</span>
- </span><span class="line">asmttpd<span class="sb">`</span>sys_write:
- </span><span class="line">-&gt; 0x29ae &lt;+0&gt;: pushq %rdi
- </span><span class="line"> 0x29af &lt;+1&gt;: pushq %rsi
- </span><span class="line"> 0x29b0 &lt;+2&gt;: pushq %rdx
- </span><span class="line"> 0x29b1 &lt;+3&gt;: pushq %r10
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>dumping the values of registers:</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- <span class="line-number">2</span>
- <span class="line-number">3</span>
- <span class="line-number">4</span>
- <span class="line-number">5</span>
- <span class="line-number">6</span>
- <span class="line-number">7</span>
- <span class="line-number">8</span>
- <span class="line-number">9</span>
- <span class="line-number">10</span>
- <span class="line-number">11</span>
- <span class="line-number">12</span>
- <span class="line-number">13</span>
- <span class="line-number">14</span>
- <span class="line-number">15</span>
- <span class="line-number">16</span>
- <span class="line-number">17</span>
- <span class="line-number">18</span>
- <span class="line-number">19</span>
- <span class="line-number">20</span>
- <span class="line-number">21</span>
- <span class="line-number">22</span>
- <span class="line-number">23</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="o">(</span>lldb<span class="o">)</span> register <span class="nb">read</span>
- </span><span class="line">General Purpose Registers:
- </span><span class="line"> <span class="nv">rax</span> <span class="o">=</span> 0x0000000000002a90 asmttpd<span class="sb">`</span>start
- </span><span class="line"> <span class="nv">rbx</span> <span class="o">=</span> 0x0000000000000000
- </span><span class="line"> <span class="nv">rcx</span> <span class="o">=</span> 0x00007fff5fbffaf8
- </span><span class="line"> <span class="nv">rdx</span> <span class="o">=</span> 0x00007fff5fbffa40
- </span><span class="line"> <span class="nv">rdi</span> <span class="o">=</span> 0x00000000000030cc start_text
- </span><span class="line"> <span class="nv">rsi</span> <span class="o">=</span> 0x000000000000000f
- </span><span class="line"> <span class="nv">rbp</span> <span class="o">=</span> 0x00007fff5fbffa18
- </span><span class="line"> <span class="nv">rsp</span> <span class="o">=</span> 0x00007fff5fbff9b8
- </span><span class="line"> <span class="nv">r8</span> <span class="o">=</span> 0x0000000000000000
- </span><span class="line"> <span class="nv">r9</span> <span class="o">=</span> 0x00007fff7b1670c8 atexit_mutex + 24
- </span><span class="line"> <span class="nv">r10</span> <span class="o">=</span> 0x00000000ffffffff
- </span><span class="line"> <span class="nv">r11</span> <span class="o">=</span> 0xffffffff00000000
- </span><span class="line"> <span class="nv">r12</span> <span class="o">=</span> 0x0000000000000000
- </span><span class="line"> <span class="nv">r13</span> <span class="o">=</span> 0x0000000000000000
- </span><span class="line"> <span class="nv">r14</span> <span class="o">=</span> 0x0000000000000000
- </span><span class="line"> <span class="nv">r15</span> <span class="o">=</span> 0x0000000000000000
- </span><span class="line"> <span class="nv">rip</span> <span class="o">=</span> 0x00000000000029ae asmttpd<span class="sb">`</span>sys_write
- </span><span class="line"> <span class="nv">rflags</span> <span class="o">=</span> 0x0000000000000246
- </span><span class="line"> <span class="nv">cs</span> <span class="o">=</span> 0x000000000000002b
- </span><span class="line"> <span class="nv">fs</span> <span class="o">=</span> 0x0000000000000000
- </span><span class="line"> <span class="nv">gs</span> <span class="o">=</span> 0x0000000000000000
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>read just one register:</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- <span class="line-number">2</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="o">(</span>lldb<span class="o">)</span> register <span class="nb">read </span>rdi
- </span><span class="line"> <span class="nv">rdi</span> <span class="o">=</span> 0x00000000000030cc start_text
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>When you’re trying to figure out what system calls are made by some C code,
- using dtruss is very helpful. dtruss is available on OSX and seems to be some
- kind of wrapper around DTrace.</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- <span class="line-number">2</span>
- <span class="line-number">3</span>
- <span class="line-number">4</span>
- <span class="line-number">5</span>
- <span class="line-number">6</span>
- <span class="line-number">7</span>
- <span class="line-number">8</span>
- <span class="line-number">9</span>
- <span class="line-number">10</span>
- <span class="line-number">11</span>
- <span class="line-number">12</span>
- <span class="line-number">13</span>
- <span class="line-number">14</span>
- <span class="line-number">15</span>
- <span class="line-number">16</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="nv">$ </span>cat sleep.c
- </span><span class="line"><span class="c">#include &lt;time.h&gt;</span>
- </span><span class="line">int main <span class="o">()</span> <span class="o">{</span>
- </span><span class="line"> struct timespec <span class="nv">rqtp</span> <span class="o">=</span> <span class="o">{</span>
- </span><span class="line"> 2,
- </span><span class="line"> 0
- </span><span class="line"> <span class="o">}</span>;
- </span><span class="line">
- </span><span class="line"> nanosleep<span class="o">(</span>&amp;rqtp, NULL<span class="o">)</span>;
- </span><span class="line"><span class="o">}</span>
- </span><span class="line">
- </span><span class="line"><span class="nv">$ </span>clang sleep.c
- </span><span class="line">
- </span><span class="line"><span class="nv">$ </span>sudo dtruss ./a.out
- </span><span class="line">...all kinds of fun stuff
- </span><span class="line">__semwait_signal<span class="o">(</span>0xB03, 0x0, 0x1<span class="o">)</span> <span class="o">=</span> -1 Err#60
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>If you compile with <code>-g</code> to emit debug symbols, you can use lldb’s disassemble
- command to get the equivalent assembly:</p>
-
- <figure class="code"><span/><div class="highlight"><table><tbody><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
- <span class="line-number">2</span>
- <span class="line-number">3</span>
- <span class="line-number">4</span>
- <span class="line-number">5</span>
- <span class="line-number">6</span>
- <span class="line-number">7</span>
- <span class="line-number">8</span>
- <span class="line-number">9</span>
- <span class="line-number">10</span>
- <span class="line-number">11</span>
- <span class="line-number">12</span>
- <span class="line-number">13</span>
- <span class="line-number">14</span>
- <span class="line-number">15</span>
- <span class="line-number">16</span>
- <span class="line-number">17</span>
- <span class="line-number">18</span>
- <span class="line-number">19</span>
- <span class="line-number">20</span>
- <span class="line-number">21</span>
- <span class="line-number">22</span>
- <span class="line-number">23</span>
- <span class="line-number">24</span>
- <span class="line-number">25</span>
- <span class="line-number">26</span>
- <span class="line-number">27</span>
- <span class="line-number">28</span>
- <span class="line-number">29</span>
- <span class="line-number">30</span>
- <span class="line-number">31</span>
- <span class="line-number">32</span>
- <span class="line-number">33</span>
- <span class="line-number">34</span>
- <span class="line-number">35</span>
- <span class="line-number">36</span>
- <span class="line-number">37</span>
- </pre></td><td class="code"><pre><code class="sh"><span class="line"><span class="nv">$ </span>clang sleep.c -g
- </span><span class="line"><span class="nv">$ </span>lldb a.out
- </span><span class="line"><span class="o">(</span>lldb<span class="o">)</span> target create <span class="s2">"a.out"</span>
- </span><span class="line">Current executable <span class="nb">set </span>to <span class="s1">'a.out'</span> <span class="o">(</span>x86_64<span class="o">)</span>.
- </span><span class="line"><span class="o">(</span>lldb<span class="o">)</span> b main
- </span><span class="line">Breakpoint 1: <span class="nv">where</span> <span class="o">=</span> a.out<span class="sb">`</span>main + 16 at sleep.c:3, <span class="nv">address</span> <span class="o">=</span> 0x0000000100000f40
- </span><span class="line"><span class="o">(</span>lldb<span class="o">)</span> r
- </span><span class="line">Process 33213 launched: <span class="s1">'/Users/Nicholas/code/assembly/asmttpd/a.out'</span> <span class="o">(</span>x86_64<span class="o">)</span>
- </span><span class="line">Process 33213 stopped
- </span><span class="line">* thread <span class="c">#1: tid = 0xeca04, 0x0000000100000f40 a.out`main + 16 at sleep.c:3, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1</span>
- </span><span class="line"> frame <span class="c">#0: 0x0000000100000f40 a.out`main + 16 at sleep.c:3</span>
- </span><span class="line"> 1 <span class="c">#include &lt;time.h&gt;</span>
- </span><span class="line"> 2 int main <span class="o">()</span> <span class="o">{</span>
- </span><span class="line">-&gt; 3 struct timespec <span class="nv">rqtp</span> <span class="o">=</span> <span class="o">{</span>
- </span><span class="line"> 4 2,
- </span><span class="line"> 5 0
- </span><span class="line"> 6 <span class="o">}</span>;
- </span><span class="line"> 7
- </span><span class="line"><span class="o">(</span>lldb<span class="o">)</span> disassemble
- </span><span class="line">a.out<span class="sb">`</span>main:
- </span><span class="line"> 0x100000f30 &lt;+0&gt;: pushq %rbp
- </span><span class="line"> 0x100000f31 &lt;+1&gt;: movq %rsp, %rbp
- </span><span class="line"> 0x100000f34 &lt;+4&gt;: subq <span class="nv">$0x20</span>, %rsp
- </span><span class="line"> 0x100000f38 &lt;+8&gt;: leaq -0x10<span class="o">(</span>%rbp<span class="o">)</span>, %rdi
- </span><span class="line"> 0x100000f3c &lt;+12&gt;: xorl %eax, %eax
- </span><span class="line"> 0x100000f3e &lt;+14&gt;: movl %eax, %esi
- </span><span class="line">-&gt; 0x100000f40 &lt;+16&gt;: movq 0x49<span class="o">(</span>%rip<span class="o">)</span>, %rcx
- </span><span class="line"> 0x100000f47 &lt;+23&gt;: movq %rcx, -0x10<span class="o">(</span>%rbp<span class="o">)</span>
- </span><span class="line"> 0x100000f4b &lt;+27&gt;: movq 0x46<span class="o">(</span>%rip<span class="o">)</span>, %rcx
- </span><span class="line"> 0x100000f52 &lt;+34&gt;: movq %rcx, -0x8<span class="o">(</span>%rbp<span class="o">)</span>
- </span><span class="line"> 0x100000f56 &lt;+38&gt;: callq 0x100000f68 ; symbol stub <span class="k">for</span>: nanosleep
- </span><span class="line"> 0x100000f5b &lt;+43&gt;: xorl %edx, %edx
- </span><span class="line"> 0x100000f5d &lt;+45&gt;: movl %eax, -0x14<span class="o">(</span>%rbp<span class="o">)</span>
- </span><span class="line"> 0x100000f60 &lt;+48&gt;: movl %edx, %eax
- </span><span class="line"> 0x100000f62 &lt;+50&gt;: addq <span class="nv">$0x20</span>, %rsp
- </span><span class="line"> 0x100000f66 &lt;+54&gt;: popq %rbp
- </span><span class="line"> 0x100000f67 &lt;+55&gt;: retq
- </span></code></pre></td></tr></tbody></table></div></figure>
-
-
- <p>Anyways, I’ve been learning some interesting things about OSX that I’ll be
- sharing soon. If you’d like to learn more about x86-64 assembly programming,
- you should read my other posts about
- <a href="http://nickdesaulniers.github.io/blog/2014/04/18/lets-write-some-x86-64/">writing x86-64</a>
- and a toy
- <a href="http://nickdesaulniers.github.io/blog/2015/05/25/interpreter-compiler-jit/">JIT for Brainfuck</a>
- (<a href="https://www.reddit.com/r/programming/comments/377ov9/interpreter_compiler_jit/crkkrz4">the creator of Brainfuck liked it</a>).</p>
-
- <p>I should also do a post on
- <a href="http://rr-project.org/">Mozilla’s rr</a>,
- because it can do amazing things like step backwards. Another day…</p></div>
- </content>
- <updated>2016-01-21T04:04:00Z</updated>
- <source>
- <id>http://nickdesaulniers.github.io/</id>
- <author>
- <name>Nick Desaulniers</name>
- </author>
- <link href="http://nickdesaulniers.github.io/atom.xml" rel="self" type="application/atom+xml"/>
- <link href="http://nickdesaulniers.github.io/" rel="alternate" type="text/html"/>
- <title>Nick Desaulniers</title>
- <updated>2016-01-21T05:07:32Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en">
- <id>https://rail.merail.ca/posts/rebooting-productivity.html</id>
- <link href="https://rail.merail.ca/posts/rebooting-productivity.html" rel="alternate" type="text/html"/>
- <title>Rebooting productivity</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div><p>Every new year gives you an opportunity to sit back, relax,
- <span class="strike">have some scotch</span> and re-think the passed year. Holidays give
- you enough free time. Even if you decide to not take a vacation around
- the holidays, it's usually calm and peaceful.</p>
- <p>This time, I found myself thinking mostly about productivity, being
- effective, feeling busy, overwhelmed with work and other related topics.</p>
- <p>When I started at Mozilla (almost 6 years ago!), I tried to apply all my
- GTD and time management knowledge and techniques. Working remotely and
- in a different time zone was an advantage - I had close to zero
- interruptions. It worked perfect.</p>
- <p>Last year I realized that my productivity skills had faded away somehow.
- 40h+ workweeks, working on weekends, delivering goals in the last week
- of quarter don't sound like good signs. Instead of being productive I
- felt busy.</p>
- <p>"Every crisis is an opportunity". Time to make a step back and reboot
- myself. Burning out at work is not a good idea. :)</p>
- <p>Here are some ideas/tips that I wrote down for myself you may found
- useful.</p>
- <div class="section" id="health-related">
- <h3>Health related</h3>
- <ul class="simple">
- <li>Morning exercises. A 20-minute walk will wake your brain up and
- generate enough endorphins for the first half of the day.</li>
- <li>Meditation. 2x20min a day is ideal; 2x10min would work too. Something
- like <a class="reference external" href="http://www.calm.com/">calm.com</a> makes this a peace of cake.</li>
- </ul>
- </div>
- <div class="section" id="concentration">
- <h3>Concentration</h3>
- <ul class="simple">
- <li>Task #1: make a daily plan. No plan - no work.</li>
- <li>Don't start your day by reading emails. Get one (little) thing done
- first - THEN check your email.</li>
- <li>Try to define outcomes, not tasks. "Ship XYZ" instead of "Work on XYZ".</li>
- <li>Meetings are time consuming, so "Set a goal for each meeting".
- Consider skipping a meeting if you don't have any goal set, unless it's a
- beer-and-tell meeting! :)</li>
- <li>Constantly ask yourself if what you're working on is important.</li>
- <li>3-4 times a day ask yourself whether you are doing something towards
- your goal or just finding something else to keep you busy. If you want
- to look busy, take your phone and walk around the office with some
- papers in your hand. Everybody will think that you are a busy person!
- This way you can take a break and look busy at the same time!</li>
- <li>Take breaks! <a class="reference external" href="https://en.wikipedia.org/wiki/Pomodoro_Technique">Pomodoro technique</a> has this option
- built-in. Taking breaks helps not only to avoid <a class="reference external" href="https://en.wikipedia.org/wiki/Repetitive_strain_injury">RSI</a>, but also
- keeps your brain sane and gives you time to ask yourself the questions
- mentioned above. I use <a class="reference external" href="http://www.workrave.org/">Workrave</a> on my
- laptop, but you can use a real kitchen timer instead.</li>
- <li>Wear headphones, especially at office. Noise cancelling ones are even
- better. White noise, nature sounds, or instrumental music are your
- friends.</li>
- </ul>
- </div>
- <div class="section" id="home-office">
- <h3>(Home) Office</h3>
- <ul class="simple">
- <li>Make sure you enjoy your work environment. Why on the earth would you
- spend your valuable time working without joy?!</li>
- <li>De-clutter and organize your desk. Less things around - less
- distractions.</li>
- <li>Desk, chair, monitor, keyboard, mouse, etc - don't cheap out on them.
- Your health is more important and expensive. Thanks to <a class="reference external" href="https://twitter.com/mhoye">mhoye</a> for this advice!</li>
- </ul>
- </div>
- <div class="section" id="other">
- <h3>Other</h3>
- <ul class="simple">
- <li>Don't check email every 30 seconds. If there is an emergency, they
- will call you! :)</li>
- <li>Reward yourself at a certain time. "I'm going to have a chocolate at
- 11am", or "MFBT at 4pm sharp!" are good examples. Don't forget, you
- are <a class="reference external" href="https://en.wikipedia.org/wiki/Classical_conditioning">Pavlov's dog</a> too!</li>
- <li>Don't try to read everything NOW. Save it for later and read in a
- batch.</li>
- <li>Capture all creative ideas. You can delete them later. ;)</li>
- <li>Prepare for next task before break. Make sure you know what's next, so
- you can think about it during the break.</li>
- </ul>
- <p>This is my list of things that I try to use everyday. Looking forward to
- see improvements!</p>
- <p>I would appreciate your thoughts this topic. Feel free to comment or
- send a private email.</p>
- <p>Happy Productive New Year!</p>
- </div></div></div>
- </summary>
- <updated>2016-01-21T02:06:37Z</updated>
- <category term="mozilla"/>
- <category term="productivity"/>
- <author>
- <name>Rail Aliiev</name>
- </author>
- <source>
- <id>https://rail.merail.ca/</id>
- <link href="https://rail.merail.ca/" rel="alternate" type="text/html"/>
- <link href="https://rail.merail.ca/categories/mozilla.xml" rel="self" type="application/rss+xml"/>
- <title>Rail's Blog (mozilla)</title>
- <updated>2016-01-21T02:31:38Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://blog.rust-lang.org/2016/01/21/Rust-1.6.html</id>
- <link href="http://blog.rust-lang.org/2016/01/21/Rust-1.6.html" rel="alternate" type="text/html"/>
- <title>Announcing Rust 1.6</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Hello 2016! We’re happy to announce the first Rust release of the year, 1.6.
- Rust is a systems programming language focused on safety, speed, and
- concurrency.</p>
-
- <p>As always, you can <a href="http://www.rust-lang.org/install.html">install Rust 1.6</a> from the appropriate page on our
- website, and check out the <a href="https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-160-2016-01-21">detailed release notes for 1.6</a> on GitHub.
- About 1100 patches were landed in this release.</p>
-
- <h3 id="what-39-s-in-1-6-stable">What’s in 1.6 stable</h3>
-
- <p>This release contains a number of small refinements, one major feature, and
- a change to <a href="https://crates.io">Crates.io</a>.</p>
-
- <h4 id="libcore-stabilization">libcore stabilization</h4>
-
- <p>The largest new feature in 1.6 is that <a href="http://doc.rust-lang.org/nightly/core/"><code>libcore</code></a> is now stable! Rust’s
- standard library is two-tiered: there’s a small core library, <code>libcore</code>, and
- the full standard library, <code>libstd</code>, that builds on top of it. <code>libcore</code> is
- completely platform agnostic, and requires only a handful of external symbols
- to be defined. Rust’s <code>libstd</code> builds on top of <code>libcore</code>, adding support for
- memory allocation, I/O, and concurrency. Applications using Rust in the
- embedded space, as well as those writing operating systems, often eschew
- <code>libstd</code>, using only <code>libcore</code>.</p>
-
- <p><code>libcore</code> being stabilized is a major step towards being able to write the
- lowest levels of software using stable Rust. There’s still future work to be
- done, however. This will allow for a library ecosystem to develop around
- <code>libcore</code>, but <em>applications</em> are not fully supported yet. Expect to hear more
- about this in future release notes.</p>
-
- <h4 id="library-stabilizations">Library stabilizations</h4>
-
- <p>About 30 library functions and methods are now stable in 1.6. Notable
- improvements include:</p>
-
- <p>The <code>drain()</code> family of functions on collections. These methods let you move
- elements out of a collection while allowing them to retain their backing
- memory, reducing allocation in certain situations.</p>
-
- <p>A number of implementations of <code>From</code> for converting between standard library
- types, mainly between various integral and floating-point types.</p>
-
- <p>Finally, <code>Vec::extend_from_slice()</code>, which was previously known as
- <code>push_all()</code>. This method has a significantly faster implementation than the
- more general <code>extend()</code>.</p>
-
- <p>See the <a href="https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-160-2016-01-21">detailed release notes</a> for more.</p>
-
- <h4 id="crates-io-disallows-wildcards">Crates.io disallows wildcards</h4>
-
- <p>If you maintain a crate on <a href="https://crates.io">Crates.io</a>, you might have seen
- a warning: newly uploaded crates are no longer allowed to use a wildcard when
- describing their dependencies. In other words, this is not allowed:</p>
- <div class="highlight"><pre><code class="language-toml"><span class="p">[</span><span class="n">dependencies</span><span class="p">]</span>
- <span class="n">regex</span> <span class="o">=</span> <span class="s">"*"</span>
- </code></pre></div>
- <p>Instead, you must actually specify <a href="http://doc.crates.io/crates-io.html#using-cratesio-based-crates">a specific version or range of
- versions</a>, using one of the <code>semver</code> crate’s various options: <code>^</code>,
- <code>~</code>, or <code>=</code>.</p>
-
- <p>A wildcard dependency means that you work with any possible version of your
- dependency. This is highly unlikely to be true, and causes unnecessary breakage
- in the ecosystem. We’ve been advertising this change as a warning for some time;
- now it’s time to turn it into an error.</p>
-
- <h3 id="contributors-to-1-6">Contributors to 1.6</h3>
-
- <p>We had 132 individuals contribute to 1.6. Thank you so much!</p>
-
- <ul>
- <li>Aaron Turon</li>
- <li>Adam Badawy</li>
- <li>Aleksey Kladov</li>
- <li>Alexander Bulaev</li>
- <li>Alex Burka</li>
- <li>Alex Crichton</li>
- <li>Alex Gaynor</li>
- <li>Alexis Beingessner</li>
- <li>Amanieu d'Antras</li>
- <li>Amit Saha</li>
- <li>Andrea Canciani</li>
- <li>Andrew Paseltiner</li>
- <li>androm3da</li>
- <li>angelsl</li>
- <li>Angus Lees</li>
- <li>Antti Keränen</li>
- <li>arcnmx</li>
- <li>Ariel Ben-Yehuda</li>
- <li>Ashkan Kiani</li>
- <li>Barosl Lee</li>
- <li>Benjamin Herr</li>
- <li>Ben Striegel</li>
- <li>Bhargav Patel</li>
- <li>Björn Steinbrink</li>
- <li>Boris Egorov</li>
- <li>bors</li>
- <li>Brian Anderson</li>
- <li>Bruno Tavares</li>
- <li>Bryce Van Dyk</li>
- <li>Cameron Sun</li>
- <li>Christopher Sumnicht</li>
- <li>Cole Reynolds</li>
- <li>corentih</li>
- <li>Daniel Campbell</li>
- <li>Daniel Keep</li>
- <li>Daniel Rollins</li>
- <li>Daniel Trebbien</li>
- <li>Danilo Bargen</li>
- <li>Devon Hollowood</li>
- <li>Doug Goldstein</li>
- <li>Dylan McKay</li>
- <li>ebadf</li>
- <li>Eli Friedman</li>
- <li>Eric Findlay</li>
- <li>Erik Davidson</li>
- <li>Felix S. Klock II</li>
- <li>Florian Hahn</li>
- <li>Florian Hartwig</li>
- <li>Gleb Kozyrev</li>
- <li>Guillaume Gomez</li>
- <li>Huon Wilson</li>
- <li>Igor Shuvalov</li>
- <li>Ivan Ivaschenko</li>
- <li>Ivan Kozik</li>
- <li>Ivan Stankovic</li>
- <li>Jack Fransham</li>
- <li>Jake Goulding</li>
- <li>Jake Worth</li>
- <li>James Miller</li>
- <li>Jan Likar</li>
- <li>Jean Maillard</li>
- <li>Jeffrey Seyfried</li>
- <li>Jethro Beekman</li>
- <li>John KÃ¥re Alsaker</li>
- <li>John Talling</li>
- <li>Jonas Schievink</li>
- <li>Jonathan S</li>
- <li>Jose Narvaez</li>
- <li>Josh Austin</li>
- <li>Josh Stone</li>
- <li>Joshua Holmer</li>
- <li>JP Sugarbroad</li>
- <li>jrburke</li>
- <li>Kevin Butler</li>
- <li>Kevin Yeh</li>
- <li>Kohei Hasegawa</li>
- <li>Kyle Mayes</li>
- <li>Lee Jeffery</li>
- <li>Manish Goregaokar</li>
- <li>Marcell Pardavi</li>
- <li>Markus Unterwaditzer</li>
- <li>Martin Pool</li>
- <li>Marvin Löbel</li>
- <li>Matt Brubeck</li>
- <li>Matthias Bussonnier</li>
- <li>Matthias Kauer</li>
- <li>mdinger</li>
- <li>Michael Layzell</li>
- <li>Michael Neumann</li>
- <li>Michael Sproul</li>
- <li>Michael Woerister</li>
- <li>Mihaly Barasz</li>
- <li>Mika Attila</li>
- <li>mitaa</li>
- <li>Ms2ger</li>
- <li>Nicholas Mazzuca</li>
- <li>Nick Cameron</li>
- <li>Niko Matsakis</li>
- <li>Ole Krüger</li>
- <li>Oliver Middleton</li>
- <li>Oliver Schneider</li>
- <li>Ori Avtalion</li>
- <li>Paul A. Jungwirth</li>
- <li>Peter Atashian</li>
- <li>Philipp Matthias Schäfer</li>
- <li>pierzchalski</li>
- <li>Ravi Shankar</li>
- <li>Ricardo Martins</li>
- <li>Ricardo Signes</li>
- <li>Richard Diamond</li>
- <li>Rizky Luthfianto</li>
- <li>Ryan Scheel</li>
- <li>Scott Olson</li>
- <li>Sean Griffin</li>
- <li>Sebastian Hahn</li>
- <li>Sébastien Marie</li>
- <li>Seo Sanghyeon</li>
- <li>Simonas Kazlauskas</li>
- <li>Simon Sapin</li>
- <li>Stepan Koltsov</li>
- <li>Steve Klabnik</li>
- <li>Steven Fackler</li>
- <li>Tamir Duberstein</li>
- <li>Tobias Bucher</li>
- <li>Toby Scrace</li>
- <li>Tshepang Lekhonkhobe</li>
- <li>Ulrik Sverdrup</li>
- <li>Vadim Chugunov</li>
- <li>Vadim Petrochenkov</li>
- <li>William Throwe</li>
- <li>xd1le</li>
- <li>Xmasreturns</li>
- </ul></div>
- </summary>
- <updated>2016-01-21T00:00:00Z</updated>
- <source>
- <id>http://blog.rust-lang.org/</id>
- <author>
- <name>The Rust Programming Language Blog</name>
- </author>
- <link href="http://blog.rust-lang.org/" rel="alternate" type="text/html"/>
- <link href="http://blog.rust-lang.org/feed.xml" rel="self" type="application/rss+xml"/>
- <subtitle>Words from the Rust team</subtitle>
- <title>The Rust Programming Language Blog</title>
- <updated>2016-01-21T21:36:56Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://blog.mozilla.org/addons/?p=7644</id>
- <link href="https://blog.mozilla.org/addons/2016/01/20/archiving-amo-stats/" rel="alternate" type="text/html"/>
- <title>Archiving AMO Stats</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">One of the advantages of listing an add-on or theme on addons.mozilla.org (AMO) is that you’ll get statistics on your add-on’s usage. These stats, which are covered by the Mozilla privacy policy, provide add-on developers with information such as the … <a class="go" href="https://blog.mozilla.org/addons/2016/01/20/archiving-amo-stats/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>One of the advantages of listing an add-on or theme on <a href="https://addons.mozilla.org" target="_blank">addons.mozilla.org</a> (AMO) is that you’ll get statistics on your add-on’s usage. These stats, which are covered by the <a href="https://www.mozilla.org/privacy/" target="_blank">Mozilla privacy policy</a>, provide add-on developers with information such as the number of downloads and daily users, among other insights.</p>
- <p>Currently, the data that generates these statistics can go back as far as 2007, as we haven’t had an archiving policy. As a result, statistics take up the vast majority of disk space in our database and require a significant amount of processing and operations time. Statistics over a year old are very rarely accessed, and the value of their generation is very low, while the costs are increasing.</p>
- <p>To reduce our operating and development costs, and increase the site’s reliability for developers, we are introducing an archiving policy.</p>
- <p>In the coming weeks, statistics data <strong>over one year old</strong> will no longer be stored in the AMO database, and reports generated from them will no longer be accessible through AMO’s add-on statistics pages. Instead, the data will be archived and maintained as plain text files, which developers can download. We will write a follow-up post when these archives become available.</p>
- <p>If you’ve chosen to keep your add-on’s statistics private, they will remain private when stats are archived. You can check your privacy settings by going to your add-on in the <a href="https://addons.mozilla.org/developers/addons" target="_blank">Developer Hub</a>, clicking on <strong>Edit Listing</strong>, and then <strong>Technical Details</strong>.</p>
- <p><a href="https://blog.mozilla.org/addons/files/2016/01/Screenshot-2016-01-20-14.52.33.png"><img alt="editlisting" class="alignnone size-large wp-image-7645" height="389" src="https://blog.mozilla.org/addons/files/2016/01/Screenshot-2016-01-20-14.52.33-600x389.png" width="600"/></a></p>
- <p>The total number of users and other cumulative counts on add-ons and themes will not be affected and these will continue to function.</p>
- <p>If you have feedback or concerns, please head to our <a href="https://discourse.mozilla-community.org/t/archiving-of-add-on-statistics/6573" target="_blank">forum post</a> on this topic.</p></div>
- </content>
- <updated>2016-01-20T23:54:09Z</updated>
- <category term="developers"/>
- <category term="policy"/>
- <author>
- <name>Andy McKay</name>
- </author>
- <source>
- <id>https://blog.mozilla.org/addons</id>
- <link href="https://blog.mozilla.org/addons/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://blog.mozilla.org/addons" rel="alternate" type="text/html"/>
- <title>Mozilla Add-ons Blog</title>
- <updated>2016-01-25T20:46:40Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://air.mozilla.org/the-joy-of-coding-episode-41/</id>
- <link href="https://air.mozilla.org/the-joy-of-coding-episode-41/" rel="alternate" type="text/html"/>
- <title>The Joy of Coding - Episode 41</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
- <img alt="The Joy of Coding - Episode 41" class="wp-post-image" height="90" src="https://air.cdn.mozilla.net/media/cache/cb/68/cb68b6ac48452be7e7f25ddc7b63c959.png" width="160"/>
- mconley livehacks on real Firefox bugs while thinking aloud.
- </p></div>
- </summary>
- <updated>2016-01-20T18:00:00Z</updated>
- <author>
- <name>Air Mozilla</name>
- </author>
- <source>
- <id>https://air.mozilla.org/</id>
- <link href="https://air.mozilla.org/" rel="alternate" type="text/html"/>
- <link href="https://air.mozilla.org/" rel="self" type="application/rss+xml"/>
- <rights>Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.</rights>
- <subtitle>Air Mozilla is the Internet multimedia presence of Mozilla, with live and pre-recorded shows, interviews, news snippets, tutorial videos, and features about the Mozilla community.</subtitle>
- <title>Air Mozilla</title>
- <updated>2016-01-25T20:31:50Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://blog.mozilla.org/nfroyd/?p=452</id>
- <link href="https://blog.mozilla.org/nfroyd/2016/01/20/gecko-and-c-onboarding-presentation/" rel="alternate" type="text/html"/>
- <title>gecko and c++ onboarding presentation</title>
- <summary>One of the things the Firefox team has been doing recently is having onboarding sessions for new hires. This onboarding currently covers: 1st day setup Bugzilla Building Firefox Desktop Firefox Architecture / Product Communication and Community Javascript and the DOM C++ and Gecko Shipping Software Telemetry Org structure and career development My first day consisted […]</summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>One of the things the Firefox team has been doing recently is having onboarding sessions for new hires. This onboarding currently covers:</p>
- <ul>
- <li>1st day setup</li>
- <li>Bugzilla</li>
- <li>Building Firefox</li>
- <li>Desktop Firefox Architecture / Product</li>
- <li>Communication and Community</li>
- <li>Javascript and the DOM</li>
- <li>C++ and Gecko</li>
- <li>Shipping Software</li>
- <li>Telemetry</li>
- <li>Org structure and career development</li>
- </ul>
- <p>My first day consisted of some useful HR presentations and then I was given my laptop and a pointer to a wiki page on building Firefox. Needless to say, it took me a while to get started! It would have been super convenient to have an introduction to all the stuff above.</p>
- <p>I’ve been asked to do the C++ and Gecko session three times. All of the sessions are open to whoever wants to come, not just the new hires, and I think yesterday’s session was easily the most well-attended yet: somewhere between 10 and 20 people showed up. Yesterday’s session was the first session where I made the slides available to attendees (should have been doing that from the start…) and it seemed equally useful to make the slides available to a broader audience as well. The <a href="https://docs.google.com/presentation/d/1ZHUkNzZK2TrF5_4MWd_lqEq7Ph5B6CDbNsizIkBxbnQ/edit?usp=sharing">Gecko and C++ Onboarding slides</a> are up now!</p>
- <p>This presentation is a “living†presentation; it will get updated for future sessions with feedback and as I think of things that should have been in the presentation or better ways to set things up (some diagrams would be nice…). If you have feedback (good, bad, or ugly) on particular things in the slides or you have suggestions on what other things should be covered, please contact me! Next time I do this I’ll try to record the presentation so folks can watch that if they prefer.</p></div>
- </content>
- <updated>2016-01-20T16:48:29Z</updated>
- <category term="Uncategorized"/>
- <category term="c++"/>
- <category term="mozilla"/>
- <category term="onboarding"/>
- <category term="presentations"/>
- <author>
- <name>Nathan Froyd</name>
- </author>
- <source>
- <id>https://blog.mozilla.org/nfroyd</id>
- <link href="https://blog.mozilla.org/nfroyd/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://blog.mozilla.org/nfroyd" rel="alternate" type="text/html"/>
- <subtitle>writing code to help other people write code</subtitle>
- <title>Nathan's Blog</title>
- <updated>2016-01-20T17:01:01Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en">
- <id>http://andreasgal.com/?p=573</id>
- <link href="http://andreasgal.com/2016/01/20/brendan-is-back-to-save-the-web/" rel="alternate" type="text/html"/>
- <title>Brendan is back to save the Web</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Brendan is back, and he has a plan to save the Web. Its a big and bold plan, and it may just work. I am pretty excited about this. If you have 5 minutes to read along I’ll explain why I think you should be as well. The Web is broken Lets face it, the Web […]<img alt="" border="0" height="1" src="http://pixel.wp.com/b.gif?host=andreasgal.com&amp;blog=891661&amp;post=573&amp;subd=andreasgal&amp;ref=&amp;feed=1" width="1"/></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p class="p1">Brendan is <a href="https://github.com/brave">back</a>, and he has a <a href="http://brave.com/">plan</a> to save the Web. Its a big and bold plan, and it may just work. I am pretty excited about this. If you have 5 minutes to read along I’ll explain why I think you should be as well.</p>
- <p class="p1"><strong>The Web is broken</strong></p>
- <p class="p1">Lets face it, the Web today is a mess. Everywhere we go online we are constantly inundated with annoying ads. Often pages are more ads than content, and the more ads the industry throws at us, the more we ignore them, the more obnoxious ads get, trying to catch our attention. As Brendan explains in his blog post, the browser used to be on the user’s side—we call browsers the user agent for a reason. Part of the early success of Firefox was that it blocked popup ads. But somewhere over the last 10 years of modern Web browsers, browsers lost their way and stopped being the user’s agent alone. Why?</p>
- <p class="p1"><strong>Browsers aren’t free</strong></p>
- <p class="p1">Making a modern Web browser is not free. It takes hundreds of engineers to make a competitive modern browser engine. Someone has to pay for that, and that someone needs to have a reason to pay for it. Google doesn’t make Chrome for the good of mankind. Google makes Chrome so you can consume more Web and along with it, more Google ads. Each time you click on one, Google makes more money. Chrome is a billion dollar business for Google. And the same is true for pretty much every other browser. Every major browser out there is funded through advertisement. No browser maker can escape this dilemma. Maybe now you understand why no major browser ships with a builtin enabled by default ad-blocker, even though ad-blockers are by far the most popular add-ons.</p>
- <p class="p1"><strong>Our privacy is at stake</strong></p>
- <p class="p1">It’s not just the unregulated flood of advertisement that needs a solution. Every ad you see is often selected based on sensitive private information advertisement networks have extracted from your browsing behavior through tracking. Remember how the FBI used to track what books Americans read at the library, and it was a big scandal? Today the Googles and Facebooks of the world know almost every site you visit, everything you buy online, and they use this data to target you with advertisement. I am often puzzled why people are so afraid of the NSA spying on us but show so little concern about all the deeply personal data Google and Facebook are amassing about everyone.</p>
- <p class="p1"><strong>Blocking alone doesn’t scale</strong></p>
- <p class="p1">I wish the solution was as easy as just blocking all ads. There is a lot of great Web content out there: news, entertainment, educational content. It’s not free to make all this content, but we have gotten used to consuming it “for freeâ€. Banning all ads without an alternative mechanism would break the economic backbone of the Web. This dilemma has existed for many years, and the big browser vendors seem to have given up on it. It’s hard to blame them. How do you disrupt the status quo without sawing off the (ad revenue) branch you are sitting on?</p>
- <p class="p1"><strong>It takes an newcomer to fix this mess</strong></p>
- <p class="p1">I think its unlikely that the incumbent browser vendors will make any bold moves to solve this mess. There is too much money at stake. I am excited to see a startup take a swipe at this problem, because they have little to lose (seed money aside). Brave is getting the user agent back into the game. Browsers have intentionally remained silent onlookers to the ad industry invading users’ privacy. With Brave, Brendan makes the user agent step up and fight for the user as it was always intended to do.</p>
- <p class="p1">Brave basically consists of two parts: part one blocks third party ad content and tracking signals. Instead of these Brave inserts alternative ad content. Sites can sign up to get a fair share of any ads that Brave displays for them. The big change in comparison to the status quo is that the Brave user agent is in control and can regulate what you see. It’s like a speed limit for advertisement on the Web, with the goal to restore balance and give sites a fair way to monetize while giving the user control through the user agent.</p>
- <p class="p1"><strong>Making money with a better Web</strong></p>
- <p class="p1">The ironic part of Brave is that its for-profit. Brave can make money by reducing obnoxious ads and protecting your privacy at the same time. If Brave succeeds, it’s going to drain money away from the crappy privacy-invasive obnoxious advertisement world we have today, and publishers and sites will start transacting in the new Brave world that is regulated by the user agent. Brave will take a cut of these transactions. And I think this is key. It aligns the incentives right. The current funding structure of major browsers encourages them to keep things as they are. Brave’s incentive is to bring down the whole diseased temple and usher in a better Web. Exciting.</p>
- <p class="p1"><strong>Quick update:</strong> I had a chance to look over the Brave GitHub repo. It looks like the Brave Desktop browser is based on Chromium, not Gecko. Yes, you read that right. <span style="text-decoration: underline;">Brave is using Google’s rendering engine, not Mozilla’s.</span> Much to write about this one, but it will definitely help Brave “hide†better in the large volume of Chrome users, making it harder for sites to identify and block Brave users. Brave for iOS seems to be a <span style="text-decoration: underline;">fork of Firefox for iOS, but it manages to block ads</span> (Mozilla says they can’t).</p><br/>Filed under: <a href="http://andreasgal.com/category/mozilla/">Mozilla</a> <a href="http://feeds.wordpress.com/1.0/gocomments/andreasgal.wordpress.com/573/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andreasgal.wordpress.com/573/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/andreasgal.wordpress.com/573/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andreasgal.wordpress.com/573/"/></a> <a href="http://feeds.wordpress.com/1.0/gofacebook/andreasgal.wordpress.com/573/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andreasgal.wordpress.com/573/"/></a> <a href="http://feeds.wordpress.com/1.0/gotwitter/andreasgal.wordpress.com/573/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andreasgal.wordpress.com/573/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/andreasgal.wordpress.com/573/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andreasgal.wordpress.com/573/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/andreasgal.wordpress.com/573/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andreasgal.wordpress.com/573/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/andreasgal.wordpress.com/573/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andreasgal.wordpress.com/573/"/></a> <img alt="" border="0" height="1" src="http://pixel.wp.com/b.gif?host=andreasgal.com&amp;blog=891661&amp;post=573&amp;subd=andreasgal&amp;ref=&amp;feed=1" width="1"/></div>
- </content>
- <updated>2016-01-20T16:00:00Z</updated>
- <category term="Mozilla"/>
- <author>
- <name>Andreas</name>
- </author>
- <source>
- <id>http://andreasgal.com</id>
- <logo>http://s2.wp.com/i/buttonw-com.png</logo>
- <link href="http://andreasgal.com/feed/" rel="self" type="application/rss+xml"/>
- <link href="http://andreasgal.com" rel="alternate" type="text/html"/>
- <link href="http://andreasgal.com/osd.xml" rel="search" title="Andreas Gal " type="application/opensearchdescription+xml"/>
- <link href="http://andreasgal.com/?pushpress=hub" rel="hub" type="text/html"/>
- <subtitle>Entrepreneur. Technologist. Former CTO Mozilla</subtitle>
- <title>Andreas Gal</title>
- <updated>2016-01-22T11:45:34Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>https://miketaylr.com/posts/2016/01/at-media-webkit-transform-three-dee.html</id>
- <link href="https://miketaylr.com/posts/2016/01/at-media-webkit-transform-three-dee.html" rel="alternate" type="text/html"/>
- <title>🙅 @media (-webkit-transform-3d)</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><code>@media (-webkit-transform-3d)</code> is a funny thing that exists on the web.</p>
-
- <p>It's like, a <a href="https://drafts.csswg.org/mediaqueries-4/#mq-features">media query feature</a> in the form of a prefixed CSS property, which should tell you if your (once upon a time probably Safari-only) browser supports 3D transforms, invented back in the day before we had <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@supports"><code>@supports</code></a>.</p>
-
- <p>(According to <a href="https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariCSSRef/Articles/OtherStandardCSS3Features.html#//apple_ref/doc/uid/TP40007601-SW3">Apple docs</a> it first appeared in Safari 4, along side the other <code>-webkit-transition</code> and <code>-webkit-transform-2d</code> hybrid-media-query-feature-prefixed-css-properties-things that you should immediately forget exist.)</p>
-
- <p>Older versions of Modernizr <a href="https://github.com/Modernizr/Modernizr/blob/66c694d136241d356e0d24fcbaa5c068b0b0cdae/feature-detects/css/transforms3d.js#L26-L27">used this (and only this)</a> to detect support for 3D transforms, and that seemed pretty OK. (They also did the polite thing and tested <code>@media (transform-3d)</code>, but no browser has ever actually supported that, as it turns out). And because they're so consistently polite, they've since <a href="https://github.com/patrickkettner/Modernizr/commit/a54308e47e269a058472854b1ef417bd54f4e616">updated the test</a> to prefer <code>@supports</code> too (via a pull request from Edge developer Jacob Rossi).</p>
-
- <p>As it turns out other browsers have been <a href="http://caniuse.com/#feat=transforms3d">updated to support 3D CSS transforms</a>, but sites didn't go back and update their version of Modernizr. So unless you support <code>@media (-webkit-transform-3d)</code> these sites break. Niche websites like <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1239136">yahoo.com</a> and <a href="https://github.com/webcompat/web-bugs/issues/2151">about.com</a>.</p>
-
- <p>So, anyways. I added <a href="https://compat.spec.whatwg.org/#css-media-queries-webkit-transform-3d"><code>@media (-webkit-transform-3d)</code> to the Compat Standard</a> and we <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1239799">added support for it Firefox</a> so websites stop breaking.</p>
-
- <p>But you shouldn't ever use it—use <code>@supports</code>. In fact, don't even share this blog post. Maybe delete it from your browser history just in case.</p></div>
- </summary>
- <updated>2016-01-20T08:00:00Z</updated>
- <author>
- <name>Mike Taylor</name>
- </author>
- <source>
- <id>https://miketaylr.com/posts</id>
- <link href="https://miketaylr.com/posts" rel="alternate" type="text/html"/>
- <link href="https://miketaylr.com/posts/rss.xml" rel="self" type="application/rss+xml"/>
- <rights>3000</rights>
- <subtitle>Erotic web browser fan-fiction.</subtitle>
- <title>Mike Taylr Dot Com Web Log</title>
- <updated>2016-01-20T19:46:39Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en">
- <id>http://globau.wordpress.com/?p=881</id>
- <link href="https://globau.wordpress.com/2016/01/20/happy-bmo-push-day-166/" rel="alternate" type="text/html"/>
- <title>happy bmo push day!</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">the following changes have been pushed to bugzilla.mozilla.org: [1236161] when converting a BMP attachment to PNG fails a zero byte attachment is created [1231918] error handler doesn’t close multi-part responses discuss these changes on mozilla.tools.bmo.Filed under: bmo, mozilla<img alt="" border="0" height="1" src="https://pixel.wp.com/b.gif?host=globau.wordpress.com&amp;blog=25718030&amp;post=881&amp;subd=globau&amp;ref=&amp;feed=1" width="1"/></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>the following changes have been pushed to bugzilla.mozilla.org:</p>
- <ul>
- <li>[<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1236161" target="_blank">1236161</a>] when converting a BMP attachment to PNG fails a zero byte attachment is created</li>
- <li>[<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1231918" target="_blank">1231918</a>] error handler doesn’t close multi-part responses</li>
- </ul>
- <p>discuss these changes on <a href="https://lists.mozilla.org/listinfo/tools-bmo" target="_blank">mozilla.tools.bmo</a>.</p><br/>Filed under: <a href="https://globau.wordpress.com/category/mozilla/bmo/">bmo</a>, <a href="https://globau.wordpress.com/category/mozilla/">mozilla</a> <img alt="" border="0" height="1" src="https://pixel.wp.com/b.gif?host=globau.wordpress.com&amp;blog=25718030&amp;post=881&amp;subd=globau&amp;ref=&amp;feed=1" width="1"/></div>
- </content>
- <updated>2016-01-20T07:33:46Z</updated>
- <category term="bmo"/>
- <category term="mozilla"/>
- <author>
- <name>glob</name>
- </author>
- <source>
- <id>https://globau.wordpress.com</id>
- <logo>https://s2.wp.com/i/buttonw-com.png</logo>
- <link href="https://globau.wordpress.com/category/mozilla/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://globau.wordpress.com" rel="alternate" type="text/html"/>
- <link href="https://globau.wordpress.com/osd.xml" rel="search" title="glob blog" type="application/opensearchdescription+xml"/>
- <link href="https://globau.wordpress.com/?pushpress=hub" rel="hub" type="text/html"/>
- <title>mozilla – glob blog</title>
- <updated>2016-01-26T19:01:06Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>https://www.alex-johnson.net/tag/mozilla/rss/85d84c54-ed0c-4ee5-beb3-8823edb3c074</id>
- <link href="https://www.alex-johnson.net/removing-honeycomb-code/" rel="alternate" type="text/html"/>
- <title>Removing Honeycomb Code</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>As an effort to reduce the APK size of Firefox for Android and to remove unnecessary code, I will be helping remove the Honeycomb code throughout the Fennec project. Honeycomb will not be supported since Firefox 46, so this code is not necessary. <br/>
- <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1217675">Bug 1217675</a> will keep track of the</p></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>As an effort to reduce the APK size of Firefox for Android and to remove unnecessary code, I will be helping remove the Honeycomb code throughout the Fennec project. Honeycomb will not be supported since Firefox 46, so this code is not necessary. <br/>
- <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1217675">Bug 1217675</a> will keep track of the progress. <br/>
- Hopefully this will help reduce the APK size some and clean up the road for <a href="https://www.youtube.com/watch?v=NJ6kzW5t02Y">killing Gingerbread</a> hopefully sometime in the near future.</p></div>
- </content>
- <updated>2016-01-20T04:59:34Z</updated>
- <category term="Mozilla"/>
- <category term="Android"/>
- <category term="Mobile"/>
- <author>
- <name>Alex Johnson</name>
- </author>
- <source>
- <id>https://www.alex-johnson.net/</id>
- <link href="https://www.alex-johnson.net/" rel="alternate" type="text/html"/>
- <link href="https://www.alex-johnson.net/tag/mozilla/rss/" rel="self" type="application/rss+xml"/>
- <subtitle>Open source evangelist; lover of technology and video games.</subtitle>
- <title>Mozilla - Alex Johnson</title>
- <updated>2016-01-26T19:01:53Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://www.brianbondy.com/blog/id/172</id>
- <link href="http://www.brianbondy.com/blog/172/brave-software" rel="alternate" type="text/html"/>
- <title>Brave Software</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p/><p>Since June of last year, I’ve been co-founding a new startup called <a href="https://brave.com/">Brave Software</a> with <a href="https://en.wikipedia.org/wiki/Brendan_Eich">Brendan Eich</a>.
- With our amazing team, we're developing something pretty epic.</p><p/>
- <p/><p>We're building the next-generation of browsers for smartphones and laptops as part of our new ad-tech platform.
- Our terms of use give our users control over their personal data by blocking ad trackers and third party cookies.
- We re-integrate fewer and better ads directly into programmatic ad positions, paying revenue shares to users and publishers to support both of these essential parties in the web ecosystem.</p><p/>
- <p/><p>Coming built in, we have new faster engines for tracking protection, ad block, HTTPS Everywhere, safe ads with rev-share, and more.
- We're seeing massive web page load time speedups.</p><p/>
-
-
- <p/><p>We're starting to bring people in for early developer build access on all platforms.</p><p/>
- <p/><p>I’m happy to share that the browsers we’re developing were made fully open sourced.
- We welcome contributors, and would love your help.</p><p/>
- <p/><p>Some of the repositories include:</p><p/>
- <ul>
- <li><a href="https://github.com/brave/browser-laptop">Brave OSX and Windows x64 browsers</a>: Prototyped as a Gecko based browser, but now replaced with a powerful new browser built on top of the electron framework. The electron framework is the same one in use by Slack and the Atom editor. It uses the latest libchromiumcontent and Node.</li>
- <li><a href="https://github.com/brave/link-bubble">Brave for Android</a>: Formerly Link Bubble, working as a background service so you can use other apps as your pages load.</li>
- <li><a href="https://github.com/brave/browser-ios">Brave for iOS</a>: Originally forked from Firefox for iOS but with all of the built-in greatness described above.</li>
- <li>And many others: Website, updater code, vault, electron fork, and others.</li>
- </ul></div>
- </summary>
- <updated>2016-01-20T00:00:00Z</updated>
- <category term="brave"/>
- <category term="electron"/>
- <category term="node"/>
- <category term="firefox"/>
- <category term="firefox-ios"/>
- <category term="mozilla"/>
- <category term="gecko"/>
- <author>
- <name>Brian R. Bondy</name>
- </author>
- <source>
- <id>http://www.brianbondy.com/blog/tagged/mozilla</id>
- <logo>http://www.brianbondy.com/img/logo.png</logo>
- <link href="http://www.brianbondy.com/blog/tagged/mozilla" rel="alternate" type="text/html"/>
- <link href="http://www.brianbondy.com/feeds/rss/mozilla" rel="self" type="application/rss+xml"/>
- <subtitle>Blog posts tagged mozilla by Brian R. Bondy</subtitle>
- <title>Brian R. Bondy's feed for tag mozilla</title>
- <updated>2016-01-26T19:01:09Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://coffeeonthekeyboard.com/rss/0388d8a6-fc86-477e-a161-1b356e01fe77</id>
- <link href="http://coffeeonthekeyboard.com/piefection-slides-up/" rel="alternate" type="text/html"/>
- <title>PIEfection Slides Up</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I put <a href="https://github.com/jsocol/talks/tree/master/2016-01-13-manhattanjs-pie">the slides for my ManhattanJS talk, "PIEfection"</a> up on GitHub the other day (sans images, but there are links in the source for all of those).</p>
-
- <p>I completely neglected to talk about the <a href="https://en.wikipedia.org/wiki/Maillard_reaction">Maillard reaction</a>, which is responsible for food tasting good, and specifically for browning pie crusts.</p></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I put <a href="https://github.com/jsocol/talks/tree/master/2016-01-13-manhattanjs-pie">the slides for my ManhattanJS talk, "PIEfection"</a> up on GitHub the other day (sans images, but there are links in the source for all of those).</p>
-
- <p>I completely neglected to talk about the <a href="https://en.wikipedia.org/wiki/Maillard_reaction">Maillard reaction</a>, which is responsible for food tasting good, and specifically for browning pie crusts. tl;dr: Amino acid (protein) + sugar + ~300°F (~150°C) = delicious. There are innumerable and poorly understood combinations of amino acids and sugars, but this class of reaction is responsible for everything from searing stakes to browning crusts to toasting marshmallows.</p>
-
- <p>Above ~330°F, you get caramelization, which is also a delicious part of the pie and crust, but you don't want to overdo it. Starting around ~400°F, you get pyrolysis (burning, charring, carbonization) and below 285°F the reaction won't occur (at least not quickly) so you won't get the delicious compounds.</p>
-
- <p>(All of these are, of course, temperatures measured in the material, not in the air of the oven.)</p>
-
- <p>So, instead of an egg wash on your top crust, try whole milk, which has more sugar to react with the gluten in the crust.</p>
-
- <p>I also didn't get a chance to mention a rolling technique I use, that I learned from a <a href="https://www.facebook.com/ellenspirerstaffing">cousin of mine</a>, in whose baking shadow I happily live.</p>
-
- <p>When rolling out a crust after it's been in the fridge, first roll it out in a long stretch, then fold it in thirds; do it again; then start rolling it out into a round. Not only do you add more layer structure (mmm, flaky, delicious layers) but it'll fill in the cracks that often form if you try to roll it out directly, resulting in a stronger crust.</p>
-
- <p>Those <a href="http://www.amazon.com/Cheese-Shaker-Pepper-Perforated-Stainless/dp/B007T40P28/ref=sr_1_1?ie=UTF8&amp;qid=1453236391&amp;sr=8-1&amp;keywords=pizza+shaker">pepper flake shakers</a>, filled with flour, are a great way to keep adding flour to the workspace without worrying about your buttery hands.</p>
-
- <p>For transferring the crust to the pie plate, try rolling it up onto your rolling pin and unrolling it on the plate. <a href="http://www.amazon.com/Ateco-20-Inch-Length-French-Rolling/dp/B000KESQ1G">Tapered (or "French") rolling pins</a> (or wine bottle) are particularly good at this since they don't have moving parts.</p>
-
- <p>Finally, thanks again to <a href="https://twitter.com/renrutnnej">Jenn</a> for helping me get pies from one island to another. It would not have been possible without her!</p></div>
- </content>
- <updated>2016-01-19T20:45:34Z</updated>
- <author>
- <name>James Socol</name>
- </author>
- <source>
- <id>http://coffeeonthekeyboard.com/</id>
- <link href="http://coffeeonthekeyboard.com/" rel="alternate" type="text/html"/>
- <link href="http://coffeeonthekeyboard.com/rss/" rel="self" type="application/rss+xml"/>
- <subtitle>Coffee on the Keyboard</subtitle>
- <title>Coffee on the Keyboard</title>
- <updated>2016-01-25T18:00:43Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://air.mozilla.org/reprendre-le-controle-de-sa-vie-privee-sur-internet/</id>
- <link href="https://air.mozilla.org/reprendre-le-controle-de-sa-vie-privee-sur-internet/" rel="alternate" type="text/html"/>
- <title>Reprendre le contrôle de sa vie privée sur Internet</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
- <img alt="Reprendre le contr&#xF4;le de sa vie priv&#xE9;e sur Internet" class="wp-post-image" height="90" src="https://air.cdn.mozilla.net/media/cache/be/f6/bef62897fb87e08dc8392fe61d10bcfa.png" width="160"/>
- L'omniprésence des réseaux sociaux, des moteurs de recherches et de la publicité est-elle compatible avec notre droit à la vie privée ?
- </p></div>
- </summary>
- <updated>2016-01-19T18:00:00Z</updated>
- <author>
- <name>Air Mozilla</name>
- </author>
- <source>
- <id>https://air.mozilla.org/</id>
- <link href="https://air.mozilla.org/" rel="alternate" type="text/html"/>
- <link href="https://air.mozilla.org/" rel="self" type="application/rss+xml"/>
- <rights>Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.</rights>
- <subtitle>Air Mozilla is the Internet multimedia presence of Mozilla, with live and pre-recorded shows, interviews, news snippets, tutorial videos, and features about the Mozilla community.</subtitle>
- <title>Air Mozilla</title>
- <updated>2016-01-25T20:31:50Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://mykzilla.org/?p=245</id>
- <link href="https://mykzilla.org/2016/01/19/new-year-new-blogware/" rel="alternate" type="text/html"/>
- <title>New Year, New Blogware</title>
- <summary>Four score and many moons ago, I decided to move this blog from Blogger to WordPress. The transition took longer than expected, but it’s finally done. If you’ve been following along at the old address, https://mykzilla.blogspot.com/, now’s the time to update your address book! If you’ve been going to https://mykzilla.org/, however, or you read the […]</summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Four score and many moons ago, I decided to move this blog from Blogger to WordPress. The transition took longer than expected, but it’s finally done.</p>
- <p>If you’ve been following along at the old address, <a href="https://mykzilla.blogspot.com/">https://mykzilla.blogspot.com/</a>, now’s the time to update your address book! If you’ve been going to <a href="https://mykzilla.org/">https://mykzilla.org/</a>, however, or you read the blog on <a href="http://planet.mozilla.org/">Planet Mozilla</a>, then there’s nothing to do, as that’s the new address, and Planet Mozilla has been updated to syndicate posts from it.</p></div>
- </content>
- <updated>2016-01-19T16:56:05Z</updated>
- <category term="Mozilla"/>
- <author>
- <name>Myk Melez</name>
- </author>
- <source>
- <id>https://mykzilla.org</id>
- <logo>https://mykzilla.org/wp-content/uploads/2016/01/cropped-headshot-2014-32x32.jpg</logo>
- <link href="https://mykzilla.org/category/mozilla/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://mykzilla.org" rel="alternate" type="text/html"/>
- <title>Mozilla – Mykzilla</title>
- <updated>2016-01-19T17:30:17Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://michaelkohler.info/?p=348</id>
- <link href="https://michaelkohler.info/2016/mozillas-strategische-leitlinien-fur-2016-und-danach" rel="alternate" type="text/html"/>
- <title>Mozillas strategische Leitlinien für 2016 und danach</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Dieser Beitrag wurde zuerst im Blog auf https://blog.mozilla.org/community veröffentlicht. Herzlichen Dank an Aryx und Coce für die Übersetzung! Auf der ganzen Welt arbeiten leidenschaftliche Mozillianer am Fortschritt für Mozillas Mission. Aber fragt man fünf verschiedene Mozillianer, was die Mission ist, erhält man womöglich sieben verschiedene Antworten. Am Ende des letzten Jahres legte Mozillas CEO Chris Beard klare Vorstellungen über Mozillas Mission, Vision und Rolle dar und zeigte auf, wie unsere Produkte uns diesem Ziel in den nächsten fünf Jahren näher bringen. Das Ziel dieser strategischen Leitlinien besteht darin, für Mozilla...<a class="read-more" href="https://michaelkohler.info/2016/mozillas-strategische-leitlinien-fur-2016-und-danach">read more</a><img alt="" height="0" src="http://piwik.michaelkohler.info/piwik.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fmichaelkohler.info%2F2016%2Fmozillas-strategische-leitlinien-fur-2016-und-danach&amp;action_name=Mozillas+strategische+Leitlinien+f%C3%BCr+2016+und+danach&amp;urlref=https%3A%2F%2Fmichaelkohler.info%2Ffeed" style="border: 0; width: 0; height: 0;" width="0"/></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Dieser Beitrag wurde zuerst im Blog auf<a href="https://blog.mozilla.org/community"> https://blog.mozilla.org/community</a> veröffentlicht. Herzlichen Dank an Aryx und Coce für die Übersetzung!</p>
- <p>Auf der ganzen Welt arbeiten leidenschaftliche Mozillianer am Fortschritt für Mozillas Mission. Aber fragt man fünf verschiedene Mozillianer, was die Mission ist, erhält man womöglich sieben verschiedene Antworten.</p>
- <p>Am Ende des letzten Jahres legte Mozillas CEO Chris Beard klare Vorstellungen über Mozillas Mission, Vision und Rolle dar und zeigte auf, wie unsere Produkte uns diesem Ziel in den nächsten fünf Jahren näher bringen. Das Ziel dieser strategischen Leitlinien besteht darin, für Mozilla insgesamt ein prägnantes, gemeinsames Verständnis unserer Ziele zu entwickeln, die uns als Individuen das Treffen von Entscheidungen und Erkennen von Möglichkeiten erleichtert, mit denen wir Mozilla voranbringen.</p>
- <p>Mozillas Mission können wir nicht alleine erreichen. Die Tausenden von Mozillianern auf der ganzen Welt müssen dahinter stehen, damit wir zügig und mit lauterer Stimme als je zuvor Unglaubliches erreichen können.</p>
- <p>Deswegen ist eine der sechs<a href="https://docs.google.com/presentation/d/1A3Ma9gNawAYYGbYC2bUW0wUwcpHuvyMiZvHNiMLriw0/edit#slide=id.gdaa7a0bd0_1_0"> strategischen Initiativen</a> des Participation Teams für die erste Jahreshälfte, möglichst viele Mozillianer über diese Leitlinien aufzuklären, damit wir 2016 den bisher wesentlichsten Einfluss erzielen können. Wir werden einen weiteren Beitrag veröffentlichen, der sich näher mit der Strategie des Participation Teams für das Jahr 2016 befassen wird.</p>
- <p><img alt="" class="alignnone" height="335" src="https://ffp4g1ylyit3jdyti1hqcvtb-wpengine.netdna-ssl.com/community/files/2016/01/Screen-Shot-2015-12-18-at-2.02.07-PM-600x335.png" width="600"/></p>
- <p>Das Verstehen dieser Strategie wird unabdingbar sein für jeden, der bei Mozilla in diesem Jahr etwas bewirken möchte, denn sie wird bestimmen, wofür wir eintreten, wo wir unsere Ressourcen einsetzen und auf welche Projekte wir uns 2016 konzentrieren werden.</p>
- <p>Zu Jahresbeginn werden wir näher auf diese Strategie eingehen und weitere Details dazu bekanntgeben, wie die diversen Teams und Projekte bei Mozilla auf diese Ziele hinarbeiten.</p>
- <p>Der aktuelle Aufruf zum Handeln besteht darin, im Kontext Ihrer Arbeit über diese Ziele nachzudenken und darüber, wie Sie im kommenden Jahr bei Mozilla mitwirken möchten. Dies hilft, Ihre Innovationen, Ambitionen und Ihren Einfluss im Jahr 2016 zu gestalten.</p>
- <p>Wir hoffen, dass Sie mitdiskutieren und Ihre Fragen, Kommentare und Pläne für das Vorantreiben der strategischen Leitlinien im Jahr 2016<a href="https://discourse.mozilla-community.org/t/mozillas-strategic-narrative-2016/6397"> hier</a> auf Discourse teilen und Ihre Gedanken auf Twitter mit dem Hashtag <a href="https://twitter.com/search?q=%23mozilla2016strategy&amp;src=typd">#Mozilla2016Strategy</a> mitteilen.</p>
- <p> </p>
- <h3>Mission, Vision &amp; Strategie</h3>
- <p><b>Unsere Mission</b></p>
- <p>Dafür zu sorgen, dass das Internet eine weltweite öffentliche Ressource ist, die allen zugänglich ist.</p>
- <p><b>Unsere Vision</b></p>
- <p>Ein Internet, für das Menschen tatsächlich an erster Stelle stehen. Ein Internet, in dem Menschen ihr eigenes Erlebnis gestalten können. Ein Internet, in dem die Menschen selbst entscheiden können sowie sicher und unabhängig sind.</p>
- <p><b>Unsere Rolle</b></p>
- <p>Mozilla setzt sich im wahrsten Sinne des Wortes in Ihrem Online-Leben für Sie ein. Wir setzen uns für Sie ein, sowohl in Ihrem Online-Erlebnis als auch für Ihre Interessen beim Zustand des Internets.</p>
- <p><b>Unsere Arbeit</b></p>
- <p>Unsere Säulen</p>
- <ol>
- <li><b>Produkte:</b> Wir entwickeln Produkte mit Menschen im Mittelpunkt sowie Bildungsprogramme, mit deren Hilfe Menschen online ihr gesamtes Potential ausschöpfen können.</li>
- <li><b>Technologie:</b> Wir entwickeln robuste technische Lösungen, die das Internet über verschiedene Plattformen hinweg zum Leben erwecken.</li>
- <li><b>Menschen:</b> Wir entwickeln Führungspersonen und Mitwirkende in der Gemeinschaft, die das Internet erfinden, gestalten und verteidigen.</li>
- </ol>
- <p>Wir wir positive Veränderungen in Zukunft anpacken wollen</p>
- <p>Die Arbeitsweise ist ebensowichtig wie das Ziel. Unsere Gesundheit und bleibender Einfluss hängen davon ab, wie sehr unsere Produkte und Aktivitäten:</p>
- <ol>
- <li>Interoperabilität, Open Source und offene Standards fördern,</li>
- <li>Gemeinschaften aufbauen und fördern,</li>
- <li>Für politische Veränderungen und rechtlichen Schutz eintreten sowie</li>
- <li>Netzbürger bilden und einbeziehen.</li>
- </ol>
- <p> </p>
- <img alt="" height="0" src="http://piwik.michaelkohler.info/piwik.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fmichaelkohler.info%2F2016%2Fmozillas-strategische-leitlinien-fur-2016-und-danach&amp;action_name=Mozillas+strategische+Leitlinien+f%C3%BCr+2016+und+danach&amp;urlref=https%3A%2F%2Fmichaelkohler.info%2Ffeed" style="border: 0; width: 0; height: 0;" width="0"/></div>
- </content>
- <updated>2016-01-19T15:27:24Z</updated>
- <category term="Mozilla"/>
- <category term="MozillaDeutsch"/>
- <author>
- <name>Michael Kohler</name>
- </author>
- <source>
- <id>https://michaelkohler.info</id>
- <link href="https://michaelkohler.info/category/mozilla/feed" rel="self" type="application/rss+xml"/>
- <link href="https://michaelkohler.info" rel="alternate" type="text/html"/>
- <title>Mozilla – Michael Kohler</title>
- <updated>2016-01-19T15:31:45Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en">
- <id>http://dlawrence.wordpress.com/?p=27</id>
- <link href="https://dlawrence.wordpress.com/2016/01/19/happy-bmo-push-day-3/" rel="alternate" type="text/html"/>
- <title>happy bmo push day!</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">the following changes have been pushed to bugzilla.mozilla.org: [1238573] Change label of “New Bug†menu to “New/Clone Bug†[1239065] Project Kickoff Form: Adjustments needed to Mozilla Infosec review portion [1240157] Fix a typo in bug.rst [1236461] Mass update mozilla-reps group discuss these changes on mozilla.tools.bmo.<img alt="" border="0" height="1" src="https://pixel.wp.com/b.gif?host=dlawrence.wordpress.com&amp;blog=58816&amp;post=27&amp;subd=dlawrence&amp;ref=&amp;feed=1" width="1"/></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>the following changes have been pushed to bugzilla.mozilla.org:</p>
- <ul>
- <li>[<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1238573" target="_blank">1238573</a>] Change label of “New Bug†menu to “New/Clone Bugâ€</li>
- <li>[<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1239065" target="_blank">1239065</a>] Project Kickoff Form: Adjustments needed to Mozilla Infosec review portion</li>
- <li>[<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1240157" target="_blank">1240157</a>] Fix a typo in bug.rst</li>
- <li>[<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1236461" target="_blank">1236461</a>] Mass update mozilla-reps group</li>
- </ul>
- <p>discuss these changes on <a href="https://lists.mozilla.org/listinfo/tools-bmo" target="_blank">mozilla.tools.bmo</a>.</p><br/> <a href="http://feeds.wordpress.com/1.0/gocomments/dlawrence.wordpress.com/27/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/dlawrence.wordpress.com/27/"/></a> <img alt="" border="0" height="1" src="https://pixel.wp.com/b.gif?host=dlawrence.wordpress.com&amp;blog=58816&amp;post=27&amp;subd=dlawrence&amp;ref=&amp;feed=1" width="1"/></div>
- </content>
- <updated>2016-01-19T14:49:59Z</updated>
- <category term="Uncategorized"/>
- <author>
- <name>dlawrence</name>
- </author>
- <source>
- <id>https://dlawrence.wordpress.com</id>
- <logo>https://s2.wp.com/i/buttonw-com.png</logo>
- <link href="https://dlawrence.wordpress.com/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://dlawrence.wordpress.com" rel="alternate" type="text/html"/>
- <link href="https://dlawrence.wordpress.com/osd.xml" rel="search" title="Dave's Ramblings" type="application/opensearchdescription+xml"/>
- <link href="https://dlawrence.wordpress.com/?pushpress=hub" rel="hub" type="text/html"/>
- <subtitle>Thoughts somehow related to web, linux, mobile and other things I am interested in</subtitle>
- <title>Dave's Ramblings</title>
- <updated>2016-01-26T14:31:39Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://soledadpenades.com/?p=6335</id>
- <link href="http://soledadpenades.com/2016/01/19/hardware-hack-day-mozldn-1/" rel="alternate" type="text/html"/>
- <link href="https://flattr.com/submit/auto?user_id=8399&amp;popout=1&amp;url=http%3A%2F%2Fsoledadpenades.com%2F2016%2F01%2F19%2Fhardware-hack-day-mozldn-1%2F&amp;language=en_GB&amp;category=text&amp;title=Hardware+Hack+Day+%40+MozLDN%2C+1&amp;description=Last+week+we+ran+an+internal+%26%238220%3Bhack+day%26%238221%3B+here+at+the+Mozilla+space+in+London.+It+was+just+a+bunch+of+software+engineers+looking+at+various+hardware+boards+and+things...&amp;tags=arduino%2Clinux%2Cmdns%2Cmozilla%2Craspberry+pi%2Cwi-fi%2Cblog" rel="payment" title="Flattr this!" type="text/html"/>
- <title>Hardware Hack Day @ MozLDN, 1</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Last week we ran an internal “hack day†here at the Mozilla space in London. It was just a bunch of software engineers looking at various hardware boards and things and learning about them Here’s what we did! Sole I essentially kind of bricked my Arduino Duemilanove trying to get it working with Johnny Five, … <a class="more-link" href="http://soledadpenades.com/2016/01/19/hardware-hack-day-mozldn-1/">Continue reading <span class="screen-reader-text">Hardware Hack Day @ MozLDN, 1</span> <span class="meta-nav">→</span></a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Last week we ran an internal “hack day†here at the Mozilla space in London. It was just a bunch of <em>software</em> engineers looking at various <em>hardware</em> boards and things and learning about them <img alt=":-)" class="wp-smiley" src="http://soledadpenades.com/wp-includes/images/smilies/simple-smile.png" style="height: 1em;"/></p>
- <p>Here’s what we did!</p>
- <h3><a href="http://soledadpenades.com/">Sole</a></h3>
- <p>I essentially <a href="http://soledadpenades.com/2016/01/19/kind-of-bricking-an-arduino-duemilanove-by-exhausting-its-memory/">kind of bricked my Arduino Duemilanove</a> trying to get it working with Johnny Five, but it was fine–apparently there’s a way to recover it using another Arduino, and someone offered to help with that in the next <a href="http://www.meetup.com/NodeBots-of-London/events/227890374/">NodeBots</a> London, which I’m going to attend.</p>
- <h3><a href="http://ardeenelinfierno.com/">Francisco</a></h3>
- <p>Thinks he’s having issues with cables. It seems like the boards are not reset automatically by the Arduino IDE nowadays? He found the button in the board actually resets the board when pressed i.e. it’s the RESET button.</p>
- <p>On the Raspberry Pi side of things, he was very happy to put all his old-school Linux skills in action configuring network interfaces without GUIs!</p>
- <h3><a href="http://gu.illau.me/">Guillaume</a></h3>
- <p>Played with mDNS advertising and listening to services on Raspberry Pi.</p>
- <p>(He was very quiet)</p>
- <p>(He also built a very nice LEGO case for the Raspberry Pi, but I do not have a picture, so just imagine it).</p>
- <h3><a href="http://wilsonpage.co.uk/">Wilson</a></h3>
- <blockquote><p>
- Wilson: “I got my Raspberry Pi on the Wi-Fiâ€</p>
- <p>Francisco: “Sorry?â€</p>
- <p>Wilson: “I mean, you got my Raspberry Pi on the network. And now I’m trying to build a web app on the Pi…â€</p></blockquote>
- <h3><a href="http://chrislord.net/">Chris</a></h3>
- <p>Exploring the Pebble with Linux. There’s a libpebble, and he managed to connect…</p>
- <p><del datetime="2016-01-20T11:22:33+00:00"><em><small>(sorry, I had to leave early so I do not know what else did Chris do!)</small></em></del></p>
- <p>Updated, 20 January: Chris told me he just managed to successfully connect to the Pebble watch using the bluetooth WebAPI. It requires two Gecko patches (one regression patch and one obvious logic error that he hasn’t filed yet). PROGRESS!</p>
- <p>~~~</p>
- <p>So as you can see we didn’t really get super far in just a day, and I even ended up with unusable hardware. BUT! we all learned something, and next time we know what NOT to do (or at least I DO KNOW what NOT to do!).</p>
- <p><a href="http://soledadpenades.com/?flattrss_redirect&amp;id=6335&amp;md5=40427d69faa3b9c2d1530732fd78e66d" target="_blank" title="Flattr"><img alt="flattr this!" src="http://soledadpenades.com/wp-content/plugins/flattr/img/flattr-badge-large.png"/></a></p></div>
- </content>
- <updated>2016-01-19T13:31:55Z</updated>
- <category term="Events"/>
- <category term="Hardware"/>
- <category term="arduino"/>
- <category term="linux"/>
- <category term="mdns"/>
- <category term="mozilla"/>
- <category term="raspberry pi"/>
- <category term="wi-fi"/>
- <author>
- <name>sole</name>
- </author>
- <source>
- <id>http://soledadpenades.com</id>
- <link href="http://soledadpenades.com/tag/mozilla/feed/" rel="self" type="application/rss+xml"/>
- <link href="http://soledadpenades.com" rel="alternate" type="text/html"/>
- <subtitle>repeat 4[fd 100 rt 90]</subtitle>
- <title>mozilla – soledad penadés</title>
- <updated>2016-01-26T02:46:29Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://daniel.haxx.se/blog/?p=8544</id>
- <link href="http://daniel.haxx.se/blog/2016/01/19/subject-urgent-warning/" rel="alternate" type="text/html"/>
- <title>“Subject: Urgent Warningâ€</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Back in December I got a desperate email from this person. A woman who said her Instagram had been hacked and since she found my contact info in the app she mailed me and asked for help. I of course replied and said that I have nothing to do with her being hacked but I … <a class="more-link" href="http://daniel.haxx.se/blog/2016/01/19/subject-urgent-warning/">Continue reading <span class="screen-reader-text">“Subject: Urgent Warningâ€</span> <span class="meta-nav">→</span></a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Back in December I got a desperate email from this person. A woman who said her Instagram had been hacked and since she found my contact info in the app she mailed me and asked for help. I of course replied and said that I have nothing to do with her being hacked but I also have nothing to do with Instagram other than that they use software I’ve written.</p>
- <p>Today she writes back. Clearly not convinced I told the truth before, and now she strikes back with more “evidence†of my wrongdoings.</p>
- <p><em>Dear Daniel,</em></p>
- <p><em>I had emailed you a couple months ago about my “screen dumps†aka screenshots and asked for your help with restoring my Instagram account since it had been hacked, my photos changed, and your name was included in the coding. You claimed to have no involvement whatsoever in developing a third party app for Instagram and could not help me salvage my original Instagram photos, pre-hacked, despite Instagram serving as my Photography portfolio and my career is a Photographer.</em></p>
- <p><em>Since you weren’t aware that your name was attached to Instagram related hacking code, I thought you might want to know, in case you weren’t already aware, that your name is also included in Spotify terms and conditions. I came across this information using my Spotify which has also been hacked into and would love your help hacking out of Spotify. Also, I have yet to figure out how to unhack the hackers from my Instagram so if you change your mind and want to restore my Instagram to its original form as well as help me secure my account from future privacy breaches, I’d be extremely grateful. As you know, changing my passwords did nothing to resolve the problem. Please keep in mind that Facebook owns Instagram and these are big companies that you likely don’t want to have a trail of evidence that you are a part of an Instagram and Spotify hacking ring. Also, Spotify is a major partner of Spotify so you are likely familiar with the coding for all of these illegally developed third party apps. I’d be grateful for your help fixing this error immediately.</em></p>
- <p><em>Thank you,</em></p>
- <p>[name redacted]</p>
- <p><em>P.S. Please see attached screen dump for a screen shot of your contact info included in Spotify (or what more likely seems to be a hacked Spotify developed illegally by a third party).</em></p>
- <p><a href="http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_7393.png" rel="attachment wp-att-8545"><img alt="Spotify credits screenshot" class="aligncenter size-medium wp-image-8545" height="450" src="http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_7393-253x450.png" width="253"/></a></p>
- <p>Here’s the Instagram screenshot she sent me in a previous email:</p>
- <p><a href="http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_2156.jpg" rel="attachment wp-att-8546"><img alt="Instagram credits screenshot" class="aligncenter size-medium wp-image-8546" height="450" src="http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_2156-253x450.jpg" width="253"/></a></p>
- <p>I’ve tried to respond with calm and clear reasonable logic and technical details on why she’s seeing my name there. That clearly failed. What do I try next?</p></div>
- </content>
- <updated>2016-01-19T08:37:32Z</updated>
- <category term="cURL and libcurl"/>
- <category term="Open Source"/>
- <category term="Technology"/>
- <category term="hacking"/>
- <category term="Mail"/>
- <author>
- <name>Daniel Stenberg</name>
- </author>
- <source>
- <id>http://daniel.haxx.se/blog</id>
- <logo>http://daniel.haxx.se/blog/wp-content/uploads/2015/08/cropped-Daniel-head-greenshirt-32x32.jpg</logo>
- <link href="http://daniel.haxx.se/blog/feed/" rel="self" type="application/rss+xml"/>
- <link href="http://daniel.haxx.se/blog" rel="alternate" type="text/html"/>
- <subtitle>tech, open source and networking</subtitle>
- <title>daniel.haxx.se</title>
- <updated>2016-01-26T07:16:26Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-us">
- <id>http://edunham.net/2016/01/19/how_much_knowledge_do_you_need_to_give_a_conference_talk.html</id>
- <link href="http://edunham.net/2016/01/19/how_much_knowledge_do_you_need_to_give_a_conference_talk.html" rel="alternate" type="text/html"/>
- <title>How much knowledge do you need to give a conference talk?</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><h3>How much knowledge do you need to give a conference talk?</h3>
- <p>I was recently asked an excellent question when I promoted the <a class="reference external" href="http://www.linuxfestnorthwest.org/2016/present">LFNW CFP</a> on
- IRC:</p>
- <blockquote>
- <div>As someone who has never done a talk, but wants to, what kind of knowledge
- do you need about a subject to give a talk on it?</div></blockquote>
- <p>If you answer “yes†to any of the following questions, you know enough to
- propose a talk:</p>
- <ul class="simple">
- <li>Do you have a <strong>hobby</strong> that most tech people aren’t experts on? Talk
- about applying a lesson or skill from that hobby to tech! For instance, I
- turned a habit of reading about psychology into my <a class="reference external" href="http://talks.edunham.net/scale13x/#1">Human Hacking</a> talk.</li>
- <li>Have you ever spent a bunch of hours forcing two tools to work with each
- other, because the documentation wasn’t very helpful and Googling didn’t get
- you very far, and built something useful? “How to build ___ with ___†makes
- a catchy talk title, if the <strong>thing you built</strong> solves a common problem.</li>
- <li>Have you ever had a mentor sit down with you and explain a tool or
- technique, and the new understanding improved the quality of your work or
- code? Passing along useful <strong>lessons from your mentors</strong> is a valuable talk,
- because it allows others to benefit from the knowledge without taking as
- much of your mentor’s time.</li>
- <li>Have you seen a dozen newbies ask the same question over the course of a few
- months? When your <strong>answer to a common question</strong> starts to feel like a
- broken record, it’s time to compose it into a talk then link the newbies to
- your slides or recording!</li>
- <li>Have you taken a really <strong>interesting class</strong> lately? Can you distill part of it
- into a 1-hour lesson that would appeal to nerds who don’t have the time or
- resources to take the class themselves? (thanks <a class="reference external" href="http://lucywyman.me/">lucyw</a> for adding this to
- the list!)</li>
- <li>Have you built a cool thing that over a dozen other people use? A <strong>tutorial
- talk</strong> can not only expand your community, but its recording can augment your
- documentation and make the project more accessible for those who prefer to
- learn directly from humans!</li>
- <li>Did you benefit from a really great introductory talk when you were learning
- a tool? Consider doing your own tutorial! Any conference with beginners in
- their target audience needs at least one Git lesson, an IRC talk, and some
- discussions of how to use basic Unix utilities. These <strong>introductory talks</strong>
- are actually better when given by someone who learned the technology
- relatively recently, because newer users remember what it’s like not to know
- how to use it. Just remember to have a more expert user look over your slides
- before you present, in case you made an incorrect assumption about the tool’s
- more advanced functionality.</li>
- </ul>
- <p>I personally try to propose talks I want to hear, because the dealine of a
- CFP or conference is great motivation to prioritize a cool project over
- ordinary chores.</p></div>
- </summary>
- <updated>2016-01-19T08:00:00Z</updated>
- <source>
- <id>http://edunham.net/</id>
- <author>
- <name>Emily Dunham</name>
- </author>
- <link href="http://edunham.net/" rel="alternate" type="text/html"/>
- <link href="http://edunham.net/rss.html?tag=planetmozilla" rel="self" type="application/rss+xml"/>
- <subtitle>is a "DevOps" Engineer at Mozilla Research</subtitle>
- <title>edunham</title>
- <updated>2016-01-19T08:00:00Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://quality.mozilla.org/?p=49441</id>
- <link href="https://quality.mozilla.org/2016/01/aurora-45-0-testday-results/" rel="alternate" type="text/html"/>
- <title>Aurora 45.0 Testday Results</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Howdy mozillians! Last week – on Friday, January 15th – we held Aurora 45.0 Testday; and, of course, it was another outstanding event! Thank you all – Mahmoudi Dris, Iryna Thompson, Chandrakant Dhutadmal, Preethi Dhinesh, Moin Shaikh, Ilse Macías, Hossain Al Ikram, Rezaul Huque Nayeem, Tahsan Chowdhury Akash, Kazi Nuzhat Tasnem, Fahmida … <a class="go" href="https://quality.mozilla.org/2016/01/aurora-45-0-testday-results/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Howdy mozillians!</p>
- <p>Last week – on <em>Friday, January 15th</em> – we held <a href="https://quality.mozilla.org/2016/01/firefox-45-0-aurora-testday-january-15th/">Aurora 45.0 Testday</a>; and, of course, it was another outstanding event!</p>
- <p><strong>Thank you</strong> all – <span class="author-a-oz90z4z89zz89za7qfz70zda5z87zxz85z i"><i>Mahmoudi Dris, Iryna Thompson, Chandrakant Dhutadmal, Preethi Dhinesh, Moin Shaikh, Ilse Macías, Hossain Al Ikram, Rezaul Huque Nayeem, Tahsan Chowdhury Akash, Kazi Nuzhat Tasnem, Fahmida Noor, Tazin Ahmed, Md. Ehsanul Hassan, Mohammad Maruf Islam, Kazi Sakib Ahmad, Khalid Syfullah Zaman, Asiful Kabir, Tabassum Mehnaz, Hasibul Hasan, Saddam Hossain, Mohammad Kamran Hossain, Amlan Biswas, Fazle Rabbi, Mohammed Jawad Ibne Ishaque, Asif Mahmud Shuvo, Nazir Ahmed Sabbir, Md. Raihan Ali, Md. Almas Hossain, Sadik Khan, Md. Faysal Alam Riyad, Faisal Mahmud, Md. Oliullah Sizan, Asif Mahmud Rony, Forhad Hossain </i>and<i> Tanvir Rahman </i></span>– for the participation!</p>
- <p>A big <strong>thank you</strong> to all our active moderators too!</p>
- <p><span style="color: #333333;"><span style="font-family: 'Open Sans', sans-serif;"><span style="font-size: medium;"><u>Results:</u></span></span></span></p>
- <ul>
- <li><span style="color: #333333;"><span style="font-family: 'Open Sans', sans-serif;"><span style="font-size: medium;"><strong>15</strong> issues were verified: </span></span></span><span style="color: #333333;"><span style="font-family: 'Open Sans', sans-serif;"><span style="font-size: medium;"> <span style="font-weight: 400;"><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1235821">1235821</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1228518">1228518</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1165637">1165637</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1232647">1232647</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1235379">1235379</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=842356">842356</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1222971">1222971</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=915962">915962</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1180761">1180761</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1218455">1218455</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1222747">1222747</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1210752">1210752</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1198450">1198450</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1222820">1222820</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1225514">1225514</a></span></span></span></span></li>
- <li><strong>1</strong> bug was triaged: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1230789"><span style="font-weight: 400;">1230789</span></a></li>
- <li>some failures were mentioned for <i>Search Refactoring </i>feature in the etherpads (<a href="https://public.etherpad-mozilla.org/p/testday-20160115">link 1</a> and <a href="https://public.etherpad-mozilla.org/p/bangladesh.testday-15012016">link 2</a>); please feel free to add the requested details in the etherpads or, even better, join us on <a href="http://widget01.mibbit.com/?server=irc.mozilla.org&amp;channel=%23qa" target="_blank">#qa IRC channel</a> and let’s figure them out</li>
- </ul>
- <p>I <strong>strongly</strong> advise everyone of you to reach out to us, the moderators, via <a href="http://widget01.mibbit.com/?server=irc.mozilla.org&amp;channel=%23qa">#qa</a> during the events when you encountered any kind of failures. Keep up the great work! \o/</p>
- <p>And keep an eye on QMO for upcoming events! <img alt="&#x1F609;" class="wp-smiley" src="https://s.w.org/images/core/emoji/72x72/1f609.png" style="height: 1em;"/></p></div>
- </content>
- <updated>2016-01-19T07:51:57Z</updated>
- <category term="Community"/>
- <category term="Events"/>
- <category term="QMO News"/>
- <author>
- <name>Alexandra Lucinet</name>
- </author>
- <source>
- <id>https://quality.mozilla.org</id>
- <link href="https://quality.mozilla.org/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://quality.mozilla.org" rel="alternate" type="text/html"/>
- <subtitle>Driving quality across Mozilla with data, metrics and a strong community focus</subtitle>
- <title>Mozilla Quality Assurance</title>
- <updated>2016-01-26T14:46:39Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en">
- <id>http://blog.monotonous.org/?p=678</id>
- <link href="http://blog.monotonous.org/2016/01/18/its-mlk-day-and-its-not-too-late-to-do-something-about-it/" rel="alternate" type="text/html"/>
- <link href="http://blog.monotonous.org/2016/01/18/its-mlk-day-and-its-not-too-late-to-do-something-about-it/#comments" rel="replies" type="text/html"/>
- <link href="http://blog.monotonous.org/2016/01/18/its-mlk-day-and-its-not-too-late-to-do-something-about-it/feed/atom/" rel="replies" type="application/atom+xml"/>
- <title xml:lang="en">It’s MLK Day and It’s Not Too Late to Do Something About It</title>
- <summary type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml">For the last three years I have had the opportunity to send out a reminder to Mozilla staff that Martin Luther King Jr. Day is coming up, and that U.S. employees get the day off. It has turned into my MLK Day eve ritual. I read his letters, listen to speeches, and then I compose […]<img alt="" border="0" height="1" src="http://pixel.wp.com/b.gif?host=blog.monotonous.org&amp;blog=34885741&amp;post=678&amp;subd=blogdotmonotonousdotorg&amp;ref=&amp;feed=1" width="1"/></div>
- </summary>
- <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>For the last three years I have had the opportunity to send out a reminder to Mozilla staff that Martin Luther King Jr. Day is coming up, and that U.S. employees get the day off. It has turned into my MLK Day eve ritual. I read his letters, listen to speeches, and then I compose a belabored paragraph about Dr. King with some choice quotes.</p>
- <p>If you didn’t get a chance to celebrate Dr. King’s legacy and the movements he was a part of, you still have a chance:</p>
- <ul>
- <li>Watch <a href="http://www.imdb.com/title/tt1020072/" target="_blank">Selma.</a></li>
- <li>Watch <a href="http://www.imdb.com/title/tt1592527/" target="_blank">The Black Power Mixtape</a> (it’s on Netflix).</li>
- <li>Read <a href="http://www.africa.upenn.edu/Articles_Gen/Letter_Birmingham.html" target="_blank">A Letter from a Birmingham Jail</a> (it’s really really good).</li>
- <li>Listen to his speech <a href="https://www.youtube.com/watch?v=3Qf6x9_MLD0" target="_blank">Beyond Vietnam</a>.</li>
- <li>Listen to his last speech <a href="https://www.youtube.com/watch?v=IDl84vusXos" target="_blank">I Have Been To The Mountaintop</a>.</li>
- </ul><br/> <a href="http://feeds.wordpress.com/1.0/gocomments/blogdotmonotonousdotorg.wordpress.com/678/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/blogdotmonotonousdotorg.wordpress.com/678/"/></a> <img alt="" border="0" height="1" src="http://pixel.wp.com/b.gif?host=blog.monotonous.org&amp;blog=34885741&amp;post=678&amp;subd=blogdotmonotonousdotorg&amp;ref=&amp;feed=1" width="1"/></div>
- </content>
- <updated>2016-01-18T23:35:19Z</updated>
- <published>2016-01-18T23:34:26Z</published>
- <category scheme="http://blog.monotonous.org" term="Personal"/>
- <category scheme="http://blog.monotonous.org" term="Software"/>
- <category scheme="http://blog.monotonous.org" term="World Affairs"/>
- <author>
- <name>Eitan</name>
- <uri>http://mememe82.wordpress.com/</uri>
- </author>
- <source>
- <id>http://blog.monotonous.org/feed/atom/</id>
- <link href="http://blog.monotonous.org" rel="alternate" type="text/html"/>
- <link href="http://blog.monotonous.org/feed/atom/" rel="self" type="application/atom+xml"/>
- <link href="http://blog.monotonous.org/osd.xml" rel="search" title="Monotonous.org" type="application/opensearchdescription+xml"/>
- <link href="https://s1.wp.com/opensearch.xml" rel="search" title="WordPress.com" type="application/opensearchdescription+xml"/>
- <link href="http://blog.monotonous.org/?pushpress=hub" rel="hub" type="text/html"/>
- <subtitle xml:lang="en">Eitan's Pitch</subtitle>
- <title xml:lang="en">Monotonous.org</title>
- <updated>2016-01-18T23:45:54Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://www.ncameron.org/blog/rss/0e4d587c-380c-40ce-954a-7206f69bc1dd</id>
- <link href="http://www.ncameron.org/blog/libmacro/" rel="alternate" type="text/html"/>
- <title>Libmacro</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>As I outlined in an <a href="http://ncameron.org/blog/procedural-macros-framework/">earlier post</a>, libmacro is a new crate designed to be used by procedural macro authors. It provides the basic API for procedural macros to interact with the compiler. I expect higher level functionality to be provided by library crates. In this post I'll go into</p></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>As I outlined in an <a href="http://ncameron.org/blog/procedural-macros-framework/">earlier post</a>, libmacro is a new crate designed to be used by procedural macro authors. It provides the basic API for procedural macros to interact with the compiler. I expect higher level functionality to be provided by library crates. In this post I'll go into a bit more detail about the API I think should be exposed here.</p>
-
- <p>This is a lot of stuff. I've probably missed something. If you use syntax extensions today and do something with libsyntax that would not be possible with libmacro, please let me know!</p>
-
- <p>I previously introduced <code>MacroContext</code> as one of the gateways to libmacro. All procedural macros will have access to a <code>&amp;mut MacroContext</code>.</p>
-
- <h3>Tokens</h3>
-
- <p>I described the <code>tokens</code> module in the last post, I won't repeat that here.</p>
-
- <p>There are a few more things I thought of. I mentioned a <code>TokenStream</code> which is a sequence of tokens. We should also have <code>TokenSlice</code> which is a borrowed slice of tokens (the slice to <code>TokenStream</code>'s <code>Vec</code>). These should implement the standard methods for sequences, in particular they support iteration, so can be <code>map</code>ed, etc.</p>
-
- <p>In the earlier blog post, I talked about a token kind called <code>Delimited</code> which contains a delimited sequence of tokens. I would like to rename that to <code>Sequence</code> and add a <code>None</code> variant to the <code>Delimiter</code> enum. The <code>None</code> option is so that we can have blocks of tokens without using delimiters. It will be used for noting unsafety and other properties of tokens. Furthermore, it is useful for macro expansion (replacing the interpolated AST tokens currently present). Although <code>None</code> blocks do not affect scoping, they do affect precedence and parsing.</p>
-
- <p>We should provide API for creating tokens. By default these have no hygiene information and come with a span which has no place in the source code, but shows the source of the token to be the procedural macro itself (see below for how this interacts with expansion of the current macro). I expect a <code>make_</code> function for each kind of token. We should also have API for creating macros in a given scope (which do the same thing but with provided hygiene information). This could be considered an over-rich API, since the hygiene information could be set after construction. However, since hygiene is fiddly and annoying to get right, we should make it as easy as possible to work with.</p>
-
- <p>There should also be a function for creating a token which is just a fresh name. This is useful for creating new identifiers. Although this can be done by interning a string and then creating a token around it, it is used frequently enough to deserve a helper function.</p>
-
- <h3>Emitting errors and warnings</h3>
-
- <p>Procedural macros should report errors, warnings, etc. via the <code>MacroContext</code>. They should avoid panicking as much as possible since this will crash the compiler (once <code>catch_panic</code> is available, we should use it to catch such panics and exit gracefully, however, they will certainly still meaning aborting compilation).</p>
-
- <p>Libmacro will 're-export' <code>DiagnosticBuilder</code> from <a href="https://dxr.mozilla.org/rust/source/src/libsyntax/errors/mod.rs">syntax::errors</a>. I don't actually expect this to be a literal re-export. We will use libmacro's version of <code>Span</code>, for example.</p>
-
- <pre><code>impl MacroContext {
- pub fn struct_error(&amp;self, &amp;str) -&gt; DiagnosticBuilder;
- pub fn error(&amp;self, Option&lt;Span&gt;, &amp;str);
- }
-
- pub mod errors {
- pub struct DiagnosticBuilder { ... }
- impl DiagnosticBuilder { ... }
- pub enum ErrorLevel { ... }
- }
- </code></pre>
-
- <p>There should be a macro <code>try_emit!</code>, which reduces a <code>Result&lt;T, ErrStruct&gt;</code> to a T or calls <code>emit()</code> and then calls <code>unreachable!()</code> (if the error is not fatal, then it should be upgraded to a fatal error).</p>
-
- <h3>Tokenising and quasi-quoting</h3>
-
- <p>The simplest function here is <code>tokenize</code> which takes a string (<code>&amp;str</code>) and returns a <code>Result&lt;TokenStream, ErrStruct&gt;</code>. The string is treated like source text. The success option is the tokenised version of the string. I expect this function must take a <code>MacroContext</code> argument.</p>
-
- <p>We will offer a quasi-quoting macro. This will return a <code>TokenStream</code> (in contrast to today's quasi-quoting which returns AST nodes), to be precise a <code>Result&lt;TokenStream, ErrStruct&gt;</code>. The string which is quoted may include metavariables (<code>$x</code>), and these are filled in with variables from the environment. The type of the variables should be either a <code>TokenStream</code>, a <code>TokenTree</code>, or a <code>Result&lt;TokenStream, ErrStruct&gt;</code> (in this last case, if the variable is an error, then it is just returned by the macro). For example,</p>
-
- <pre><code>fn foo(cx: &amp;mut MacroContext, tokens: TokenStream) -&gt; TokenStream {
- quote!(cx, fn foo() { $tokens }).unwrap()
- }
- </code></pre>
-
- <p>The <code>quote!</code> macro can also handle multiple tokens when the variable corresponding with the metavariable has type <code>[TokenStream]</code> (or is dereferencable to it). In this case, the same syntax as used in macros-by-example can be used. For example, if <code>x: Vec&lt;TokenStream&gt;</code> then <code>quote!(cx, ($x),*)</code> will produce a <code>TokenStream</code> of a comma-separated list of tokens from the elements of <code>x</code>.</p>
-
- <p>Since the <code>tokenize</code> function is a degenerate case of quasi-quoting, an alternative would be to always use <code>quote!</code> and remove <code>tokenize</code>. I believe there is utility in the simple function, and it must be used internally in any case.</p>
-
- <p>These functions and macros should create tokens with spans and hygiene information set as described above for making new tokens. We might also offer versions which takes a scope and uses that as the context for tokenising.</p>
-
- <h3>Parsing helper functions</h3>
-
- <p>There are some common patterns for tokens to follow in macros. In particular those used as arguments for attribute-like macros. We will offer some functions which attempt to parse tokens into these patterns. I expect there will be more of these in time; to start with:</p>
-
- <pre><code>pub mod parsing {
- // Expects `(foo = "bar"),*`
- pub fn parse_keyed_values(&amp;TokenSlice, &amp;mut MacroContext) -&gt; Result&lt;Vec&lt;(InternedString, String)&gt;, ErrStruct&gt;;
- // Expects `"bar"`
- pub fn parse_string(&amp;TokenSlice, &amp;mut MacroContext) -&gt; Result&lt;String, ErrStruct&gt;;
- }
- </code></pre>
-
- <p>To be honest, given the token design in the last post, I think <code>parse_string</code> is unnecessary, but I wanted to give more than one example of this kind of function. If <code>parse_keyed_values</code> is the only one we end up with, then that is fine.</p>
-
- <h3>Pattern matching</h3>
-
- <p>The goal with the pattern matching API is to allow procedural macros to operate on tokens in the same way as macros-by-example. The pattern language is thus the same as that for macros-by-example.</p>
-
- <p>There is a single macro, which I propose calling <code>matches</code>. Its first argument is the name of a <code>MacroContext</code>. Its second argument is the input, which must be a <code>TokenSlice</code> (or dereferencable to one). The third argument is a pattern definition. The macro produces a <code>Result&lt;T, ErrStruct&gt;</code> where <code>T</code> is the type produced by the pattern arms. If the pattern has multiple arms, then each arm must have the same type. An error is produced if none of the arms in the pattern are matched.</p>
-
- <p>The pattern language follows the language for defining macros-by-example (but is slightly stricter). There are two forms, a single pattern form and a multiple pattern form. If the first character is a <code>{</code> then the pattern is treated as a multiple pattern form, if it starts with <code>(</code> then as a single pattern form, otherwise an error (causes a panic with a <code>Bug</code> error, as opposed to returning an <code>Err</code>).</p>
-
- <p>The single pattern form is <code>(pattern) =&gt; { code }</code>. The multiple pattern form is <code>{(pattern) =&gt; { code } (pattern) =&gt; { code } ... (pattern) =&gt; { code }}</code>. <code>code</code> is any old Rust code which is executed when the corresponding pattern is matched. The pattern follows from macros-by-example - it is a series of characters treated as literals, meta-variables indicated with <code>$</code>, and the syntax for matching multiple variables. Any meta-variables are available as variables in the righthand side, e.g., <code>$x</code> becomes available as <code>x</code>. These variables have type <code>TokenStream</code> if they appear singly or <code>Vec&lt;TokenStream&gt;</code> if they appear multiply (or <code>Vec&lt;Vec&lt;TokenStream&gt;&gt;</code> and so forth).</p>
-
- <p>Examples:</p>
-
- <pre><code>matches!(cx, input, (foo($x:expr) bar) =&gt; {quote(cx, foo_bar($x).unwrap()}).unwrap()
-
- matches!(cx, input, {
- () =&gt; {
- cx.err("No input?");
- }
- (foo($($x:ident),+ bar) =&gt; {
- println!("found {} idents", x.len());
- quote!(($x);*).unwrap()
- }
- }
- })
- </code></pre>
-
- <p>Note that since we match AST items here, our backwards compatibility story is a bit complicated (though hopefully not much more so than with current macros).</p>
-
- <h3>Hygiene</h3>
-
- <p>The intention of the design is that the actual hygiene algorithm applied is irrelevant. Procedural macros should be able to use the same API if the hygiene algorithm changes (of course the result of applying the API might change). To this end, all hygiene objects are opaque and cannot be directly manipulated by macros.</p>
-
- <p>I propose one module (<code>hygiene</code>) and two types: <code>Context</code> and <code>Scope</code>.</p>
-
- <p>A <code>Context</code> is attached to each token and contains all hygiene information about that token. If two tokens have the same <code>Context</code>, then they may be compared syntactically. The reverse is not true - two tokens can have different <code>Context</code>s and still be equal. <code>Context</code>s can only be created by applying the hygiene algorithm and cannot be manipulated, only moved and stored.</p>
-
- <p><code>MacroContext</code> has a method <code>fresh_hygiene_context</code> for creating a new, fresh <code>Context</code> (i.e., a <code>Context</code> not shared with any other tokens).</p>
-
- <p><code>MacroContext</code> has a method <code>expansion_hygiene_context</code> for getting the <code>Context</code> where the macro is defined. This is equivalent to <code>.expansion_scope().direct_context()</code>, but might be more efficient (and I expect it to be used a lot).</p>
-
- <p>A <code>Scope</code> provides information about a position within an AST at a certain point during macro expansion. For example,</p>
-
- <pre><code>fn foo() {
- a
- {
- b
- c
- }
- }
- </code></pre>
-
- <p><code>a</code> and <code>b</code> will have different <code>Scope</code>s. <code>b</code> and <code>c</code> will have the same <code>Scope</code>s, even if <code>b</code> was written in this position and <code>c</code> is due to macro expansion. However, a <code>Scope</code> may contain more information than just the syntactic scopes, for example, it may contain information about pending scopes yet to be applied by the hygiene algorithm (i.e., information about <code>let</code> expressions which are in scope).</p>
-
- <p>Note that a <code>Scope</code> means a scope in the macro hygiene sense, not the commonly used sense of a scope declared with <code>{}</code>. In particular, each <code>let</code> statement starts a new scope and the items and statements in a function body are in different scopes.</p>
-
- <p>The functions <code>lookup_item_scope</code> and <code>lookup_statement_scope</code> take a <code>MacroContext</code> and a path, represented as a <code>TokenSlice</code>, and return the <code>Scope</code> which that item defines or an error if the path does not refer to an item, or the item does not define a scope of the right kind.</p>
-
- <p>The function <code>lookup_scope_for</code> is similar, but returns the <code>Scope</code> in which an item is declared.</p>
-
- <p><code>MacroContext</code> has a method <code>expansion_scope</code> for getting the scope in which the current macro is being expanded.</p>
-
- <p><code>Scope</code> has a method <code>direct_context</code> which returns a <code>Context</code> for items declared directly (c.f., via macro expansion) in that <code>Scope</code>.</p>
-
- <p><code>Scope</code> has a method <code>nested</code> which creates a fresh <code>Scope</code> nested within the receiver scope.</p>
-
- <p><code>Scope</code> has a static method <code>empty</code> for creating an empty scope, that is one with no scope information at all (note that this is different from a top-level scope).</p>
-
- <p>I expect the exact API around <code>Scope</code>s and <code>Context</code>s will need some work. <code>Scope</code> seems halfway between an intuitive, algorithm-neutral abstraction, and the scopes from the sets of scopes hygiene algorithm. I would prefer a <code>Scope</code> should be more abstract, on the other hand, macro authors may want fine-grained control over hygiene application.</p>
-
- <h4>Manipulating hygiene information on tokens,</h4>
-
- <pre><code>pub mod hygiene {
- pub fn add(cx: &amp;mut MacroContext, t: &amp;Token, scope: &amp;Scope) -&gt; Token;
- // Maybe unnecessary if we have direct access to Tokens.
- pub fn set(t: &amp;Token, cx: &amp;Context) -&gt; Token;
- // Maybe unnecessary - can use set with cx.expansion_hygiene_context().
- // Also, bad name.
- pub fn current(cx: &amp;MacroContext, t: &amp;Token) -&gt; Token;
- }
- </code></pre>
-
- <p><code>add</code> adds <code>scope</code> to any context already on <code>t</code> (<code>Context</code> should have a similar method). Note that the implementation is a bit complex - the nature of the <code>Scope</code> might mean we replace the old context completely, or add to it.</p>
-
- <h4>Applying hygiene when expanding the current macro</h4>
-
- <p>By default, the current macro will be expanded in the standard way, having hygiene applied as expected. Mechanically, hygiene information is added to tokens when the macro is expanded. Assuming the sets of scopes algorithm, scopes (for example, for the macro's definition, and for the introduction) are added to any scopes already present on the token. A token with no hygiene information will thus behave like a token in a macro-by-example macro. Hygiene due to nested scopes created by the macro do not need to be taken into account by the macro author, this is handled at expansion time.</p>
-
- <p>Procedural macro authors may want to customise hygiene application (it is common in Racket), for example, to introduce items that can be referred to by code in the call-site scope.</p>
-
- <p>We must provide an option to expand the current macro without applying hygiene; the macro author must then handle hygiene. For this to work, the macro must be able to access information about the scope in which it is applied (see <code>MacroContext::expansion_scope</code>, above) and to supply a <code>Scope</code> indicating scopes that should be added to tokens following the macro expansion.</p>
-
- <pre><code>pub mod hygiene {
- pub enum ExpansionMode {
- Automatic,
- Manual(Scope),
- }
- }
-
- impl MacroContext {
- pub fn set_hygienic_expansion(hygiene::ExpansionMode);
- }
- </code></pre>
-
- <p>We may wish to offer other modes for expansion which allow for tweaking hygiene application without requiring full manual application. One possible mode is where the author provides a <code>Scope</code> for the macro definition (rather than using the scope where the macro is actually defined), but hygiene is otherwise applied automatically. We might wish to give the author the option of applying scopes due to the macro definition, but not the introduction scopes.</p>
-
- <p>On a related note, might we want to affect how spans are applied when the current macro is expanded? I can't think of a use case right now, but it seems like something that might be wanted.</p>
-
- <p>Blocks of tokens (that is a <code>Sequence</code> token) may be marked (not sure how, exactly, perhaps using a distinguished context) such that it is expanded without any hygiene being applied or spans changed. There should be a function for creating such a <code>Sequence</code> from a <code>TokenSlice</code> in the <code>tokens</code> module. The primary motivation for this is to handle the tokens representing the body on which an annotation-like macro is present. For a 'decorator' macro, these tokens will be untouched (passed through by the macro), and since they are not touched by the macro, they should appear untouched by it (in terms of hygiene and spans).</p>
-
- <h3>Applying macros</h3>
-
- <p>We provide functionality to expand a provided macro or to lookup and expand a macro.</p>
-
- <pre><code>pub mod apply {
- pub fn expand_macro(cx: &amp;mut MacroContext,
- expansion_scope: Scope,
- macro: &amp;TokenSlice,
- macro_scope: Scope,
- input: &amp;TokenSlice)
- -&gt; Result&lt;(TokenStream, Scope), ErrStruct&gt;;
- pub fn lookup_and_expand_macro(cx: &amp;mut MacroContext,
- expansion_scope: Scope,
- macro: &amp;TokenSlice,
- input: &amp;TokenSlice)
- -&gt; Result&lt;(TokenStream, Scope), ErrStruct&gt;;
- }
- </code></pre>
-
- <p>These functions apply macro hygiene in the usual way, with <code>expansion_scope</code> dictating the scope into which the macro is expanded. Other spans and hygiene information is taken from the tokens. <code>expand_macro</code> takes pending scopes from <code>macro_scope</code>, <code>lookup_and_expand_macro</code> uses the proper pending scopes. In order to apply the hygiene algorithm, the result of the macro must be parsable. The returned scope will contain pending scopes that can be applied by the macro to subsequent tokens.</p>
-
- <p>We could provide versions that don't take an <code>expansion_scope</code> and use <code>cx.expansion_scope()</code>. Probably unnecessary.</p>
-
- <pre><code>pub mod apply {
- pub fn expand_macro_unhygienic(cx: &amp;mut MacroContext,
- macro: &amp;TokenSlice,
- input: &amp;TokenSlice)
- -&gt; Result&lt;TokenStream, ErrStruct&gt;;
- pub fn lookup_and_expand_macro_unhygienic(cx: &amp;mut MacroContext,
- macro: &amp;TokenSlice,
- input: &amp;TokenSlice)
- -&gt; Result&lt;TokenStream, ErrStruct&gt;;
- }
- </code></pre>
-
- <p>The <code>_unhygienic</code> variants expand a macro as in the first functions, but do not apply the hygiene algorithm or change any hygiene information. Any hygiene information on tokens is preserved. I'm not sure if <code>_unhygienic</code> are the right names - using these is not necessarily unhygienic, just that we are automatically applying the hygiene algorithm.</p>
-
- <p>Note that all these functions are doing an eager expansion of macros, or in Scheme terms they are <code>local-expand</code> functions. </p>
-
- <h3>Looking up items</h3>
-
- <p>The function <code>lookup_item</code> takes a <code>MacroContext</code> and a path represented as a <code>TokenSlice</code> and returns a <code>TokenStream</code> for the item referred to by the path, or an error if name resolution failed. I'm not sure where this function should live.</p>
-
- <h3>Interned strings</h3>
-
- <pre><code>pub mod strings {
- pub struct InternedString;
-
- impl InternedString {
- pub fn get(&amp;self) -&gt; String;
- }
-
- pub fn intern(cx: &amp;mut MacroContext, s: &amp;str) -&gt; Result&lt;InternedString, ErrStruct&gt;;
- pub fn find(cx: &amp;mut MacroContext, s: &amp;str) -&gt; Result&lt;InternedString, ErrStruct&gt;;
- pub fn find_or_intern(cx: &amp;mut MacroContext, s: &amp;str) -&gt; Result&lt;InternedString, ErrStruct&gt;;
- }
- </code></pre>
-
- <p><code>intern</code> interns a string and returns a fresh <code>InternedString</code>. <code>find</code> tries to find <em>an</em> existing <code>InternedString</code>.</p>
-
- <h3>Spans</h3>
-
- <p>A span gives information about where in the source code a token is defined. It also gives information about where the token came from (how it was generated, if it was generated code).</p>
-
- <p>There should be a <code>spans</code> module in libmacro, which will include a <code>Span</code> type which can be easily inter-converted with the <code>Span</code> defined in libsyntax. Libsyntax spans currently include information about stability, this will not be present in libmacro spans.</p>
-
- <p>If the programmer does nothing special with spans, then they will be 'correct' by default. There are two important cases: tokens passed to the macro and tokens made fresh by the macro. The former will have the source span indicating where they were written and will include their history. The latter will have no source span and indicate they were created by the current macro. All tokens will have the history relating to expansion of the current macro added when the macro is expanded. At macro expansion, tokens with no source span will be given the macro use-site as their source.</p>
-
- <p><code>Span</code>s can be freely copied between tokens.</p>
-
- <p>It will probably useful to make it easy to manipulate spans. For example, rather than point at the macro's defining function, point at a helper function where the token is made. Or to set the origin to the current macro when the token was produced by another which should an implementation detail. I'm not sure what such an interface should look like (and is probably not necessary in an initial library).</p>
-
- <h3>Feature gates</h3>
-
- <pre><code>pub mod features {
- pub enum FeatureStatus {
- // The feature gate is allowed.
- Allowed,
- // The feature gate has not been enabled.
- Disallowed,
- // Use of the feature is forbidden by the compiler.
- Forbidden,
- }
-
- pub fn query_feature(cx: &amp;MacroContext, feature: Token) -&gt; Result&lt;FeatureStatus, ErrStruct&gt;;
- pub fn query_feature_by_str(cx: &amp;MacroContext, feature: &amp;str) -&gt; Result&lt;FeatureStatus, ErrStruct&gt;;
- pub fn query_feature_unused(cx: &amp;MacroContext, feature: Token) -&gt; Result&lt;FeatureStatus, ErrStruct&gt;;
- pub fn query_feature_by_str_unused(cx: &amp;MacroContext, feature: &amp;str) -&gt; Result&lt;FeatureStatus, ErrStruct&gt;;
-
- pub fn used_feature_gate(cx: &amp;MacroContext, feature: Token) -&gt; Result&lt;(), ErrStruct&gt;;
- pub fn used_feature_by_str(cx: &amp;MacroContext, feature: &amp;str) -&gt; Result&lt;(), ErrStruct&gt;;
-
- pub fn allow_feature_gate(cx: &amp;MacroContext, feature: Token) -&gt; Result&lt;(), ErrStruct&gt;;
- pub fn allow_feature_by_str(cx: &amp;MacroContext, feature: &amp;str) -&gt; Result&lt;(), ErrStruct&gt;;
- pub fn disallow_feature_gate(cx: &amp;MacroContext, feature: Token) -&gt; Result&lt;(), ErrStruct&gt;;
- pub fn disallow_feature_by_str(cx: &amp;MacroContext, feature: &amp;str) -&gt; Result&lt;(), ErrStruct&gt;;
- }
- </code></pre>
-
- <p>The <code>query_*</code> functions query if a feature gate has been set. They return an error if the feature gate does not exist. The <code>_unused</code> variants do not mark the feature gate as used. The <code>used_</code> functions mark a feature gate as used, or return an error if it does not exist.</p>
-
- <p>The <code>allow_</code> and <code>disallow_</code> functions set a feature gate as allowed or disallowed for the current crate. These functions will only affect feature gates which take affect after parsing and expansion are complete. They do not affect feature gates which are checked during parsing or expansion.</p>
-
- <p>Question: do we need the <code>used_</code> functions? Could just call <code>query_</code> and ignore the result.</p>
-
- <h3>Attributes</h3>
-
- <p>We need some mechanism for setting attributes as used. I don't actually know how the unused attribute checking in the compiler works, so I can't spec this area. But, I expect <code>MacroContext</code> to make available some interface for reading attributes on a macro use and marking them as used.</p></div>
- </content>
- <updated>2016-01-18T21:40:42Z</updated>
- <category term="Mozilla"/>
- <category term="Rust"/>
- <author>
- <name>Nick Cameron</name>
- </author>
- <source>
- <id>http://www.ncameron.org/blog/</id>
- <link href="http://www.ncameron.org/blog/" rel="alternate" type="text/html"/>
- <link href="http://www.ncameron.org/blog/rss/" rel="self" type="application/rss+xml"/>
- <subtitle>I'm a research engineer at Mozilla working on Rust: the language, compiler, and tools. @nick_r_cameron</subtitle>
- <title>featherweight musings</title>
- <updated>2016-01-21T08:46:18Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://geekyogre.com/rss/63eb682d-66b4-447d-8fb6-f4ed448019df</id>
- <link href="http://geekyogre.com/skizze-progress-and-repl/" rel="alternate" type="text/html"/>
- <title>Skizze progress and REPL</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><img align="center" height="190" src="http://i.imgur.com/9z47NdA.png" width="600"/> <br/>
- <br/> <br/>
- Over the last 3 weeks, based on feedback we proceeded fledging out the concepts and the code behind <a href="https://github.com/skizzehq/skizze">Skizze</a>. <br/>
- <a href="https://medium.com/@njpatel/">Neil Patel</a> suggested the following:</p>
-
- <hr/>
-
- <p><em>So I've been thinking about the server API. I think we want to choose one thing and do it as well as possible, instead of having</em></p></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><img align="center" height="190" src="http://i.imgur.com/9z47NdA.png" width="600"/> <br/>
- <br/> <br/>
- Over the last 3 weeks, based on feedback we proceeded fledging out the concepts and the code behind <a href="https://github.com/skizzehq/skizze">Skizze</a>. <br/>
- <a href="https://medium.com/@njpatel/">Neil Patel</a> suggested the following:</p>
-
- <hr/>
-
- <p><em>So I've been thinking about the server API. I think we want to choose one thing and do it as well as possible, instead of having six ways to talk to the server. I think that helps to keep things sane and simple overall.</em></p>
-
- <p><em>Thinking about usage, I can only really imagine Skizze in an environment like <a href="https://xamarin.com/insights">ours</a>, which is high-throughput. I think that is it's 'home' and we should be optimising for that all day long.</em></p>
-
- <p><em>Taking that into account, I believe we have two options:</em></p>
-
- <ol>
- <li><p><em>We go the gRPC route, provide .proto files and let people use the existing gRPC tooling to build support for their favourite language. That means we can happily give Ruby/Node/C#/etc devs a real way to get started up with Skizze almost immediately, piggy-backing on the gRPC docs etc.</em></p></li>
- <li><p><em>We absorb the Redis Protocol. It does everything we need, is very lean, and we can (mostly) easily adapt it for what we need to do. The downside is that to get support from other libs, there will have to be actual libraries for every language. This could slow adoption, or it might be easy enough if people can reuse existing REDIS code. It's hard to tell how that would end up.</em></p></li>
- </ol>
-
- <p><em>gRPC is interesting because it's built already for distributed systems, across bad networks, and obviously is bi-directional etc. Without us having to spend time on the protocol, gRPC let's us easily add features that require streaming. Like, imagine a client being able to listen for changes in count/size and be notified instantly. That's something that gRPC is built for right now.</em></p>
-
- <p><em>I think gRPC is a bit verbose, but I think it'll pay off for ease of third-party lib support and as things grow.</em></p>
-
- <p><em>The CLI could easily be built to work with gRPC, including adding support for streaming stuff etc. Which could be pretty exciting.</em></p>
-
- <hr/>
-
- <p>That being said, we gave Skizze <a href="https://github.com/skizzehq/">a new home</a>, where based on feedback we developed .proto files and started rewriting big chunks of the code.</p>
-
- <p>We added a new wrapper called "domain" which represents a stream. It wraps around Count-Min-Log, Bloom Filter, Top-K and HyperLogLog++, so when feeding it values it feeds all the sketches. Later we intend to allow attaching and detaching sketches from "domains" (We need a better name).</p>
-
- <p>We also implemented a gRPC API which should allow easy wrapper creation in other languages.</p>
-
- <p>Special thanks go to <a href="https://twitter.com/martinpintob">Martin Pinto</a> for helping out with unit tests and <a href="http://dopeness.org">Soren Macbeth</a> for thorough feedback and ideas about the "domain" concept. <br/>
- Take a look at our initial REPL work there:</p>
-
- <p><a href="http://geekyogre.com/content/images/2016/01/MBCY64aaKL.gif"><img alt="Link to this page" border="0" src="http://geekyogre.com/content/images/2016/01/skizze-1.png"/></a> <br/>
- <a href="http://geekyogre.com/content/images/2016/01/MBCY64aaKL.gif">click for GIF</a></p></div>
- </content>
- <updated>2016-01-18T17:41:43Z</updated>
- <category term="Big Data"/>
- <category term="Data Science"/>
- <author>
- <name>Seif Lotfy</name>
- </author>
- <source>
- <id>http://geekyogre.com/</id>
- <link href="http://geekyogre.com/" rel="alternate" type="text/html"/>
- <link href="http://geekyogre.com/rss/" rel="self" type="application/rss+xml"/>
- <subtitle>The geekiest ogre alive</subtitle>
- <title>Geeky Ogre</title>
- <updated>2016-01-18T18:16:25Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en">
- <id>http://dougbelshaw.com/blog/?p=39986</id>
- <link href="http://dougbelshaw.com/blog/2016/01/18/open-badges-persona/" rel="alternate" type="text/html"/>
- <title>What a post-Persona landscape means for Open Badges</title>
- <summary>Why you shouldn't worry about Mozilla's recent announcement.</summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em><strong>Note:</strong> I don’t work for Mozilla any more, so (like <a href="https://www.youtube.com/watch?v=YQHsXMglC9A">Adele</a>) these are my thoughts ‘from the outside’…</em></p>
- <hr/>
- <h3>Introduction</h3>
- <p><a href="http://openbadges.org">Open Badges</a> is no longer a <a href="http://mozilla.org">Mozilla</a> project. In fact, it hasn’t been for a while — the <a href="http://badgealliance.org">Badge Alliance</a> was set up a couple of years ago to promote the specification on a both a technical and community basis. As I stated in a recent post, this is a <strong>good</strong> thing and means that <a href="http://dougbelshaw.com/blog/2015/11/08/bright-future-badges/">the future is bright for Open Badges</a>.</p>
- <p>However, Mozilla <em>is</em> still involved with the Open Badges project: Mark Surman, Executive Director of the Mozilla Foundation, sits on the board of the Badge Alliance. Mozilla also pays for contractors to work on the <a href="http://backpack.openbadges.org">Open Badges backpack</a> and there were badges earned at the <a href="http://mozillafestival.org">Mozilla Festival</a> a few months ago.</p>
- <p>Although it may seem strange for those used to corporates interested purely in profit, Mozilla creates what the open web needs at any given time. Like any organisation, sometimes it gets these wrong, either because the concept was flawed, or because the execution was poor. Other times, I’d argue, Mozilla doesn’t give ideas and concepts enough time to gain traction.</p>
- <h3>The end of Persona at Mozilla</h3>
- <p>Open Badges, at its very essence, is a technical specification. It allows credentials with metadata hard-coded into them to be issued, exchanged, and displayed. This is done in a secure, standardised manner.</p>
- <p><img alt="OBI diagram" class="alignnone wp-image-39987 size-full" src="http://i1.wp.com/dougbelshaw.com/blog/wp-content/uploads/2016/01/obi-diagram.png?w=100%25"/></p>
- <p>For users to be able to access their ‘backpack’ (i.e. the place they store badges) they needed a secure login system.Back in 2011 at the start of the Open Badges project it made sense to make use of Mozilla’s nascent <a href="https://www.mozilla.org/en-US/persona/">Persona</a> project. This aimed to provide a way for users to easily sign into sites around the web without using their Facebook/Google logins. These ‘social’ sign-in methods mean that users are tracked around the web — something that Mozilla was obviously against.</p>
- <p>By 2014, Persona wasn’t seen to be having the kind of ‘growth trajectory’ that Mozilla wanted. The project was transferred to <a href="http://identity.mozilla.com/post/78873831485/transitioning-persona-to-community-ownership">community ownership</a> and most of the team left Mozilla in 2015. It was <a href="https://groups.google.com/forum/#!msg/mozilla.dev.identity/mibOQrD6K0c/kt0NdMWbEQAJ">announced</a> that Persona would be shutting down as a Mozilla service in November 2016. While Persona will exist as an open source project, it won’t be hosted by Mozilla.</p>
- <h3>What this means for Open Badges</h3>
- <p>Although I’m not aware of an official announcement from the Badge Alliance, I think it’s worth making three points here.</p>
- <h5>1. You can still use Persona</h5>
- <p>If you’re a developer, you can still use Persona. It’s open source. It works.</p>
- <h5>2. Persona is not central to the Open Badges Infrastructure</h5>
- <p>The Open Badges backpack is <em>one</em> place where users can store their badges. There are others, including the <a href="https://openbadgepassport.com/">Open Badge Passport</a> and <a href="https://www.openbadgeacademy.com/">Open Badge Academy</a>. MacArthur, who seed-funded the Open Badges ecosystem, have a new platform launching through <a href="https://www.lrng.org/">LRNG</a>.</p>
- <p>It is up to the organisations behind these various solutions as to how they allow users to authenticate. They may choose to allow social logins. They may force users to create logins based on their email address. They may decide to use an open source version of Persona. It’s entirely up to them.</p>
- <h5>3. A post-Persona badges system has its advantages</h5>
- <p>The Persona authentication system runs off email addresses. This means that transitioning <em>from</em> Persona to another system is relatively straightforward. It has, however, meant that for the past few years we’ve had a recurrent problem: what do you do with people being issued badges to multiple email addresses?</p>
- <p>Tying badges to emails seemed like the easiest and fastest way to get to a critical mass in terms of Open Badge adoption. Now that’s worked, we need to think in a more nuanced way about allowing users to tie multiple identities to a single badge.</p>
- <h4>Conclusion</h4>
- <p>Persona was always a slightly awkward fit for Open Badges. Although, for a time, it made sense to use Persona for authentication to the Open Badges backpack, we’re now in a post-Persona landscape. This brings with it certain advantages.</p>
- <p>As Nate Otto wrote in his post <a href="https://medium.com/badge-alliance/open-badges-in-2016-a-look-ahead-3cfe5c3c9878#.l5mhiztwx">Open Badges in 2016: A Look Ahead</a>, the project is growing up. It’s time to move beyond what was expedient at the dawn of Open Badges and look to the future. I’m sad to see the decline of Persona, but I’m excited what the future holds!</p>
- <p style="text-align: right;"><em>Header image CC BY-NC-SA <a href="https://www.flickr.com/photos/blmiers2/6904758951/">Barbara</a></em></p></div>
- </content>
- <updated>2016-01-18T11:34:19Z</updated>
- <category term="Open Badges"/>
- <category term="Badge Alliance"/>
- <category term="future"/>
- <category term="Mozilla"/>
- <category term="Persona"/>
- <author>
- <name>Doug Belshaw</name>
- </author>
- <source>
- <id>http://dougbelshaw.com/blog</id>
- <logo>http://dougbelshaw.com/blog/wp-content/plugins/podpress/images/powered_by_podpress_large.jpg</logo>
- <category scheme="http://www.itunes.com/" term="education,"/>
- <category scheme="http://www.itunes.com/" term="technology,"/>
- <category scheme="http://www.itunes.com/" term="productivity,"/>
- <category scheme="http://www.itunes.com/" term="leadership,"/>
- <category scheme="http://www.itunes.com/" term="Mozilla"/>
- <category scheme="http://www.itunes.com/" term="Education"/>
- <category scheme="http://www.itunes.com/" term="Education Technology"/>
- <category scheme="http://www.itunes.com/" term="Technology"/>
- <category scheme="http://www.itunes.com/" term="Society &amp; Culture"/>
- <category scheme="http://www.itunes.com/" term="Philosophy"/>
- <author>
- <name>Doug Belshaw</name>
- <email>dajbelshaw@gmail.com</email>
- </author>
- <link href="http://dougbelshaw.com/blog/tag/mozilla/feed/" rel="self" type="application/rss+xml"/>
- <link href="http://dougbelshaw.com/blog" rel="alternate" type="text/html"/>
- <rights>Copyright © Open Educational Thinkering 2013</rights>
- <subtitle>Doug Belshaw's blog</subtitle>
- <title>Mozilla – Doug Belshaw’s blog</title>
- <updated>2016-01-23T07:46:17Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>tag:this-week-in-rust.org,2016-01-18:blog/2016/01/18/this-week-in-rust-114/</id>
- <link href="http://this-week-in-rust.org/blog/2016/01/18/this-week-in-rust-114/" rel="alternate" type="text/html"/>
- <title>This Week in Rust 114</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Hello and welcome to another issue of <em>This Week in Rust</em>!
- <a href="http://rust-lang.org">Rust</a> is a systems language pursuing the trifecta:
- safety, concurrency, and speed. This is a weekly summary of its progress and
- community. Want something mentioned? Tweet us at <a href="https://twitter.com/ThisWeekInRust">@ThisWeekInRust</a> or <a href="mailto:corey@octayn.net?subject=This%20Week%20in%20Rust%20Suggestion">send us an
- email</a>!
- Want to get involved? <a href="https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md">We love
- contributions</a>.</p>
- <p><em>This Week in Rust</em> is openly developed <a href="https://github.com/cmr/this-week-in-rust">on GitHub</a>.
- If you find any errors in this week's issue, <a href="https://github.com/cmr/this-week-in-rust/pulls">please submit a PR</a>.</p>
- <p>This week's edition was edited by: <a href="https://github.com/nasa42">nasa42</a>, <a href="https://github.com/brson">brson</a>, and <a href="https://github.com/llogiq">llogiq</a>.</p>
- <h3>Updates from Rust Community</h3>
- <h4>News &amp; Blog Posts</h4>
- <ul>
- <li><a href="http://gregchapple.com/contributing-to-the-rust-compiler/">Guide: Contributing to the Rust compiler</a>.</li>
- <li><a href="http://www.ncameron.org/blog/a-type-safe-and-zero-allocation-library-for-reading-and-navigating-elf-files/">A type-safe and zero-allocation library for reading and navigating ELF files</a>.</li>
- <li>[podcast] <a href="http://www.newrustacean.com/show_notes/e009/">New Rustacean podcast episode 09</a>. Getting into the nitty-gritty with Rust's traits.</li>
- <li><a href="https://jadpole.github.io/arcaders/arcaders-1-12/">ArcadeRS 1.12: Brawl, at last</a>! Part of the series <a href="https://jadpole.github.io/arcaders/arcaders-1-0/">ArcadeRS 1.0: The project</a> - a series whose objective is to explore the Rust programming language and ecosystem through the development of a simple, old-school shooter.</li>
- <li><a href="https://blog.thiago.me/raspberry-pi-bare-metal-programming-with-rust/">Raspberry Pi bare metal programming with Rust</a>.</li>
- <li><a href="http://blog.servo.org/2016/01/11/twis-47/">This week in Servo 47</a>.</li>
- <li><a href="http://www.redox-os.org/news/this-week-in-redox-10/">This week in Redox OS 10</a>.</li>
- </ul>
- <h4>Notable New Crates &amp; Project Updates</h4>
- <ul>
- <li><a href="https://github.com/ebkalderon/amethyst">Amethyst</a>. Data-oriented game engine written in Rust.</li>
- <li><a href="https://www.rust-lang.org/">Rust website</a> has received some <a href="https://www.reddit.com/r/rust/comments/40zxey/major_website_updates/">major updates</a>.</li>
- <li><a href="https://packages.debian.org/stretch/rustc">Rust</a> and <a href="https://packages.debian.org/stretch/cargo">Cargo</a> are now available in Debian stretch.</li>
- <li><a href="https://community.particle.io/t/rust-on-particle-call-for-contributors/19090">Rust on Particle: Call for contributors</a>.</li>
- <li><a href="https://dwrensha.github.io/capnproto-rust/2016/01/11/async-rpc.html">capnp-rpc-rust rewritten to use async I/O</a>.</li>
- <li><a href="https://github.com/Ogeon/palette">Palette</a>. A Rust library for linear color calculations and conversion.</li>
- </ul>
- <h3>Updates from Rust Core</h3>
- <p>164 pull requests were <a href="https://github.com/issues?q=is%3Apr+org%3Arust-lang+is%3Amerged+merged%3A2016-01-11..2016-01-18">merged in the last week</a>.</p>
- <p>See the <a href="https://internals.rust-lang.org/t/triage-digest-tue-jan-05-2016/3052">triage digest</a> and <a href="https://internals.rust-lang.org/t/subteam-reports-2016-01-08/3067">subteam reports</a> for more details.</p>
- <h4>Notable changes</h4>
- <ul>
- <li><a href="https://github.com/rust-lang/rust/pull/30943">std: Stabilize APIs for the 1.7 release</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/27807">Refactor and improve: Arena, TypedArena</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/29498">Let <code>str::replace</code> take a pattern</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30295">rustc_resolve: Fix bug in duplicate checking for extern crates</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30426">Rewrite BTreeMap to use parent pointers</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30446">Support generic associated consts</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30509">Add an <code>impl</code> for <code>Box&lt;Error&gt;</code> from String</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30533">Introduce "obligation forest" data structure into fulfillment to track backtraces</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30538">Remove negate_unsigned feature gate</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30567">llvm: Add support for vectorcall (X86_VectorCall) convention</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30676">Make coherence more tolerant of error types</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30740">Add fast path for ASCII in UTF-8 validation</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30753">Downgrade unit struct match via S(..) warnings to errors</a>.</li>
- <li><a href="https://github.com/rust-lang/rust/pull/30930">Move const block checks before lowering step</a>.</li>
- </ul>
- <h4>New Contributors</h4>
- <ul>
- <li>Anton Blanchard</li>
- <li>Jonas Tepe</li>
- <li>Jörg Krause</li>
- <li>Joshua Olson</li>
- <li>kalita.alexey</li>
- <li>Pierre Krieger</li>
- <li>Sergey Veselkov</li>
- <li>Simon Martin</li>
- <li>Steffen</li>
- <li>tomaka</li>
- </ul>
- <h4>Approved RFCs</h4>
- <p>Changes to Rust follow the Rust <a href="https://github.com/rust-lang/rfcs#rust-rfcs">RFC (request for comments)
- process</a>. These
- are the RFCs that were approved for implementation this week:</p>
- <ul>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1331">RFC 1331: <code>src/grammar</code> for the canonical grammar of the Rust language</a>.</li>
- </ul>
- <h4>Final Comment Period</h4>
- <p>Every week <a href="https://rust-lang.org/team.html">the team</a> announces the
- 'final comment period' for RFCs and key PRs which are reaching a
- decision. Express your opinions now. <a href="https://github.com/rust-lang/rfcs/labels/final-comment-period">This week's FCPs</a> are:</p>
- <ul>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1462">Add <code>[</code> to the FOLLOW(ty) in macro future-proofing rules</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1457">Rewrite <code>for</code> loop desugaring to use language items</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1320">Amend 1192 (RangeInclusive) to use an enum</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/243">Trait-based exception handling</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1361">Improve Cargo target-specific dependencies</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1129">Add a <code>IndexAssign</code> trait that allows overloading "indexed assignment" expressions like <code>a[b] = c</code></a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1196">Allow eliding more type parameters</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1296">Add an <code>alias</code> attribute to <code>#[link]</code> and <code>-l</code></a>.</li>
- </ul>
- <h4>New RFCs</h4>
- <ul>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1459">Add a used attribute to prevent symbols from being discarded</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1461">Move some net2 functionality into libstd</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1465">Add <code>some!</code> macro for unwrapping Option more safely</a>.</li>
- <li><a href="https://github.com/rust-lang/rfcs/pull/1467">Stabilize the <code>volatile_load</code> and <code>volatile_store</code> intrinsics as <code>ptr::volatile_read</code> and <code>ptr::volatile_write</code></a>.</li>
- </ul>
- <h3>Upcoming Events</h3>
- <ul>
- <li><a href="http://www.meetup.com/Rust-Meetup-Hamburg/events/227838367/">1/19. Rust Hack and Learn Hamburg @ Ponton</a>.</li>
- <li><a href="http://www.meetup.com/Rust-Bay-Area/events/227841778/">1/21. SF Bay Area: Rust Concurrency and Parallelism</a>.</li>
- <li><a href="http://www.meetup.com/opentechschool-berlin/">1/27. OpenTechSchool Berlin: Rust Hack and Learn</a>.</li>
- </ul>
- <p>If you are running a Rust event please add it to the <a href="https://www.google.com/calendar/embed?src=apd9vmbc22egenmtu5l6c5jbfc%40group.calendar.google.com">calendar</a> to get
- it mentioned here. Email <a href="mailto:erick.tryzelaar@gmail.com">Erick Tryzelaar</a> or <a href="mailto:banderson@mozilla.com">Brian
- Anderson</a> for access.</p>
- <h3>fn work(on: RustProject) -&gt; Money</h3>
- <ul>
- <li><a href="http://maidsafe.net/rust_engineer.html">Rust Engineer</a> at MaidSafe.</li>
- <li><a href="https://careers.mozilla.org/en-US/position/ozy21fwU">Research Engineer - Servo</a> at Mozilla.</li>
- <li><a href="https://careers.mozilla.org/en-US/position/o0H41fww">Senior Research Engineer - Rust</a> at Mozilla.</li>
- <li><a href="http://plv.mpi-sws.org/rustbelt/">PhD and postdoc positions</a> at MPI-SWS.</li>
- </ul>
- <p><em>Tweet us at <a href="https://twitter.com/ThisWeekInRust">@ThisWeekInRust</a> to get your job offers listed here!</em></p>
- <h3>Crate of the Week</h3>
- <p>This week's Crate of the Week is <a href="https://github.com/alexcrichton/toml-rs">toml</a>, a crate for all our configuration needs, simple yet effective.</p>
- <p>Thanks to <a href="https://users.rust-lang.org/users/stebalien">Steven Allen</a> for the suggestion.</p>
- <p><a href="https://users.rust-lang.org/t/crate-of-the-week/2704">Submit your suggestions for next week</a>!</p>
- <h3>Quote of the Week</h3>
- <blockquote>
- <p>Borrow/lifetime errors are usually Rust compiler bugs.
- Typically, I will spend 20 minutes detailing the precise conditions of
- the bug, using language that understates my immense knowledge, while
- demonstrating sympathetic understanding of the pressures placed on a
- Rust compiler developer, who is also probably studying for several exams
- at the moment. The developer reading my bug report may not understand
- this stuff as well as I do, so I will carefully trace the lifetimes of
- each variable, where memory is allocated on the stack vs the heap, which
- struct or function owns a value at any point in time, where borrows
- begin and where they... oh yeah, actually that variable really doesn't
- live long enough.</p>
- </blockquote>
- <p>— <a href="https://www.reddit.com/r/rust/comments/4084yx/my_trick_when_i_get_stuck_as_a_beginner/cysqz3s">peterjoel on /r/rust</a>.</p>
- <p>Thanks to <a href="https://users.rust-lang.org/users/WaDelma">Wa Delma</a> for the suggestion.</p>
- <p><a href="http://users.rust-lang.org/t/twir-quote-of-the-week/328">Submit your quotes for next week</a>!</p></div>
- </summary>
- <updated>2016-01-18T05:00:00Z</updated>
- <author>
- <name>Corey Richardson</name>
- </author>
- <source>
- <id>http://this-week-in-rust.org/</id>
- <link href="http://this-week-in-rust.org/" rel="alternate" type="text/html"/>
- <link href="http://this-week-in-rust.org/atom.xml" rel="self" type="application/atom+xml"/>
- <title>This Week in Rust</title>
- <updated>2016-01-25T05:00:00Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://nikkisquared.github.io/2016/01/17/what-does-your-work-mean-part-2.html</id>
- <link href="http://nikkisquared.github.io/2016/01/17/what-does-your-work-mean-part-2.html" rel="alternate" type="text/html"/>
- <title>Okay, But What Does Your Work Actually Mean, Nikki? Part 2: The Fetch Standard and Servo</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>In my previous post, I started discussing in more detail what my internship entails, by talking about my first contribution to Servo. As a refresher, my first contribution was as part of my application to Outreachy, which I later revisited during my internship after a change I introduced to the HTML Standard it relied on. I’m going to expand on that last point today- specifically, how easy it is to introduce changes in <a href="https://wiki.whatwg.org/wiki/FAQ#What_is_the_WHATWG.3F">WHATWG</a>’s various standards. I’m also going to talk about how this accessibility to changing web standards affects how I can understand it, how I can help improve it, and my work on Servo.</p>
-
- <h3>Two Ways To Change</h3>
-
- <p>There are many ways to <a href="https://wiki.whatwg.org/wiki/What_you_can_do">get involved with WHATWG</a>, but there are two that I’ve become the most familiar with: firstly, by opening a discussion about a perceived issue and asking how it should be resolved; secondly, by taking on an issue approved as needing change and making the desired change. I’ve almost entirely only done the former, and the latter only for some minor typos. Any changes that relate directly to my work, however minor, are significant for me though! Like I discussed in my previous post, I brought attention to <a href="https://github.com/whatwg/html/issues/296">an inconsistency</a> that was resolved, giving me a new task of updating my first contribution to Servo to reflect the change in the HTML Standard. I’ve done that several times since, for the Fetch Standard.</p>
-
- <h3>Understanding Fetch</h3>
-
- <p>My first two weeks of my internship were spent on reading through the majority of the <a href="https://fetch.spec.whatwg.org/">Fetch Standard</a>, primarily the various Fetch functions. I took many notes describing the steps to myself, annotated with questions I had and the answers I got from either other people on the Servo team who had worked with Fetch (including my internship mentor, of course!) or people from WHATWG who were involved in the Fetch Standard. Getting so familiar with Fetch meant a few things: I would notice minor errors (such as an out of date link) that I could submit a <a href="https://github.com/whatwg/fetch/pull/173">simple fix for</a>, or a bigger issue that I couldn’t resolve myself.</p>
-
- <h3>Discussions &amp; Resolutions</h3>
-
- <p>I’m going to go into more detail about some of those bigger issues. From my perspective, when I start a discussion about a piece of documentation (such as the Fetch Standard, or reading about a programming library Servo uses), I go into it thinking “Either this documentation is incorrect, or my understanding is incorrectâ€. Whichever the answer is, it doesn’t mean that the documentation is bad, or that I’m bad at reading comprehension. I understand best by building up a model of something in my head, putting that to practice, and asking a lot of questions along the way. I learn by getting things wrong and figuring out why I was wrong, and sometimes in the process I uncover a point that could be made more clear, or an inconsistency! I have good examples of both of the different outcomes I listed, which I’ll cover over the next two sections.</p>
-
- <h5>Looking For The Big Picture</h5>
-
- <p>Early on in my initial review of the Fetch Standard’s several protocols, I found a major step that seemed to have no use. I understood that since I was learning Fetch on a step-by-step basis, I did not have a view of the bigger picture, so I asked around what I was missing that would help me understand this. One of the people I work with on implementing Fetch agreed with me that the step seemed to have no purpose, and so we decided to <a href="https://github.com/whatwg/fetch/issues/174">open an issue</a> asking about removing it from the standard. It turned out that I had actually missed the meaning of it, as we learned. However, instead of leaving it there, I shifted the issue into asking for some explanatory notes on why this step is needed, which was fulfilled. This meant that I would have a reference to go back to should I forget the significance of the step, and that people reading the Fetch Standard in the future would be much less likely to come to the same incorrect conclusion I had.</p>
-
- <h5>A Confusing Order</h5>
-
- <p>Shortly after I had first discovered that apparent issue, I found myself struggling to comprehend a sequence of actions in another Fetch protocol. The specification seemed to say that part of an early step was meant to only be done after the final step. I unfortunately don’t remember details of the discussion I had about this- if there was a reason for why it was organized like this, I forget what it was. Regardless, it was agreed that <a href="https://github.com/whatwg/fetch/issues/176">moving those sub-steps</a> to be actually listed after the step they’re supposed to run after would be a good change. This meant that I would need to re-organize my notes to reflect the re-arranged sequence of actions, as well as have an easier time being able to follow this part of the Fetch Standard.</p>
-
- <h3>A Living Standard</h3>
-
- <p>Like I said at the start of this post, I’m going to talk about how changes in the Fetch Standard affects my work on Servo itself. What I’ve covered so far has mostly been how changes affect my understanding of the standard itself. A key aspect in understanding the Fetch protocols is reviewing them for updates that impact me. WHATWG labels every standard they author as a “<a href="https://wiki.whatwg.org/wiki/FAQ#What_does_.22Living_Standard.22_mean.3F">Living Standard</a>†for good reason. It was one thing for me to learn how easy it is to introduce changes, while knowing exactly what’s going on, but it’s another for me to understand that anybody else can, and often does, make changes to the Fetch Standard!</p>
-
- <h5>Changes Over Time</h5>
-
- <p>When an update is made to the Fetch Standard, it’s not so difficult to deal with as one might imagine. The Fetch Standard always notes the last day it was updated at the top of the document, I follow a Twitter account that <a href="https://twitter.com/fetchstandard">posts about updates</a>, and all the history can be <a href="https://github.com/whatwg/fetch/commits">seen on GitHub</a> which will show me exactly what has been changed as well as some discussion on what the change does. All of these together alert me to the fact that the Fetch Standard has been modified, and I can quickly see what was revised. If it’s relevant to what I’m going to be implementing, I update my notes to match it. Occasionally, I need to change existing code to reflect the new Standard, which is also easily done by comparing my new notes to the Fetch implementation in Servo!</p>
-
- <h5>Snapshots</h5>
-
- <p>From all of this, it might sound like the Fetch Standard is unfinished, or unreliable/inconsistent. I don’t mean to misrepresent it- the many small improvements help make the Fetch Standard, like all of WHATWG’s standards, better and more reliable. You can think of the status of the Fetch Standard at any point in time as a single, working snapshot. If somebody implemented all of Fetch as it is now, they’d have something that works by itself correctly. A different snapshot of Fetch is just that- different. It will have an improvement or two, but that doesn’t obsolete anybody who implemented it previously. It just means if they revisit the implementation, they’ll have things to update.</p>
-
- <p>Third post over.</p></div>
- </summary>
- <updated>2016-01-17T20:20:27Z</updated>
- <category term="outreachy,"/>
- <category term="planet"/>
- <source>
- <id>http://nikkisquared.github.io/</id>
- <author>
- <name>Nikki Bee</name>
- </author>
- <link href="http://nikkisquared.github.io/" rel="alternate" type="text/html"/>
- <link href="http://nikkisquared.github.io/feed.xml" rel="self" type="application/rss+xml"/>
- <subtitle>Hi! I'm currently doing an internship for Outreachy. Wow!</subtitle>
- <title>Nikki Bee Blog</title>
- <updated>2016-01-18T05:28:11Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-us">
- <id>http://ngokevin.com/blog/aframe-component/</id>
- <link href="http://ngokevin.com/blog/aframe-component/" rel="alternate" type="text/html"/>
- <title>How to Write an A-Frame VR Component</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><img align="left" hspace="5" src="http://thevrjump.com/assets/img/articles/aframe-system/aframe-example.jpg" width="320"/>Abstract representation of components by @rubenmueller of thevrjump.com.
-
- <p><a href="http://ngokevin.com/blog/aframe">A-Frame</a> is a WebVR framework that introduces the
- <a href="http://ngokevin.com/blog/aframe-vs-3dml">entity-component system</a> (<a href="http://ngokevin.com/rss/docs">docs</a>) to the DOM. The
- entity-component system treats every <strong>entity</strong> in the scene as a placeholder
- object which we apply and mix <strong>components</strong> to in order to add appearance,
- behavior, and functionality. A-Frame comes with some standard components out of
- the box like camera, geometry, material, light, or sound. However, people can
- write, publish, and register their own components to do <strong>whatever</strong> they want
- like have entities <a href="https://github.com/dmarcos/a-invaders/tree/master/js/components">collide/explode/spawn</a>, be controlled by
- <a href="https://github.com/ngokevin/aframe-physics-components">physics</a>, or <a href="https://jsbin.com/dasefeh/edit?html,output">follow a path</a>. Today, we'll be going through
- how we can write our own A-Frame components.</p>
- <blockquote>
- <p>Note that this tutorial will be covering the upcoming release of <a href="https://github.com/aframevr/aframe/blob/dev/CHANGELOG.md#dev">A-Frame
- 0.2.0</a> which vastly improves the component API.</p>
- </blockquote>
- <h3>Table of Contents</h3>
- <ul>
- <li><a href="http://ngokevin.com/rss/index.xml#what-a-component-looks-like">What a Component Looks Like</a><ul>
- <li><a href="http://ngokevin.com/rss/index.xml#from-the-dom">From the DOM</a></li>
- <li><a href="http://ngokevin.com/rss/index.xml#under-the-hood">Under the Hood</a></li>
- </ul>
- </li>
- <li><a href="http://ngokevin.com/rss/index.xml#defining-the-schema">Defining the Schema</a><ul>
- <li><a href="http://ngokevin.com/rss/index.xml#property-types">Property Types</a></li>
- <li><a href="http://ngokevin.com/rss/index.xml#single-property-schemas">Single-Property Schemas</a></li>
- <li><a href="http://ngokevin.com/rss/index.xml#multiple-property-schemas">Multiple-Property Schemas</a></li>
- </ul>
- </li>
- <li><a href="http://ngokevin.com/rss/index.xml#defining-the-lifecycle-methods">Defining the Lifecycle Methods</a><ul>
- <li><a href="http://ngokevin.com/rss/index.xml#component-init-set-up">Component.init() - Set Up</a></li>
- <li><a href="http://ngokevin.com/rss/index.xml#component-update-olddata-do-the-magic">Component.update(oldData) - Do the Magic</a></li>
- <li><a href="http://ngokevin.com/rss/index.xml#component-remove-tear-down">Component.remove() - Tear Down</a></li>
- <li><a href="http://ngokevin.com/rss/index.xml#component-tick-time-background-behavior">Component.tick() - Background Behavior</a></li>
- <li><a href="http://ngokevin.com/rss/index.xml#component-pause-and-component-play-stop-and-go">Component.pause() and Component.play() - Stop and Go</a></li>
- </ul>
- </li>
- <li><a href="http://ngokevin.com/rss/index.xml#boilerplate">Boilerplate</a></li>
- <li><a href="http://ngokevin.com/rss/index.xml#examples">Examples</a><ul>
- <li><a href="http://ngokevin.com/rss/index.xml#text-component">Text Component</a></li>
- <li><a href="http://ngokevin.com/rss/index.xml#physics-components">Physics Components</a></li>
- <li><a href="http://ngokevin.com/rss/index.xml#layout-component">Layout Component</a></li>
- </ul>
- </li>
- </ul>
- <h3>What a Component Looks Like</h3>
- <p>A component contains a bucket of data in the form of component properties. This
- data is used to modify the entity. For example, we might have an <em>engine</em>
- component. Possible properties might be <em>horsepower</em> or <em>cylinders</em>.</p>
- <p><img alt="" src="http://thevrjump.com/assets/img/articles/aframe-system/aframe-system.jpg"/>
- </p><div class="page-caption"><span>
- Abstract representation of a component by @rubenmueller of thevrjump.com.
- </span></div><p/>
- <h4>From the DOM</h4>
- <p>Let's first see what a component looks like from the DOM.</p>
- <p>For example, the <a href="https://aframe.io/docs/components/light.html">light component</a> has properties such as type, color,
- and intensity. In A-Frame, we register and configure a component to an entity
- using an HTML attribute and a style-like syntax:</p>
- <div class="highlight"><pre><span class="p">&lt;</span><span class="nt">a-entity</span> <span class="na">light</span><span class="o">=</span><span class="s">"type: point; color: crimson; intensity: 2.5"</span><span class="p">&gt;&lt;/</span><span class="nt">a-entity</span><span class="p">&gt;</span>
- </pre></div>
-
-
- <p>This would give us a light in the scene. To demonstrate composability, we could
- give the light a spherical representation by mixing in the <a href="https://aframe.io/docs/components/geometry.html">geometry
- component</a>.</p>
- <div class="highlight"><pre><span class="p">&lt;</span><span class="nt">a-entity</span> <span class="na">geometry</span><span class="o">=</span><span class="s">"primitive: sphere; radius: 5"</span>
- <span class="na">light</span><span class="o">=</span><span class="s">"type: point; color: crimson; intensity: 2.5"</span><span class="p">&gt;&lt;/</span><span class="nt">a-entity</span><span class="p">&gt;</span>
- </pre></div>
-
-
- <p>Or we can configure the position component to move the light sphere a bit to the right.</p>
- <div class="highlight"><pre><span class="p">&lt;</span><span class="nt">a-entity</span> <span class="na">geometry</span><span class="o">=</span><span class="s">"primitive: sphere; radius: 5"</span>
- <span class="na">light</span><span class="o">=</span><span class="s">"type: point; color: crimson; intensity: 2.5"</span>
- <span class="na">position</span><span class="o">=</span><span class="s">"5 0 0"</span><span class="p">&gt;&lt;/</span><span class="nt">a-entity</span><span class="p">&gt;</span>
- </pre></div>
-
-
- <p>Given the style-like syntax and that it modifies the appearance and behavior of
- DOM nodes, component properties can be thought of as a rough analog to CSS. In
- the near future, I can imagine component property stylesheets.</p>
- <h4>Under the Hood</h4>
- <p>Now let's see what a component looks like <strong>under the hood</strong>. A-Frame's most
- basic component is the <a href="https://aframe.io/docs/components/position.html">position component</a>:</p>
- <div class="highlight"><pre><span class="nx">AFRAME</span><span class="p">.</span><span class="nx">registerComponent</span><span class="p">(</span><span class="s1">'position'</span><span class="p">,</span> <span class="p">{</span>
- <span class="nx">schema</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s1">'vec3'</span> <span class="p">},</span>
-
- <span class="nx">update</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
- <span class="kd">var</span> <span class="nx">object3D</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">el</span><span class="p">.</span><span class="nx">object3D</span><span class="p">;</span>
- <span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">data</span><span class="p">;</span>
- <span class="nx">object3D</span><span class="p">.</span><span class="nx">position</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">x</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">y</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">z</span><span class="p">);</span>
- <span class="p">}</span>
- <span class="p">});</span>
- </pre></div>
-
-
- <p>The position component uses only a tiny subset of the component API, but what
- this does is register the component with the name "position", define a <code>schema</code>
- where the component's value with be parsed to an <code>{x, y, z}</code> object, and when
- the component initializes or the component's data updates, set the position of
- the entity with the <code>update</code> callback. <code>this.el</code> is a reference from the
- component to the DOM element, or entity, and <code>object3D</code> is the entity's
- <a href="http://threejs.org/">three.js</a>. Note that A-Frame is built on top of three.js so many
- components will be using the three.js API.</p>
- <p>So we see that components consist of a name and a definition, and then they can
- be registered to A-Frame. We saw the the position component definition defined
- a <code>schema</code> and an <code>update</code> handler. Components simply consist of the <code>schema</code>,
- which defines the shape of the data, and several handlers for the component to
- modify the entity in reaction to different types of events.</p>
- <p>Here is the current list of properties and methods of a component definition:</p>
- <table class="pure-table-striped">
- <tbody><tr>
- <th>Property</th>
- <th>Description</th>
- </tr>
- <tr>
- <td>data</td>
- <td>Data of the component derived from the schema default values, mixins, and the entity's attributes.</td>
- </tr>
- <tr>
- <td>el</td>
- <td>Reference to the <a href="https://aframe.io/docs/core/entity.html">entity</a> element.</td>
- </tr>
- <tr>
- <td>schema</td>
- <td>Names, types, and default values of the component property value(s)</td>
- </tr>
- </tbody></table>
-
- <table class="pure-table-striped">
- <tbody><tr><th>Method</th><th>Description</th></tr>
- <tr>
- <td>init</td>
- <td>Called once when the component is initialized.</td>
- </tr>
- <tr>
- <td>update</td>
- <td>Called both when the component is initialized and whenever the component's data changes (e.g, via <i>setAttribute</i>).</td>
- </tr>
- <tr>
- <td>remove</td>
- <td>Called when the component detaches from the element (e.g., via <i>removeAttribute</i>).</td>
- </tr>
- <tr>
- <td>tick</td>
- <td>Called on each render loop or tick of the scene.</td>
- </tr>
- <tr>
- <td>play</td>
- <td>Called whenever the scene or entity plays to add any background or dynamic behavior.</td>
- </tr>
- <tr>
- <td>pause</td>
- <td>Called whenever the scene or entity pauses to remove any background or dynamic behavior.</td>
- </tr>
- </tbody></table>
-
- <h3>Defining the Schema</h3>
- <p>The component's schema defines what type of data it takes. A component can
- either be single-property or consist of multiple properties. And properties
- have <em>property types</em>. Note that single-property schemas and property types are
- being released in A-Frame <code>v0.2.0</code>.</p>
- <p>A property might look like:</p>
- <div class="highlight"><pre><span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s1">'int'</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="mi">5</span> <span class="p">}</span>
- </pre></div>
-
-
- <p>And a schema consisting of multiple properties might look like:</p>
- <div class="highlight"><pre><span class="p">{</span>
- <span class="nx">color</span><span class="o">:</span> <span class="p">{</span> <span class="k">default</span><span class="o">:</span> <span class="s1">'#FFF'</span> <span class="p">},</span>
- <span class="nx">target</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s1">'selector'</span> <span class="p">},</span>
- <span class="nx">uv</span><span class="o">:</span> <span class="p">{</span>
- <span class="k">default</span><span class="o">:</span> <span class="s1">'1 1'</span><span class="p">,</span>
- <span class="nx">parse</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
- <span class="k">return</span> <span class="nx">value</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">' '</span><span class="p">).</span><span class="nx">map</span><span class="p">(</span><span class="nb">parseFloat</span><span class="p">);</span>
- <span class="p">}</span>
- <span class="p">},</span>
- <span class="p">}</span>
- </pre></div>
-
-
- <p>Since components in the entity-component system are just buckets of data that
- are used to affect the appearance or behavior of the entity, the schema plays a
- crucial role in the definition of the component.</p>
- <h4>Property Types</h4>
- <p>A-Frame comes with several built-in property types such as <code>boolean</code>, <code>int</code>,
- <code>number</code>, <code>selector</code>, <code>string</code>, or <code>vec3</code>. Every single property is assigned a
- type, whether explicitly through the <code>type</code> key or implictly via inferring the
- value. And each type is used to assign <code>parse</code> and <code>stringify</code> functions. The
- parser deserializes the incoming string value from the DOM to be put into the
- component's data object. The stringifier is used when using <code>setAttribute</code> to
- serialize back to the DOM.</p>
- <p>We can actually define and register our own property types:</p>
- <div class="highlight"><pre><span class="nx">AFRAME</span><span class="p">.</span><span class="nx">registerPropertyType</span><span class="p">(</span><span class="s1">'radians'</span><span class="p">,</span> <span class="p">{</span>
- <span class="nx">parse</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
-
- <span class="p">}</span>
-
- <span class="c1">// Default stringify is .toString().</span>
- <span class="p">});</span>
- </pre></div>
-
-
- <h4>Single-Property Schemas</h4>
- <p>If a component has only one property, then it must either have a <code>type</code> or a
- <code>default</code> value. If the type is defined, then the type is used to parse and
- coerce the string retrieved from the DOM (e.g., <code>getAttribute</code>). Or if the
- default value is defined, the default value is used to infer the type.</p>
- <p>Take for instance the <a href="https://aframe.io/docs/components/visible.html">visible component</a>. The schema property
- definition implicitly defines it as a boolean:</p>
- <div class="highlight"><pre><span class="nx">AFRAME</span><span class="p">.</span><span class="nx">registerComponent</span><span class="p">(</span><span class="s1">'visible'</span><span class="p">,</span> <span class="p">{</span>
- <span class="nx">schema</span><span class="o">:</span> <span class="p">{</span>
- <span class="c1">// Type will be inferred to be boolean.</span>
- <span class="k">default</span><span class="o">:</span> <span class="kc">true</span>
- <span class="p">},</span>
-
- <span class="c1">// ...</span>
- <span class="p">});</span>
- </pre></div>
-
-
- <p>Or the <a href="https://aframe.io/docs/components/rotation.html">rotation component</a> which explicitly defines the value as a <code>vec3</code>:</p>
- <div class="highlight"><pre><span class="nx">AFRAME</span><span class="p">.</span><span class="nx">registerComponent</span><span class="p">(</span><span class="s1">'rotation'</span><span class="p">,</span> <span class="p">{</span>
- <span class="nx">schema</span><span class="o">:</span> <span class="p">{</span>
- <span class="c1">// Default value will be 0, 0, 0 as defined by the vec3 property type.</span>
- <span class="nx">type</span><span class="o">:</span> <span class="s1">'vec3'</span>
- <span class="p">}</span>
-
- <span class="c1">// ...</span>
- <span class="p">});</span>
- </pre></div>
-
-
- <p>Using these defined property types, schemas are processed by
- <code>registerComponent</code> to inject default values, parsers, and stringifiers for
- each property. So if a default value is not defined, the default value will be
- whatever the property type defines as the "default default value".</p>
- <h4>Multiple-Property Schemas</h4>
- <p>If a component has multiple properties (or one named property), then it consists of
- one or more property definitions, in the form described above, in an object keyed by
- property name. For instance, a physics body component might define a schema:</p>
- <div class="highlight"><pre><span class="nx">AFRAME</span><span class="p">.</span><span class="nx">registerComponent</span><span class="p">(</span><span class="s1">'physics-body'</span><span class="p">,</span> <span class="p">{</span>
- <span class="nx">schema</span><span class="o">:</span> <span class="p">{</span>
- <span class="nx">boundingBox</span><span class="o">:</span> <span class="p">{</span>
- <span class="nx">type</span><span class="o">:</span> <span class="s1">'vec3'</span><span class="p">,</span>
- <span class="k">default</span><span class="o">:</span> <span class="p">{</span> <span class="nx">x</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">1</span> <span class="p">}</span>
- <span class="p">},</span>
- <span class="nx">mass</span><span class="o">:</span> <span class="p">{</span>
- <span class="k">default</span><span class="o">:</span> <span class="mi">0</span>
- <span class="p">},</span>
- <span class="nx">velocity</span><span class="o">:</span> <span class="p">{</span>
- <span class="nx">type</span><span class="o">:</span> <span class="s1">'vec3'</span>
- <span class="p">}</span>
- <span class="p">}</span>
- <span class="p">}</span>
- </pre></div>
-
-
- <p>Having multiple properties is what makes the component take the syntax in the
- form of <code>physics="mass: 2; velocity: 1 1 1"</code>.</p>
- <p>With the schema defined, all data coming into the component will be passed
- through the schema for parsing. Then in the lifecycle methods, the component
- has access to <code>this.data</code> which in a single-property schema is a value and in a
- multiple-propery schema is an object.</p>
- <h3>Defining the Lifecycle Methods</h3>
- <h4>Component.init() - Set Up</h4>
- <p><code>init</code> is called once in the component's lifecycle when it is mounted to the
- entity. <code>init</code> is generally used to set up variables or members that may used
- throughout the component or to set up state. Though not every component will
- need to define an <code>init</code> handler. Sort of like the component-equivalent method
- to <code>createdCallback</code> or <code>React.ComponentDidMount</code>.</p>
- <p>For example, the <code>look-at</code> component's <code>init</code> handler sets up some variables:</p>
- <div class="highlight"><pre><span class="nx">init</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
- <span class="k">this</span><span class="p">.</span><span class="nx">target3D</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
- <span class="k">this</span><span class="p">.</span><span class="nx">vector</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">THREE</span><span class="p">.</span><span class="nx">Vector3</span><span class="p">();</span>
- <span class="p">},</span>
-
- <span class="c1">// ...</span>
- </pre></div>
-
-
- <h4>Component.update(oldData) - Do the Magic</h4>
- <p>The <code>update</code> handler is called both at the beginning of the component's
- lifecycle with the initial <code>this.data</code> <em>and</em> every time the component's data
- changes (generally during the entity's <code>attributeChangedCallback</code> like with a
- <code>setAttribute</code>). The update handler gets access to the previous state of the
- component data passed in through <code>oldData</code>. The previous state of the component
- can be used to tell exactly which properties changed to do more granular
- updates.</p>
- <p>The update handler uses <code>this.data</code> to modify the entity, usually interacting
- with three.js APIs. One of the simplest update handlers is the
- <a href="https://aframe.io/docs/components/visible.html">visible</a> component's:</p>
- <div class="highlight"><pre><span class="nx">update</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
- <span class="k">this</span><span class="p">.</span><span class="nx">el</span><span class="p">.</span><span class="nx">object3D</span><span class="p">.</span><span class="nx">visible</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">data</span><span class="p">;</span>
- <span class="p">}</span>
- </pre></div>
-
-
- <p>A slightly more complex update handler might be the <a href="https://aframe.io/docs/components/light.html">light</a> component's,
- which we'll show via abbreviated code:</p>
- <div class="highlight"><pre><span class="nx">update</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">oldData</span><span class="p">)</span> <span class="p">{</span>
- <span class="kd">var</span> <span class="nx">diffData</span> <span class="o">=</span> <span class="nx">diff</span><span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="nx">oldData</span> <span class="o">||</span> <span class="p">{});</span>
-
- <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">light</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="p">(</span><span class="s1">'type'</span> <span class="k">in</span> <span class="nx">diffData</span><span class="p">))</span> <span class="p">{</span>
- <span class="c1">// If there is an existing light and the type hasn't changed, update light.</span>
- <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">diffData</span><span class="p">).</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">property</span><span class="p">)</span> <span class="p">{</span>
- <span class="nx">light</span><span class="p">[</span><span class="nx">property</span><span class="p">]</span> <span class="o">=</span> <span class="nx">diffData</span><span class="p">[</span><span class="nx">property</span><span class="p">];</span>
- <span class="p">});</span>
- <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
- <span class="c1">// No light exists yet or the type of light has changed, create a new light.</span>
- <span class="k">this</span><span class="p">.</span><span class="nx">light</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">getLight</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">data</span><span class="p">));</span>
-
- <span class="c1">// Register the object3D of type `light` to the entity.</span>
- <span class="k">this</span><span class="p">.</span><span class="nx">el</span><span class="p">.</span><span class="nx">setObject3D</span><span class="p">(</span><span class="s1">'light'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">light</span><span class="p">);</span>
- <span class="p">}</span>
- <span class="p">}</span>
- </pre></div>
-
-
- <p>The entity's <code>object3D</code> is a plain THREE.Object3D. Other three.js object types
- such as meshes, lights, and cameras can be set with <code>setObject3D</code> where they
- will be appeneded to the entity's <code>object3D</code>.</p>
- <h4>Component.remove() - Tear Down</h4>
- <p>The <code>remove</code> handler is called when the component detaches from the entity such
- as with <code>removeAttribute</code>. This is generally used to remove all modifications,
- listeners, and behaviors to the entity that the component added.</p>
- <p>For example, when the <a href="https://aframe.io/docs/components/light.html">light component</a> detaches, it removes the light
- it previously attached from the entity and thus the scene:</p>
- <div class="highlight"><pre><span class="nx">remove</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
- <span class="k">this</span><span class="p">.</span><span class="nx">el</span><span class="p">.</span><span class="nx">removeObject3D</span><span class="p">(</span><span class="s1">'light'</span><span class="p">);</span>
- <span class="p">}</span>
- </pre></div>
-
-
- <h4>Component.tick(time) - Background Behavior</h4>
- <p>The <code>tick</code> handler is called on every single tick or render loop of the scene.
- So expect it to run on the order of 60-120 times for second. The global uptime of
- the scene in seconds is passed into the tick handler.</p>
- <p>For example, the <a href="https://aframe.io/docs/components/look-at.html">look-at</a> component, which instructs an entity to
- look at another target entity, uses the tick handler to update the rotation in
- case the target entity changes its position:</p>
- <div class="highlight"><pre><span class="nx">tick</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">t</span><span class="p">)</span> <span class="p">{</span>
- <span class="c1">// target3D and vector are set from the update handler.</span>
- <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">target3D</span><span class="p">)</span> <span class="p">{</span>
- <span class="k">this</span><span class="p">.</span><span class="nx">el</span><span class="p">.</span><span class="nx">object3D</span><span class="p">.</span><span class="nx">lookAt</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">vector</span><span class="p">.</span><span class="nx">setFromMatrixPosition</span><span class="p">(</span><span class="nx">target3D</span><span class="p">.</span><span class="nx">matrixWorld</span><span class="p">));</span>
- <span class="p">}</span>
- <span class="p">}</span>
- </pre></div>
-
-
- <h4>Component.pause() and Component.play() - Stop and Go</h4>
- <p>To support pause and play, just as with a video game or to toggle entities for
- performance, components can implement <code>play</code> and <code>pause</code> handlers. These are
- invoked when the component's entity runs its <code>play</code> or <code>pause</code> method. When an
- entity plays or pauses, all of its child entities are also played or paused.</p>
- <p>Components should implement play or pause handlers if they register any
- dynamic, asynchronous, or background behavior such as animations, event
- listeners, or tick handlers.</p>
- <p>For example, the <code>look-controls</code> component simply removes its event listeners
- such that the camera does not move when the scene is paused, and it adds its
- event listeners when the scene starts playing or is resumed:</p>
- <div class="highlight"><pre><span class="nx">pause</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
- <span class="k">this</span><span class="p">.</span><span class="nx">removeEventListeners</span><span class="p">()</span>
- <span class="p">},</span>
-
- <span class="nx">play</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
- <span class="k">this</span><span class="p">.</span><span class="nx">addEventListeners</span><span class="p">()</span>
- <span class="p">}</span>
- </pre></div>
-
-
- <h3>Boilerplate</h3>
- <p>I suggest that people start off with my <a href="https://github.com/ngokevin/aframe-component-boilerplate">component boilerplate</a>,
- even hardcore tool junkies. This will get you straight into building a
- component and comes with everything you will need to publish your component
- into the wild. The boilerplate handles creating a stubbed component, build
- steps for both NPM and browser distribution files, and publishing to Github
- Pages.</p>
- <p>Generally with boilerplates, it is better to start from scratch and build your
- own boilerplate, but the A-Frame component boilerplate contains a lot of tribal
- inside knowledge about A-Frame and is updated frequently to reflect new things
- landing on A-Frame. The only possibly opinionated pieces about the boilerplate
- is the development tools it internally uses that are hidden away by NPM
- scripts.</p>
- <h3>Examples</h3>
- <p>Under construction. Stay tuned!</p>
- <h4>Text Component</h4>
- <p><a href="https://github.com/ngokevin/aframe-text-component">Text component</a></p>
- <h4>Physics Components</h4>
- <p><a href="https://github.com/ngokevin/aframe-physics-components">Physics components</a></p>
- <h4>Layout Component</h4>
- <p><a href="https://github.com/ngokevin/aframe-layout-component">Layout component</a></p></div>
- </summary>
- <updated>2016-01-17T00:00:00Z</updated>
- <source>
- <id>http://ngokevin.com/rss</id>
- <author>
- <name>Kevin Ngo</name>
- </author>
- <link href="http://ngokevin.com/rss" rel="self" type="application/rss+xml"/>
- <link href="http://ngokevin.com/rss" rel="alternate" type="text/html"/>
- <updated>2016-01-26T18:09:34Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://blog.gerv.net/?p=3527</id>
- <link href="http://feedproxy.google.com/~r/HackingForChrist/~3/DN054t04_dE/" rel="alternate" type="text/html"/>
- <link href="http://blog.gerv.net/2016/01/convenient-and-creepy/#comments" rel="replies" type="text/html"/>
- <link href="http://blog.gerv.net/2016/01/convenient-and-creepy/feed/atom/" rel="replies" type="application/atom+xml"/>
- <title xml:lang="en-US">Convenient… and Creepy</title>
- <summary type="xhtml" xml:lang="en-US"><div xmlns="http://www.w3.org/1999/xhtml">The last Mozilla All-Hands was at one of the hotels in the Walt Disney World Resort in Florida. Every attendee was issued with one of these (although their use was optional): It’s called a “Magic Bandâ€. You register it online … <a href="http://blog.gerv.net/2016/01/convenient-and-creepy/">Continue reading <span class="meta-nav">→</span></a></div>
- </summary>
- <content type="xhtml" xml:lang="en-US"><div xmlns="http://www.w3.org/1999/xhtml"><p>The last Mozilla All-Hands was at one of the hotels in the Walt Disney World Resort in Florida. Every attendee was issued with one of these (although their use was optional):<br/>
- <a href="http://blog.gerv.net/files/2016/01/Disneys_MagicBand.jpg"><img class="alignnone size-large wp-image-3530" src="http://blog.gerv.net/files/2016/01/Disneys_MagicBand-1024x832.jpg" width="292"/></a></p>
- <p>It’s called a “Magic Bandâ€. You register it online and connect it to your Disney account, and then it can be used for park entry, entry to pre-booked rides so you don’t have to queue (called “FastPass+â€), payment, picking up photos, as your room key, and all sorts of other convenient features. Note that it has no UI whatsoever – no lights, no buttons. Not even a battery compartment. (It does contain a battery, but it’s not replaceable.) These are specific design decisions – the aim is for ultra-simple convenience.</p>
- <p>One of the talks we had at the All Hands was from one of the Magic Band team. The audience reactions to some of the things he said was really interesting. He gave the example of Cinderella wishing you a Happy Birthday as you walk round the park. “Cinderella just knowsâ€, he said. Of course, in fact, her costume’s tech prompts her when it silently reads your Magic Band from a distance. This got some initial impressed applause, but it was noticeable that after a few moments, it wavered – people were thinking “Cool… er, but creepy?â€</p>
- <p>The Magic Band also has range sufficient that Disney can track you around the park. This enables some features which are good for both customers and Disney – for example, they can use it for load balancing. If one area of the park seems to be getting overcrowded, have some characters pop up in a neighbouring area to try and draw people away. But it means that they always know where you are and where you’ve been.</p>
- <p>My take-away from learning about the Magic Band is that it’s really hard to have a technical solution to this kind of requirement which allows all the Convenient features but not the Creepy features. Disney does offer an RFID-card-based solution for the privacy-conscious which does some of these things, but not all of them. And it’s easier to lose. It seems to me that the only way to distinguish the two types of feature, and get one and not the other, is policy – either the policy of the organization, or external restrictions on them (e.g. from a watchdog body’s code of conduct they sign up to, or from law). And it’s often not in the organization’s interest to limit themselves in this way.</p>
- <img alt="" height="1" src="http://feeds.feedburner.com/~r/HackingForChrist/~4/DN054t04_dE" width="1"/></div>
- </content>
- <updated>2016-01-16T12:18:38Z</updated>
- <published>2016-01-16T12:18:38Z</published>
- <category scheme="http://blog.gerv.net" term="Mozilla"/>
- <category scheme="http://blog.gerv.net" term="Syndicate"/><feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://blog.gerv.net/2016/01/convenient-and-creepy/</feedburner:origLink>
- <author>
- <name>gerv</name>
- </author>
- <source>
- <id>http://blog.gerv.net/feed/atom/</id>
- <link href="http://blog.gerv.net" rel="alternate" type="text/html"/>
- <link href="http://feeds.feedburner.com/HackingForChrist" rel="self" type="application/atom+xml"/>
- <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
- <subtitle xml:lang="en-US">Gervase Markham</subtitle>
- <title xml:lang="en-US">Syndicate – Hacking for Christ</title>
- <updated>2016-01-16T12:18:38Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://www.christianheilmann.com/?p=4957</id>
- <link href="https://www.christianheilmann.com/2016/01/16/dont-tell-me-what-my-browser-cant-do/" rel="alternate" type="text/html"/>
- <title>Don’t tell me what my browser can’t do!</title>
- <summary>Chances are, your guess is wrong! Arrogance towards possible customers never pays out – as shown in “Pretty Woman†There is nothing more frustrating than being capable of something and not getting a chance to do it. The same goes for being blocked out from something although you are capable of consuming it. Or you’re […]</summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em class="markup--em markup--p-em">Chances are, your guess is wrong!</em></p>
-
- <p/><figure><img alt="you are obviously in the wrong place" src="https://d262ilb51hltx0.cloudfront.net/max/800/1*l9jPbOyAl00kjPhyNYA-IQ.jpeg" width="100%"/>Arrogance towards possible customers never pays out – as shown in “Pretty Womanâ€</figure><p/>
-
- <p>There is nothing more frustrating than being capable of something and not getting a chance to do it. The same goes for being blocked out from something although you are capable of consuming it. Or you’re even willing to put some extra effort or even money in and you still don’t get to consume it.</p>
-
- <p>For example, I’d happily pay $50 a month to get access to Netflix’s world-wide library from any country I’m in. But the companies Netflix get their content from won’t go for that. Movies and TV show are budgeted by predicted revenue in different geographical markets with month-long breaks in between the releases. A world-wide network capable of delivering content in real time? Preposterous — let’s shut that down.</p>
-
- <p>On a less “let’s break a 100 year old monopoly†scale of annoyance, <a href="https://twitter.com/codepo8/status/687616620529844224">I tweeted yesterday something glib and apparently cruel</a>:</p>
-
- <p/><blockquote>“Sorry, but your browser does not support WebGL!†– sorry, you are a shit coder.</blockquote><p/>
-
- <p><strong>And I stand by this</strong>. I went to a web site that promised me some cute, pointless animation and technological demo. I was using Firefox Nightly — a WebGL capable browser. I also went there with Microsoft Edge — another WebGL capable browser. Finally, using Chrome, I was able to delight in seeing an animation.</p>
-
- <p><strong>I’m not saying the creators of that thing lack in development capabilities</strong>. The demo was slick, beautiful and well coded. They still do lack in two things developers of <em>web products </em>(and I count apps into that) should have: empathy for the end user and an understanding that they are not in control.</p>
-
- <p>Now, I am a pretty capable technical person. When you tell me that I might be lacking WebGL, I know what you mean. I don’t lack WebGL. I was blocked out because the web site did browser sniffing instead of capability testing. But I know what could be the problem.</p>
-
- <p>A normal user of the web has no idea what WebGL is and — if you’re lucky — will try to find it on an app store. If you’re not lucky all you did is confuse a person. A person who went through the effort to click a link, open a browser and wait for your thing to load. A person that feels stupid for using your product as they have no clue what WebGL is and won’t ask. Humans hate feeling stupid and we do anything not to appear it or show it.</p>
-
- <p>This is what I mean by empathy for the end user. Our problems should never become theirs.</p>
-
- <p/><blockquote>A cryptic error message telling the user that they lack some technology helps nobody and is sloppy development at best, sheer arrogance at worst.</blockquote><p/>
-
- <p>The web is, sadly enough, littered with unhelpful error messages and assumptions that it is the user’s fault when they can’t consume the thing we built.</p>
-
- <p>Here’s a reality check — this is what our users should have to do to consume the things we build:</p>
-
- <p><img alt="" height="600" src="https://d262ilb51hltx0.cloudfront.net/max/800/1*DXtRIWTu-UzRb0YB-h8SmA.png" width="10"/></p>
-
- <p><strong>That’s right. Nothing</strong>. This is the web. Everybody is invited to consume, contribute and create. This is what made it the success it is. This is what will make it outlive whatever other platform threatens it with shiny impressive interactions. Interactions at that time impossible to achieve with web technologies.</p>
-
- <p>Whenever I mention this, the knee-jerk reaction is the same:</p>
-
- <p/><blockquote class="graf--blockquote graf-after--p" id="79d6" name="79d6">How can you expect us to build delightful experiences close to magic (and whatever other soundbites were in the last Apple keynote) if we keep having to support old browsers and users with terrible setups?</blockquote><p/>
-
- <p>You don’t have to support old browsers and terrible setups. But you are not allowed to block them out. It is a simple matter of giving a usable interface to end users. A button that does nothing when you click it is not a good experience. Test if the functionality is available, then create or show the button. <strong class="markup--strong markup--p-strong">This is as simple as it is.</strong></p>
-
- <p>If you really have to rely on some technology then show people what they are missing out on and tell them how to upgrade. A screenshot or a video of a WebGL animation is still lovely to see. A message telling me I have no WebGL less so.</p>
-
- <p>Even more on the black and white scale, what the discussion boils down to is in essence:</p>
-
- <p/><blockquote class="graf--blockquote graf-after--p" id="a775" name="a775">But it is 2016 — surely we can expect people to have JavaScript enabled — it is after all “the assembly language of the webâ€</blockquote><p/>
-
- <p>Despite the cringe-worthy <a href="http://www.hanselman.com/blog/JavaScriptIsAssemblyLanguageForTheWebSematicMarkupIsDeadCleanVsMachinecodedHTML.aspx">misquote of the assembly language</a> thing, here is a harsh truth:</p>
-
- <p/><blockquote>You can absolutely expect JavaScript to be available on your end users computers in 2016. At the same time it is painfully <strong>naive</strong> to expect it to work under all circumstances.</blockquote><p/>
-
- <p><strong>JavaScript is brittle</strong>. <span class="caps">HTML</span> and <span class="caps">CSS</span> both are <em>fault tolerant</em>. If something goes wrong in <span class="caps">HTML</span>, browsers either display the content of the element or try to fix minor issues like unclosed elements for you. <span class="caps">CSS</span> skips lines of code it can’t understand and merrily goes on its way to show the rest of it. JavaScript breaks on errors and tells you that something went wrong. It will not execute the rest of the script, but throws in the towel and tells you to get your house in order first.</p>
-
- <p>There <a href="http://kryogenix.org/code/browser/everyonehasjs.html">are many outside influences</a> that will interfere with the execution of your JavaScript. That’s why a non-naive and non-arrogant — a dedicated and seasoned web developer — will never rely on it. Instead, you treat it as an enhancement and in an almost paranoid fashion test for the availability of everything before you access it.</p>
-
- <p><strong>Sorry (not sorry) — this will never go away</strong>. This is the nature of JavaScript. And it is a good thing. It means we can access new features of the language as they come along instead of getting stuck in a certain state. It means we have to think about using it every time instead of relying on libraries to do the work for us. It means that we need to keep evolving with the web — a living and constantly changing medium, and not a software platform. That’s just part of it.</p>
-
- <p>This is why the whole discussion about JavaScript enabled or disabled is a massive waste of time. It is not the availability of JavaScript we need to worry about. It is our products breaking in perfectly capable environments because we rely on perfect execution instead of writing defensive code. A tumblr like <a class="markup--anchor markup--p-anchor" href="http://sighjavascript.tumblr.com/" rel="nofollow">Sigh, JavaScript</a> is fun, but is pithy finger-pointing.</p>
-
- <p/><blockquote>There is nothing wrong with using JavaScript to build things. Just be aware that the error handling is your responsibility.</blockquote><p/>
-
- <p>Any message telling the user that they have to turn on JavaScript to use a certain product is a proof that you care more about your developer convenience than your users.</p>
-
- <p/><blockquote>It is damn hard these days to turn off JavaScript – you are complaining about a almost non-existent issue and tell the confused user to do something they don’t know how to.</blockquote><p/>
-
- <p>The chance that something in the JavaScript execution of any of your dozens of dependencies went wrong is much higher – and this is your job to fix. This is why advice like <a href="http://webdesign.tutsplus.com/tutorials/quick-tip-dont-forget-the-noscript-element--cms-25498">using noscript to provide alternative content</a> is terrible. It means you double your workload instead of enhancing what works. Who knows? If you start with something not JavaScript dependent (or running it server side) you might find that you don’t need the complex solution you started with in the first place. Faster, smaller, easier. Sounds good, right?</p>
-
- <p>So, please, stop sniffing my browser, you will fail and tell me lies. Stop pretending that working with a brittle technology is the user’s fault when something goes wrong.</p>
-
- <p/><blockquote>As web developers we work in the service industry. We deliver products to people. And keeping these people happy and non-worried is our job. Nothing more, nothing less.</blockquote><p/>
-
- <p>Without users, your product is nothing. Sure, we are better paid and well educated and we are not flipping burgers. But we have no right whatsoever to be arrogant and not understanding that our mistakes are not the fault of our end users.</p>
-
- <p>Our demeanor when complaining about how stupid our end users and their terrible setups are reminds me of <a href="https://www.youtube.com/watch?v=CSj5stmFkQ0">this Mitchell and Webb sketch</a>.</p>
-
- <p/>
-
- <p><strong class="markup--strong markup--p-strong">Don’t be that person. </strong>Our job is to enable people to consume, participate and create the web. This is magic. This is beautiful. This is incredibly rewarding. The next markets we should care about are ready to be as excited about the web as we were when we first encountered it. Browsers are good these days. Use what they offer after testing for it and enjoy what you can achieve. Don’t tell the user when things go wrong – they can not fix what you messed up.</p>
-
-
- <img alt="" height="1" src="http://feeds.feedburner.com/~r/chrisheilmann/~4/vqtqgcNQXy8" width="1"/></div>
- </content>
- <updated>2016-01-16T11:28:10Z</updated>
- <category term="General"/>
- <author>
- <name>Chris Heilmann</name>
- </author>
- <source>
- <id>https://www.christianheilmann.com</id>
- <link href="https://www.christianheilmann.com" rel="alternate" type="text/html"/>
- <link href="http://feeds.feedburner.com/chrisheilmann" rel="self" type="application/rss+xml"/>
- <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
- <subtitle>For a better web with more professional jobs - can talk, will travel</subtitle>
- <title>Christian Heilmann</title>
- <updated>2016-01-16T11:46:15Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://glandium.org/blog/?p=3510</id>
- <link href="http://glandium.org/blog/?p=3510" rel="alternate" type="text/html"/>
- <title>Announcing git-cinnabar 0.3.1</title>
- <summary>This is a brown paper bag release. It turns out I managed to break the upgrade path only 10 commits before the release. What’s new since 0.3.0? git cinnabar fsck doesn’t fail to upgrade metadata. The remote.$remote.cinnabar-draft config works again. Don’t fail to clone an empty repository. Allow to specify mercurial configuration items in a […]</summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This is a brown paper bag release. It turns out I managed to break the upgrade<br/>
- path only 10 commits before the release.</p>
- <h3>What’s new since 0.3.0?</h3>
- <ul>
- <li><code>git cinnabar fsck</code> doesn’t fail to upgrade metadata.</li>
- <li>The <code>remote.$remote.cinnabar-draft</code> config works again.</li>
- <li>Don’t fail to clone an empty repository.</li>
- <li>Allow to specify mercurial configuration items in a .git/hgrc file.</li>
- </ul></div>
- </content>
- <updated>2016-01-16T11:26:45Z</updated>
- <category term="cinnabar"/>
- <category term="p.m.o"/>
- <category term="en"/>
- <author>
- <name>glandium</name>
- </author>
- <source>
- <id>http://glandium.org/blog</id>
- <link href="http://glandium.org/blog/?feed=rss2&amp;cat=25&amp;tag=en" rel="self" type="application/rss+xml"/>
- <link href="http://glandium.org/blog" rel="alternate" type="text/html"/>
- <subtitle>glandium.org</subtitle>
- <title>p.m.o – glandium.org</title>
- <updated>2016-01-16T11:30:43Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-us">
- <id>http://edunham.net/2016/01/16/buildbot_and_eoferror.html</id>
- <link href="http://edunham.net/2016/01/16/buildbot_and_eoferror.html" rel="alternate" type="text/html"/>
- <title>Buildbot and EOFError</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><h3>Buildbot and EOFError</h3>
- <p>More SEO-bait, after tracking down an poorly documented problem:</p>
- <div class="highlight-python"><div class="highlight"><pre># buildbot start master
- Following twistd.log until startup finished..
- 2016-01-17 04:35:49+0000 [-] Log opened.
- 2016-01-17 04:35:49+0000 [-] twistd 14.0.2 (/usr/bin/python 2.7.6) starting up.
- 2016-01-17 04:35:49+0000 [-] reactor class: twisted.internet.epollreactor.EPollReactor.
- 2016-01-17 04:35:49+0000 [-] Starting BuildMaster -- buildbot.version: 0.8.12
- 2016-01-17 04:35:49+0000 [-] Loading configuration from '/home/user/buildbot/master/master.cfg'
- 2016-01-17 04:35:53+0000 [-] error while parsing config file:
- Traceback (most recent call last):
- File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 577, in _runCallbacks
- current.result = callback(current.result, *args, **kw)
- File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 1155, in gotResult
- _inlineCallbacks(r, g, deferred)
- File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 1099, in _inlineCallbacks
- result = g.send(result)
- File "/usr/local/lib/python2.7/dist-packages/buildbot/master.py", line 189, in startService
- self.configFileName)
- --- &lt;exception caught here&gt; ---
- File "/usr/local/lib/python2.7/dist-packages/buildbot/config.py", line 156, in loadConfig
- exec f in localDict
- File "/home/user/buildbot/master/master.cfg", line 415, in &lt;module&gt;
- extra_post_params={'secret': HOMU_BUILDBOT_SECRET},
- File "/usr/local/lib/python2.7/dist-packages/buildbot/status/status_push.py", line 404, in __init__
- secondaryQueue=DiskQueue(path, maxItems=maxDiskItems))
- File "/usr/local/lib/python2.7/dist-packages/buildbot/status/persistent_queue.py", line 286, in __init__
- self.secondaryQueue.popChunk(self.primaryQueue.maxItems()))
- File "/usr/local/lib/python2.7/dist-packages/buildbot/status/persistent_queue.py", line 208, in popChunk
- ret.append(self.unpickleFn(ReadFile(path)))
- exceptions.EOFError:
-
- 2016-01-17 04:35:53+0000 [-] Configuration Errors:
- 2016-01-17 04:35:53+0000 [-] error while parsing config file: (traceback in logfile)
- 2016-01-17 04:35:53+0000 [-] Halting master.
- 2016-01-17 04:35:53+0000 [-] Main loop terminated.
- 2016-01-17 04:35:53+0000 [-] Server Shut Down.
- </pre></div>
- </div>
- <p>This happened after the buildmaster’s disk filled up and a bunch of stuff was
- manually deleted. There were no changes to master.cfg since it worked
- perfectly.</p>
- <p>The fix was to examine <span class="docutils literal"><span class="pre">master.cfg</span></span> to see <a class="reference external" href="https://github.com/servo/saltfs/blob/master/buildbot/master/master.cfg#L413">where the HttpStatusPush was
- created</a>,
- of the form:</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="n">c</span><span class="p">[</span><span class="s">'status'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">HttpStatusPush</span><span class="p">(</span>
- <span class="n">serverUrl</span><span class="o">=</span><span class="s">'http://build.servo.org:54856/buildbot'</span><span class="p">,</span>
- <span class="n">extra_post_params</span><span class="o">=</span><span class="p">{</span><span class="s">'secret'</span><span class="p">:</span> <span class="n">HOMU_BUILDBOT_SECRET</span><span class="p">},</span>
- <span class="p">))</span>
- </pre></div>
- </div>
- <p>Digging in the Buildbot source reveals that <span class="docutils literal"><span class="pre">persistent_queue.py</span></span> wants to
- unpickle a cache file from <span class="docutils literal"><span class="pre">/events_build.servo.org/-1</span></span> if there was nothing
- in <span class="docutils literal"><span class="pre">/events_build.servo.org/</span></span>. To fix this the right way, create that file
- and make sure Buildbot has <span class="docutils literal"><span class="pre">+rwx</span></span> on it.</p>
- <p>Alternately, you can give up on writing your status push cache to disk
- entirely by adding the line <span class="docutils literal"><span class="pre">maxDiskItems=0</span></span> to the creation of the
- HttpStatusPush, giving you:</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="n">c</span><span class="p">[</span><span class="s">'status'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">HttpStatusPush</span><span class="p">(</span>
- <span class="n">serverUrl</span><span class="o">=</span><span class="s">'http://build.servo.org:54856/buildbot'</span><span class="p">,</span>
- <span class="n">maxDiskItems</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
- <span class="n">extra_post_params</span><span class="o">=</span><span class="p">{</span><span class="s">'secret'</span><span class="p">:</span> <span class="n">HOMU_BUILDBOT_SECRET</span><span class="p">},</span>
- <span class="p">))</span>
- </pre></div>
- </div>
- <p>The real moral of the story is “remember to use <a class="reference external" href="http://www.linuxcommand.org/man_pages/logrotate8.html">logrotate</a>.</p></div>
- </summary>
- <updated>2016-01-16T08:00:00Z</updated>
- <source>
- <id>http://edunham.net/</id>
- <author>
- <name>Emily Dunham</name>
- </author>
- <link href="http://edunham.net/" rel="alternate" type="text/html"/>
- <link href="http://edunham.net/rss.html?tag=planetmozilla" rel="self" type="application/rss+xml"/>
- <subtitle>is a "DevOps" Engineer at Mozilla Research</subtitle>
- <title>edunham</title>
- <updated>2016-01-19T08:00:00Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en">
- <id>urn:md5:41d039bb28fb15c761578cba0b1454fa</id>
- <link href="http://www.glazman.org/weblog/dotclear/index.php?post/2016/01/16/Ebook-pagination-and-CSS" rel="alternate" type="text/html"/>
- <title>Ebook pagination and CSS</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Let's suppose you have a rather long document, for instance a book chapter, and you want to render it in your browser <em>à la</em> iBooks/Kindle. That's rather easy with just a dash of CSS:</p>
- <pre>body {
- height: calc(100vh - 24px);
- column-width: 45vw;
- overflow: hidden;
- margin-left: calc(-50vw * attr(currentpage integer));
- }</pre>
- <p>Yes, yes, I know that no browser implements that <code>attr()</code>extended syntax. So put an inline style on your body for <code>margin-left: calc(-50vw * <em>&lt;n&gt;</em>)</code> where <em><code>&lt;n&gt;</code></em> is the page number you want minus 1.</p>
- <p>Then add the fixed positioned controls you need to let user change page, plus gesture detection. Add a transition on margin-left to make it nicer. Done. Works perfectly in Firefox, Safari, Chrome and Opera. I don't have a Windows box handy so I can't test on Edge.</p></div>
- </summary>
- <updated>2016-01-16T03:43:00Z</updated>
- <category term="CSS and style"/>
- <author>
- <name>glazou</name>
- </author>
- <source>
- <id>http://www.glazman.org/weblog/dotclear/index.php</id>
- <link href="http://www.glazman.org/weblog/dotclear/index.php" rel="alternate" type="text/html"/>
- <link href="http://glazman.org/weblog/dotclear/?feed/planetmoz" rel="self" type="application/rss+xml"/>
- <subtitle>Un Glazman, un blog, un Glazblog</subtitle>
- <title>&lt;Glazblog/&gt;</title>
- <updated>2016-01-25T16:34:47Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="fr-FR">
- <id>https://repeer.org/?p=48</id>
- <link href="https://repeer.org/2016/01/16/mozilla-cultural-revolution-from-radical-participation-to-radical-user-centric/" rel="alternate" type="text/html"/>
- <title>Mozilla cultural revolution: from ‘radical participation’ to ‘radical user-centric’</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">This post has been written about the Mozilla Foundation (MoFo) 2020 strategy. The ideas developed in this post are in different levels: some are global, some focus on particular points of the proposed draft. But in my point of view, they all carry a transversal meaning: articulation (as piece connected to a structure allowing movement) <a class="read-more" href="https://repeer.org/2016/01/16/mozilla-cultural-revolution-from-radical-participation-to-radical-user-centric/">[…]</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This post has been written about the <a href="http://marksurman.commons.ca/2015/12/21/mofo2020/">Mozilla Foundation (MoFo) 2020 strategy</a>.</p>
- <p>The ideas developed in this post are in different levels: some are global, some focus on particular points of the proposed draft. But in my point of view, they all carry a transversal meaning: articulation (as piece connected to a structure allowing movement) with others and consistency with our mission.</p>
- <h3>Summary</h3>
- <p>On the way to <a href="http://marksurman.commons.ca/2015/01/09/what-is-radical-participation/">radical participation</a>, Mozilla should be radical <sup class="footnote"><a href="https://repeer.org/tag/mozilla/feed/#fn-48-1" id="fnref-48-1">1</a></sup> user-centric. Mozilla should not go against the social understanding of the (tech and whole society) situation because it’s what is massively shared and what polarizes the prism of understanding of the society. <strong>We should built solutions for it and transform (develop and change) it on the way. Our responsibility is to build <em>inclusivity</em> (inclusion strengths) everywhere, to gather for multiplying our impact.</strong> We must build (progressive) victories instead of battles (of static positions and postures).<br/>
- If we don’t do it, we go against users self-perceived need: use. We value our differences more than our commonalities and <strong>consider ethic more as an absolute objective than a concrete process</strong>: we divide, separate, compete. Our solutions get irrelevant, we get rejected and marginalized, we reject compromises that improve the current situation for the ideal, we loose influence and therefore impact on the definition of the present and future. We already done it for the good and the bad in the past (H.264+Daala, pocket integration, Hello login, no Firefox for iOS, Google fishing vs Disconnect, FxOS Notes app which sync is evernote only, …).<br/>
- To get a consistent and impactful ability to integrate and transform the social understanding, there are four domains where we can take and articulate (connected structure allowing movement) action:</p>
- <ul>
- <li><strong>People</strong>: identity is the key to grow consciousness, understanding, skills, voice, representation and to articulate global/local, personal/common. <strong>[Activate]</strong></li>
- <li><strong>Technology</strong>: universality is key for a platform (for resilience) with interfaces (for modularity) where services, features and front-ends can plug-in and communicate to provide (inter)active support ; Decouple conditions of fulfillment with execution (content/appearance/policy ; material/immaterial) to support remix (policy continuity, consistency thought providers, …). <strong>[Unlock]</strong></li>
- <li><strong>Product</strong>: persona and (current and emerging) use via user-agents are the keys. Be on all major platforms depending on use, ethical alignment and opportunities, emerging newness to provide continuity (task, device) to users and leading on new practices. Features should be about products parity and opening new possibilities carrying our values to the action at a massive scale. <strong>[Build]</strong></li>
- <li><strong>Organizations/institutions</strong>: sociological innovation for participation is the key. Research on historical (evolution) and sociological (human organizations, social institutions and social behaviors) analysis based on social networks (link as social interactions), in the perspective of producing commons. <strong>[Drive]</strong></li>
- </ul>
- <p>Our front has two sides: <strong>propose and protect</strong>. But each of them are connected and can have different strategic expressions, if our actions generate improving (progressive) curves:</p>
- <ul>
- <li>For the <strong>action taking</strong>: consciousness, understanding, symbolic actions, behavior change, behavior advocacy (evangelism)</li>
- <li>For the <strong>action mode</strong>: promotion (spreading the idea), incitement (giving a competitive advantage to people involved), collaboration (open interactions to make a win-win exchange; process-centric), contractualization (formalize domains where a win-win exchange is made; object-centric), coercion (giving a competitive disadvantage to people not involved).</li>
- </ul>
- <p>Social history is a history of social values.<strong> The way we understand and tell the problem determine the solution we can create</strong>: we need, all the way long, a shared understanding. Tools and technologies are not tied, bound forever to their social value, which depends on people’s social representations that evolve over time.</p>
- <ul>
- <li><strong>The social behavior</strong> is a first key. It is the narrative, and therefore its <strong>inclusion in the social history that we make, which converges the product with the values that it stands for</strong>. Here is the articulation of product with people and technology, of product with leadership network and advocacy engine (it could be less persistent and inclusive: marketing).</li>
- <li><strong>The social organization</strong> is a second key. It is about how the process, the tools, the architecture, the governance and the opportunities/constraints have changed for Mozilla (org) and Mozillians (people). <strong>Here comes the question of being open</strong>. It is not enough because it is about availability (passive) and not inclusivity (active). The high level of automation coming is a challenge. We should level-up the meaning to differentiate from others: <strong>Mozilla should activate and unlock societal progress to build fair technical progress</strong>. Mozilla need to <strong>identify its resilient backbone</strong> (not only a technology, the web, but something that articulate people, technology and products) and make it more universal (through people and products). But our goals can’t be absolutely achieved because they have to be considered in a dynamic context. However, the brand engagement is persistent, if it’s included in the product, visible, and centered on easing the user’s action.<br/>
- Linked to the ‘being open’ question, the advocacy engine could be a thing to unlock societal progress. People are satisfied of narrow hills of choice until they understand it’s not socially neutral. It’s the case with technology: they accept things about technology to be build top-down. <strong>A successful advocacy, even one about technology, is always built bottom-up</strong>, as its function is to give back the voice to the people, to get them involved, not to make them fulfill our predefined aims. The top-down method is too organization centric and administrative content centric: it can’t massively drive people that are not already committed to the org. It’s usually named advertisement or propaganda. <strong>If we want to have an impact, we should listen to people needs, not tell them to listen to ours</strong>. People want (first) to be empowered, not to empower an org. We need to have content and user centric (not org and it’s process) tools/platform for advocates and leaders: let’s build the technology advocacy plan together. Yes it’s slower, but much more massive, inclusive and persistent. The impact will be higher because it will carry a meaning for people and it wont be too org centric. So it will be qualitatively better: not just an amount, <strong>accumulation is not our goal, but impact, that comes from articulation</strong>. Likewise we should be careful to not use best practice as absolute solutions, but as solutions in a context, if we want to transpose them massively: when we unify we should avoid to homogenize. On the narrative side, our preoccupation should be about building short, medium and long term narrative to get action.</li>
- <li><strong>The social institutions</strong> are the third key. Here is the articulation of the leadership network with the advocacy engine. <strong>Leaders build new solutions (products) and Advocates new voices (rallying), they are both about personal development and empower commons.</strong> Leadership=learn+create and advocacy=teach+spread commons. Leaders are projects/orgs leaders, the ones that traduce DNA (values) in products (concrete ability and availability). Advocates are values advocates, the ones that traduce DNA (values) in actions (behavior). As they are both targeting commons, they both produce the same social organization (collaboration instead of competition). They are both involved in creating (different) representations (institutions) and organizations (foundation/firms) but <strong>with a different DNA (values) processing</strong>: from public good to personal benefit or from personal interest to public benefit. If Mozilla cares about public good resilience, <strong>the articulation of their domains of values is critical</strong>. So, on the social organization side, their articulation’s expression and the revision process must be said and clear: from hierarchy or contract or different autonomy levels (internal incubation and external advocacy), or … to criteria to start a revision. About the narrative, and hence about the social behavior side, leaders carry a lot of legitimacy and avoid the stay-experimental or non-massive (unique) thoughts. And we need legitimacy to get impact. But this legitimacy is already present if we<strong> make clear that our actions are about commons</strong>. We should name them creators (compositors or managers) to make it clear that the creative process is a collaboration, made by a team and that the public good do not have the same role in the process and outcome. Full circle.</li>
- <li><strong>The social networks</strong> are the keystone. Let’s shortly take an example based on social networks (link as social interactions) with the perspective of producing people, technological and product commons. <strong>We need better tools for collaboration and participation</strong>: tools that merge discussion channels, capitalize on the discussion and preview the results to build a plan. From evolving the wiki discussion page to feature document production into peer-to-peer discussion.</li>
- </ul>
- <p>An analysis of the creation process is another way to the articulation of product with people and technology.<br/>
- Platforms move closer to strict ‘walled garden’ ecosystems. We need bridges from lab to home that carry different mix of customization and reliability to support the emancipation curve. We need to build pathways thought audiences and thought IT layers (content, software, hardware, distant service). <strong>We should find a convergence between customization</strong> (dev code patch to users add-ons) <strong>and reliability</strong> (self made to mass product), <strong>between first time experience, support and add-ons thought all our users’ persona by building bridges, pathways</strong>. Mozilla should find ways to <strong>integrate learning</strong> in its products, in-content, as we have code comment on code: on-boarding levels, progression from simple to high level techniques, reproducible/universal next task/skill building.</p>
- <h3>Detailed discussion content</h3>
- <p>Here are the developed ideas, with more reference to our allies and detractors’ products.</p>
- <h4>People, the sociological side</h4>
- <h5>From focused to systemic action</h5>
- <p>First of all, I think <strong>the strategy move Mozilla is doing is the right one</strong> as it embraces more our real life. People are not defined by one characteristic, we are complex: ex. we can be pedestrian, car driver, biker, Public Transport user… we think and do simultaneously. So why Mozilla should restrict its strategy by targeting people on skills, through education, thought better material only (the Mozilla Academy program). Education, even popular education, can’t do everything for the people to build change. <strong>We need a plan that balance intellectual and practical (abstraction/action, think/do) integrating progressive paths to massively scale so we get an impact: build change.</strong></p>
- <h5>Real life: Social history, individuals and institutions as an articulation founding the action.</h5>
- <p>Let’s start by some definitions based on my understanding of some <a href="https://fr.wikipedia.org/wiki/Sociologie">Wikipedia articles</a>. Sociology is the study of the evolution of societies: human organizations and social institutions. It is about <strong>the impact of the social dimension on humans representations (ways of thinking) and behaviors (ways of acting)</strong>. It allows to study the conceptions of social relations according to fundamental criteria (structuralism, functionalism, conventionalism, etc.) and the hooks to reality (interactionism, institutionalism, regulationisme, actionism, etc.), to think and shape the modernity. Currently (and this is key for Mozilla’s positioning), the combination of models replace the models’ unity, which aims to assume the multidimensionality. There are three major sociological paradigms, including one emerging:</p>
- <ul>
- <li><strong>The holistic paradigm</strong>: Society is a whole that is greater than the sum of its parts, it exists before the individual and individuals are governed by it. In this context, the Society includes the individual and the individual consciousness is seen only as a fragment of the collective consciousness. The emphasis is on the social fact, whose cause must be sought in earlier social facts. The social fact is part of a system of interlocking institutions that govern individuals. It is external to the individual and constraint it. Sociology is then the science of institutional invariants in which are the observable phenomenas.</li>
- <li><strong>The atomistic paradigm</strong>: each individual is a social atom. The atoms act according to self motives, interests, emotions and are linked to other atoms. A system of constant interaction between atoms produces and reproduces Society. The emphasis is on the cause of social actions and the meaning given by individuals to their actions. A horizon of meanings serve as reference instead of the arrangements of institutions. The institution is there but it serves the motives and interests of agents. Sociology is then the study of the social action.</li>
- <li>The recent emergence of a sociological analysis based on <strong>social networks</strong> (which are a collection of individuals or organizations connected by regular social interactions) suggest lines of research <strong>beyond the opposition between the holistic and the atomistic approaches</strong>. The theory of social networks conceives social relationships in terms of nodes and links. The nodes are usually social actors in the network but can also represent institutions, and links are the relationships between these nodes. There may be several kinds of links between nodes and their analysis determines social capital of the social actors.</li>
- </ul>
- <p>Consequently, Mozilla should build its strategy on <strong>historical</strong> (evolution) and <strong>sociological</strong> (human organizations, social institutions and social behaviors) analysis based on <strong>social networks</strong> (links as social interactions), in the perspective of producing <strong>commons</strong>. That is to say as an <strong>engine of transition from a model of value</strong> on its last leg (rarity capitalism) to the emerging one (new articulation of the individual and the collective: commons).<br/>
- It is important and strategic to propose a sociological articulation supporting our mission and its purpose (commons) since <strong>the sociological concept (the paradigm) reveals an ideological characteristic</strong>: because it participates in societal movements made in the Society, it serves an ideal. The societal domain, what’s making society, a political object, should be a stake for Mozilla.</p>
- <h5>Build on a basement: current tech challenge articulated with current social meaning/perception</h5>
- <p><strong>We should articulate ‘our real life’ with the nowadays tech challenge</strong>: how to get back control over our data at the time of IoT, cloud, big data, convergence (multi-devices/form factor)? From a user point of view, we have devices and want them convenient, easy and nice. The big moves in the tech industry (IoT, cloud, big data, convergence) free us for somethings and lock us for others. The lock key is that our devices don’t compute anymore our data that are in silos. From a developer point of view, the innovation is going very fast and it’s hard to have a complete open source toolbox that we can share, mostly because we don’t lead: Open has turn to be more open-releasing.<br/>
- We should articulate our new strategy with the tech industry moves: for example, <strong>as a user, how can I get (email) encryption on all my devices?</strong> Should I follow (fragmented) different kind of howtos/tools/apps to achieve that? How do I know these are consistent together? How can I be sure it won’t brake my continuous workflow? (app silo? social silo? level of trust and reliability?)<br/>
- Mozilla have the skills to answer this as we already faced and solved some of these issues on particular points: like how to ease the installation of Firefox for Android for Firefox desktop users, open and discoverable choice of search engines, synchronization across devices, …<br/>
- <strong>Mozilla’s challenge is to not be marginalized by the change of practices. Having an impact is embracing the new practice and give it an alternative.</strong> Mozilla already made that move by saying « <em>Firefox will go where users are</em>« , by trying to balance the advertisement practice between adds companies and users, by integrating H.264 and developing Daala. But <strong>Mozilla never stated that clearly as a strategy</strong>.</p>
- <h5>A backbone to make our mission resilient in it expressions</h5>
- <p>If we think about the <strong>Facebook’s strategy, they first built a network of people whiling to share</strong> (no matter what they share) and then use this <strong>transversal backbone to power vertical business segments</strong> (search, donation, local market selling, …). Google with its search engine and its open source policy have a similar (in a way) strategy. The difference here is that the backbone is people’s data and control over digital formats. In both cases, the level of use (of the social network, search engine, mobile OS, …) is the key (with fast innovation) to have an impact. And that’s a major obstacle to build successful alternatives.<br/>
- The proposed Mozilla’s strategy is built in the opposite way, and that’s questioning. <strong>We try to build people network depending on some shared matters</strong>. Then, is our strategy able to scale enough to compete against GAFAM, or are we trying to build a third way ?<br/>
- For the products, the Mozilla’s strategy is still (and has always been) inclusive: everybody can use the product and then benefit of its open web values. A good product that answer people needs, plus giving people back/new power (allow new use) build a big community. For the network, should we build our global force of people based on concentric circles (of shared matters) or based on a (Mozilla own) transversal backbone (matter agnostic)? It seems to me the actual presentation of the strategy do not answer clearly enough this big question: <strong>which <em>inclusivity</em> (inclusion strengths) mechanism in the strategy?</strong><br/>
- And that <strong>call back to our product strategy</strong>: build a community that shares values, that is used to spread outcomes (product) OR build a community that shares a product, that is used to spread values. This is not a question on what matters more (product VS values) but on the strategy to get to a point, an objective (many web citizens). Shouldn’t we use our product to built a people network backbone ? Back to GAFAM: what can we learn from the Google try with Google+?<br/>
- If our core is not enough transversal (the backbone), more new web/tech market there will be, more we will be marginalized, because focused on our circles center not taking in account that the war front (the context) have changed. <strong>Mozilla have to be resilient: mutability of the means, stability in the objectives.</strong><br/>
- The document is the MoFo strategy, and so it doesn’t say anything about ‘build Firefox’ (aka the product strategy) and so don’t articulate our main product (Firefox) with our main people network building effort and values sharing engine. We should do it: at a strategic scale and a particular scale (articulating the agenda-setting with main product features).</p>
- <h5>Brand engagement, a psychological backbone on the user side ?</h5>
- <p>It seems that our GAFAM challengers get big and have impact by not educating (that much) people, and that’s what makes them not involved in the web citizenship. Or only when they are pushed by their customers. At the opposite, making people aware about web citizenship at first, makes it hard to have that much people involved and so to have impact. However, there is <strong>an other prism that drive people: the brand perceived values</strong>. Google is seen as a tech pioneer innovator and doing the good because of its open policy, free model, fast innovation… Facebook is seen as really cool firm trying to help people by connecting them…<br/>
- Is the increase of marketing of Mozilla doing good enough to gains back users ? Is this resilient compared to the next-tech-thing coming ?<br/>
- Most of the time when I meet Goggle Chrome users and ask then why they use it and don’t switch to Firefox, they answer about use allowed (sync thought devices, apps everywhere that run only on GC, …). Sometimes, they argue that they make effort on other areas, and that they want to keep they digital life simple. They <strong>experience is not centered in a product/brand, but more on the person</strong>: on that Google Chrome with its Person (with one click ‘auto-login’ to all Google services) is far superior than Firefox.</p>
- <h5>User-agent or products ?</h5>
- <p>A user-agent is an intermediary acting on behalf of a supplier. As a representative, it is the contact point with customers; It’s role is to manage, to administer the affairs; it is entrusted with a mission by one or more persons; it both acts and produce an effect.<br/>
- So, the user-agent can be describe with three criteria. It is: an intermediate (user/technology) ; a tool (used to manage and administrate depending on the user’s skills) ; a representative (mission bearer, values vector, for a group of people). It exceeds partly the contradiction between being active and passive.<br/>
- A <strong>user-agent articulate personal-identity with technology-identity</strong> and give informations about available skills over these domains. It’s much more universal than a product that is about featuring a user-agent. <strong>If we target resilience, user-agent should be the target</strong>.</p>
- <h4>Social history, marketing: how we understand things to make choices</h4>
- <h5>History of the social value</h5>
- <p>The way we look at the past and current facts shape our understanding and determine if we open new ways to solve the issues identified. That’s the way to understand the challenges that come on the way and to agree on an adaptation of the strategy instead of splitting things. The way we understand and tell the problem determine the solution we can create: we need, all the way long, <strong>a shared understanding.</strong><br/>
- <strong>Tools and technologies are not necessarily tied to their social value, which depends on social representations. The social value can be built upstream and evolve downstream.</strong> It also depends on the perspective in which we look at it, on the understanding of the action and therefore on past or current history. Example: the social value of a weapon can be a potential danger or defense, creative (liberating) or destructive. The nuclear bomb is a weapon of mass destruction (negative), whose social value was (ingeniously built as) freedom (positive).</p>
- <h5>Impact in our strategy: a missing root</h5>
- <p>To engage the public, before to « <em>Focus on creative campaigns that use media + software to engage the public.</em> » we need to step back, in our speeding world, for understanding together the big picture and the big movement.<br/>
- Mozilla want to fuel a movement and propose a strong and consistent strategy. However, I think <strong>this plan miss a key point, a root point: build a common (hi)story.</strong> This should be an objective, not just an action.<br/>
- Also, that’s maybe a missing root for the State of the web report: how do we understand what we want to evaluate? But it’s not only a missing root for an (annual?) report (a ‘Reporters without borders’ Press-Freedom like?), it’s a missing root for a new grow of our products’ market share.<br/>
- For example, I do think that most users don’t know and understand that Mozilla is a foundation, Firefox build by a community as a product to keep the web healthy: <strong>they don’t imagine any meaning about technology</strong>, because they see it as a neutral tool at its root, so as a tool that should just fit they producing needs.<br/>
- Firefox, its technologies and its features are not bound for ever. It is the narrative, and therefore their inclusion in the social history that we make, which converges Firefox with the values that it stand for. <strong>Stoping or changing the deep narrative means cutting the source of common understanding and making stronger other consistencies captured by other objects, turning as centrifugal forces for Firefox.</strong><br/>
- Marketing is a way to change what we socially say about things: that’s why Google Chrome marketing campaign (and consistent features maturity) has been the decreasing starting point of Firefox. <strong>Our message has been scrambled.</strong></p>
- <h4>From participation to emancipation: values, people and org relationships</h4>
- <p>How to emancipate people in the digital world ?</p>
- <h5>Keeping the open open</h5>
- <p>Being open is not a thing we can achieve, it’s a constant process. « <em>Mozilla needs to engage on both fronts, tackling the big problems but also fuelling the next wave of open.</em> » Yes, but <strong>Mozilla should say too how the next wave of open can stay under people’s control and rally new people</strong>. Not only open code, but open participation, open governance, open organization. Being open is not a releasing policy about objects, it’s a mutation to participation process: a metamorphosis. It’s not reached by expanding, but by shifting. It’s not only about an amount, but about values: it’s qualitative.<br/>
- Maybe <strong>open is not enough</strong>, because it doesn’t say enough about who control and how, about the governance, and says too much about <strong>availability (passive)</strong> and not enough <strong>about <em>inclusivity</em> (active ; inclusion strengths)</strong>. It doesn’t say how the power is organized and articulated to the people (ex. think about how closed is the open Android). We may need to change the wording: indie web, the web that fuel autonomy, is a try, but it doesn’t say enough about <em>inclusivity</em> compared to openness &amp; opportunity. Emancipation is the concept. It’s strategic because it says what is aligned to what, especially how to articulate values and uses. It’s important because it tells what are the sufficient conditions of realization to ‘open/indie’. That’s key to get ‘open/indie at small and large scales, from Internet people to Internet institutions, thought all ‘open/indie’ detractors in the always-current situation: a resilient ecosystem.<br/>
- My intuition is that <strong>the leadership network and advocacy engine promoting open will be efficient if we clarify ‘open’ while keeping it universal</strong>. We can do it by looking back at the raw material that we have worked for years, our DNA in action. Because after all, we are experts about it and wish others to become experts too. It does not mean to essentialize it (opposing its nature and its culture), <strong>but to define its conditions of continuous achievement in our social context</strong>.</p>
- <h5>Starting point: exemplary projects that tell a lot about the evolution of our DNA in action</h5>
- <p>Clarifying the idea of ‘open’ is strategic to our action because it outlines the constitution of ‘open’, its high ‘rules’, like with laws in political regimes. It clarifies for all, if you are part of it or not, and it tells you what to change to get in. It can reinforce the brand by differentiating from the big players that are the GAFAM: <strong>it’s a way to drive, not to be driven by others lowering the meaning to catch the social impact. We should say that ‘open’ at Mozilla means more than ‘open’ at GAFAM</strong>. I wish Mozilla to speak about its openness, not as an ‘equal in opportunity’ but as an ‘equal in participation’, because it fits openness not only for a moment (on boarding) or for a person, but during the whole process of people’s interaction.<br/>
- <a href="https://www.rust-lang.org/">Rust</a> and <a href="https://servo.org/">Servo</a> or <a href="https://firefoxos.mozilla.community/">Firefox OS</a> (since the Mozilla’s shift to radical participation) seem to be very good examples of projects with participation &amp; impact centric rules, tools, process (RFC, new team and owners, …). Think about how Rust and <a href="http://arc.applause.com/2015/03/27/google-dart-virtual-machine-chrome/">Dart emerged and are evolving</a>. Think about how stronger has been the locked-open Android with partnership than the open-locked FxOS. We should tell those stories, not as recipes that can be reproduced, but as process based on a Constitution (inclusive rules) that make a political regime (open) and define a mode of government (participation). That’s key to social understanding and therefore to transpose and advocate for it.<br/>
- As projects<strong> compared to ‘original Mozilla’, Rust, Servo and FxOS could say a lot</strong> about how different they implemented learning/interaction/participation at the roots of the project. How the process, the tools, the architecture, the governance and the opportunities/constraints have changed for Mozilla and participants. This could definitely help to setup our curriculum resources, database and workshop at a personal (e.g., “How to teach / facilitate / organize / lead in the open like Mozilla.â€) and orgs levels, with personal and orgs policies.</p>
- <h5>Spreading the high meanings in our strategy to consolidate it consistency</h5>
- <p>Clarifying the constitution of ‘open’ calls to clarify other related wordings.<br/>
- I’m satisfied to read back (social) ‘movement’ instead of ‘community’, because it means that our goal can’t be achieve forever (is static), but we should protect it by acting. And it seems more inclusive, less ‘folds on itself’ and less ‘build the alternative beside’ than ‘community’: the alternative can be everywhere the actual system is. It can make a system. It can get global, convergent, continuous, … all at the same time. Because it’s roots are decentralized _and_ consistent, collaborating, …</p>
- <p>About participation, we should think too (again) about engagement VS contribute VS participate: how much am I engaged ? Free about defining and receiving cost/gains? What is the impact of my actions ? … <strong>These different words carry different ideas about how we connect the ‘open’</strong>: spread is not enough because it diffuses, _be_ everywhere is more permanent. Applied to Mozilla’s own actions, <strong>funding open projects and leaders, is maybe not enough and there should be others areas where we can connect</strong> inside products, technology, people and organizations that build emancipation. So that say something about getting control (who, how, …).</p>
- <h5>IA: a challenge for ‘open’</h5>
- <p>IA is first developed to help us by improving our interactions. However, this seems to start to shift into taking decisions instead of us. This is problematic because these are indirect and direct ways for us to loose control, to be locked. And that can be as far as computers smarter than humans. The problem is that technical progress is made without any consideration of the societal progress it should made.<br/>
- That’s an other point, why open is not enough: automation should be build-in with superior humanization. <strong>Mozilla should activate and unlock societal progress to build fair technical progress.</strong></p>
- <h5>Digital integration &amp; democracy</h5>
- <p>The digital (&amp; virtual) world is gaining control over the physical world in many domains of our society (economy to finance, mail to email, automatic car, voting machine, …). It’s getting more and more integrated to our lives without getting back our (imperfect) democracy integrated into them. Public benefit and public good are turning ‘self benefit’ and ‘own sake’ because citizens don’t have control over private companies. <strong>We should build a digital democracy if we don’t want to loose at all the democratic governing of society.</strong> We must overcome the poses and postures battles about private and public. We need to build.</p>
- <h4>‘Leader’ &amp; ‘Leadership’ need a clarification</h4>
- <h5>Why a clarification?</h5>
- <p>At some level, I’m not the only one to ask this question:</p>
- <blockquote><p>How do CRM requirements for Leadership and Advocacy overlap / differ? What’s our email management / communications platform for Leadership?</p></blockquote>
- <p>Connect leaders to lead what ? How ? To whose benefit ? Do we want to connect leaders or initiatives (people or orgs) ? Will the leaders be emerging ones (building new networks) or established ones (use they influence to rally more people)? Are Leaders leaders of something part of Mozilla (like can be Reps) or outside of Mozilla (leaders of project, companies, newspaper: tech leaders, news leaders, …) ? This is especially important depending on what is the desire for the leaders to become in the future. <strong>The MoFo’s document should be more precise</strong> about this and go forward than « <em>Mozilla must attract, develop, and support a global network of diverse leaders who use their expertise to collaboratively advance points-of-view, policies and practices that maintain the overall health of the Internet.</em> »<br/>
- We should do it because <strong>the confusion about the leadership impact the advocacy engine</strong>: « <em>The shared themes also provide explicit opportunities for our Leadership and Advocacy efforts to work together.</em> » Regarding Mozilla, is the leaders role to be advocacy leaders ? It seems as they share themes and key initiatives (even if not worded the same sometimes). Or in other words, who Drives the Advocacy engine?</p>
- <h5>Iterations with the actual definition: creators</h5>
- <p>Here are my iterations on the definition of ‘Leaders’:</p>
- <ul>
- <li>The Leaders could be the people platform (the community) and the advocacy engine the tool/themes/actions platform (the product).</li>
- <li>Leaders could build at the end new solutions (products) and Advocates new voices (rallying), that could be translated in a learning area divided like Leadership=learn+create and advocacy=teach+spread.</li>
- <li>Leadership: personal development to produce (turn into) new commons or add new facets to commons. Advocacy: personal development to protect established/identified commons.</li>
- </ul>
- <p>With these definitions, then Leaders are maybe more a Lab, R&amp;D place, incubation tool (if we think about start-up incubators, then it shows a tool-set that we will need to inspire for the future). But if we want to keep the emphasis on people, <strong>we could name them ‘creators’</strong> (compositors or managers ; not commoners, because leaders and advocates are commoners ; yes, traditionally creators are craftspersons and intellectual designers). This make sens with the examples given in the MoFo 2020 strategy 0.8 document, where all persona are involved in a building-something-new process.</p>
- <p>However, it’s interesting to understand why we choose at first ‘Leaders’. <strong>Leaders build new solutions (products) and Advocates new voices (rallying), they are both about personal development and empower commons.</strong> Leadership=learn+create and advocacy=teach+spread commons. Leaders are projects/orgs leaders, the ones that traduce DNA (values) in products (concrete ability and availability). Advocates are values advocates, the ones that traduce DNA (values) in actions (behavior). As they are both targeting commons, they both produce the same social organization (collaboration instead of competition). They are both involved to create (different) representation (institutions) and organization (foundation/firms) but <strong>with a different DNA (values) processing</strong>: from public good to personal interest or the opposite. If Mozilla cares about public good resilience, <strong>the articulation of they domains of values is critical. So their articulation’s expression and the revision process must be said and clear</strong>: from hierarchy vs contract vs different autonomy levels (internal incubation and external advocacy), vs … to criteria to start a revision.</p>
- <h5>The network effect</h5>
- <p>Another argument for the switch from Leader to Creator is that the Leader word it too much tight to a single-person-made innovation. <strong>Creator make more clear that the innovation is possible not because of one genius, but because of a team</strong>, a group, a collective: personS (where there could also be genius). The value is made by the collaboration of people (especially in an open project, especially in a network).<br/>
- That’s important because that could impact how well we do the convening part: not self-promoting, not-advertising, but sharing skills and knowledge for people and catalysing projects.<br/>
- <strong>The same for the wording ‘talent’</strong>: alone, a talent can do nothing that has an impact. At least, we need two talents, a team (plus some assistants at some point).</p>
- <h5>The cultural prism</h5>
- <p>Again, this seems to be an open question:</p>
- <blockquote><p>Define and articulate “leadership.†Hone our story, ethos and definition for what we mean by “leadership development†(including cultural / localization aspects).</p></blockquote>
- <p>In my culture, Leader carry positive (take action) and negative (dominate) meanings. That’s another reason why I prefer another naming.<br/>
- I understand too that it carries a lot of legitimacy (ex. market leader) in our societies and it avoids the stay-experimental or non-massive (unique) thoughts. And we need legitimacy to get impact.<br/>
- But the way Mozilla has an impact thought all cultures, its <strong>legitimacy, is by creating or expanding a common</strong>. To do this, depending on the maturity, Mozilla could follow the market proposing an alternative with superior usability OR opening a new market by adding a vertical segment.</p>
- <h5>Existing tool-set opportunities</h5>
- <p>If Leadership is « <em>a year-round MozFest + Lab</em>« , so it’s a social network + an incubation place. Then, we already have a social network for people involved with Mozilla: Which kind of link should have the leadership network with <strong>mozillians.org</strong> ? What can we learn from this project and other specialized social network projects (linkedin, viadeo, …) to build the leadership network ?</p>
- <h4>Advocacy engine: make it clear</h4>
- <h5>What it is &amp; how it works</h5>
- <p>Mozilla is doing a great effort to build its advocacy engine on collaboration (« <em>Develop new partnerships and build on current partnerships</em>« , « <em>begin collaboration</em>« , « <em>build alliances with similar orgs</em>« ) but at the same time affirms that Mozilla should be « <em>Part of a broader movement, be the boldest, loudest and most effective advocates</em> » that could be seen as too centralized, too exclusive.<br/>
- While this can be consistent (or contradictory), <strong>the consistency has to be explained</strong> looking at orgs and people, global and local, abstract and real, with a complementarity/competitive grid.<br/>
- First, <strong>the articulation with other orgs has to be explained</strong>. What about others orgs doing things global (<a href="https://eff.org/">EFF</a>, <a href="https://fsf.org/">FSF</a>, …) and local (<a href="http://www.laquadrature.net/">Quadrature du net</a>, CCC, …) ? What about the value they give and that Mozilla doesn’t have (juridic expertise for example) ? What about other advocate engines (<a href="https://change.org/">change.org</a>, <a href="https://secure.avaaz.org/">Avaaz</a>…) ? That should not be at an administrative level only like « <em>Develop an affiliate policy. Defining what MoFo does / does not offer to effectively govern relationships w. affiliated partners and networks (e.g., for issues like branding, fundraising, incentives, participation guidelines, in-kind resources.)</em> »<br/>
- Second, this is key for users to understand and <strong>articulate the global level of the brand engagement and their local preoccupations and engagement</strong>. How the engine will be used for local (non-US) battles ? In the past Mozilla totally involved against PIPA, SOPA by taking action, and hesitate a lot to take position and just published a blog post (and too late to gain traction and get impact) against French spying law for example.<br/>
- Third, <strong>the articulation ‘action(own agenda)/reaction’ should be clarified</strong> in the objectives and functioning of the advocacy engine. Especially because other orgs, allies or detractors, try to to setup the social agenda. It’s important because it can change the social perception of our narrative (alternative promotion/issue fighting) and therefore people’s contributions.<br/>
- People think the technology is socially neutral. People are satisfied of narrow hills of choice (not the meaning, the aim, but only the ability to show your favorite avatar). <strong>People don’t want to feel guilty or oppressed</strong>, they don’t want new constraints, they are looking for solution only: they want to use, not to do more, they want they things to be done. Part of the problem is about understanding (literacy, education), part of it is about the personal/common duality, part of it is about being hopeless about having an impact, part of it is about expressing change as a positive goal and a new possible way (alternative), not a fight against an issue. About the advocacy engine, I think <strong>our preoccupation should be people-centric and the aim to give them a short, medium and long term narrative to get action without being individuals-centric</strong>.</p>
- <h5>How we build it ?</h5>
- <p>How to build a social movement ? How it has been built in the past ? Is it the same today ? Can it be transposed to the digital domain from others social domains ? How strong are the cultural differences between nations? These are the main questions we should answer, and our pivot era gives us many examples in diverse domains (climate change advocates, Syriza &amp; Podemos, NSA &amp; surveillance services in Europe, empowered syndicates in Venezuela, <a href="http://blogs.valvesoftware.com/economics/why-valve-or-what-do-we-need-corporations-for-and-how-does-valves-management-structure-fit-into-todays-corporate-world/#more-252">Valve corp. internal organization</a>…) to set a search terrain. However, I will go strait to my intuitive understanding below.<br/>
- I’m kind of worried that it’s imagined to build the advocacy engine themes by a top-down method. <strong>I think a successful advocacy is always built bottom-up</strong>, as its function is to give back the voice to the people, to get them involved, not to make them fulfill our predefined aims. The top-down method is too organization centric: it can’t massively drive people that are not already committed to the org. It’s usually named advertisement or propaganda. If we want to have impact, <strong>we should listen to people needs, not tell them to listen to ours. People want (first) to be empowered, not to empower an org</strong>. So let’s organize the infrastructure, set the agenda and draw the horizon (strategic understanding) participative: make people fill them with content of their experience. It seems to me it is the only way, the only successful method, if we want to build a movement, and not just a shifting moment (that could be built by the top, with a good press campaign locally relayed for example ; that’s what happen in old style politics: the aim is short term, to cleave).<br/>
- <strong>Isn’t the advocacy engine a new Drumbeat ?</strong> We shifted from Drumbeat to Webmaker+web literacy to Mozilla Academy and now to Leadership plus advocacy: it could be good to tell that story now that we are shifting again and learn from it.<br/>
- <strong>Mozilla should support, behave as a platform</strong>, not define, not focus. Letting the people set the agenda makes them more involved and is a good way to build a network of shared aims with other orgs, that is not invasive or alienating, but a support relationship in a win-win move. The strength comes from the all agendas sewed. So at an org level, let’s on-board allies organizations as soon as plan building-time (now), to build it together. Yes it’s slower, but much more massive, inclusive and persistent.</p>
- <h5>How we evaluate it: cultural bias &amp; qualitative analysis</h5>
- <p>First, about the agenda-setting KPI for 2016, should these KPI be an evaluation of the inclusion and rank in others strategic agendas, governance systems and productions (outcome/products) ? Others org could be from different domains: political, social, economy orgs.<br/>
- Then, as a wide size audience KPI, Mozilla wants « <em>celebration of our campaigns with ‘headline KPIs’ including number of actions, and number of advocates.</em>« . While doing this could be the right thing to do for some cultures, it could be the worst for others. I think that these KPI don’t carry a meaning for people and are too org centric. In a way, they are to generic: it’s just an amount. <strong>Accumulation is not our goal: we want impact that is the grow of articulated actions</strong> made by diverse people toward the same aim. <strong>We need our massive KPI to be more qualitative</strong>, or at least find a way to present them in a more qualitative way: interactive map ? a global to local prism that engages people for the next step ?</p>
- <h5>Best practices &amp; massive impact</h5>
- <p>Selecting best practices are an appealing method when we want to have a fast and strong impact in a wide area. However, <strong>when we unify we should avoid to homogenize</strong>. The gain in area by scaling-up is always at the cost of loosing local impact because it is not corresponding to local specificities, hence to local expectations. Federating instead of scaling-up is a way to solve this challenge. So we should be careful to not <strong>use best practice as absolute solutions, but as solutions in a context</strong> if we want to transpose them massively.</p>
- <h5>Tools &amp; platform balanced between user-centric and org-centric outcomes</h5>
- <p>It’s good to hear that we will build a advocacy platform. As we ‘had’ bugzilla+svn then mercurial (hg)+… and are going to the <strong>integrated</strong>, <strong>pluggable</strong> and <strong>content-centric</strong> (but non-free; admin tools are closed source) github (targeting more coder than users, but with a lower entry price for users still), we need to be able to have the same kind of tool for advocates and leaders. Something inspired maybe at some levels by the remixing tools we built in Webmakers for web users.</p>
- <h4>From experiment to production: support (self made to mass product) + modularity (dev code patch to users add-ons).</h4>
- <p><strong>We need pathways from lab to home that carry different mix of customization and reliability to support the emancipation curve.</strong><br/>
- Users want things to work, because they want to use it. Geeks want to be able to modify a lot and accept to put their hands in the engine to build growing reliability. Advanced users want to customize their experience and keep control and understanding on working status. They want to be able to fix the reliability at a medium/low technical cost. They are OK to gain more control at these prices. Users want to use things to do what they need and want to trust a reliability maintained for them. They are OK to gain control at a no technical cost. Depending on the matter we all have different skill levels, so we are all geeks, advanced users and users depending on our position or on the moment. And depending on our aspirations, we all want to be able to move from one category to an other. That’s what we need to build: we don’t just need to « <em>better articulate the value to our audiences</em>« , <strong>we need to build pathways thought audiences and thought IT layers</strong> (content, software, hardware, distant service). <strong>We should find a convergence between customization and reliability, between first time experience, support and add-ons thought all our users’ persona by building bridges, pathways</strong>. So, « <em>better articulate the value to our audiences</em> » should not be restrained in our minds to the Mozilla Leadership Network.<br/>
- <strong>Part of this is being done in other projects outside of Mozilla in the commons movement.</strong> There are many, but let’s take just one example, the <a href="https://www.fairphone.com/">Fairphone</a> project: modularity, howtos, … all this help to break the product-to-use walls and drive appropriation/emancipation. <strong>Products are less product and brand centric and more people/user centric</strong>.<br/>
- Part of this has been done inside Mozilla, like integrating learning in our products, in-content, as we have code comment on code. I think <strong>the <a href="https://wiki.mozilla.org/Firefox_OS/Spark">Spark</a> project on Firefox OS is on a promising path</strong>, even if maybe immature: it maybe has not been released mainstream because it misses bridges/pathways (on-boarding levels, progression from simple to high level techniques, and no or not enough reproducible/universal next task/skill building).<br/>
- So some solutions start to emerge, the direction is here, but has never been conceived and implemented that globally, as there isn’t integrated pathways with choice and opportunity and a strategy embracing all products and technologies (platform, tools, …).</p>
- <h4>Better tools for collaboration and participation: task-centric to process-centric (use) infrastructure</h4>
- <p><strong>The open community should definitely improve the collaboration tools and infrastructure to ease participation.</strong><br/>
- <strong><a href="http://www.discourse.org">Discourse</a> ‘merged’ discussion channels</strong>: email+forum(+instant, messaging, … and others peer-to-peer discussion?). <strong><a href="http://stackexchange.com">Stack exchange</a> merged the questioning/solving process</strong> and added a vote mechanism to rank answers: it eased the collaboration on editing the statement and the results while staying synchronous with the discussion and keeping the discussion history. We need such kind of possibilities with discourse: <strong>capitalize on the discussion and preview the results to build a plan.</strong><br/>
- This exist in document oriented software (that added collaboration editing tools), but not that much in collaboration software (that don’t produce documents). For example, while discussing the future plan for Fx/FxOS be supported to keep track on a doc about the proposals plans + criteria &amp; dependencies. In action, it is from <a href="https://mail.mozilla.org/pipermail/firefox-dev/2015-July/003063.html">this</a> plus all the discussion taking place to <a href="https://mail.mozilla.org/pipermail/firefox-dev/2015-July/003119.html">that</a>.<br/>
- This is maybe something like integrating Discourse+Wiki, maybe with the need to have competing and ranked (both for content and underlaying meaning of content=strategy?) plan/page proposals. <strong>From evolving the wiki discussion page to featuring document production into peer-to-peer discussion.</strong></p>
- <h4>A recovering strategy: from fail to win</h4>
- <p>There is maybe one thing that is in the shadow in this plan: <strong>what do we do when/if we (partially) fail ?</strong><br/>
- I think at least we should say that <strong>we document</strong> (keep research going on) to be able to outline and spread the outcomes of what we tried to fight against. So we still try to built consciousness to be ready for the next round.</p>
- <p> </p>
- <p><em>If you see some contradiction in my thoughts, let’s say it’s my state of thinking right now: please voice them so we can go forward.</em><br/>
- <em> The same for thoughts that are voiced definitive (like users are): take it as a first attempt with my bias: let’s state these bias to go forward.</em></p>
- <div class="footnotes" id="footnotes-48">
- <div class="footnotedivider"/>
- <ol>
- <li id="fn-48-1"> ‘<em>Radical</em>‘ can be in some cultures an euphemism to ‘<em>violent</em>‘. Let’s be clear that the change by increasing violence is done to make a popular uprising of some part against others. While it does not help the majority to magically understand that the minority is right, it stigmatize the radical-violent-changers and in the way it discredits the alternative proposed. <span class="footnotereverse"><a href="https://repeer.org/tag/mozilla/feed/#fnref-48-1">↩</a></span></li>
- </ol>
- </div></div>
- </content>
- <updated>2016-01-16T00:27:13Z</updated>
- <category term="Mozilla"/>
- <category term="Technologie"/>
- <category term="[EN]"/>
- <category term="Firefox"/>
- <category term="Firefox OS"/>
- <category term="Rust"/>
- <category term="Servo"/>
- <category term="Social networks"/>
- <author>
- <name>Nicolas</name>
- </author>
- <source>
- <id>https://repeer.org</id>
- <link href="https://repeer.org/tag/mozilla/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://repeer.org" rel="alternate" type="text/html"/>
- <subtitle>Reprenez le pouvoir !</subtitle>
- <title>Repeer » Mozilla</title>
- <updated>2016-01-16T00:46:46Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en">
- <id>http://bluesock.org/%7Ewillkg/blog/pyvideo/status_20160115.html</id>
- <link href="http://bluesock.org/%7Ewillkg/blog/pyvideo/status_20160115.html" rel="alternate" type="text/html"/>
- <title>pyvideo status: January 15th, 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div class="section" id="what-is-pyvideo-org">
- <h3>What is pyvideo.org</h3>
- <p><a class="reference external" href="http://pyvideo.org/">pyvideo.org</a> is an index of Python-related conference and user-group videos on
- the Internet. Saw a session you liked and want to share it? It's likely you can
- find it, watch it, and share it with pyvideo.org.</p>
- <p>This is the latest status report for all things happening on the site.</p>
- <p>It's also an announcement about the end.</p>
- <p><a href="http://bluesock.org/~willkg/blog/pyvideo/status_20160115.html">Read more…</a> (5 mins to read)</p></div></div>
- </summary>
- <updated>2016-01-15T23:30:00Z</updated>
- <category term="dev"/>
- <category term="python"/>
- <category term="pyvideo"/>
- <category term="richard"/>
- <author>
- <name>Will Kahn-Greene</name>
- </author>
- <source>
- <id>http://bluesock.org/%7Ewillkg/blog/</id>
- <link href="http://bluesock.org/%7Ewillkg/blog/" rel="alternate" type="text/html"/>
- <link href="http://bluesock.org/~willkg/blog/rss.xml" rel="self" type="application/rss+xml"/>
- <subtitle>Will Kahn-Greene's blog of Python, Mozilla, GNU/Linux, random content, dennis, Input, SUMO, and other projects mixed in there ad hoc, half-baked and with a twist of lemon</subtitle>
- <title>Will's blog</title>
- <updated>2016-01-16T16:31:16Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>http://coopcoopbware.tumblr.com/post/137371863755</id>
- <link href="http://coopcoopbware.tumblr.com/post/137371863755" rel="alternate" type="text/html"/>
- <title>RelEng &amp; RelOps Weekly Highlights - January 15, 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>One of releng’s big goals for Q1 is to deliver a beta via <a href="https://bugzil.la/release-promotion" target="_blank">build promotion</a>. It was great to have some tangible progress there this week with bouncer submission.</p>
-
- <p>Lots of other stuff in-flight, more details below!
- </p><p><b>Modernize infrastructure</b>:</p>
-
- <p>Dustin worked with Armen and Joel Maher to run Firefox tests in TaskCluster on an older EC2 instance type where the tests seem to fail less often, perhaps because they are single-CPU or slower.</p>
-
- <p><b>Improve CI pipeline</b>:</p>
-
- <p>We turned off automation for b2g 2.2 builds this week, which allowed us to remove some code, reduce some complexity, and regain some small amount of capacity. Thanks to Vlad and Alin on buildduty for helping to land those patches. (<a href="https://bugzil.la/1236835" target="_blank">https://bugzil.la/1236835</a> and <a href="https://bugzil.la/1237985" target="_blank">https://bugzil.la/1237985</a>)</p>
-
- <p>In a similar vein, Callek landed code to disable all b2g desktop builds and tests on all trees. Another win for increased capacity and reduced complexity! (<a href="https://bugzil.la/1236835" target="_blank">https://bugzil.la/1236835</a>)</p>
-
- <p><b>Release</b>:</p>
-
- <p>Kim finished integrating bouncer submission with our release promotion project. That’s one more blocker out of the way! (<a href="https://bugzil.la/1215204" target="_blank">https://bugzil.la/1215204</a>)</p>
-
- <p>Ben landed several enhancements to our update server: adding aliases to update rules (<a href="https://bugzil.la/1067402" target="_blank">https://bugzil.la/1067402</a>), and allowing fallbacks for rules with whitelists (<a href="https://bugzil.la/1235073" target="_blank">https://bugzil.la/1235073</a>).</p>
-
- <p><b>Operational</b>:</p>
- <p>There was some excitement last Sunday when all the trees were closed due to timeouts connectivity issues between our SCL3 datacentre and AWS. (<a href="https://bugzil.la/238369" target="_blank">https://bugzil.la/238369</a>)</p>
-
- <p><b>Build config</b>:</p>
-
- <p>Mike released v0.7.4 of <a href="http://gittup.org/tup/" target="_blank">tup</a>, and is working on generating the tup backend from moz.build. We hope to offer tup as an alternative build backend sometime soon.</p>
-
- <p>See you all next week!</p></div>
- </summary>
- <updated>2016-01-15T22:44:13Z</updated>
- <category term="Mozilla"/>
- <category term="releng"/>
- <category term="highlights"/>
- <source>
- <id>http://coopcoopbware.tumblr.com/</id>
- <author>
- <name>Chris Cooper</name>
- </author>
- <link href="http://coopcoopbware.tumblr.com/" rel="alternate" type="text/html"/>
- <link href="http://coopcoopbware.tumblr.com/tagged/Mozilla/rss" rel="self" type="application/rss+xml"/>
- <title>Five different types of fried cheese</title>
- <updated>2016-01-22T21:00:12Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://air.mozilla.org/webdev-beer-and-tell-january-2016/</id>
- <link href="https://air.mozilla.org/webdev-beer-and-tell-january-2016/" rel="alternate" type="text/html"/>
- <title>Webdev Beer and Tell: January 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
- <img alt="Webdev Beer and Tell: January 2016" class="wp-post-image" height="90" src="https://air.cdn.mozilla.net/media/cache/35/0f/350f246037ead3bab95fdbd4c2b77484.png" width="160"/>
- Once a month web developers across the Mozilla community get together (in person and virtually) to share what cool stuff we've been working on in...
- </p></div>
- </summary>
- <updated>2016-01-15T22:00:00Z</updated>
- <author>
- <name>Air Mozilla</name>
- </author>
- <source>
- <id>https://air.mozilla.org/</id>
- <link href="https://air.mozilla.org/" rel="alternate" type="text/html"/>
- <link href="https://air.mozilla.org/" rel="self" type="application/rss+xml"/>
- <rights>Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.</rights>
- <subtitle>Air Mozilla is the Internet multimedia presence of Mozilla, with live and pre-recorded shows, interviews, news snippets, tutorial videos, and features about the Mozilla community.</subtitle>
- <title>Air Mozilla</title>
- <updated>2016-01-25T20:31:50Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://blog.mozilla.org/sumo/?p=3665</id>
- <link href="https://blog.mozilla.org/sumo/2016/01/15/whats-up-with-sumo-15th-january/" rel="alternate" type="text/html"/>
- <title>What’s up with SUMO – 15th January</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Hello, SUMO Nation! The second post of the year is here. Have you had a good time in 2016 so far? Let us know in the comments! Now, let’s get going with the updates and activity summaries. It will be … <a class="go" href="https://blog.mozilla.org/sumo/2016/01/15/whats-up-with-sumo-15th-january/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><strong>Hello, SUMO Nation!</strong></p>
- <p>The second post of the year is here. Have you had a good time in 2016 so far? Let us know in the comments!</p>
- <p>Now, let’s get going with the updates and activity summaries. It will be brief today, I promise.</p>
- <h3><strong class="author-name">Welcome, new contributors!<br/>
- </strong></h3>
- <ul>
- <li class="author">
- <div class="author"><a class="username" href="https://support.mozilla.org/en-US/user/Andy.Yang">Andy.Yang</a></div>
- </li>
- </ul>
- <div class="author">After the massive influx over the last few weeks, we only had Andy introducing himself recently – the warmer the welcome for him!</div>
- <div class="author"/>
- <div class="author">If you just joined us, don’t hesitate – come over and <a href="https://support.mozilla.org/forums/buddies" target="_blank">say “hi†in the forums!</a></div>
- <div class="author"/>
- <div class="author">
- <h3><strong>Contributors of the week<br/>
- </strong></h3>
- <ul>
- <li><a href="https://blog.mozilla.org/sumo/2016/01/08/whats-up-with-sumo-8th-january/" target="_blank">All the people who joined us in the winter season so far!</a></li>
- </ul>
- <div class="" id="magicdomid64">
- <p><strong><span style="text-decoration: underline;">We salute you!</span></strong></p>
- </div>
- <div class="author">Don’t forget that if you are new to SUMO and someone helped you get started in a nice way you can <a href="https://support.mozilla.org/forums/buddies/711364?last=65670" target="_blank">nominate them for the Buddy of the Month!</a></div>
- <div class="author"/>
- </div>
- <h3><strong>Most recent SUMO Community meeting</strong></h3>
- <ul>
- <li><a href="https://public.etherpad-mozilla.org/p/sumo-2016-01-11" target="_blank">You can read the notes here</a> and see the video on our <a href="https://www.youtube.com/channel/UCaiposaIhA7HfMqH2NIciyA/videos" target="_blank">YouTube channel</a> and <a href="https://air.mozilla.org/search/?q=sumo" target="_blank">at AirMozilla</a>.<del> </del><del><br/>
- </del></li>
- <li><strong>IMPORTANT: We are considering changing the way the meetings work. Help us figure out what’s best for you – join the discussion on the forums in this thread: <a href="https://support.mozilla.org/en-US/forums/contributors/711752?last=67873">(Monday) Community Meetings in 2016</a>.</strong></li>
- </ul>
- <h3><strong>The next SUMO Community meeting… </strong></h3>
- <ul>
- <li style="text-align: left;">is happening on <a href="https://public.etherpad-mozilla.org/p/sumo-2016-01-18" target="_blank">Monday the 18th – join us</a>!</li>
- <li style="text-align: left;"><strong>Reminder: if you want to add a discussion topic to the upcoming meeting agenda:</strong>
- <ul>
- <li style="text-align: left;">Start a thread in the <a href="https://support.mozilla.org/forums/contributors" target="_blank">Community Forums</a>, so that everyone in the community can see what will be discussed and voice their opinion here before Monday (this will make it easier to have an efficient meeting).</li>
- <li style="text-align: left;">Please do so as soon as you can before the meeting, so that people have time to read, think, and reply (and also add it to the agenda).</li>
- <li style="text-align: left;">If you can, please attend the meeting in person (or via IRC), so we can follow up on your discussion topic during the meeting with your feedback.</li>
- </ul>
- </li>
- </ul>
- <h3><strong class="author-g-ivsra51ph44x461i">Developers</strong></h3>
- <ul>
- <li>The new version of the Ask A Question page is here!</li>
- <li>The 2.0 version of the KPI dashboard is in the works.</li>
- <li><a href="http://edwin.mozilla.io/t/sumo" target="_blank">You can see the current state of the backlog our developers are working on here</a>.</li>
- <li><a href="https://public.etherpad-mozilla.org/p/sumo-p-2016-01-14" target="_blank">The latest SUMO Platform meeting notes can be found here</a>.</li>
- <li>Interested in learning how Kitsune (the engine behind SUMO) works? <a href="http://kitsune.readthedocs.org/" target="_blank">Read more about it here</a> and <a href="https://github.com/mozilla/kitsune/" target="_blank">fork it on GitHub</a>!</li>
- </ul>
- <h3><strong>Community</strong></h3>
- <ul>
- <li>Our awesome Bangladesh SUMO Warriors are on the road again! Follow their adventures on Twitter under this tag: <a href="https://twitter.com/search?q=%23sumotourctg" target="_blank">#sumotourctg</a></li>
- <li>
- <div class="title"><a href="https://support.mozilla.org/forums/contributors/711729?last=67763">Reminder: take a look at our Work Week Summary for Mozlando. We need your feedback for a few things there.</a></div>
- </li>
- <li>
- <div class="title">Ongoing reminder: if you think you can benefit from getting <a href="https://wiki.mozilla.org/Community_Hardware" target="_blank">a second-hand device</a> to help you with contributing to SUMO, you know where to find us.</div>
- </li>
- </ul>
- <h3><strong class="user-chip" title="adriel0415">Support Forum</strong></h3>
- <ul>
- <li>Say hello to the new people on the forums!
- <ul>
- <li><span class="author-a-z87zkz70z39yz83zw7ykz89z3gz82zt"><a href="https://support.mozilla.org/user/Tomi55" target="_blank">Tomi55</a> (Hungarian)</span></li>
- <li><span class="author-a-z87zkz70z39yz83zw7ykz89z3gz82zt"><a href="https://support.mozilla.org/user/jdc20181" target="_blank">jdc20181</a> (English)</span></li>
- <li><span class="author-a-z87zkz70z39yz83zw7ykz89z3gz82zt"><a href="https://support.mozilla.org/user/andexi" target="_blank">andexi</a> (Spanish)</span></li>
- <li><span class="author-a-z87zkz70z39yz83zw7ykz89z3gz82zt"><a href="https://support.mozilla.org/user/Qantas94Heavy" target="_blank">Qantas94Heavy</a> (English)</span></li>
- <li><span class="author-a-z87zkz70z39yz83zw7ykz89z3gz82zt"><a href="https://support.mozilla.org/user/samuelms79" target="_blank">samuelms79</a> (Brazilian-PT)</span></li>
- <li><span class="author-a-z87zkz70z39yz83zw7ykz89z3gz82zt"><a href="https://support.mozilla.org/user/jorgecomun" target="_blank">jorgecomun</a> (Spanish)</span></li>
- </ul>
- </li>
- </ul>
- <div class="">
- <h3><strong class="author-g-ivsra51ph44x461i">Knowledge Base</strong></h3>
- <div class="" id="magicdomid90">
- <div class="" id="magicdomid82">
- <ul class="list-bullet1">
- <li><span class="author-a-z87zjz80zxwjz85z4z65zytdpz68zoz69z"><a href="https://support.mozilla.org/forums/knowledge-base-articles/711304#post-65289" target="_blank">Thanks to everyone who took part in the most recent KB Day!</a></span></li>
- <li>Version 44 updates should be live now.</li>
- <li><span class="author-a-w2dz70zaz70z7z89zqz78ziz69zz78zz85zz90zj"><a href="https://docs.google.com/spreadsheets/d/1lkpRPJp9P1P5MRU-c9dwbDC0w5bMmrMdu-BNMp1xe8w/edit#gid=6" target="_blank">Ongoing reminder: learn more about upcoming English article updates by clicking here</a></span>.</li>
- <li><span style="text-decoration: underline;">Ongoing reminder #2:<a href="https://support.mozilla.org/forums/knowledge-base-articles/" target="_blank"> do you have ideas about improving the KB guidelines and training materials? Let us know in the forums</a>!</span></li>
- </ul>
- </div>
- <div class="" id="magicdomid83">
- <h3><strong class="author-g-ivsra51ph44x461i">Localization</strong></h3>
- </div>
- </div>
- </div>
- <div class="" id="magicdomid95">
- <ul>
- <li>Thanks to everyone writing in with problems, ideas, reports of bugs – all your feedback matters!</li>
- </ul>
- </div>
- <div class="" id="magicdomid75">
- <h3><strong>Firefox<br/>
- </strong></h3>
- <ul>
- <li><strong>for Android</strong>
- <ul>
- <li><a href="https://support.mozilla.org/forums/contributors/711712?last=67653">Learn more about Firefox 43 for Android from the official thread with release notes / issues / discussions</a>.</li>
- <li>
- <div class="title"><a href="https://support.mozilla.org/forums/contributors/711718?last=67822">Reminder: Roland is sharing Firefox 44 for Android release notes / issues / discussions</a> with everyone in the forum.</div>
- </li>
- </ul>
- </li>
- </ul>
- <ul>
- <li><strong>for Desktop</strong>
- <ul>
- <li>The <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1238620" target="_blank">uploading issues reported by many users are being tracked here.</a></li>
- <li><a href="https://support.mozilla.org/questions/firefox?tagged=bug1208145&amp;show=all" target="_blank">The “show passwords†button has been removed from the password manager for the Beta of Version 44</a>. The developers are looking into <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1208145" target="_blank">last minute fixes for that in this bug</a>.</li>
- <li>Also in Version 44, the <span class="author-a-kz88zz80zhz89z6hlz81znytez70zz66zz68z"><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=606655" target="_blank">“ask me everytime†option for cookies will be removed from the privacy panel.</a></span></li>
- </ul>
- </li>
- </ul>
- <ul>
- <li><strong>for iOS</strong>
- <div class="" id="magicdomid85">
- <ul class="list-bullet1">
- <li><span class="author-a-107uz69zz81zhz78z0z78zz84zz66zz76zz82zz77zj"><a href="https://www.mozilla.org/en-US/firefox/ios/1.4/releasenotes/" target="_blank">Firefox for iOS 1.4 primarily with features for China is here</a>.<br/>
- </span></li>
- </ul>
- </div>
- <div class="" id="magicdomid86">
- <ul class="list-bullet1">
- <li><span class="author-a-107uz69zz81zhz78z0z78zz84zz66zz76zz82zz77zj">Firefox for iOS 2.0 is after 1.4 and hopefully sometime this quarter!</span></li>
- </ul>
- </div>
- </li>
- </ul>
- </div>
- <p>Not that many updates this week, since we’re coming out of our winter slumber (even though winter will be here for a while, still) and plotting an awesome 2016 with you and for you. Take it easy, have a great weekend and see you around SUMO.</p></div>
- </content>
- <updated>2016-01-15T19:38:51Z</updated>
- <category term="General"/>
- <author>
- <name>Michał</name>
- </author>
- <source>
- <id>https://blog.mozilla.org/sumo</id>
- <link href="https://blog.mozilla.org/sumo/feed/" rel="self" type="application/rss+xml"/>
- <link href="https://blog.mozilla.org/sumo" rel="alternate" type="text/html"/>
- <subtitle>SUpport MOzilla's official blog - rocking the helpful web since 2008!</subtitle>
- <title>SUMO Blog</title>
- <updated>2016-01-25T09:31:47Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://air.mozilla.org/paris-firefox-os-hackathon-presentations/</id>
- <link href="https://air.mozilla.org/paris-firefox-os-hackathon-presentations/" rel="alternate" type="text/html"/>
- <title>Paris Firefox OS Hackathon Presentations</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
- <img alt="Paris Firefox OS Hackathon Presentations" class="wp-post-image" height="90" src="https://air.cdn.mozilla.net/media/cache/35/83/358305bfa246fff07d707061082134aa.png" width="160"/>
- As an introduction to this weekend's Firefox OS Hackathon in Paris we'll have two presentations: - Guillaume Marty will talk about the current state of...
- </p></div>
- </summary>
- <updated>2016-01-15T18:00:00Z</updated>
- <author>
- <name>Air Mozilla</name>
- </author>
- <source>
- <id>https://air.mozilla.org/</id>
- <link href="https://air.mozilla.org/" rel="alternate" type="text/html"/>
- <link href="https://air.mozilla.org/" rel="self" type="application/rss+xml"/>
- <rights>Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.</rights>
- <subtitle>Air Mozilla is the Internet multimedia presence of Mozilla, with live and pre-recorded shows, interviews, news snippets, tutorial videos, and features about the Mozilla community.</subtitle>
- <title>Air Mozilla</title>
- <updated>2016-01-25T20:31:49Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>https://tacticalsecret.com/tag/mozilla/rss/db7fec0c-34d3-4633-9904-79b98aab34e7</id>
- <link href="https://tacticalsecret.com/renewing-lets-encrypt-certs-nginx/" rel="alternate" type="text/html"/>
- <title>Renewing Let's Encrypt Certs (Nginx)</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>All the first <a href="https://crt.sh/?id=10172479">Let's Encrypt certs for my websites</a> from the LE private beta began expiring last week, so it was time to work through the renewal tooling. I wanted a script that:</p>
-
- <ol>
- <li>Would be okay to run daily, so there'd be plenty of retries if something went wrong, </li>
- <li>Wouldn't</li></ol></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>All the first <a href="https://crt.sh/?id=10172479">Let's Encrypt certs for my websites</a> from the LE private beta began expiring last week, so it was time to work through the renewal tooling. I wanted a script that:</p>
-
- <ol>
- <li>Would be okay to run daily, so there'd be plenty of retries if something went wrong, </li>
- <li>Wouldn't require extra config for me to forget about if I add a new site, </li>
- <li>Would only renew certificates expiring in the next few weeks.</li>
- </ol>
-
- <p>The official Let's Encrypt client team is hard at work producing a great renew tool to handle all this, but it's not released yet. Of course I could use <a href="https://caddyserver.com/">Caddy Server</a> that <a href="https://www.youtube.com/watch?v=nk4EWHvvZtI">just handles all this</a>, but I have a lot invested in Nginx here.</p>
-
- <p>So I wrote a short script and <a href="https://gist.github.com/jcjones/432eeaa6a2bf25e2c746">put it up in a Gist</a>. </p>
-
- <p>The script is designed to run daily, with a random start between 00:00 and 02:00 to protect against load spikes at Let's Encrypt's infrastructure. It doesn't do any real reporting, though, except to maintain <code>/var/log/letsencrypt/renew.log</code> as the most-recent failure if one fails.</p>
-
- <p>It's written to handle Nginx with Upstart's <code>service</code> command. It's pretty modular though; you could make this operate any webserver, or use the webroot method quite easily. Feel free to use the OpenSSL SubjectAlternativeName processing code for whatever purposes you have.</p>
-
- <p>Happy renewing!</p></div>
- </content>
- <updated>2016-01-15T16:01:19Z</updated>
- <category term="letsencrypt"/>
- <category term="mozilla"/>
- <author>
- <name>James 'J.C.' Jones</name>
- </author>
- <source>
- <id>https://tacticalsecret.com/</id>
- <link href="https://tacticalsecret.com/" rel="alternate" type="text/html"/>
- <link href="https://tacticalsecret.com/tag/mozilla/rss/" rel="self" type="application/rss+xml"/>
- <subtitle>On a mission to solve information security issues for the whole Internet. That, and whatever else comes up.</subtitle>
- <title>mozilla - The Internet of Secure Things</title>
- <updated>2016-01-21T17:31:50Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="es-ES">
- <id>http://firefoxmania.uci.cu/?p=15521</id>
- <link href="http://firefoxmania.uci.cu/conoce-los-complementos-destacados-para-enero-2016/" rel="alternate" type="text/html"/>
- <title>Conoce los complementos destacados para enero</title>
- <summary>Comenzó un nuevo año y con él, te traemos nuevos e interesantes complementos para tu navegador preferido que mejoran con creces tu experiencia de navegación. Durante los próximos 6 meses estará trabajando nuevos miembros en el Add-ons Board Team, en la próxima selección desde Firefoxmanía te avisaremos.</summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p style="text-align: left;">Comenzó un nuevo año y con él, te traemos nuevos e interesantes complementos para tu navegador preferido que mejoran con creces tu experiencia de navegación. Durante los próximos 6 meses estará trabajando nuevos miembros en el Add-ons Board Team, en la próxima selección desde Firefoxmanía te avisaremos.</p>
- <h3 style="text-align: left;">Elección del mes: uMatrix</h3>
- <p>uMatrix es muy parecido a un <em>firewall</em> y desde una ventana fácilmente podrás controlar todos los lugares a donde tu navegador tiene permitido conectarse, qué tipo de datos pueden descargarse y cual puede ejecutar.</p>
- <blockquote><p>Esta puede ser la extensión perfecta para el control avanzado de los usuarios.</p></blockquote>
- <p><span id="more-15521"/></p>
-
- <a href="http://firefoxmania.uci.cu/conoce-los-complementos-destacados-para-enero-2016/umatrix/"><img alt="Interfaz principal de uMatrix" class="attachment-thumbnail size-thumbnail" height="160" src="http://firefoxmania.uci.cu/wp-content/uploads/2016/01/uMatrix-160x160.png" width="160"/></a>
- <a href="http://firefoxmania.uci.cu/conoce-los-complementos-destacados-para-enero-2016/umatrix2/"><img alt="Opciones de configuraci&#xF3;n de uMatrix" class="attachment-thumbnail size-thumbnail" height="160" src="http://firefoxmania.uci.cu/wp-content/uploads/2016/01/uMatrix2-160x160.png" width="160"/></a>
-
- <p><em><a href="http://addons.firefoxmania.uci.cu/umatrix/" target="_blank">Instalar uMatrix »</a></em></p>
- <h3>También te recomendamos</h3>
- <p style="text-align: left;"><a href="http://addons.firefoxmania.uci.cu/https-everywhere/" target="_blank">⇒ HTTPS Everywhere</a> por <a href="https://addons.mozilla.org/en-US/firefox/user/eff-technologists/" title="EFF Technologists">EFF Technologists</a></p>
- <p style="text-align: left;">Protege tus comunicaciones habilitando la encriptación HTTPS automáticamente en los sitios conocidos que la soportan, incluso cuando navegas mediante sitios que no incluyen el prefijo “https†en la URL.</p>
- <p style="text-align: left;"><a href="http://addons.firefoxmania.uci.cu/add-to-search-bar/" target="_blank">⇒ Add to Search Bar</a> por <a href="https://addons.mozilla.org/firefox/user/dr-evil/" target="_blank" title="AdblockLite">Dr. Evil</a></p>
- <p style="text-align: left;">Hace posible que cualquier página con un formulario de búsqueda disponible pueda ser añadido fácilmente a la barra de búsqueda de Firefox.</p>
- <div class="wp-caption aligncenter" id="attachment_15528" style="width: 262px;"><a href="http://firefoxmania.uci.cu/wp-content/uploads/2016/01/add_to_search_bar.png" rel="attachment wp-att-15528"><img alt="add_to_search_bar" class="wp-image-15528 size-medium" height="226" src="http://firefoxmania.uci.cu/wp-content/uploads/2016/01/add_to_search_bar-252x226.png" width="252"/></a><p class="wp-caption-text">Añadiendo la búsqueda de un sitio web a la barra de búsqueda</p></div>
- <p style="text-align: left;"><a href="http://addons.firefoxmania.uci.cu/duplicate-tabs-closer/" target="_blank">⇒ Duplicate Tabs Closer</a> por <a href="https://addons.mozilla.org/firefox/user/peuj/" target="_blank" title="The 1-Click YouTube Video Download Team">Peuj</a></p>
- <p style="text-align: left;">Detecta las pestañas duplicadas en tu navegador y automáticamente las cierra.</p>
- <h3 style="text-align: left;">Nomina tus complementos favoritos</h3>
- <p style="text-align: left;">A nosotros nos encantaría que <strong>fueras parte del proceso</strong> de seleccionar los mejores complementos para Firefox y nos gustaría escucharte. <em>¿No sabes cómo?</em> Sólo tienes que <em>enviar un correo electrónico</em> a la dirección <strong>amo-featured@mozilla.org</strong> con el nombre del complemento o el archivo de instalación y los miembros evaluarán tu recomendación.</p>
- <p style="text-align: left;"><strong>Fuente:</strong> <a href="https://blog.mozilla.org/addons/2016/01/01/january-2016-featured-add-ons/" target="_blank">Mozilla Add-ons Blog</a></p></div>
- </content>
- <updated>2016-01-15T15:10:26Z</updated>
- <category term="Addons"/>
- <category term="firefox"/>
- <category term="complementos"/>
- <author>
- <name>Yunier J</name>
- </author>
- <source>
- <id>http://firefoxmania.uci.cu</id>
- <link href="http://firefoxmania.uci.cu/author/sosa/feed/" rel="self" type="application/rss+xml"/>
- <link href="http://firefoxmania.uci.cu" rel="alternate" type="text/html"/>
- <subtitle>Comunidad Mozilla Firefox de Cuba</subtitle>
- <title>Yunier J – Firefoxmanía</title>
- <updated>2016-01-23T12:16:22Z</updated>
- </source>
- </entry>
-
- <entry>
- <id>https://timtaubert.de/blog/2016/01/build-your-own-signal-desktop</id>
- <link href="https://timtaubert.de/blog/2016/01/build-your-own-signal-desktop/" rel="alternate" type="text/html"/>
- <title>Build Your Own Signal Desktop</title>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>The Signal Private Messenger is great. <strong>Use it.</strong> It’s probably the best secure
- messenger on the market. When recently a desktop app was announced people were
- eager to join the beta and even happier when an invite finally showed up in
- their inbox. So was I, it’s a great app and works surprisingly well for an early
- version.</p>
-
- <p>The only problem is that it’s a Chrome App. Apart from excluding folks with
- other browsers it’s also a shitty user experience. If you too want your
- messaging app not tied to a browser then let’s just build our own standalone
- variant of Signal Desktop.</p>
-
- <h3>NW.js beta with Chrome App support</h3>
-
- <p>Signal Desktop is a Chrome App, so the easiest way to turn it into a standalone
- app is to use <a href="http://nwjs.io/">NW.js</a>. Conveniently, their next release v0.13
- will ship with Chrome App support and is available for download as a beta
- version.</p>
-
- <p>First, make sure you have <code>git</code> and <code>npm</code> installed. Then open a terminal and
- prepare a temporary build directory to which we can download a few things and
- where we can build the app:</p>
-
- <figure class="code"><div class="highlight"><pre>$ mkdir signal-build
- $ cd signal-build
- </pre></div></figure>
-
-
- <h3>[OS X] Packaging Signal and NW.js</h3>
-
- <p>Download the latest beta of NW.js and <code>unzip</code> it. We’ll extract the application
- and use it as a template for our Signal clone. The NW.js project does
- unfortunately not seem to provide a secure source (or at least hashes)
- for their downloads.</p>
-
- <figure class="code"><div class="highlight"><pre>$ wget http://dl.nwjs.io/v0.13.0-beta3/nwjs-sdk-v0.13.0-beta3-osx-x64.zip
- $ unzip nwjs-sdk-v0.13.0-beta3-osx-x64.zip
- $ cp -r nwjs-sdk-v0.13.0-beta3-osx-x64/nwjs.app SignalPrivateMessenger.app
- </pre></div></figure>
-
-
- <p>Next, clone the Signal repository and use NPM to install the necessary modules.
- Run the <code>grunt</code> automation tool to build the application.</p>
-
- <figure class="code"><div class="highlight"><pre>$ git clone https://github.com/WhisperSystems/Signal-Desktop.git
- $ cd Signal-Desktop/
- $ npm install
- $ node_modules/grunt-cli/bin/grunt
- </pre></div></figure>
-
-
- <p>Finally, simply to copy the <code>dist</code> folder containing all the juicy Signal files
- into the application template we created a few moments ago.</p>
-
- <figure class="code"><div class="highlight"><pre>$ cp -r dist ../SignalPrivateMessenger.app/Contents/Resources/app.nw
- $ open ..
- </pre></div></figure>
-
-
- <p>The last command opens a Finder window. Move <code>SignalPrivateMessenger.app</code> to
- your Applications folder and launch it as usual. You should now see a welcome
- page!</p>
-
- <h3>[Linux] Packaging Signal and NW.js</h3>
-
- <p>The build instructions for Linux aren’t too different but I’ll write them down,
- if just for convenience. Start by cloning the Signal Desktop repository and
- build.</p>
-
- <figure class="code"><div class="highlight"><pre>$ git clone https://github.com/WhisperSystems/Signal-Desktop.git
- $ cd Signal-Desktop/
- $ npm install
- $ node_modules/grunt-cli/bin/grunt
- </pre></div></figure>
-
-
- <p>The <code>dist</code> folder contains the app, ready to be launched. <code>zip</code> it and place
- the resulting package somewhere handy.</p>
-
- <figure class="code"><div class="highlight"><pre>$ cd dist
- $ zip -r ../../package.nw *
- </pre></div></figure>
-
-
- <p>Back to the top. Download the NW.js binary, extract it, and change into the
- newly created directory. Move the <code>package.nw</code> file we created earlier next to
- the <code>nw</code> binary and we’re done. The <code>nwjs-sdk-v0.13.0-beta3-linux-x64</code> folder
- does now contain the standalone Signal app.</p>
-
- <figure class="code"><div class="highlight"><pre>$ cd ../..
- $ wget http://dl.nwjs.io/v0.13.0-beta3/nwjs-sdk-v0.13.0-beta3-linux-x64.tar.gz
- $ tar xfz nwjs-sdk-v0.13.0-beta3-linux-x64.tar.gz
- $ cd nwjs-sdk-v0.13.0-beta3-linux-x64
- $ mv ../package.nw .
- </pre></div></figure>
-
-
- <p>Finally, launch NW.js. You should see a welcome page!</p>
-
- <figure class="code"><div class="highlight"><pre>$ ./nw
- </pre></div></figure>
-
-
- <h3>If you see something, file something</h3>
-
- <p>Our standalone Signal clone mostly works, but it’s far from perfect. We’re
- pulling from master and that might bring breaking changes that weren’t
- sufficiently tested.</p>
-
- <p>We don’t have the right icons. The app crashes when you click a media message.
- It opens a blank popup when you click a link. It’s quite big because also NW.js
- has bugs and so we have to use the SDK build for now. In the future it would be
- great to have automatic updates, and maybe even signed builds.</p>
-
- <p>Remember, Signal Desktop is beta, and completely untested with NW.js. If you
- want to help file bugs, but only after checking that those affect the Chrome
- App too. If you want to fix a bug only occurring in the standalone version
- it’s probably best to file a pull request and cross fingers.</p>
-
- <h3>Is this secure?</h3>
-
- <p>Great question! I don’t know. I would love to get some more insights from people
- that know more about the NW.js security model and whether it comes with all the
- protections Chromium can offer. Another interesting question is whether bundling
- Signal Desktop with NW.js is in any way worse (from a security perspective) than
- installing it as a Chrome extension. If you happen to have an opinion about
- that, I would love to hear it.</p>
-
- <p>Another important thing to keep in mind is that when building Signal on your
- own you will possibly miss automatic and signed security updates from the
- Chrome Web Store. Keep an eye on the repository and rebuild your app from
- time to time to not fall behind too much.</p></div>
- </content>
- <updated>2016-01-15T14:00:00Z</updated>
- <source>
- <id>https://timtaubert.de/</id>
- <author>
- <name>Tim Taubert</name>
- </author>
- <link href="https://timtaubert.de/atom.xml" rel="self" type="application/atom+xml"/>
- <link href="https://timtaubert.de/" rel="alternate" type="text/html"/>
- <title>Tim Taubert</title>
- <updated>2016-01-15T15:04:09Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://glandium.org/blog/?p=3579</id>
- <link href="http://glandium.org/blog/?p=3579" rel="alternate" type="text/html"/>
- <title>Announcing git-cinnabar 0.3.0</title>
- <summary>Git-cinnabar is a git remote helper to interact with mercurial repositories. It allows to clone, pull and push from/to mercurial remote repositories, using git. Get it on github. These release notes are also available on the git-cinnabar wiki. Development had been stalled for a few months, with many improvements in the next branch without any […]</summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Git-cinnabar is a git remote helper to interact with mercurial repositories. It allows to clone, pull and push from/to mercurial remote repositories, using git.</p>
- <p><a href="https://github.com/glandium/git-cinnabar">Get it on github</a>.</p>
- <p>These release notes are also <a href="https://github.com/glandium/git-cinnabar/wiki/Release-Notes:-0.3.0">available on the git-cinnabar wiki</a>.</p>
- <p>Development had been stalled for a few months, with many improvements in the<br/>
- <code>next</code> branch without any new release. I used some time during the new year<br/>
- break and after in order to straighten things up in order to create a new<br/>
- release, delaying many of the originally planned changes to a future 0.4.0<br/>
- release.</p>
- <h3>What’s new since 0.2.2?</h3>
- <ul>
- <li>Speed and memory usage were improved when doing <code>git push</code>.</li>
- <li>Now works on Windows, at least to some extent. See <a href="http://glandium.org/blog/Windows-Support">details</a>.</li>
- <li>Support for pre-0.1.0 git-cinnabar repositories was removed. You must first<br/>
- use a git-cinnabar version between 0.1.0 and 0.2.2 to upgrade its metadata.</li>
- <li>It is now possible to attach/graft git-cinnabar metadata to existing commits<br/>
- matching mercurial changesets. This allows to migrate from some other<br/>
- hg-to-git tool to git-cinnabar while preserving the existing git commits.<br/>
- See <a href="http://glandium.org/blog/Mozilla%3A-Using-a-git-clone-of-gecko%E2%80%90dev-to-push-to-mercurial">an example of how this works with the git clone of the Gecko mercurial<br/>
- repository</a>
- </li>
- <li>Avoid mercurial printing its progress bar, messing up with git-cinnabar’s<br/>
- output.</li>
- <li>It is now possible to fetch from an incremental mercurial bundle (without<br/>
- a root changeset).</li>
- <li>It is now possible to push to a new mercurial repository without <code>-f</code>.</li>
- <li>By default, reject pushing a new root to a mercurial repository.</li>
- <li>Make the connection to a mercurial repository through ssh respect the<br/>
- <code>GIT_SSH</code> and <code>GIT_SSH_COMMAND</code> environment variables.</li>
- <li>
- <code>git cinnabar</code> now has a proper argument parser for all its subcommands.</li>
- <li>
- </li>
- <li>A new <code>git cinnabar python</code> command allows to run python scripts or open a<br/>
- python shell with the right sys.path to import the cinnabar module.</li>
- <li>All git-cinnabar metadata is now kept under a single ref (although for<br/>
- convenience, other refs are created, but they can be derived if necessary).</li>
- <li>Consequently, a new <code>git cinnabar rollback</code> command allows to roll back to<br/>
- previous metadata states.</li>
- <li>git-cinnabar metadata now tracks the manifests DAG.</li>
- <li>A new <code>git cinnabar bundle</code> command allows to create mercurial bundles,<br/>
- mostly for debugging purposes, without requiring to hit a mercurial server.</li>
- <li>Updated git to 2.7.0 for the native helper.</li>
- </ul>
- <h3>Development process changes</h3>
- <p>Up to before this release closing in, the <code>master</code> branch was dedicated to<br/>
- releases, and development was happening on the <code>next</code> branch, until a new<br/>
- release happens.</p>
- <p>From now on, the <code>release</code> branch will take dot-release fixes and new<br/>
- releases, while the <code>master</code> branch will receive all changes that are<br/>
- validated through testing (currently semi-automatically tested with<br/>
- out-of-tree tests based on four real-life mercurial repositories, with<br/>
- some automated CI based on in-tree tests used in the future).</p>
- <p>The <code>next</code> branch will receive changes to be tested in CI when things<br/>
- will be hooked up, and may have rewritten history as a consequence of<br/>
- wanting passing tests on every commit on <code>master</code>.</p></div>
- </content>
- <updated>2016-01-15T08:56:40Z</updated>
- <category term="cinnabar"/>
- <category term="p.m.o"/>
- <category term="en"/>
- <author>
- <name>glandium</name>
- </author>
- <source>
- <id>http://glandium.org/blog</id>
- <link href="http://glandium.org/blog/?feed=rss2&amp;cat=25&amp;tag=en" rel="self" type="application/rss+xml"/>
- <link href="http://glandium.org/blog" rel="alternate" type="text/html"/>
- <subtitle>glandium.org</subtitle>
- <title>p.m.o – glandium.org</title>
- <updated>2016-01-16T11:30:44Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://air.mozilla.org/web-qa-weekly-meeting-20160114/</id>
- <link href="https://air.mozilla.org/web-qa-weekly-meeting-20160114/" rel="alternate" type="text/html"/>
- <title>Web QA Weekly Meeting, 14 Jan 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
- <img alt="Web QA Weekly Meeting" class="wp-post-image" height="90" src="https://air.cdn.mozilla.net/media/cache/f5/13/f5137857516694df0458e837c2d3a4be.png" width="160"/>
- This is our weekly gathering of Mozilla'a Web QA team filled with discussion on our current and future projects, ideas, demos, and fun facts.
- </p></div>
- </summary>
- <updated>2016-01-14T17:00:00Z</updated>
- <author>
- <name>Air Mozilla</name>
- </author>
- <source>
- <id>https://air.mozilla.org/</id>
- <link href="https://air.mozilla.org/" rel="alternate" type="text/html"/>
- <link href="https://air.mozilla.org/" rel="self" type="application/rss+xml"/>
- <rights>Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.</rights>
- <subtitle>Air Mozilla is the Internet multimedia presence of Mozilla, with live and pre-recorded shows, interviews, news snippets, tutorial videos, and features about the Mozilla community.</subtitle>
- <title>Air Mozilla</title>
- <updated>2016-01-25T20:31:49Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>https://air.mozilla.org/reps-weekly-20160114/</id>
- <link href="https://air.mozilla.org/reps-weekly-20160114/" rel="alternate" type="text/html"/>
- <title>Reps weekly, 14 Jan 2016</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
- <img alt="Reps weekly" class="wp-post-image" height="90" src="https://air.cdn.mozilla.net/media/cache/ea/95/ea959e7cca319261380787a7d8f66a94.png" width="160"/>
- This is a weekly call with some of the Reps to discuss all matters about/affecting Reps and invite Reps to share their work with everyone.
- </p></div>
- </summary>
- <updated>2016-01-14T16:00:00Z</updated>
- <author>
- <name>Air Mozilla</name>
- </author>
- <source>
- <id>https://air.mozilla.org/</id>
- <link href="https://air.mozilla.org/" rel="alternate" type="text/html"/>
- <link href="https://air.mozilla.org/" rel="self" type="application/rss+xml"/>
- <rights>Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.</rights>
- <subtitle>Air Mozilla is the Internet multimedia presence of Mozilla, with live and pre-recorded shows, interviews, news snippets, tutorial videos, and features about the Mozilla community.</subtitle>
- <title>Air Mozilla</title>
- <updated>2016-01-25T20:31:50Z</updated>
- </source>
- </entry>
-
- <entry xml:lang="en-US">
- <id>http://blog.mozilla.org/community/?p=2281</id>
- <link href="http://blog.mozilla.org/community/2016/01/13/32c3-report-chaos-time-zone/" rel="alternate" type="text/html"/>
- <title>32C3 Report – Chaos Time Zone</title>
- <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Written by Valentin Schmitt. Entering the CCH (Congress Center Hamburg) between Christmas and new year brings you somewhere else than Hamburg on Central European Time. Most people you’ll meet will say they are from Internet (or the Internets, if they … <a class="go" href="http://blog.mozilla.org/community/2016/01/13/32c3-report-chaos-time-zone/">Continue reading</a></div>
- </summary>
- <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Written by <a href="https://mozillians.org/en-US/u/Valentin/">Valentin Schmitt</a>.</p>
- <p>Entering the CCH (Congress Center Hamburg) between Christmas and new year brings you somewhere else than Hamburg on Central European Time.</p>
- <p>Most people you’ll meet will say they are from Internet (or the Internets, if they are funny), and for a few days you’ll live in -what a friend of mine called- Chaos Time Zone: a blurry mix of everyone’s time difference. Days are pretty shorts anyway and you’ll probably spend a lot of time under artificial light, so it won’t help your internal clock keeping on track. The organizers will gently remind you the 6,2,1 rule: 6 hours of sleep, 2 meals and 1 shower per day, that should keep you safe. You’ll probably meet a lot of great people, and will often have a hard time to decide which talk or workshop to go to.<br/>
- This is the <a href="https://events.ccc.de/congress/2015/wiki/Static:Main_Page">32nd Chaos Communication Congress</a>. Welcome, and have fun!</p>
- <div class="wp-caption aligncenter" id="attachment_2282" style="width: 610px;"><a href="https://www.flickr.com/photos/mariobehling/23398995803/"><img alt="32C3 Chaos Communication Congress" class="size-large wp-image-2282" height="400" src="https://blog.mozilla.org/community/files/2016/01/CCCPost1-600x400.jpg" width="600"/></a><p class="wp-caption-text">32C3 Chaos Communication Congress – Photo: Mario Behling</p></div>
- <h3>FxOS is not dead.</h3>
- <p>I looked for a screen printer, or anything to do myself a t-shirt with the message “Firefox OS is not dead!†on it, but very surprisingly regarding the variety of machines there, I couldn’t find any on site. I really wanted to do that, because most of the people I talked to about<br/>
- Firefox OS answered me “But isn’t Firefox OS dead?â€. I bet it won’t come as a surprise for you, as there was a lot of feedback from the community regarding what some might call “a PR disasterâ€. It just made it very clear to me that we (still) have to communicate a lot on this topic, and very loudly, because the tech news websites will be less likely to spread the word this time.</p>
- <p>Once this detail (<b>*cough*</b>) was clarified, almost everybody I had the chance to talk to showed a lot of interested for the project, the only ones who didn’t were the hardcore Free Software enthusiasts, whom have been disappointed by Mozilla recent policy choices (like the tiles with<br/>
- advertisement, or the DRM support in Firefox desktop), or the people who care less about software freedom and prefer an iPhone to a free (as in freedom) mobile OS.</p>
- <div class="wp-caption aligncenter" id="attachment_2283" style="width: 610px;"><a href="https://www.flickr.com/photos/mariobehling/23943014701"><img alt="Mozilla and Firefox at 32C3 with friends" class="size-large wp-image-2283" height="400" src="https://blog.mozilla.org/community/files/2016/01/CCCPost2-600x400.jpg" width="600"/></a><p class="wp-caption-text">Mozilla and Firefox at 32C3 with friends – Photo: Mario Behling</p></div>
- <h3>“Well, it’s Mozilla.â€</h3>
- <p>Mozilla has a pretty good image in the Free Software community, and the main reason why people never tried a Firefox OS device is only because they never had the chance to do so (not many devices marketed in Europe or the US, not many ports on mainstream phones). Fortunately enough, I had some foxfooding devices to hand out. The <a href="https://firefoxos.mozilla.community/foxfooding-faq/">foxfooding program</a> had a very positive reception, most people were happy to have the chance to try the OS, participate in sending data to Mozilla, file bugs, some were eager to develop apps, and try port the OS on their favorite phone or device (the RasPi got a bunch of them very excited).</p>
- <p>More importantly, they really asked me how to flash a device, where to find the documentation to get started, how to file a bug. The people I handed a device to planned to show it to their colleagues, friends and fellow hacktivists, and were very excited to have phone with a hardware good enough to provide a responsive experience.</p>
- <h3>Questions?</h3>
- <p>“Is there a Signal app or any secure messaging app?â€<br/>
- “Can I use Tor?â€<br/>
- “Can I keep OSM maps in cache?â€<br/>
- “Is there an app for WhatsApp?â€<br/>
- These were the questions I was asked the most. It’s pretty expected that the hackers community is looking for reliable privacy tools, but I was a bit surprised by the last question that still came up several times. <img alt=":)" class="wp-smiley" src="http://blog.mozilla.org/community/wp-includes/images/smilies/simple-smile.png" style="height: 1em;"/></p>
- <h3>Mozillians, assemble!</h3>
- <p>An <a href="https://events.ccc.de/congress/2015/wiki/Static:Assemblies">assembly</a> is the name the Chaos Communication Congress gives to the physical place (typically a bunch of tables with a power outlet) within the CCH where people can gather to hack, share ideas and have self organized-sessions on a particular topic, or around a particular project, there were 277 registered this year.</p>
- <div class="wp-caption aligncenter" id="attachment_2284" style="width: 610px;"><a href="https://www.flickr.com/photos/fossasia/23742587859"><img alt="Assembling Under The Lights" class="size-large wp-image-2284" height="450" src="https://blog.mozilla.org/community/files/2016/01/CCCPost3-600x450.jpg" width="600"/></a><p class="wp-caption-text">Assembling Under The Lights – Photo: Hong Phuc FOSSASIA</p></div>
- <p>With the Mozilla Assembly, we had several sessions (directly at the Assembly or in dedicated rooms) over these 4 days:</p>
- <ul>
- <li>Several Nightly Firefox OS workshops, combining more than 50 participants;</li>
- <li>The Mozilla community meetup that gathered 20 participants;</li>
- <li>a Thunderbird session with 42 participants;</li>
- <li>an IoT and Firefox OS workshop, in a dedicated room that was <a href="https://www.flickr.com/photos/fossasia/23485427703/">packed with 90 participants</a>;</li>
- </ul>
- <p>On average, there were around 15 Mozillians at the Assembly and a continuous flow of people from different community.</p>
- <p>Other projects where Mozilla is involved were represented, <a href="https://media.ccc.de/v/32c3-7528-let_s_encrypt_--_what_launching_a_free_ca_looks_like">like Let’s Encrypt</a>, with a talk so successful that the conference room was full, and New Palmyra, for which Mozillians organized a session for 25 participants.</p>
- <p>The hackers and makers communities have a real ethical and practical interest in a mobile or embedded OS that’s trustworthy and hackable, we bear similar values and Firefox OS is a great opportunity to strengthen the ties between us.</p></div>
- </content>
- <updated>2016-01-13T22:55:23Z</updated>
- <category term="Events"/>
- <category term="Participation"/>
- <category term="Privacy"/>
- <category term="32c3"/>
- <category term="CCC"/>
- <category term="contributor"/>
- <category term="firefox os"/>
- <category term="Moz32c3"/>
- <category term="MozParticipation"/>
- <category term="Participation Team"/>
- <category term="privacy"/>
- <author>
- <name>Brian King</name>
- </author>
- <source>
- <id>http://blog.mozilla.org/community</id>
- <link href="http://blog.mozilla.org/community/feed/" rel="self" type="application/rss+xml"/>
- <link href="http://blog.mozilla.org/community" rel="alternate" type="text/html"/>
- <subtitle>News and notes from and for the Mozilla community.</subtitle>
- <title>about:community</title>
- <updated>2016-01-25T16:31:43Z</updated>
- </source>
- </entry>
-</feed>
diff --git a/mobile/android/tests/background/junit4/resources/feed_atom_wikipedia.xml b/mobile/android/tests/background/junit4/resources/feed_atom_wikipedia.xml
deleted file mode 100644
index 8b0344c59..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_atom_wikipedia.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- https://en.wikipedia.org/wiki/Atom_%28standard%29#Example_of_an_Atom_1.0_feed
--->
-<feed xmlns="http://www.w3.org/2005/Atom">
-
- <title>Example Feed</title>
- <subtitle>A subtitle.</subtitle>
- <link href="http://example.org/feed/" rel="self" />
- <link href="http://example.org/" />
- <id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
- <updated>2003-12-13T18:30:02Z</updated>
-
-
- <entry>
- <title>Atom-Powered Robots Run Amok</title>
- <link href="http://example.org/2003/12/13/atom03" />
- <link rel="alternate" type="text/html" href="http://example.org/2003/12/13/atom03.html"/>
- <link rel="edit" href="http://example.org/2003/12/13/atom03/edit"/>
- <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
- <updated>2003-12-13T18:30:02Z</updated>
- <summary>Some text.</summary>
- <content type="xhtml">
- <div xmlns="http://www.w3.org/1999/xhtml">
- <p>This is the entry content.</p>
- </div>
- </content>
- <author>
- <name>John Doe</name>
- <email>johndoe@example.com</email>
- </author>
- </entry>
-
-</feed> \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/resources/feed_rss10_planetmozilla.xml b/mobile/android/tests/background/junit4/resources/feed_rss10_planetmozilla.xml
deleted file mode 100644
index 2cfd93d3c..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_rss10_planetmozilla.xml
+++ /dev/null
@@ -1,3860 +0,0 @@
-<?xml version="1.0"?>
-<rdf:RDF
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:foaf="http://xmlns.com/foaf/0.1/"
- xmlns:content="http://purl.org/rss/1.0/modules/content/"
- xmlns:atom="http://www.w3.org/2005/Atom"
- xmlns="http://purl.org/rss/1.0/"
- >
- <channel rdf:about="http://planet.mozilla.org/">
- <title>Planet Mozilla</title>
- <link>http://planet.mozilla.org/</link>
- <description>Planet Mozilla - http://planet.mozilla.org/</description>
- <atom:link rel="self" href="http://planet.mozilla.org/rss10.xml" type="application/rss+xml"/>
-
- <items>
- <rdf:Seq>
- <rdf:li rdf:resource="http://dblohm7.ca/blog/2016/01/26/announcing-mozdbgext" />
- <rdf:li rdf:resource="http://firefoxmania.uci.cu/?p=15548" />
- <rdf:li rdf:resource="https://quality.mozilla.org/?p=49454" />
- <rdf:li rdf:resource="http://dlawrence.wordpress.com/?p=29" />
- <rdf:li rdf:resource="http://blog.mozilla.org/tanvi/?p=198" />
- <rdf:li rdf:resource="https://blog.mozilla.org/?p=9166" />
- <rdf:li rdf:resource="http://benoitgirard.wordpress.com/?p=651" />
- <rdf:li rdf:resource="http://blog.servo.org/2016/01/25/twis-48/" />
- <rdf:li rdf:resource="https://air.mozilla.org/mozilla-weekly-project-meeting-20160125/" />
- <rdf:li rdf:resource="http://blog.mozilla.org/community/?p=2292" />
- <rdf:li rdf:resource="tag:literaci.es,2014:Post/digital-skills-curriculum" />
- <rdf:li rdf:resource="https://fundraising.mozilla.org/?p=800" />
- <rdf:li rdf:resource="http://www.agmweb.ca/robbie-burns" />
- <rdf:li rdf:resource="tag:this-week-in-rust.org,2016-01-25:blog/2016/01/25/this-week-in-rust-115/" />
- <rdf:li rdf:resource="tag:blogger.com,1999:blog-1015214236289077798.post-7056349209464984020" />
- <rdf:li rdf:resource="https://blog.mozilla.org/netpolicy/?p=907" />
- <rdf:li rdf:resource="http://blog.mozilla.org/addons/?p=7640" />
- <rdf:li rdf:resource="http://coopcoopbware.tumblr.com/post/137832199980" />
- <rdf:li rdf:resource="https://air.mozilla.org/foundation-demos-january-22-2016/" />
- <rdf:li rdf:resource="http://blog.mozilla.org/sumo/?p=3667" />
- <rdf:li rdf:resource="https://air.mozilla.org/bay-area-rust-meetup-january-2016/" />
- <rdf:li rdf:resource="https://blog.lizardwrangler.com/?p=3953" />
- <rdf:li rdf:resource="https://blog.mozilla.org/webdev/?p=4082" />
- <rdf:li rdf:resource="http://blog.mozilla.org/community/?p=2287" />
- <rdf:li rdf:resource="https://blog.mozilla.org/netpolicy/?p=912" />
- <rdf:li rdf:resource="https://tacticalsecret.com/tag/mozilla/rss/9c39ad13-14ae-4456-a84e-13612637d832" />
- <rdf:li rdf:resource="https://air.mozilla.org/web-qa-weekly-meeting-20160121/" />
- <rdf:li rdf:resource="http://soledadpenades.com/?p=6379" />
- <rdf:li rdf:resource="http://pierros.papadeas.gr/?p=447" />
- <rdf:li rdf:resource="http://adamlofting.com/?p=1396" />
- <rdf:li rdf:resource="http://blog.ziade.org/2016/01/21/a-pelican-web-editor/" />
- <rdf:li rdf:resource="http://www.ncameron.org/blog/rss/631106eb-e7b1-47d5-82f9-cb6ad210ea89" />
- <rdf:li rdf:resource="http://nickdesaulniers.github.io/blog/2016/01/20/debugging-x86-64-assembly-with-lldb-and-dtrace" />
- <rdf:li rdf:resource="https://rail.merail.ca/posts/rebooting-productivity.html" />
- <rdf:li rdf:resource="http://blog.rust-lang.org/2016/01/21/Rust-1.6.html" />
- <rdf:li rdf:resource="http://blog.mozilla.org/addons/?p=7644" />
- <rdf:li rdf:resource="https://air.mozilla.org/the-joy-of-coding-episode-41/" />
- <rdf:li rdf:resource="http://blog.mozilla.org/nfroyd/?p=452" />
- <rdf:li rdf:resource="http://andreasgal.com/?p=573" />
- <rdf:li rdf:resource="https://miketaylr.com/posts/2016/01/at-media-webkit-transform-three-dee.html" />
- <rdf:li rdf:resource="http://globau.wordpress.com/?p=881" />
- <rdf:li rdf:resource="https://www.alex-johnson.net/tag/mozilla/rss/85d84c54-ed0c-4ee5-beb3-8823edb3c074" />
- <rdf:li rdf:resource="http://www.brianbondy.com/blog/id/172" />
- <rdf:li rdf:resource="http://coffeeonthekeyboard.com/rss/0388d8a6-fc86-477e-a161-1b356e01fe77" />
- <rdf:li rdf:resource="https://air.mozilla.org/reprendre-le-controle-de-sa-vie-privee-sur-internet/" />
- <rdf:li rdf:resource="https://mykzilla.org/?p=245" />
- <rdf:li rdf:resource="http://michaelkohler.info/?p=348" />
- <rdf:li rdf:resource="http://dlawrence.wordpress.com/?p=27" />
- <rdf:li rdf:resource="http://soledadpenades.com/?p=6335" />
- <rdf:li rdf:resource="http://daniel.haxx.se/blog/?p=8544" />
- <rdf:li rdf:resource="http://edunham.net/2016/01/19/how_much_knowledge_do_you_need_to_give_a_conference_talk.html" />
- <rdf:li rdf:resource="https://quality.mozilla.org/?p=49441" />
- <rdf:li rdf:resource="http://blog.monotonous.org/?p=678" />
- <rdf:li rdf:resource="http://www.ncameron.org/blog/rss/0e4d587c-380c-40ce-954a-7206f69bc1dd" />
- <rdf:li rdf:resource="http://geekyogre.com/rss/63eb682d-66b4-447d-8fb6-f4ed448019df" />
- <rdf:li rdf:resource="http://dougbelshaw.com/blog/?p=39986" />
- <rdf:li rdf:resource="tag:this-week-in-rust.org,2016-01-18:blog/2016/01/18/this-week-in-rust-114/" />
- <rdf:li rdf:resource="http://nikkisquared.github.io/2016/01/17/what-does-your-work-mean-part-2.html" />
- <rdf:li rdf:resource="http://ngokevin.com/blog/aframe-component/" />
- <rdf:li rdf:resource="http://blog.gerv.net/?p=3527" />
- <rdf:li rdf:resource="https://www.christianheilmann.com/?p=4957" />
- <rdf:li rdf:resource="http://glandium.org/blog/?p=3510" />
- <rdf:li rdf:resource="http://edunham.net/2016/01/16/buildbot_and_eoferror.html" />
- <rdf:li rdf:resource="urn:md5:41d039bb28fb15c761578cba0b1454fa" />
- <rdf:li rdf:resource="https://repeer.org/?p=48" />
- <rdf:li rdf:resource="http://bluesock.org/%7Ewillkg/blog/pyvideo/status_20160115.html" />
- <rdf:li rdf:resource="http://coopcoopbware.tumblr.com/post/137371863755" />
- <rdf:li rdf:resource="https://air.mozilla.org/webdev-beer-and-tell-january-2016/" />
- <rdf:li rdf:resource="http://blog.mozilla.org/sumo/?p=3665" />
- <rdf:li rdf:resource="https://air.mozilla.org/paris-firefox-os-hackathon-presentations/" />
- <rdf:li rdf:resource="https://tacticalsecret.com/tag/mozilla/rss/db7fec0c-34d3-4633-9904-79b98aab34e7" />
- <rdf:li rdf:resource="http://firefoxmania.uci.cu/?p=15521" />
- <rdf:li rdf:resource="https://timtaubert.de/blog/2016/01/build-your-own-signal-desktop" />
- <rdf:li rdf:resource="http://glandium.org/blog/?p=3579" />
- <rdf:li rdf:resource="https://air.mozilla.org/web-qa-weekly-meeting-20160114/" />
- </rdf:Seq>
- </items>
- </channel>
-
- <item rdf:about="http://dblohm7.ca/blog/2016/01/26/announcing-mozdbgext">
- <title>Aaron Klotz: Announcing Mozdbgext</title>
- <link>http://dblohm7.ca/blog/2016/01/26/announcing-mozdbgext/</link>
- <content:encoded>&lt;p&gt;A well-known problem at Mozilla is that, while most of our desktop users run
- Windows, most of Mozilla’s developers do not. There are a lot of problems that
- result from that, but one of the most frustrating to me is that sometimes
- those of us that actually use Windows for development find ourselves at a
- disadvantage when it comes to tooling or other productivity enhancers.&lt;/p&gt;
-
- &lt;p&gt;In many ways this problem is also a Catch-22: People don’t want to use Windows
- for many reasons, but tooling is big part of the problem. OTOH, nobody is
- motivated to improve the tooling situation if nobody is actually going to
- use them.&lt;/p&gt;
-
- &lt;p&gt;A couple of weeks ago my frustrations with the situation boiled over when I
- learned that our &lt;code&gt;Cpp&lt;/code&gt; unit test suite could not log symbolicated call stacks,
- resulting in my filing of &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1238305&quot; title=&quot;cppunittests do not look up breakpad symbols for logged stack traces&quot;&gt;bug 1238305&lt;/a&gt; and &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1240605&quot; title=&quot;Set _NT_SYMBOL_PATH on Windows test machines&quot;&gt;bug 1240605&lt;/a&gt;. Not only could we
- not log those stacks, in many situations we could not view them in a debugger
- either.&lt;/p&gt;
-
- &lt;p&gt;Due to the fact that PDB files consume a large amount of disk space, we don’t
- keep those when building from integration or try repositories. Unfortunately
- they are be quite useful to have when there is a build failure. Most of our
- integration builds, however, do include breakpad symbols. Developers may also
- explicitly &lt;a href=&quot;https://wiki.mozilla.org/ReleaseEngineering/TryServer#Getting_debug_symbols&quot;&gt;request symbols&lt;/a&gt;
- for their try builds.&lt;/p&gt;
-
- &lt;p&gt;A couple of years ago I had begun working on a WinDbg debugger extension that
- was tailored to Mozilla development. It had mostly bitrotted over time, but I
- decided to resurrect it for a new purpose: to help WinDbg&lt;sup&gt;&lt;a href=&quot;http://dblohm7.ca/atom.xml#fn1&quot; id=&quot;r1&quot;&gt;*&lt;/a&gt;&lt;/sup&gt;
- grok breakpad.&lt;/p&gt;
-
- &lt;h3&gt;Enter mozdbgext&lt;/h3&gt;
-
- &lt;p&gt;&lt;a href=&quot;https://github.com/dblohm7/mozdbgext&quot;&gt;&lt;code&gt;mozdbgext&lt;/code&gt;&lt;/a&gt; is the result. This extension
- adds a few commands that makes Win32 debugging with breakpad a little bit easier.&lt;/p&gt;
-
- &lt;p&gt;The original plan was that I wanted &lt;code&gt;mozdbgext&lt;/code&gt; to load breakpad symbols and then
- insert them into the debugger’s symbol table via the &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/windows/hardware/ff537943%28v=vs.85%29.aspx&quot;&gt;&lt;code&gt;IDebugSymbols3::AddSyntheticSymbol&lt;/code&gt;&lt;/a&gt;
- API. Unfortunately the design of this API is not well equipped for bulk loading
- of synthetic symbols: each individual symbol insertion causes the debugger to
- re-sort its entire symbol table. Since &lt;code&gt;xul.dll&lt;/code&gt;’s quantity of symbols is in the
- six-figure range, using this API to load that quantity of symbols is
- prohibitively expensive. I tweeted a Microsoft PM who works on Debugging Tools
- for Windows, asking if there would be any improvements there, but it sounds like
- this is not going to be happening any time soon.&lt;/p&gt;
-
- &lt;p&gt;My original plan would have been ideal from a UX perspective: the breakpad
- symbols would look just like any other symbols in the debugger and could be
- accessed and manipulated using the same set of commands. Since synthetic symbols
- would not work for me in this case, I went for “Plan B:†Extension commands that
- are separate from, but analagous to, regular WinDbg commands.&lt;/p&gt;
-
- &lt;p&gt;I plan to continuously improve the commands that are available. Until I have a
- proper README checked in, I’ll introduce the commands here.&lt;/p&gt;
-
- &lt;h4&gt;Loading the Extension&lt;/h4&gt;
-
- &lt;ol&gt;
- &lt;li&gt;Use the &lt;code&gt;.load&lt;/code&gt; command: &lt;code&gt;.load &amp;lt;path_to_mozdbgext_dll&amp;gt;&lt;/code&gt;&lt;/li&gt;
- &lt;/ol&gt;
-
-
- &lt;h4&gt;Loading the Breakpad Symbols&lt;/h4&gt;
-
- &lt;ol&gt;
- &lt;li&gt;Extract the breakpad symbols into a directory.&lt;/li&gt;
- &lt;li&gt;In the debugger, enter &lt;code&gt;!bploadsyms &amp;lt;path_to_breakpad_symbol_directory&amp;gt;&lt;/code&gt;&lt;/li&gt;
- &lt;li&gt;Note that this command will take some time to load all the relevant symbols.&lt;/li&gt;
- &lt;/ol&gt;
-
-
- &lt;h4&gt;Working with Breakpad Symbols&lt;/h4&gt;
-
- &lt;p&gt;&lt;strong&gt;Note: You must have successfully run the &lt;code&gt;!bploadsyms&lt;/code&gt; command first!&lt;/strong&gt;&lt;/p&gt;
-
- &lt;p&gt;As a general guide, I am attempting to name each breakpad command similarly to
- the native WinDbg command, except that the command name is prefixed by &lt;code&gt;!bp&lt;/code&gt;.&lt;/p&gt;
-
- &lt;ul&gt;
- &lt;li&gt;Stack trace: &lt;code&gt;!bpk&lt;/code&gt;&lt;/li&gt;
- &lt;li&gt;Find nearest symbol to address: &lt;code&gt;!bpln &amp;lt;address&amp;gt;&lt;/code&gt; where &lt;em&gt;address&lt;/em&gt; is specified
- as a hexadecimal value.&lt;/li&gt;
- &lt;/ul&gt;
-
-
- &lt;h4&gt;Downloading windbgext&lt;/h4&gt;
-
- &lt;p&gt;I have pre-built a &lt;a href=&quot;https://github.com/dblohm7/mozdbgext/blob/master/bin/mozdbgext.dll?raw=true&quot;&gt;32-bit binary&lt;/a&gt;
- (which obviously requires 32-bit WinDbg). I have not built a 64-bit binary yet,
- but the code should be source compatible.&lt;/p&gt;
-
- &lt;p&gt;Note that there are several other commands that are “roughed-in†at this point
- and do not work correctly yet. Please stick to the documented commands at this
- time.&lt;/p&gt;
-
- &lt;hr /&gt;
-
- &lt;p&gt;&lt;sup&gt;&lt;a href=&quot;http://dblohm7.ca/atom.xml#r1&quot; id=&quot;fn1&quot;&gt;*&lt;/a&gt;&lt;/sup&gt; When I write “WinDbgâ€, I am really
- referring to any debugger in the &lt;em&gt;Debugging Tools for Windows&lt;/em&gt; package,
- including &lt;code&gt;cdb&lt;/code&gt;.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-26T19:45:00+00:00</dc:date>
- </item>
- <item rdf:about="http://firefoxmania.uci.cu/?p=15548">
- <title>Yunier José Sosa Vázquez: Soporte para WebM/VP9, más seguridad y nuevas herramientas para desarrolladores en el nuevo Firefox</title>
- <link>http://firefoxmania.uci.cu/soporte-para-webmvp9-mas-seguridad-y-nuevas-herramientas-para-desarrolladores-en-el-nuevo-firefox/</link>
- <content:encoded>&lt;p style=&quot;text-align: left;&quot;&gt;¡Como pasa el tiempo amigos! Casi sin darnos cuenta han transcurrido 6 semanas y hasta hemos comenzado un año nuevo, un año en el que Mozilla prepara nuevas funcionalidades que harán de Firefox un mejor como por ejemplo: la &lt;a href=&quot;http://firefoxmania.uci.cu/como-se-hace-activar-electrolysis-en-firefox/&quot; target=&quot;_blank&quot;&gt;separación de procesos&lt;/a&gt;, el uso de vías alternas para &lt;a href=&quot;http://firefoxmania.uci.cu/el-futuro-de-los-plugins-npapi-en-firefox/&quot; target=&quot;_blank&quot;&gt;ejecutar plugins&lt;/a&gt; y la nueva API para desarrollar &lt;a href=&quot;http://firefoxmania.uci.cu/el-futuro-de-los-complementos-en-firefox/&quot; target=&quot;_blank&quot;&gt;complementos “multi navegadorâ€&lt;/a&gt;.&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;Desde el anuncio en 2010 del formato de video WebM, &lt;a href=&quot;https://blog.mozilla.org/blog/2010/05/19/open-web-open-video-and-webm/&quot; target=&quot;_blank&quot;&gt;Mozilla ha mostrado un especial interés&lt;/a&gt; al ser una alternativa potente frente a los formatos propietarios del mercado que existían en aquel momento y de esta forma mejorar la experiencia de los usuarios al reproducir videos en la web. Con esta liberación se ha habilitado el &lt;strong&gt;soporte para WebM/VP9 en aquellos sistemas que no soportan MP4/H.264&lt;/strong&gt;.&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;Desde algunas versiones atrás, Firefox incluye el plugin &lt;a href=&quot;http://andreasgal.com/2014/10/14/openh264-now-in-firefox/&quot; target=&quot;_blank&quot;&gt;OpenH264 proveído por Cisco&lt;/a&gt; para cumplir las especificaciones de WebRTC y habilitar las llamadas con dispositivos que lo requieran. Ahora, si el &lt;strong&gt;decodificador de H.264 está disponible&lt;/strong&gt; en el sistema, entonces se habilita este codec de video.&lt;span id=&quot;more-15548&quot;&gt;&lt;/span&gt;&lt;/p&gt;
- &lt;h3 style=&quot;text-align: left;&quot;&gt;&lt;em&gt;Novedades para desarrolladores&lt;/em&gt;&lt;/h3&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;En esta oportunidad, los desarrolladores podrán contar con herramientas de animación y filtros CSS, informes sobre consumo de memoria, depuración de WebSocket y más. Todo esto puedes leerlo en &lt;a href=&quot;https://www.mozilla-hispano.org/edicion-para-desarrolladores-44-editor-visual-manejo-de-memoria/&quot; target=&quot;_blank&quot;&gt;el blog de Labs&lt;/a&gt; de Mozilla Hispano.&lt;/p&gt;
- &lt;h3 style=&quot;text-align: left;&quot;&gt;&lt;em&gt;Novedades en Android&lt;/em&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Los usuarios pueden elegir la página de inicio a mostrar, en vez de los sitios más visitados.&lt;/li&gt;
- &lt;li&gt;El servicio de impresión de Android permite activar la impresión en la nube.&lt;/li&gt;
- &lt;li&gt;Al &lt;a href=&quot;https://developer.chrome.com/multidevice/android/intents&quot; target=&quot;_blank&quot;&gt;intentar abrir una URIs&lt;/a&gt;, se le pregunta al usuario si desea abrirla en una pestaña privada.&lt;/li&gt;
- &lt;li&gt;Adicionado el soporte para ejecutar URIs con el protocolo mms.&lt;/li&gt;
- &lt;li&gt;Fácil acceso a la configuración de la búsqueda mientras buscamos en Internet.&lt;/li&gt;
- &lt;li&gt;Ahora se muestran las sugerencias del historial de búsqueda.&lt;/li&gt;
- &lt;li&gt;La página Cuentas Firefox ahora está basada en la web.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;em&gt;Otras novedades&lt;/em&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;El soporte para el algoritmo criptográfico RC4 ha sido removido.&lt;/li&gt;
- &lt;li&gt;Soporte para el formato de compresión brotli cuando se usa HTTPS.&lt;/li&gt;
- &lt;li&gt;Uso de un certificado de firmado SHA256 para las versiones de Windows en aras de adaptarse a los nuevos requerimientos.&lt;/li&gt;
- &lt;li&gt;Para soportar el descriptor unicode-range de las fuentes web, el algoritmo de concordancia en Linux usa el mismo código como en las demás plataformas.&lt;/li&gt;
- &lt;li&gt;Firefox no confiará más en la autoridad de certificación Equifax Secure Certificate Authority 1024-bit root o UTN – DATACorp SGC para validar &lt;a href=&quot;https://support.mozilla.org/ta/kb/secure-website-certificate&quot; target=&quot;_blank&quot;&gt;certificados web seguros&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;El soporte para el teclado en pantalla ha sido temporalmente desactivado en Windows 8 y 8.1.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;Si deseas conocer más, puedes leer las &lt;a href=&quot;http://www.mozilla.org/en-US/firefox/44.0/releasenotes/&quot; target=&quot;_blank&quot;&gt;notas de lanzamiento&lt;/a&gt; (en inglés) para conocer más novedades.&lt;/p&gt;
- &lt;p&gt;&lt;strong&gt;Aclaración para la versión móvil.&lt;/strong&gt;&lt;/p&gt;
- &lt;p&gt;En las descargas se pueden encontrar 3 versiones para Android. El archivo que contiene &lt;strong&gt;i386&lt;/strong&gt; es para los dispositivos que tengan la &lt;strong&gt;arquitectura de Intel&lt;/strong&gt;. Mientras que en los nombrados &lt;strong&gt;arm&lt;/strong&gt;, el que dice &lt;strong&gt;api11 funciona con Honeycomb (3.0) o superior&lt;/strong&gt; y el de &lt;strong&gt;api9 es para Gingerbread (2.3)&lt;/strong&gt;.&lt;/p&gt;
- &lt;p&gt;Puedes obtener esta versión desde nuestra &lt;a href=&quot;http://firefoxmania.uci.cu/download/&quot; target=&quot;_blank&quot;&gt;zona de Descargas&lt;/a&gt; en español e inglés para Linux, Mac, Windows y Android. Recuerda que para navegar a través de servidores proxy debes modificar la preferencia &lt;strong&gt;network.auth.force-generic-ntlm&lt;/strong&gt; a &lt;code&gt;true&lt;/code&gt; desde &lt;a target=&quot;_blank&quot;&gt;about:config&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Si te ha gustado, por favor comparte con tus amigos esta noticia en las redes sociales. No dudes en dejarnos un comentario.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-26T18:56:54+00:00</dc:date>
- <dc:creator>Yunier J</dc:creator>
- </item>
- <item rdf:about="https://quality.mozilla.org/?p=49454">
- <title>QMO: Firefox 45.0 Beta 3 Testday, February 5th</title>
- <link>https://quality.mozilla.org/2016/01/firefox-45-0-beta-3-testday-february-5th/</link>
- <content:encoded>&lt;p&gt;Hello Mozillians,&lt;/p&gt;
- &lt;p&gt;We are happy to announce that &lt;strong&gt;Friday, February 5th&lt;/strong&gt;, we are organizing &lt;strong&gt;Firefox 45.0 Beta 3 Testday&lt;/strong&gt;. We will be focusing our testing on the following features: &lt;em&gt;Search Refactoring, Synced Tabs Menu, Text to Speech and Grouped Tabs Migration&lt;/em&gt;. Check out the detailed instructions via &lt;a href=&quot;https://public.etherpad-mozilla.org/p/testday-20160205&quot; target=&quot;_blank&quot;&gt;this etherpad&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;No previous testing experience is required, so feel free to join us on &lt;strong&gt;&lt;a href=&quot;http://widget01.mibbit.com/?server=irc.mozilla.org&amp;amp;channel=%23qa&quot;&gt;#qa IRC channel&lt;/a&gt;&lt;/strong&gt; where our moderators will offer you guidance and answer your questions.&lt;/p&gt;
- &lt;p&gt;Join us and help us make Firefox better! See you on &lt;strong&gt;Friday&lt;/strong&gt;!&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-26T14:40:55+00:00</dc:date>
- <dc:creator>vasilica.mihasca</dc:creator>
- </item>
- <item rdf:about="http://dlawrence.wordpress.com/?p=29">
- <title>David Lawrence: Happy BMO Push Day!</title>
- <link>https://dlawrence.wordpress.com/2016/01/26/happy-bmo-push-day-4/</link>
- <content:encoded>&lt;p&gt;the following changes have been pushed to bugzilla.mozilla.org:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1240575&quot; target=&quot;_blank&quot;&gt;1240575&lt;/a&gt;] Update form.reps.budget&lt;/li&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1226028&quot; target=&quot;_blank&quot;&gt;1226028&lt;/a&gt;] API for batching MozReview requests&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;discuss these changes on &lt;a href=&quot;https://lists.mozilla.org/listinfo/tools-bmo&quot; target=&quot;_blank&quot;&gt;mozilla.tools.bmo&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gocomments/dlawrence.wordpress.com/29/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/dlawrence.wordpress.com/29/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;https://pixel.wp.com/b.gif?host=dlawrence.wordpress.com&amp;amp;blog=58816&amp;amp;post=29&amp;amp;subd=dlawrence&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</content:encoded>
- <dc:date>2016-01-26T14:27:50+00:00</dc:date>
- <dc:creator>dlawrence</dc:creator>
- </item>
- <item rdf:about="http://blog.mozilla.org/tanvi/?p=198">
- <title>Tanvi Vyas: Updated Firefox Security Indicators</title>
- <link>https://blog.mozilla.org/tanvi/2016/01/26/updated-firefox-security-indicators/</link>
- <content:encoded>&lt;p&gt;&lt;em&gt;This article has been coauthored by Aislinn Grigas, Senior Interaction Designer, Firefox Desktop&lt;/em&gt;&lt;br /&gt;
- &lt;em&gt;Cross posting with &lt;a href=&quot;https://blog.mozilla.org/security/2015/11/03/updated-firefox-security-indicators-2/&quot;&gt;Mozilla’s Security Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;November 3, 2015&lt;/p&gt;
- &lt;p&gt;Over the past few months, Mozilla has been improving the user experience of our privacy and security features in Firefox. One specific initiative has focused on the feedback shown in our address bar around a site’s security. The major changes are highlighted below along with the rationale behind each change.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://blog.mozilla.org/security/files/2015/10/combo-graph21.png&quot;&gt;&lt;img alt=&quot;&quot; class=&quot;alignnone wp-image-2045 size-full&quot; height=&quot;914&quot; src=&quot;https://blog.mozilla.org/security/files/2015/10/combo-graph21.png&quot; width=&quot;1518&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;h3&gt;Change to DV Certificate treatment in the address bar&lt;/h3&gt;
- &lt;p&gt;Color and iconography is commonly used today to communicate to users when a site is secure. The most widely used patterns are coloring a lock icon and parts of the address bar green. This treatment has a straightforward rationale given green = good in most cultures. Firefox has historically used two different color treatments for the lock icon – a gray lock for &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-validated_certificate&quot;&gt;Domain-validated (DV) certificates&lt;/a&gt; and a green lock for &lt;a href=&quot;https://en.wikipedia.org/wiki/Extended_Validation_Certificate&quot;&gt;Extended Validation (EV) certificates&lt;/a&gt;. The average user is likely not going to understand this color distinction between EV and DV certificates. The overarching message we want users to take from both certificate states is that their connection to the site is secure. We’re therefore updating the color of the lock when a DV certificate is used to match that of an EV certificate.&lt;/p&gt;
- &lt;p&gt;Although the same green icon will be used, the UI for a site using EV certificates will continue to differ from a site using a DV certificate. Specifically, EV certificates are used when &lt;a href=&quot;https://en.wikipedia.org/wiki/Certificate_authority&quot;&gt;Certificate Authorities (CA)&lt;/a&gt; verify the owner of a domain. Hence, we will continue to include the organization name verified by the CA in the address bar.&lt;/p&gt;
- &lt;h3&gt;Changes to Mixed Content Blocker UI on HTTPS sites&lt;/h3&gt;
- &lt;p&gt;A second change we’re introducing addresses what happens when a page served over a secure connection contains &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Security/MixedContent&quot;&gt;Mixed Content&lt;/a&gt;. Firefox’s Mixed Content Blocker proactively blocks &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Security/MixedContent#Mixed_active_content&quot;&gt;Mixed Active Content&lt;/a&gt; by default. Users historically saw a &lt;a href=&quot;https://people.mozilla.org/~tvyas/FigureA.jpg&quot;&gt;shield icon&lt;/a&gt; when Mixed Active Content was blocked and were given the option to disable the protection.&lt;/p&gt;
- &lt;p&gt;Since the Mixed Content state is closely tied to site security, the information should be communicated in one place instead of having two separate icons. Moreover, we have seen that the &lt;a href=&quot;https://telemetry.mozilla.org/new-pipeline/dist.html#!cumulative=0&amp;amp;end_date=2015-09-17&amp;amp;keys=__none__!__none__!__none__&amp;amp;max_channel_version=beta%252F41&amp;amp;measure=MIXED_CONTENT_UNBLOCK_COUNTER&amp;amp;min_channel_version=null&amp;amp;product=Firefox&amp;amp;sanitize=1&amp;amp;sort_keys=submissions&amp;amp;start_date=2015-08-11&amp;amp;table=0&amp;amp;trim=1&amp;amp;use_submission_date=0&quot;&gt;number of times users override mixed content protection&lt;/a&gt; is slim, and hence the need for dedicated mixed content iconography is diminishing. Firefox is also using the shield icon for another feature in &lt;a href=&quot;https://support.mozilla.org/en-US/kb/private-browsing-use-firefox-without-history&quot;&gt;Private Browsing Mode&lt;/a&gt; and we want to avoid making the iconography ambiguous.&lt;/p&gt;
- &lt;p&gt;The updated design that ships with Firefox 42 combines the lock icon with a warning sign which represents Mixed Content. When Firefox blocks Mixed Active Content, we retain the green lock since the HTTP content is blocked and hence the site remains secure.&lt;/p&gt;
- &lt;p&gt;For users who want to learn more about a site’s security state, we have added an informational panel to further explain differences in page security. This panel appears anytime a user clicks on the lock icon in the address bar.&lt;/p&gt;
- &lt;p&gt;Previously users could &lt;a href=&quot;https://people.mozilla.org/~tvyas/FigureB.jpg&quot;&gt;click on the shield icon&lt;/a&gt; in the rare case they needed to override mixed content protection. With this new UI, users can still do this by clicking the arrow icon to expose more information about the site security, along with a disable protection button.&lt;/p&gt;
- &lt;div class=&quot;wp-caption alignnone&quot; id=&quot;attachment_2034&quot; style=&quot;width: 557px;&quot;&gt;&lt;a href=&quot;https://blog.mozilla.org/security/files/2015/10/mixed-active-content-click-and-subpanel.png&quot;&gt;&lt;img alt=&quot;mixed active content click and subpanel&quot; class=&quot;wp-image-2034 &quot; height=&quot;176&quot; src=&quot;https://blog.mozilla.org/security/files/2015/10/mixed-active-content-click-and-subpanel.png&quot; width=&quot;547&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Users can click the lock with warning icon and proceed to disable Mixed Content Protection.&lt;/p&gt;&lt;/div&gt;
- &lt;h3&gt;&lt;/h3&gt;
- &lt;h3&gt;Loading Mixed Passive Content on HTTPS sites&lt;/h3&gt;
- &lt;p&gt;There is a second category of Mixed Content called &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Security/MixedContent#Mixed_passivedisplay_content&quot;&gt;Mixed Passive Content&lt;/a&gt;. Firefox does not block Mixed Passive Content by default. However, when it is loaded on an HTTPS page, we let the user know with iconography and text. In previous versions of Firefox, we used a gray warning sign to reflect this case.&lt;/p&gt;
- &lt;p&gt;We have updated this iconography in Firefox 42 to a gray lock with a yellow warning sign. We degrade the lock from green to gray to emphasize that the site is no longer completely secure. In addition, we use a vibrant color for the warning icon to amplify that there is something wrong with the security state of the page.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://blog.mozilla.org/security/files/2015/10/mixed-passive-click1.png&quot;&gt;&lt;img alt=&quot;&quot; class=&quot;alignnone wp-image-2042 &quot; height=&quot;100&quot; src=&quot;https://blog.mozilla.org/security/files/2015/10/mixed-passive-click1-600x221.png&quot; width=&quot;268&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;We also use this iconography when the certificate or TLS connection used by the website relies on deprecated cryptographic algorithms.&lt;/p&gt;
- &lt;p&gt;The above changes will be rolled out in Firefox 42. Overall, the design improvements make it simpler for our users to understand whether or not their interactions with a site are secure.&lt;/p&gt;
- &lt;h3&gt;Firefox Mobile&lt;/h3&gt;
- &lt;p&gt;We have made similar changes to the site security indicators in Firefox for Android, which you can learn more about &lt;a href=&quot;https://support.mozilla.org/en-US/kb/mixed-content-blocker-firefox-android#w_how-do-i-know-if-a-page-has-mixed-content&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-26T05:58:29+00:00</dc:date>
- <dc:creator>Tanvi Vyas</dc:creator>
- </item>
- <item rdf:about="https://blog.mozilla.org/?p=9166">
- <title>The Mozilla Blog: Firefox Can Now Get Push Notifications From Your Favorite Sites</title>
- <link>https://blog.mozilla.org/blog/2016/01/25/firefox-can-now-get-push-notifications-from-your-favorite-sites/</link>
- <content:encoded>&lt;p&gt;UPDATED TO CLARIFY HOW TO MANAGE PUSH NOTIFICATIONS&lt;/p&gt;
- &lt;p&gt;Firefox for Windows, Mac and Linux now lets you choose to receive push notifications from websites if you give them permission. This is similar to Web notifications, except now you can receive notifications for websites even when they’re not loaded in a tab. This is super useful for websites like email, weather, social networks and shopping, which you might check frequently for updates.&lt;/p&gt;
- &lt;p&gt;You can manage your notifications in the Control Center by clicking the green lock icon on the left side of the address bar. You can learn more about how to manage push notifications&lt;a href=&quot;https://support.mozilla.org/en-US/kb/push-notifications-firefox?as=u&amp;amp;utm_source=inproduct#w_upgraded-notifications&quot;&gt; here&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;b&gt;Push Notifications for Web Developers&lt;/b&gt;&lt;br /&gt;
- To make this functionality possible, Mozilla helped establish the Web Push W3C standard that’s gaining momentum across the Web. We also continue to explore the new design pattern known as&lt;a href=&quot;https://blog.mozilla.org/futurereleases/2015/11/17/extending-the-webs-capabilities-in-firefox-and-beyond/&quot;&gt; Progressive Web Apps&lt;/a&gt;. If you’re a developer who wants to implement push notifications on your site, you can learn more in this&lt;a href=&quot;https://hacks.mozilla.org/2016/01/web-push-arrives-in-firefox-44/&quot;&gt; Hacks blog post&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;b&gt;More information:&lt;/b&gt;&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;Download&lt;a href=&quot;https://www.mozilla.org/firefox/new/&quot;&gt; Firefox for Windows, Mac, Linux&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Release Notes for&lt;a href=&quot;https://www.mozilla.org/firefox/44.0/releasenotes/&quot;&gt; Firefox for Windows, Mac, Linux&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Download&lt;a href=&quot;https://play.google.com/store/apps/details?id=org.mozilla.firefox&amp;amp;referrer=utm_source%3Dmozilla%26utm_medium&quot;&gt; Firefox for Android&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Release Notes for&lt;a href=&quot;https://www.mozilla.org/firefox/android/44.0/releasenotes/&quot;&gt; Firefox for Android&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;</content:encoded>
- <dc:date>2016-01-26T01:56:50+00:00</dc:date>
- <dc:creator>Mozilla</dc:creator>
- </item>
- <item rdf:about="http://benoitgirard.wordpress.com/?p=651">
- <title>Benoit Girard: Using RecordReplay to investigate intermittent oranges</title>
- <link>https://benoitgirard.wordpress.com/2016/01/25/using-recordreplay-to-investigate-intermittent-oranges/</link>
- <content:encoded>&lt;p&gt;This is a quick write up to summarize my, and Jeff’s, experience, using RR to debug a &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1226748&quot;&gt;fairly rare intermittent reftest failure&lt;/a&gt;. There’s still a lot of be learned about how to use RR effectively so I’m hoping sharing this will help others.&lt;/p&gt;
- &lt;h3&gt;Finding the root of the bad pixel&lt;/h3&gt;
- &lt;p&gt;First given a offending pixel I was able to set a breakpoint on it using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Hacking_Tips#rr_with_reftest&quot;&gt;these instructions&lt;/a&gt;. Next using &lt;a href=&quot;https://github.com/jrmuizel/rr-dataflow&quot;&gt;rr-dataflow&lt;/a&gt; I was able to step from the offending bad pixel to the display item responsible for this pixel. Let me emphasize this for a second since it’s incredibly impressive. rr + rr-dataflow allows you to go from a buffer, through an intermediate surface, to the compositor on another thread, through another intermediate surface, back to the main thread and eventually back to the relevant display item. All of this was automated except for when the two pixels are blended together which is logically ambiguous. The speed at which rr was able to reverse continue through this execution was very impressive!&lt;/p&gt;
- &lt;p&gt;Here’s the trace of this part: &lt;a href=&quot;https://gist.github.com/bgirard/e707e9b97556b500d9ae&quot;&gt;rr-trace-reftest-pixel-origin&lt;/a&gt;&lt;/p&gt;
- &lt;h3&gt;Understanding the decoding step&lt;/h3&gt;
- &lt;p&gt;From here I started comparing a replay of a failing test and a non failing step and it was clear that the DisplayList was different. In one we have a nsDisplayBackgroundColor in the other we don’t. From here I was able to step through the decoder and compare the sequence. This was very useful in ruling out possible theories. It was easy to step forward and backwards in the good and bad replay debugging sessions to test out various theories about race conditions and understanding at which part of the decode process the image was rejected. It turned out that we sent two decodes, one for the metadata that is used to sized the frame tree and the other one for the image data itself.&lt;/p&gt;
- &lt;h3&gt;Comparing the frame tree&lt;/h3&gt;
- &lt;p&gt;In hindsight, it would have been more effective to start debugging this test by looking at the frame tree (and I imagine for other tests looking at the display list and layer tree) first would have been a quicker start. It works even better if you have a good and a bad trace to compare the difference in the frame tree. From here, I found that the difference in the layer tree came from a change hint that wasn’t guaranteed to come in before the draw.&lt;/p&gt;
- &lt;p&gt;The problem is now well understood: When we do a sync decode on reftest draw, if there’s an image error we wont flush the style hints since we’re already too deep in the painting pipeline.&lt;/p&gt;
- &lt;h3&gt;Take away&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Finding the root cause of a bad pixel is very easy, and fast, to do using rr-dataflow.&lt;/li&gt;
- &lt;li&gt;However it might be better to look for obvious frame tree/display list/layer tree difference(s) first.&lt;/li&gt;
- &lt;li&gt;Debugging a replay is a lot simpler then debugging against non-determinist re-runs and a lot less frustrating too.&lt;/li&gt;
- &lt;li&gt;rr is really useful for race conditions, especially rare ones.&lt;/li&gt;
- &lt;/ul&gt;&lt;br /&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gocomments/benoitgirard.wordpress.com/651/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/benoitgirard.wordpress.com/651/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;https://pixel.wp.com/b.gif?host=benoitgirard.wordpress.com&amp;amp;blog=12112851&amp;amp;post=651&amp;amp;subd=benoitgirard&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</content:encoded>
- <dc:date>2016-01-25T22:16:01+00:00</dc:date>
- <dc:creator>benoitgirard</dc:creator>
- </item>
- <item rdf:about="http://blog.servo.org/2016/01/25/twis-48/">
- <title>The Servo Blog: These Weeks In Servo 48</title>
- <link>http://blog.servo.org/2016/01/25/twis-48/</link>
- <content:encoded>&lt;p&gt;In the &lt;a href=&quot;https://github.com/pulls?page=1&amp;amp;q=is%3Apr+is%3Amerged+closed%3A2016-01-11..2016-01-25+user%3Aservo&quot;&gt;last two weeks&lt;/a&gt;, we landed 130 PRs in the Servo organization’s repositories.&lt;/p&gt;
-
- &lt;p&gt;After months of work by vlad and many others, Windows support &lt;a href=&quot;https://github.com/servo/servo/pull/9385&quot;&gt;landed&lt;/a&gt;! Thanks to everyone who contributed fixes, tests, reviews, and even encouragement (or impatience!) to help us make this happen.&lt;/p&gt;
-
- &lt;h3 id=&quot;notable-additions&quot;&gt;Notable Additions&lt;/h3&gt;
-
- &lt;ul&gt;
- &lt;li&gt;nikki &lt;a href=&quot;https://github.com/servo/servo/pull/9391&quot;&gt;added&lt;/a&gt; tests and support for checking the Fetch redirect count&lt;/li&gt;
- &lt;li&gt;glennw &lt;a href=&quot;https://github.com/servo/servo/pull/9359&quot;&gt;implemented&lt;/a&gt; horizontal scrolling with arrow keys&lt;/li&gt;
- &lt;li&gt;simon &lt;a href=&quot;https://github.com/servo/servo/pull/9333&quot;&gt;created&lt;/a&gt; a script that parses all of the CSS properties parsed by Servo&lt;/li&gt;
- &lt;li&gt;ms2ger &lt;a href=&quot;https://github.com/servo/servo/pull/9293&quot;&gt;removed&lt;/a&gt; the legacy reftest framework&lt;/li&gt;
- &lt;li&gt;fernando &lt;a href=&quot;https://github.com/servo/crowbot/pull/33&quot;&gt;made&lt;/a&gt; crowbot able to rejoin IRC after it accidentally floods the channel&lt;/li&gt;
- &lt;li&gt;jack &lt;a href=&quot;https://github.com/servo/saltfs/pull/193&quot;&gt;added&lt;/a&gt; testing the &lt;code&gt;geckolib&lt;/code&gt; target to our CI&lt;/li&gt;
- &lt;li&gt;antrik &lt;a href=&quot;https://github.com/servo/ipc-channel/pull/25&quot;&gt;fixed&lt;/a&gt; transfer corruption in ipc-channel on 32-bit&lt;/li&gt;
- &lt;li&gt;valentin &lt;a href=&quot;https://github.com/servo/rust-url/pull/119&quot;&gt;added&lt;/a&gt; and simon &lt;a href=&quot;https://github.com/servo/rust-url/pull/152&quot;&gt;extended&lt;/a&gt; IDNA support in rust-url, which is required for both web and Gecko compatibility&lt;/li&gt;
- &lt;/ul&gt;
-
- &lt;h3 id=&quot;new-contributors&quot;&gt;New Contributors&lt;/h3&gt;
-
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/Chandler&quot;&gt;Chandler Abraham&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/DarinM223&quot;&gt;Darin Minamoto&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/coder543&quot;&gt;Josh Leverette&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/shssoichiro&quot;&gt;Joshua Holmer&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/therealkbhat&quot;&gt;Kishor Bhat&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/MonsieurLanza&quot;&gt;Lanza&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/mattkuo&quot;&gt;Matthew Kuo&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/waterlink&quot;&gt;Oleksii Fedorov&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/stspyder&quot;&gt;St.Spyder&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/vvuk&quot;&gt;Vladimir Vukicevic&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/apopiak&quot;&gt;apopiak&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/askalski&quot;&gt;askalski&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
-
- &lt;h3 id=&quot;screenshot&quot;&gt;Screenshot&lt;/h3&gt;
-
- &lt;p&gt;Screencast of this post being upvoted on reddit… from Windows!&lt;/p&gt;
-
- &lt;p&gt;&lt;img alt=&quot;(screencast)&quot; src=&quot;http://blog.servo.org/images/upvote-windows.gif&quot; title=&quot;Screencast of upvoting on Reddit on Windows.&quot; /&gt;&lt;/p&gt;
-
- &lt;h3 id=&quot;meetings&quot;&gt;Meetings&lt;/h3&gt;
-
- &lt;p&gt;We had a &lt;a href=&quot;https://github.com/servo/servo/wiki/Meeting-2016-01-11&quot;&gt;meeting&lt;/a&gt; on some CI-related woes, documenting tags and mentoring, and dependencies for the style subsystem.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-25T20:30:00+00:00</dc:date>
- </item>
- <item rdf:about="https://air.mozilla.org/mozilla-weekly-project-meeting-20160125/">
- <title>Air Mozilla: Mozilla Weekly Project Meeting, 25 Jan 2016</title>
- <link>https://air.mozilla.org/mozilla-weekly-project-meeting-20160125/</link>
- <content:encoded>&lt;p&gt;
- &lt;img alt=&quot;Mozilla Weekly Project Meeting&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/e9/4f/e94fbd7f8df916c75a60e63a85b9168c.png&quot; width=&quot;160&quot; /&gt;
- The Monday Project Meeting
- &lt;/p&gt;</content:encoded>
- <dc:date>2016-01-25T19:00:00+00:00</dc:date>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item rdf:about="http://blog.mozilla.org/community/?p=2292">
- <title>About:Community: Firefox 44 new contributors</title>
- <link>http://blog.mozilla.org/community/2016/01/25/firefox-44-new-contributors/</link>
- <content:encoded>&lt;p&gt;With the release of Firefox 44, we are pleased to welcome the &lt;strong&gt;28 developers&lt;/strong&gt; who contributed their first code change to Firefox in this release, &lt;strong&gt;23&lt;/strong&gt; of whom were brand new volunteers! Please join us in thanking each of these diligent and enthusiastic individuals, and take a look at their contributions:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;mkm: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208124&quot;&gt;1208124&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Aditya Motwani: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1209087&quot;&gt;1209087&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Aniket Vyas: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1197309&quot;&gt;1197309&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1197315&quot;&gt;1197315&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Chirath R: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1216941&quot;&gt;1216941&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Christiane Ruetten: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1209091&quot;&gt;1209091&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Fernando Campo: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1199815&quot;&gt;1199815&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Grisha Pushkov: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=994555&quot;&gt;994555&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Guang-De Lin: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1150305&quot;&gt;1150305&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Hassen ben tanfous: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1074804&quot;&gt;1074804&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Helen V. Holmes: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1205046&quot;&gt;1205046&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Henrik Tjäder: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1161698&quot;&gt;1161698&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1209912&quot;&gt;1209912&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Johann Hofmann: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1192432&quot;&gt;1192432&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1198405&quot;&gt;1198405&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1204072&quot;&gt;1204072&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Kapeel Sable: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1212171&quot;&gt;1212171&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Manav Batra: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1202618&quot;&gt;1202618&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1212280&quot;&gt;1212280&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1214626&quot;&gt;1214626&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Manuel Casas Barrado: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1172662&quot;&gt;1172662&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1193674&quot;&gt;1193674&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1200693&quot;&gt;1200693&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1203298&quot;&gt;1203298&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1205684&quot;&gt;1205684&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1212331&quot;&gt;1212331&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1212338&quot;&gt;1212338&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1214582&quot;&gt;1214582&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Matt Howell: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208626&quot;&gt;1208626&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Matthew Turnbull: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1213620&quot;&gt;1213620&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Olivier Yiptong: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1210936&quot;&gt;1210936&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1210940&quot;&gt;1210940&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1213078&quot;&gt;1213078&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Piotr Tworek: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1209446&quot;&gt;1209446&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Rocik: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1070719&quot;&gt;1070719&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Roland Sako: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1207733&quot;&gt;1207733&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Ronald Claveau: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1207266&quot;&gt;1207266&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Sanchit Nevgi: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1205181&quot;&gt;1205181&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Shaif Chowdhury: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1185606&quot;&gt;1185606&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208121&quot;&gt;1208121&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Shubham Jain: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208470&quot;&gt;1208470&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208705&quot;&gt;1208705&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Stanislas Daniel Claude Dolcini: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1147197&quot;&gt;1147197&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Stephanie Ouillon: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1178533&quot;&gt;1178533&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1201626&quot;&gt;1201626&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Tim Huang: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1181489&quot;&gt;1181489&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;simplyblue24: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1218204&quot;&gt;1218204&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;</content:encoded>
- <dc:date>2016-01-25T16:21:33+00:00</dc:date>
- <dc:creator>Josh Matthews</dc:creator>
- </item>
- <item rdf:about="tag:literaci.es,2014:Post/digital-skills-curriculum">
- <title>Doug Belshaw: 3 things to consider when designing a digital skills framework</title>
- <link>http://literaci.es/digital-skills-curriculum</link>
- <content:encoded>&lt;p&gt;&lt;img alt=&quot;Learning to credential&quot; src=&quot;http://bryanmmathers.com/wp-content/uploads/2016/01/learning-to-credential.png&quot; /&gt;&lt;/p&gt;
-
- &lt;p&gt;The image above was created by &lt;a href=&quot;http://bryanmmathers.com/learning-to-credential&quot; rel=&quot;nofollow&quot;&gt;Bryan Mathers&lt;/a&gt; for our &lt;a href=&quot;https://goo.gl/QqwUKP&quot; rel=&quot;nofollow&quot;&gt;presentation&lt;/a&gt; at &lt;a href=&quot;http://bettshow.com&quot; rel=&quot;nofollow&quot;&gt;BETT&lt;/a&gt; last week. It shows the way that, in broad brushstrokes, learning design &lt;em&gt;should&lt;/em&gt; happen. Before microcredentials such as &lt;a href=&quot;http://openbadges.org&quot; rel=&quot;nofollow&quot;&gt;Open Badges&lt;/a&gt; this was a difficult thing to do as both the credential and the assessment are usually given to educators. The flow tends to go &lt;em&gt;backwards&lt;/em&gt; from credentials instead of forwards from what we want people to learn.&lt;/p&gt;
-
- &lt;p&gt;But what if you really &lt;em&gt;were&lt;/em&gt; starting from scratch? How could you design a digital skills framework that contains knowledge, skills, and behaviours worth learning? Having written my &lt;a href=&quot;http://neverendingthesis.com&quot; rel=&quot;nofollow&quot;&gt;thesis&lt;/a&gt; on digital literacies and led Mozilla’s &lt;a href=&quot;https://teach.mozilla.org/activities/web-literacy/&quot; rel=&quot;nofollow&quot;&gt;Web Literacy Map&lt;/a&gt; for a couple of years, I’ve got some suggestions. &lt;/p&gt;
- &lt;h3&gt;
- &lt;a class=&quot;head_anchor&quot; href=&quot;http://literaci.es/feed#1-define-your-audience&quot; name=&quot;1-define-your-audience&quot; rel=&quot;nofollow&quot;&gt; &lt;/a&gt;1. Define your audience&lt;/h3&gt;
- &lt;p&gt;One of the most important things to define is who your audience is for your digital skills framework. Is it for learners to read? Who are they? How old are they? Are you excluding anyone on purpose? Why / why not?&lt;/p&gt;
-
- &lt;p&gt;You might want to do some research and work around &lt;a href=&quot;https://en.wikipedia.org/wiki/Persona_(user_experience)&quot; rel=&quot;nofollow&quot;&gt;user personas&lt;/a&gt; as part of a user-centred design approach. This ensures you’re designing for real people instead of figments of your imagination (or, worse still, in line with your prejudices).&lt;/p&gt;
-
- &lt;p&gt;It’s also good practice to make the language used in the skills framework as precise as possible. Jargon is technical language used for the sake of it. There may be times when it’s impossible not to use a word (e.g. ’&lt;a href=&quot;https://en.wikipedia.org/wiki/Meme&quot; rel=&quot;nofollow&quot;&gt;meme&lt;/a&gt;’). If you do this then link to a definition or include a glossary. It’s also useful to check the ‘reading level’ of your framework and, if you really want a challenge, try using &lt;a href=&quot;http://splasho.com/upgoer5/&quot; rel=&quot;nofollow&quot;&gt;Up-Goer Five&lt;/a&gt; language.&lt;/p&gt;
- &lt;h3&gt;
- &lt;a class=&quot;head_anchor&quot; href=&quot;http://literaci.es/feed#2-focus-on-verbs&quot; name=&quot;2-focus-on-verbs&quot; rel=&quot;nofollow&quot;&gt; &lt;/a&gt;2. Focus on verbs&lt;/h3&gt;
- &lt;p&gt;It’s extremely easy, when creating a framework for learning, to fall into the 'knowledge trap’. Our aim when creating the raw materials from which someone can build a curriculum is to focus on &lt;em&gt;action&lt;/em&gt;. Knowledge should make a difference in practice.&lt;/p&gt;
-
- &lt;p&gt;One straightforward way to ensure that you’re focusing on action rather than head knowledge is to use &lt;strong&gt;verbs&lt;/strong&gt; when constructing your digital skills framework. If you’re familiar with &lt;a href=&quot;https://en.wikipedia.org/wiki/Bloom%27s_taxonomy&quot; rel=&quot;nofollow&quot;&gt;Bloom’s Taxonomy&lt;/a&gt;, then you may find &lt;a href=&quot;http://byrdseed.com/differentiator/&quot; rel=&quot;nofollow&quot;&gt;The Differentiator&lt;/a&gt; useful. This pairs verbs with the various levels of Bloom’s.&lt;/p&gt;
- &lt;h3&gt;
- &lt;a class=&quot;head_anchor&quot; href=&quot;http://literaci.es/feed#3-add-version-numbers&quot; name=&quot;3-add-version-numbers&quot; rel=&quot;nofollow&quot;&gt; &lt;/a&gt;3. Add version numbers&lt;/h3&gt;
- &lt;p&gt;A framework needs to be a living, breathing thing. It should be subject to revision and updated often. For this reason, you should add version numbers to your documentation. Ideally, the latest version should be at a canonical URL and you should archive previous versions to static URLs. &lt;/p&gt;
-
- &lt;p&gt;I would also advise releasing the first version of your framework not as 'version 1.0’ but as 'v0.1’. This shows that you’re willing for others to provide input, that there will be further versions, and that you know you haven’t got it right first time (and forevermore). &lt;/p&gt;
-
- &lt;hr /&gt;
-
- &lt;p&gt;&lt;strong&gt;Questions? Comments?&lt;/strong&gt; Ask me on Twitter (&lt;a href=&quot;http://twitter.com/dajbelshaw&quot; rel=&quot;nofollow&quot;&gt;@dajbelshaw&lt;/a&gt;). I also consult around this kind of thing, so hit me up on &lt;a href=&quot;http://literaci.es/hello@dynamicskillset.com&quot; rel=&quot;nofollow&quot;&gt;hello@dynamicskillset.com&lt;/a&gt;&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-25T14:46:34+00:00</dc:date>
- </item>
- <item rdf:about="https://fundraising.mozilla.org/?p=800">
- <title>Mozilla Fundraising: Why did you decide to donate today?</title>
- <link>https://fundraising.mozilla.org/why-did-you-decide-to-donate-today/</link>
- <content:encoded>This year, we asked some of our donors why they decided to donate to our end of year fundraising campaign. The Survey The Audience The survey was shown to a random sample of donors whose browser language was set to … &lt;a class=&quot;go&quot; href=&quot;https://fundraising.mozilla.org/why-did-you-decide-to-donate-today/&quot;&gt;Continue reading&lt;/a&gt;</content:encoded>
- <dc:date>2016-01-25T13:31:34+00:00</dc:date>
- <dc:creator>Adam Lofting</dc:creator>
- </item>
- <item rdf:about="http://www.agmweb.ca/robbie-burns">
- <title>Andy McKay: Robbie Burns</title>
- <link>http://www.agmweb.ca/2016-01-25-robbie-burns/</link>
- <content:encoded>&lt;p&gt;Tonight is Robbie Burns night, in honour of that great Scottish poet. But tonight had me thinking about another night in my past.&lt;/p&gt;
-
- &lt;p&gt;It was about 5 years ago, maybe less, I struggle to remember now. I was in the UK visiting family and my Dad was sick. Cancer and it's treatment is tough, you have good weeks, you have bad weeks and you have really fucking bad weeks. This was a good week and for some reason I was in the UK.&lt;/p&gt;
-
- &lt;p&gt;Myself, my brother and my sister-in-law went down to see him that night. It was Robbie Burns night and that meant an excuse for haggis, really, truly terrible scotch, Scottish dancing and all that. There are many times when I look back at time with my Dad in those last few years. This was definitely one of those times. He was my Dad at his best, cracking jokes and having fun. Living life to the absolute fullest, while you still have that chance.&lt;/p&gt;
-
- &lt;p&gt;We had a great night. That ended way too soon.&lt;/p&gt;
-
- &lt;p&gt;Not long after that the cancer came back and that was that.&lt;/p&gt;
-
- &lt;p&gt;But suddenly tonight, in a bar in Portland I had these memories of my Dad in a waistcoat cracking jokes and having fun on Robbie Burns night. No-one else in the bar seemed to know what night it was. You'd think Robbie Burns night might get a little bit more appreciation, but hey.&lt;/p&gt;
-
- &lt;p&gt;In the many years I've been running this blog I've never written about my Dad passing away. Here's the first time. I miss him.&lt;/p&gt;
-
- &lt;p&gt;Hey Robbie Burns? Thanks for making me remember that night.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-25T08:00:00+00:00</dc:date>
- </item>
- <item rdf:about="tag:this-week-in-rust.org,2016-01-25:blog/2016/01/25/this-week-in-rust-115/">
- <title>This Week In Rust: This Week in Rust 115</title>
- <link>http://this-week-in-rust.org/blog/2016/01/25/this-week-in-rust-115/</link>
- <content:encoded>&lt;p&gt;Hello and welcome to another issue of &lt;em&gt;This Week in Rust&lt;/em&gt;!
- &lt;a href=&quot;http://rust-lang.org&quot;&gt;Rust&lt;/a&gt; is a systems language pursuing the trifecta:
- safety, concurrency, and speed. This is a weekly summary of its progress and
- community. Want something mentioned? Tweet us at &lt;a href=&quot;https://twitter.com/ThisWeekInRust&quot;&gt;@ThisWeekInRust&lt;/a&gt; or &lt;a href=&quot;mailto:corey@octayn.net?subject=This%20Week%20in%20Rust%20Suggestion&quot;&gt;send us an
- email&lt;/a&gt;!
- Want to get involved? &lt;a href=&quot;https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md&quot;&gt;We love
- contributions&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;This Week in Rust&lt;/em&gt; is openly developed &lt;a href=&quot;https://github.com/cmr/this-week-in-rust&quot;&gt;on GitHub&lt;/a&gt;.
- If you find any errors in this week's issue, &lt;a href=&quot;https://github.com/cmr/this-week-in-rust/pulls&quot;&gt;please submit a PR&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;This week's edition was edited by: &lt;a href=&quot;https://github.com/nasa42&quot;&gt;nasa42&lt;/a&gt;, &lt;a href=&quot;https://github.com/brson&quot;&gt;brson&lt;/a&gt;, and &lt;a href=&quot;https://github.com/llogiq&quot;&gt;llogiq&lt;/a&gt;.&lt;/p&gt;
- &lt;h3&gt;Updates from Rust Community&lt;/h3&gt;
- &lt;h4&gt;News &amp;amp; Blog Posts&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;img alt=&quot;balloon&quot; class=&quot;emoji&quot; src=&quot;https://cdn.discourse.org/business/images/emoji/emoji_one/balloon.png?v=0&quot; title=&quot;:balloon:&quot; /&gt;&lt;img alt=&quot;tada&quot; class=&quot;emoji&quot; src=&quot;https://cdn.discourse.org/business/images/emoji/emoji_one/tada.png?v=0&quot; title=&quot;:tada:&quot; /&gt; &lt;a href=&quot;http://blog.rust-lang.org/2016/01/21/Rust-1.6.html&quot;&gt;Announcing Rust 1.6&lt;/a&gt;. &lt;img alt=&quot;tada&quot; class=&quot;emoji&quot; src=&quot;https://cdn.discourse.org/business/images/emoji/emoji_one/tada.png?v=0&quot; title=&quot;:tada:&quot; /&gt;&lt;img alt=&quot;balloon&quot; class=&quot;emoji&quot; src=&quot;https://cdn.discourse.org/business/images/emoji/emoji_one/balloon.png?v=0&quot; title=&quot;:balloon:&quot; /&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.poumeyrol.fr/2016/01/15/Awkward-zone/&quot;&gt;Rust, BigData and my laptop&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;[pdf]&lt;a href=&quot;https://cdn.rawgit.com/Gankro/thesis/master/thesis.pdf&quot;&gt;You can't spell trust without Rust&lt;/a&gt;. Analysis of the semantics and expressiveness of Rust’s type system.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.ncameron.org/blog/libmacro/&quot;&gt;Libmacro - an API for procedural macros to interact with the compiler&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.jonathanturner.org/2016/01/rust-and-blub-paradox.html&quot;&gt;Rust and the Blub Paradox&lt;/a&gt;. And the &lt;a href=&quot;http://www.jonathanturner.org/2016/01/rethinking-the-blub-paradox.html&quot;&gt;follow-up&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;[video] &lt;a href=&quot;https://www.youtube.com/channel/UC4mpLlHn0FOekNg05yCnkzQ/videos&quot;&gt;Ferris Makes Emulators&lt;/a&gt;. Live stream of Ferris developing a N64 emulator in Rust (also on &lt;a href=&quot;http://www.twitch.tv/ferrisstreamsstuff/profile&quot;&gt;Twitch&lt;/a&gt;).&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Notable New Crates &amp;amp; Project Updates&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://areweconcurrentyet.com/&quot;&gt;Are we concurrent yet&lt;/a&gt;?&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/gfx-rs/gfx&quot;&gt;GFX&lt;/a&gt; epic rewrite for the Pipeline State Objects paradigm has &lt;a href=&quot;https://github.com/gfx-rs/gfx/pull/828&quot;&gt;landed&lt;/a&gt;, described &lt;a href=&quot;http://gfx-rs.github.io/2016/01/22/pso.html&quot;&gt;on the blog&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/mcarton/rust-herbie-lint&quot;&gt;Herbie&lt;/a&gt;. A rustc plugin to check for numerical instability.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://blog.piston.rs/2016/01/23/dynamo/&quot;&gt;Dynamo&lt;/a&gt;. A rusty dynamically typed scripting language.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/whitequark/rust-vnc&quot;&gt;rust-vnc&lt;/a&gt;. An implementation of VNC protocol, client state machine and a client.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;Updates from Rust Core&lt;/h3&gt;
- &lt;p&gt;129 pull requests were &lt;a href=&quot;https://github.com/issues?q=is%3Apr+org%3Arust-lang+is%3Amerged+merged%3A2016-01-18..2016-01-25&quot;&gt;merged in the last week&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;See the &lt;a href=&quot;https://internals.rust-lang.org/t/triage-digest-mon-jan-25-2016/3111&quot;&gt;triage digest&lt;/a&gt; and &lt;a href=&quot;https://internals.rust-lang.org/t/subteam-reports-2016-01-22/3106&quot;&gt;subteam reports&lt;/a&gt; for more details.&lt;/p&gt;
- &lt;h4&gt;Notable changes&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30872&quot;&gt;Implement RFC 1252 expanding the OpenOptions structure&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/book/pull/58&quot;&gt;Book: First draft of 'ownership'&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/cargo/pull/2205&quot;&gt;Cargo: Add convenience syntax to install current crate&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/cargo/pull/2196&quot;&gt;Cargo: Introduce cargo metadata subcommand&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/cargo/pull/2081&quot;&gt;Cargo: Implement &lt;code&gt;cargo init&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/cargo/pull/2270&quot;&gt;Cargo: Emit a warning when manifest specifies empty dependency constraints&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/29520&quot;&gt;Change name when outputting staticlibs on Windows&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30998&quot;&gt;Make &lt;code&gt;btree_set::{IntoIter, Iter, Range}&lt;/code&gt; covariant&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30917&quot;&gt;Avoid bounds checking at &lt;code&gt;slice::binary_search&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30894&quot;&gt;&lt;code&gt;std::sync::mpsc&lt;/code&gt;: Add &lt;code&gt;fmt::Debug&lt;/code&gt; stubs&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30882&quot;&gt;resolve: Fix variant namespacing&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;New Contributors&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;Adrian Heine&lt;/li&gt;
- &lt;li&gt;Andrea Bedini&lt;/li&gt;
- &lt;li&gt;Guillaume Bonnet&lt;/li&gt;
- &lt;li&gt;Kamal Marhubi&lt;/li&gt;
- &lt;li&gt;Keith Yeung&lt;/li&gt;
- &lt;li&gt;Marc Bowes&lt;/li&gt;
- &lt;li&gt;Martin&lt;/li&gt;
- &lt;li&gt;mopp&lt;/li&gt;
- &lt;li&gt;Olaf Buddenhagen&lt;/li&gt;
- &lt;li&gt;Paul Dicker&lt;/li&gt;
- &lt;li&gt;Peter Kolloch&lt;/li&gt;
- &lt;li&gt;Stephen (Ziyun) Li&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Approved RFCs&lt;/h4&gt;
- &lt;p&gt;Changes to Rust follow the Rust &lt;a href=&quot;https://github.com/rust-lang/rfcs#rust-rfcs&quot;&gt;RFC (request for comments)
- process&lt;/a&gt;. These
- are the RFCs that were approved for implementation this week:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1462&quot;&gt;Amendment to RFC 550: Add &lt;code&gt;[&lt;/code&gt; to the FOLLOW(ty) in macro future-proofing rules&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1320&quot;&gt;Amendment to RFC 1192: Amend &lt;code&gt;RangeInclusive&lt;/code&gt; to use an enum&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Final Comment Period&lt;/h4&gt;
- &lt;p&gt;Every week &lt;a href=&quot;https://rust-lang.org/team.html&quot;&gt;the team&lt;/a&gt; announces the
- 'final comment period' for RFCs and key PRs which are reaching a
- decision. Express your opinions now. &lt;a href=&quot;https://github.com/rust-lang/rfcs/labels/final-comment-period&quot;&gt;This week's FCPs&lt;/a&gt; are:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/243&quot;&gt;Trait-based exception handling&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1361&quot;&gt;Improve Cargo target-specific dependencies&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1129&quot;&gt;Add a &lt;code&gt;IndexAssign&lt;/code&gt; trait that allows overloading &quot;indexed assignment&quot; expressions like &lt;code&gt;a[b] = c&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1196&quot;&gt;Allow eliding more type parameters&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1296&quot;&gt;Add an &lt;code&gt;alias&lt;/code&gt; attribute to &lt;code&gt;#[link]&lt;/code&gt; and &lt;code&gt;-l&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;New RFCs&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1477&quot;&gt;Add compiler support for generic atomic operations&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1478&quot;&gt;Translate undefined generic intrinsics to an LLVM &lt;code&gt;unreachable&lt;/code&gt; and a lint&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;Upcoming Events&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/opentechschool-berlin/&quot;&gt;1/27. OpenTechSchool Berlin: Rust Hack and Learn&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/Tokyo-Rust-Meetup/events/227871840/&quot;&gt;1/28. Tokyo Rust Meetup #2&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/Rust-Berlin/events/227321071/&quot;&gt;2/3. Rust Berlin: Leaf and Collenchyma&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/de/Rust-Cologne-Bonn/events/227534456/&quot;&gt;2/3. Rust Meetup in Cologne / Germany&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://www.eventbrite.com/e/mozilla-rust-seattle-meetup-tickets-12222326307?aff=erelexporg&quot;&gt;2/8. Seattle Rust Meetup&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/de-DE/Rust-Rhein-Main/events/228170051/&quot;&gt;2/12. Embedded Rust Workshop Frankfurt&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;If you are running a Rust event please add it to the &lt;a href=&quot;https://www.google.com/calendar/embed?src=apd9vmbc22egenmtu5l6c5jbfc%40group.calendar.google.com&quot;&gt;calendar&lt;/a&gt; to get
- it mentioned here. Email &lt;a href=&quot;mailto:erick.tryzelaar@gmail.com&quot;&gt;Erick Tryzelaar&lt;/a&gt; or &lt;a href=&quot;mailto:banderson@mozilla.com&quot;&gt;Brian
- Anderson&lt;/a&gt; for access.&lt;/p&gt;
- &lt;h3&gt;fn work(on: RustProject) -&amp;gt; Money&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://maidsafe.net/rust_engineer.html&quot;&gt;Rust Engineer&lt;/a&gt; at MaidSafe.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://careers.mozilla.org/en-US/position/ozy21fwU&quot;&gt;Research Engineer - Servo&lt;/a&gt; at Mozilla.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://careers.mozilla.org/en-US/position/o0H41fww&quot;&gt;Senior Research Engineer - Rust&lt;/a&gt; at Mozilla.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://plv.mpi-sws.org/rustbelt/&quot;&gt;PhD and postdoc positions&lt;/a&gt; at MPI-SWS.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;&lt;em&gt;Tweet us at &lt;a href=&quot;https://twitter.com/ThisWeekInRust&quot;&gt;@ThisWeekInRust&lt;/a&gt; to get your job offers listed here!&lt;/em&gt;&lt;/p&gt;
- &lt;h3&gt;Crate of the Week&lt;/h3&gt;
- &lt;p&gt;This week's Crate of the Week is &lt;a href=&quot;https://github.com/phildawes/racer&quot;&gt;racer&lt;/a&gt; which powers code completion in all Rust development environments.&lt;/p&gt;
- &lt;p&gt;Thanks to &lt;a href=&quot;https://users.rust-lang.org/users/stebalien&quot;&gt;Steven Allen&lt;/a&gt; for the suggestion.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://users.rust-lang.org/t/crate-of-the-week/2704&quot;&gt;Submit your suggestions for next week&lt;/a&gt;!&lt;/p&gt;
- &lt;h3&gt;Quote of the Week&lt;/h3&gt;
- &lt;blockquote&gt;
- &lt;p&gt;Memory errors are fundamentally state errors, and Rust's move semantics, borrowing, and aliasing XOR mutating help enormously for me to reason about how my program changes state as it executes, to avoid accidental shared state and side effects at a distance. Rust more than any other language I know enables me to do compiler driven design. And internalizing its rules has helped me design better systems, even in other languages.&lt;/p&gt;
- &lt;/blockquote&gt;
- &lt;p&gt;— &lt;a href=&quot;https://www.reddit.com/r/rust/comments/4275gz/rust_and_the_blub_paradox/cz8akv9&quot;&gt;desiringmachines on /r/rust&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Thanks to &lt;a href=&quot;https://users.rust-lang.org/users/dikaiosune&quot;&gt;dikaiosune&lt;/a&gt; for the suggestion.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://users.rust-lang.org/t/twir-quote-of-the-week/328&quot;&gt;Submit your quotes for next week&lt;/a&gt;!&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-25T05:00:00+00:00</dc:date>
- <dc:creator>Corey Richardson</dc:creator>
- </item>
- <item rdf:about="tag:blogger.com,1999:blog-1015214236289077798.post-7056349209464984020">
- <title>Cameron Kaiser: 38.6.0 available</title>
- <link>http://tenfourfox.blogspot.com/2016/01/3860-available.html</link>
- <content:encoded>TenFourFox 38.6.0 is available for testing (&lt;a href=&quot;https://sourceforge.net/projects/tenfourfox/files/38.6.0/&quot;&gt;downloads&lt;/a&gt;, &lt;a href=&quot;https://github.com/classilla/tenfourfox/wiki/Hashes&quot;&gt;hashes&lt;/a&gt;, &lt;a href=&quot;https://github.com/classilla/tenfourfox/wiki/ZZReleaseNotes3860&quot;&gt;release notes&lt;/a&gt;). I'm sorry it's been so quiet around here; I'm in the middle of a backbreaking Master's course, my last one before I'm finally done with the lousy thing, and I haven't had any time to start on 45 so far. 38.6 does have some other fixes in it, though: I think I found the last place where bookmark backups were being mistakenly saved in LZ4 based on Chris Trusch's report, and the problematic fonts on the iCloud login page are now blacklisted, so you should be able to login again. I can't do much more testing than that, however, since I don't use iCloud personally, so other lapses in font functionality will require the font URL and I'll add them to the blacklist in 38.7. The browser will go live Monday Pacific time as usual. (The temporary workaround is to set &lt;tt&gt;gfx.downloadable_fonts.enabled&lt;/tt&gt; to &lt;tt&gt;false&lt;/tt&gt;, and switch the setting back when you don't need it anymore.) &lt;p&gt;Speaking of, downloadable fonts were exactly the same problem on the Sun Ultra-3 laptop I've been refurbishing; Oracle still provides a free Solaris 10 build of 38ESR, but it crashes on web fonts for reasons I have yet to diagnose, so I just have them turned off. Yes, it really is a SPARC laptop, a rebranded Tadpole Viper, and I think the fastest one ever made in this form factor (a 1.2GHz UltraSPARC IIIi). It's pretty much what I expected the PowerBook G5 would have been -- hot, overthrottled and power-hungry -- but Tadpole actually built the thing and it's not a disaster, relatively speaking. There's no JIT in this Firefox build, the brand new battery gets only 70 minutes of runtime even with the CPU clock-skewed to hell, it stands a very good chance of rendering me sterile and/or medium rare if I actually use it in my lap and it had at least one sudden overtemp shutdown and pooped all over the filesystem, but between Firefox, Star Office and &lt;tt&gt;pkgsrc&lt;/tt&gt; I can actually use it. More on that for laughs in a future post. &lt;/p&gt;&lt;p&gt;It has been pointed out to me that Leopard Webkit has not made an update in over three months, so hopefully Tobias is still doing okay with his port.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-23T06:02:00+00:00</dc:date>
- <dc:creator>ClassicHasClass</dc:creator>
- </item>
- <item rdf:about="https://blog.mozilla.org/netpolicy/?p=907">
- <title>Mozilla Privacy Blog: Addressing the Chilling Effect of Patent Damages</title>
- <link>https://blog.mozilla.org/netpolicy/2016/01/22/addressing-the-chilling-effect-of-patent-damages/</link>
- <content:encoded>&lt;p&gt;Last year, we unveiled the &lt;a href=&quot;https://www.mozilla.org/about/patents/license/&quot;&gt;Mozilla Open Software Patent License&lt;/a&gt; as part of our &lt;a href=&quot;https://www.mozilla.org/about/patents/&quot;&gt;Initiative&lt;/a&gt; to help limit the negative impacts that patents have on open source software. While those were an important first step for us, we continue to do more. This past Wednesday, Mozilla joined several other tech and software companies in filing an &lt;a href=&quot;https://blog.mozilla.org/netpolicy/files/2016/01/Halo-Stryker-Internet-Companies-brief.pdf&quot;&gt;amicus brief&lt;/a&gt; with the Supreme Court of the United States in the &lt;i&gt;Halo&lt;/i&gt; and &lt;i&gt;Stryker&lt;/i&gt; cases.&lt;/p&gt;
- &lt;p&gt;In the brief, we urge the Court to limit the availability of treble damages. Treble damages are significant because they greatly increase the amount of money owed if a defendant is found to “willfully infringe†a patent. As a result, many open source projects and technology companies will refuse to look into or engage in discussions about patents, in order to avoid even a remote possibility of willful infringement. This makes it very hard to address the chilling effects that patents can have on open source software development, open innovation, and collaborative efforts.&lt;/p&gt;
- &lt;p&gt;We hope that our brief will help the Court see how this legal standard has affected technology companies and persuade the Court to limit treble damages.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-23T00:17:34+00:00</dc:date>
- <dc:creator>Elvin Lee</dc:creator>
- </item>
- <item rdf:about="http://blog.mozilla.org/addons/?p=7640">
- <title>Mozilla Addons Blog: Add-on Signing Update</title>
- <link>https://blog.mozilla.org/addons/2016/01/22/add-on-signing-update/</link>
- <content:encoded>&lt;p&gt;In Firefox 43, we made it a default requirement for add-ons to be signed. This requirement can be disabled by &lt;a href=&quot;https://wiki.mozilla.org/Addons/Extension_Signing#FAQ&quot;&gt;toggling a preference&lt;/a&gt; that was originally scheduled to be removed in Firefox 44 for release and beta versions (this preference will continue to be available in the Nightly, Developer, and ESR Editions of Firefox for the foreseeable future). &lt;/p&gt;
- &lt;p&gt;We are delaying the removal of this preference to Firefox 46 for a couple of reasons: We’re adding a feature in Firefox 45 that allows &lt;a href=&quot;https://blog.mozilla.org/addons/2015/12/23/loading-temporary-add-ons/&quot;&gt;temporarily loading unsigned restartless add-ons&lt;/a&gt; in release, which will allow developers of those add-ons to use Firefox for testing, and we’d like this option to be available when we remove the preference. We also want to ensure that developers have adequate time to finish the transition to signed add-ons. &lt;/p&gt;
- &lt;p&gt;The &lt;a href=&quot;https://wiki.mozilla.org/Addons/Extension_Signing#Timeline&quot;&gt;updated timeline&lt;/a&gt; is available on the signing wiki, and you can look up &lt;a href=&quot;https://wiki.mozilla.org/RapidRelease/Calendar&quot;&gt;release dates for Firefox versions&lt;/a&gt; on the releases wiki. Signing will be mandatory in the beta and release versions of Firefox from 46 onwards, at which point unbranded builds based on beta and release will be provided for testing.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-22T22:40:59+00:00</dc:date>
- <dc:creator>Kev Needham</dc:creator>
- </item>
- <item rdf:about="http://coopcoopbware.tumblr.com/post/137832199980">
- <title>Chris Cooper: RelEng &amp; RelOps Weekly Highlights - January 22, 2016</title>
- <link>http://coopcoopbware.tumblr.com/post/137832199980</link>
- <content:encoded>&lt;p&gt;&lt;/p&gt;&lt;figure class=&quot;alignright&quot;&gt;&lt;a href=&quot;https://www.flickr.com/photos/proud2bcan8dn/1150097247/in/faves-19934681@N00/&quot; target=&quot;_blank&quot; title=&quot;wine-and-pies&quot;&gt;&lt;img alt=&quot;wine-and-pies&quot; src=&quot;https://farm2.staticflickr.com/1216/1150097247_2f11cb4c2d_z.jpg?zz=1&quot; width=&quot;200px&quot; /&gt;&lt;/a&gt;Releng: drinkin’ wine and makin’ pies.&lt;/figure&gt;It’s encouraging to see more progress this week on both the build/release promotion and TaskCluster migration fronts, our two major efforts for this quarter.&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Modernize infrastructure:&lt;/b&gt;&lt;/p&gt;
- &lt;p&gt;In a continuing effort to enable faster, more reliable, and more easily-run tests for TaskCluster components, Dustin landed support for an in-memory, credential-free mock of Azure Table Storage in the &lt;a href=&quot;https://www.npmjs.com/package/azure-entities&quot; target=&quot;_blank&quot;&gt;azure-entities&lt;/a&gt; package. Together with the fake mock support he added to &lt;a href=&quot;https://github.com/djmitche/taskcluster-lib-testing&quot; target=&quot;_blank&quot;&gt;taskcluster-lib-testing&lt;/a&gt;, this allows tests for components like taskcluster-hooks to run without network access and without the need for any credentials, substantially decreasing the barrier to external contributions.&lt;/p&gt;
-
- &lt;p&gt;All release promotion tasks are now signed by default. Thanks to Rail for his work here to help improve verifiability and chain-of-custody in our upcoming release process. (&lt;a href=&quot;https://bugzil.la/1239682&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1239682&lt;/a&gt;)
- Beetmover has been spotted in the wild! Jordan has been working on this new tool as part of our release promotion project. Beetmover helps move build artifacts from one place to another (generally between S3 buckets these days), but can also be extended to perform validation actions inline, e.g. checksums and anti-virus. (&lt;a href=&quot;https://bugzil.la/1225899&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1225899&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;Dustin configured the “desktop-test†and “desktop-build†docker images to build automatically on push. That means that you can modify the Dockerfile under `testing/docker`, push to try, and have the try job run in the resulting image, all without pushing any images. This should enable much quicker iteration on tweaks to the docker images. Note, however, that updates to the base OS images (ubuntu1204-build and centos6-build) still require manual pushes.&lt;/p&gt;
-
- &lt;p&gt;Mark landed Puppet code for base windows 10 support including secrets and ssh keys management.&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Improve CI pipeline:&lt;/b&gt;&lt;/p&gt;
-
- &lt;p&gt;Vlad and Amy repurposed 10 Windows XP machines as Windows 7 to improve the wait times in that test pool (&lt;a href=&quot;https://bugzil.la/1239785&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1239785&lt;/a&gt;)
- Armen and Joel have been working on porting the Gecko tests to run under TaskCluster, and have narrowed the failures down to the single digits. This puts us on-track to enable Linux debug builds and tests in TaskCluster as the canonical build/test process.&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Release:&lt;/b&gt;&lt;/p&gt;
-
- &lt;p&gt;Ben finished up work on enhanced Release Blob validation in Balrog (&lt;a href=&quot;https://bugzil.la/703040&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/703040&lt;/a&gt;), which makes it much more difficult to enter bad data into our update server.&lt;/p&gt;
-
- &lt;p&gt;You may recall Mihai, our former intern who &lt;a href=&quot;http://coopcoopbware.tumblr.com/post/133490693210/welcome-back-mihai&quot; target=&quot;_blank&quot;&gt;we just hired back in November&lt;/a&gt;. Shortly after joining the team, he jumped into the &lt;a href=&quot;https://wiki.mozilla.org/ReleaseEngineering/Releaseduty&quot; target=&quot;_blank&quot;&gt;releaseduty&lt;/a&gt; rotation to provide much-needed extra bandwidth. The learning curve here is steep, but over the course of the Firefox 44 release cycle, he’s taken on more and more responsibility. He’s even volunteered to do releaseduty for the Firefox 45 release cycle as well. Perhaps the most impressive thing is that he’s also taken the time to update (or write) the releaseduty docs so that the next person who joins the rotation will be that much further ahead of the game. Thanks for your hard work here, Mihai!&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Operational:&lt;/b&gt;&lt;/p&gt;
-
- &lt;p&gt;Hal did some cleanup work to remove unused mozharness configs and directories from the build mercurial repos. These resources have long-since moved into the main mozilla-central tree. Hopefully this will make it easier for contributors to find the canonical copy! (&lt;a href=&quot;https://bugzil.la/1239003&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1239003&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Hiring:&lt;/b&gt;&lt;/p&gt;
-
- &lt;p&gt;We’re still hiring for a full-time &lt;a href=&quot;https://careers.mozilla.org/position/oi8b2fwn&quot; target=&quot;_blank&quot;&gt;Build &amp;amp; Release Engineer&lt;/a&gt;, and we are still accepting applications for &lt;a href=&quot;https://careers.mozilla.org/position/ofA51fwF&quot; target=&quot;_blank&quot;&gt;interns for 2016&lt;/a&gt;. Come join us!&lt;/p&gt;
-
- &lt;p&gt;Well, I don’t know about you, but all that hard work makes me hungry for pie. See you next week!&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-22T20:49:38+00:00</dc:date>
- </item>
- <item rdf:about="https://air.mozilla.org/foundation-demos-january-22-2016/">
- <title>Air Mozilla: Foundation Demos January 22 2016</title>
- <link>https://air.mozilla.org/foundation-demos-january-22-2016/</link>
- <content:encoded>&lt;p&gt;
- &lt;img alt=&quot;Foundation Demos January 22 2016&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/1c/a0/1ca0b9b2609cdd4e6e3577a8c3df8cfc.jpg&quot; width=&quot;160&quot; /&gt;
- Mozilla Foundation Demos January 22 2016
- &lt;/p&gt;</content:encoded>
- <dc:date>2016-01-22T18:00:00+00:00</dc:date>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item rdf:about="http://blog.mozilla.org/sumo/?p=3667">
- <title>Support.Mozilla.Org: What’s up with SUMO – 22nd January</title>
- <link>https://blog.mozilla.org/sumo/2016/01/22/whats-up-with-sumo-22nd-january/</link>
- <content:encoded>&lt;p&gt;&lt;strong&gt;Hello, SUMO Nation!&lt;/strong&gt;&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://blog.mozilla.org/sumo/files/2016/01/sumo_logo.png&quot;&gt;&lt;img alt=&quot;sumo_logo&quot; class=&quot;aligncenter size-full wp-image-3670&quot; height=&quot;387&quot; src=&quot;http://blog.mozilla.org/sumo/files/2016/01/sumo_logo.png&quot; width=&quot;383&quot; /&gt;&lt;/a&gt;The third week of the new year is already behind us. Time flies when you’re not paying attention… What are you going to do this weekend? Let us know in the comments, if you feel like sharing :-) I hope to be in the mountains, getting some fresh (bracing) air, and enjoying nature.&lt;/p&gt;
- &lt;h3&gt;&lt;strong class=&quot;username&quot;&gt;Welcome, new contributors!&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li class=&quot;author&quot;&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;a class=&quot;username&quot; href=&quot;https://support.mozilla.org/user/johnmwc2&quot; target=&quot;_blank&quot;&gt;johnmwc2&lt;/a&gt;&lt;/div&gt;
- &lt;/li&gt;
- &lt;li class=&quot;author&quot;&gt;&lt;a class=&quot;author-name&quot; href=&quot;https://support.mozilla.org/user/myanesp&quot; target=&quot;_blank&quot;&gt;myanesp&lt;/a&gt;&lt;/li&gt;
- &lt;li class=&quot;author&quot;&gt;&lt;a class=&quot;author-name&quot; href=&quot;https://support.mozilla.org/user/Harish.A&quot; target=&quot;_blank&quot;&gt;Harish.A&lt;/a&gt;&lt;/li&gt;
- &lt;li class=&quot;author&quot;&gt;&lt;a class=&quot;author-name&quot; href=&quot;https://support.mozilla.org/user/hoolibob&quot; target=&quot;_blank&quot;&gt;hoolibob&lt;/a&gt;&lt;/li&gt;
- &lt;li class=&quot;author&quot;&gt;&lt;a class=&quot;author-name&quot; href=&quot;https://support.mozilla.org/user/Meteoro890&quot; target=&quot;_blank&quot;&gt;Meteoro890&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;author&quot;&gt;If you just joined us, don’t hesitate – come over and &lt;a href=&quot;https://support.mozilla.org/forums/buddies&quot; target=&quot;_blank&quot;&gt;say “hi†in the forums!&lt;/a&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;
- &lt;h3&gt;&lt;strong&gt;Contributors of the week&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z74z1rz89z69z76zbz72zz69zz67z9z82zniz71z&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/safwan.rahman&quot; target=&quot;_blank&quot;&gt;Safwan&lt;/a&gt; for his work on the &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=619284&quot; target=&quot;_blank&quot;&gt;draft feature for l10n / KB editing&lt;/a&gt; – rock on!&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/user/artist&quot; target=&quot;_blank&quot;&gt;Artist&lt;/a&gt; and &lt;a href=&quot;https://support.mozilla.org/user/pollti&quot; target=&quot;_blank&quot;&gt;Pollti&lt;/a&gt; for their the work on updating important articles for Focus with limited time – woot!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid64&quot;&gt;
- &lt;p&gt;&lt;strong&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;We salute you!&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
- &lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;Don’t forget that if you are new to SUMO and someone helped you get started in a nice way you can &lt;a href=&quot;https://support.mozilla.org/forums/buddies/711364?last=65670&quot; target=&quot;_blank&quot;&gt;nominate them for the Buddy of the Month!&lt;/a&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;/div&gt;
- &lt;/div&gt;
- &lt;h3&gt;&lt;strong&gt;Most recent SUMO Community meeting&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-2016-01-18&quot; target=&quot;_blank&quot;&gt;You can read the notes here&lt;/a&gt; (most of the staff members were AFK due to MLK Day in the US) and see the video on our &lt;a href=&quot;https://www.youtube.com/channel/UCaiposaIhA7HfMqH2NIciyA/videos&quot; target=&quot;_blank&quot;&gt;YouTube channel&lt;/a&gt; and &lt;a href=&quot;https://air.mozilla.org/search/?q=sumo&quot; target=&quot;_blank&quot;&gt;at AirMozilla&lt;/a&gt;.&lt;del&gt; &lt;/del&gt;&lt;del&gt;&lt;br /&gt;
- &lt;/del&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;IMPORTANT: We are considering changing the way the meetings work. Help us figure out what’s best for you – join the discussion on the forums in this thread: &lt;a href=&quot;https://support.mozilla.org/en-US/forums/contributors/711752?last=67873&quot;&gt;(Monday) Community Meetings in 2016&lt;/a&gt;.&lt;/strong&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong&gt;The next SUMO Community meeting… &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;is happening on &lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-2016-01-25&quot; target=&quot;_blank&quot;&gt;Monday the 25th – join us&lt;/a&gt;!&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Reminder: if you want to add a discussion topic to the upcoming meeting agenda:&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;Start a thread in the &lt;a href=&quot;https://support.mozilla.org/forums/contributors&quot; target=&quot;_blank&quot;&gt;Community Forums&lt;/a&gt;, so that everyone in the community can see what will be discussed and voice their opinion here before Monday (this will make it easier to have an efficient meeting).&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;Please do so as soon as you can before the meeting, so that people have time to read, think, and reply (and also add it to the agenda).&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;If you can, please attend the meeting in person (or via IRC), so we can follow up on your discussion topic during the meeting with your feedback.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-g-ivsra51ph44x461i&quot;&gt;Developers&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://edwin.mozilla.io/t/sumo&quot; target=&quot;_blank&quot;&gt;You can see the current state of the backlog our developers are working on here&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-p-2016-01-21&quot; target=&quot;_blank&quot;&gt;The latest SUMO Platform meeting notes can be found here&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Interested in learning how Kitsune (the engine behind SUMO) works? &lt;a href=&quot;http://kitsune.readthedocs.org/&quot; target=&quot;_blank&quot;&gt;Read more about it here&lt;/a&gt; and &lt;a href=&quot;https://github.com/mozilla/kitsune/&quot; target=&quot;_blank&quot;&gt;fork it on GitHub&lt;/a&gt;!&lt;/li&gt;
- &lt;li&gt;We have a new link for promoting contributions to Kitsune’s code. Please use &lt;strong&gt;http://mzl.la/SUMOdev&lt;/strong&gt; whenever you want to show interested people to see what Kitsune is all about – thanks!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;&lt;a href=&quot;http://blog.mozilla.org/sumo/files/2016/01/mission_developers.png&quot;&gt;&lt;img alt=&quot;mission_developers&quot; class=&quot;aligncenter size-full wp-image-3668&quot; height=&quot;406&quot; src=&quot;http://blog.mozilla.org/sumo/files/2016/01/mission_developers.png&quot; width=&quot;437&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;h3&gt;&lt;strong&gt;Social&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Next week, there will be a kick-off meeting for the rethinking of Mozilla’s general support strategy through social networks. &lt;a href=&quot;https://support.mozilla.org/user/Madasan&quot; target=&quot;_blank&quot;&gt;Are you interested in taking part? Let Madalina know!&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong&gt;Community&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;The NDA process and list is currently being reworked under the leadership of the Participation Team. Expect to see messaging on this subject in the coming days.&lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711729?last=67763&quot;&gt;IMPORTANT: take a look at our Work Week Summary for Mozlando. We need your feedback for a few things there.&lt;/a&gt;&lt;/strong&gt;&lt;/div&gt;
- &lt;/li&gt;
- &lt;li&gt;Are you going to FOSDEM next week? Would you like to have a small SUMO-meetup? &lt;a href=&quot;https://support.mozilla.org/user/vesper&quot; target=&quot;_blank&quot;&gt;Let me know&lt;/a&gt;!&lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;Ongoing reminder: if you think you can benefit from getting &lt;a href=&quot;https://wiki.mozilla.org/Community_Hardware&quot; target=&quot;_blank&quot;&gt;a second-hand device&lt;/a&gt; to help you with contributing to SUMO, you know where to find us.&lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;&lt;a href=&quot;http://blog.mozilla.org/sumo/files/2016/01/hero_support.png&quot;&gt;&lt;img alt=&quot;hero_support&quot; class=&quot;aligncenter size-full wp-image-3669&quot; height=&quot;383&quot; src=&quot;http://blog.mozilla.org/sumo/files/2016/01/hero_support.png&quot; width=&quot;367&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;div class=&quot;&quot;&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid83&quot;&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-g-ivsra51ph44x461i&quot;&gt;Localization&lt;/strong&gt;&lt;/h3&gt;
- &lt;/div&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid95&quot;&gt;
- &lt;ul&gt;
- &lt;li&gt;You can &lt;a href=&quot;https://support.mozilla.org/forums/l10n-forum/711781&quot; target=&quot;_blank&quot;&gt;read more about the recent “infrequent contributor survey†in this thread&lt;/a&gt;. In short: the good news is that we’re doing a good job at making it easy enough for everyone to contribute. The bad news – we’re not doing enough to make sure they know what to do after their first contribution. Expect some changes in the messaging for first-time contributors to the KB :-)&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1012384&quot; target=&quot;_blank&quot;&gt;Our magical l10n dashboards keep being magical&lt;/a&gt; ;-) Thank you for your patience. If you see any discrepancies between the number of localized articles and the percentage shown in the bar, file a bug!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid75&quot;&gt;
- &lt;h3&gt;&lt;strong&gt;Firefox&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for Android&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711712?last=67653&quot;&gt;Learn more about Firefox 43 for Android from the official thread with release notes / issues / discussions&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711718?last=67822&quot;&gt;Reminder: Roland is sharing Firefox 44 for Android release notes / issues / discussions&lt;/a&gt; with everyone in the forum.&lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for Desktop&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li&gt;Heads up – next week should be release week! Keep your eyes peeled ;-)&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for iOS&lt;/strong&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid85&quot;&gt;
- &lt;ul class=&quot;list-bullet1&quot;&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-107uz69zz81zhz78z0z78zz84zz66zz76zz82zz77zj&quot;&gt;No news from the world of Firefox for iOS this week.&lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;p&gt;Thank you for reading all the way down here… More to come next week! You know where to find us, so see you around – keep rocking the open &amp;amp; helpful web!&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-22T17:43:56+00:00</dc:date>
- <dc:creator>Michał</dc:creator>
- </item>
- <item rdf:about="https://air.mozilla.org/bay-area-rust-meetup-january-2016/">
- <title>Air Mozilla: Bay Area Rust Meetup January 2016</title>
- <link>https://air.mozilla.org/bay-area-rust-meetup-january-2016/</link>
- <content:encoded>&lt;p&gt;
- &lt;img alt=&quot;Bay Area Rust Meetup January 2016&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/87/4f/874f4abef76f55213d50e43d6417ed99.png&quot; width=&quot;160&quot; /&gt;
- Bay Area Rust meetup for January 2016. Topics TBD.
- &lt;/p&gt;</content:encoded>
- <dc:date>2016-01-22T03:00:00+00:00</dc:date>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item rdf:about="https://blog.lizardwrangler.com/?p=3953">
- <title>Mitchell Baker: Honored to Participate in New UN Panel on Women’s Economic Empowerment</title>
- <link>http://blog.lizardwrangler.com/2016/01/22/honored-to-participate-in-new-un-panel-on-womens-economic-empowerment/</link>
- <content:encoded>Women’s economic empowerment is necessary for many reasons. It is necessary to bring health, safety and opportunity to half of humanity. It is necessary to bring investment and health to families and communities. It is necessary to unlock economic growth and build more stable societies. Today the UN Secretary General Ban Ki-moon launched the first […]</content:encoded>
- <dc:date>2016-01-22T02:45:58+00:00</dc:date>
- <dc:creator>Mitchell Baker</dc:creator>
- </item>
- <item rdf:about="https://blog.mozilla.org/webdev/?p=4082">
- <title>Mozilla WebDev Community: Beer and Tell – January 2016</title>
- <link>https://blog.mozilla.org/webdev/2016/01/21/beer-and-tell-january-2016/</link>
- <content:encoded>&lt;p&gt;Once a month, web developers from across the Mozilla Project get together to talk about our side projects and drink, an occurrence we like to call “Beer and Tellâ€.&lt;/p&gt;
- &lt;p&gt;There’s a &lt;a href=&quot;https://wiki.mozilla.org/Webdev/Beer_And_Tell/January_2016&quot;&gt;wiki page available&lt;/a&gt; with a list of the presenters, as well as links to their presentation materials. There’s also a &lt;a href=&quot;https://air.mozilla.org/webdev-beer-and-tell-january-2016/&quot;&gt;recording available&lt;/a&gt; courtesy of Air Mozilla.&lt;/p&gt;
- &lt;h3&gt;shobson: CSS-Only Disco Ball&lt;/h3&gt;
- &lt;p&gt;First up was &lt;a href=&quot;https://mozillians.org/en-US/u/stephaniehobson/&quot;&gt;shobson&lt;/a&gt; with a cool demo of an &lt;a href=&quot;http://codepen.io/stephaniehobson/pen/ZGZBVW?editors=110&quot;&gt;animated disco ball made entirely with CSS&lt;/a&gt;. The demo uses a repeated radial gradient for the background, and linear gradients plus a border radius for the disco ball itself. The demo was made for use in shobson’s &lt;a href=&quot;https://www.youtube.com/watch?v=7poVasAQjos&quot;&gt;WordCamp talk&lt;/a&gt; about debugging CSS. A &lt;a href=&quot;http://stephaniehobson.ca/wordpress/2015/08/15/how-to-debug-css/&quot;&gt;blog post&lt;/a&gt; with notes from the talk is available as well.&lt;/p&gt;
- &lt;h3&gt;craigcook: Proton – A CSS Framework for Prototyping&lt;/h3&gt;
- &lt;p&gt;Next was &lt;a href=&quot;https://mozillians.org/en-US/u/craigcook/&quot;&gt;craigcook&lt;/a&gt;, who presented &lt;a href=&quot;http://craigcook.github.io/proton/&quot;&gt;Proton&lt;/a&gt;. It’s a CSS framework that is intentionally ugly to encourage use for prototypes only. Unlike other CSS frameworks, the temptation to reuse the classes from the framework in your final page doesn’t occur, which helps avoid the presentational classes that plague sites built using a framework normally.&lt;/p&gt;
- &lt;p&gt;Proton’s website includes an overview of the layout and components provided, as well as examples of prototypes made using the framework.&lt;/p&gt;
- &lt;hr /&gt;
- &lt;p&gt;If you’re interested in attending the next Beer and Tell, sign up for the &lt;a href=&quot;https://lists.mozilla.org/listinfo/dev-webdev&quot;&gt;dev-webdev@lists.mozilla.org mailing list&lt;/a&gt;. An email is sent out a week beforehand with connection details. You could even add yourself to the wiki and show off your side-project!&lt;/p&gt;
- &lt;p&gt;See you next month!&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-21T18:56:46+00:00</dc:date>
- <dc:creator>Michael Kelly</dc:creator>
- </item>
- <item rdf:about="http://blog.mozilla.org/community/?p=2287">
- <title>About:Community: This Month at Mozilla</title>
- <link>http://blog.mozilla.org/community/2016/01/21/this-month-at-mozilla/</link>
- <content:encoded>&lt;p style=&quot;text-align: center;&quot;&gt;&lt;em&gt;A lot of exciting things are happening with Participation at Mozilla this month. Here’s a quick round-up of some of the things that are going on!&lt;/em&gt;&lt;/p&gt;
- &lt;h3&gt;&lt;b&gt;Mozillians Profiles Got a Facelift: &lt;/b&gt;&lt;/h3&gt;
- &lt;p&gt;Since the start of this year, the Participation Infrastructure team has had a renewed focus on making mozillians.org a modern community directory to meet Mozilla’s growing needs.&lt;/p&gt;
- &lt;p&gt;Their first target for 2016 was to improve the UX on the profile edit interface.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://blog.mozilla.org/community/files/2016/01/new-profile-768x548.png&quot;&gt;&lt;img alt=&quot;new-profile-768x548&quot; class=&quot;aligncenter wp-image-2288 size-large&quot; height=&quot;428&quot; src=&quot;https://blog.mozilla.org/community/files/2016/01/new-profile-768x548-600x428.png&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
- â€We chose it due to relatively self-contained nature of it, and cause many people were not happy with the current UX. After research of existing tools and applying latest best practices, we designed, coded and deployed a new profile edit interface (which by the way is renamed to Settings now) that we are happy to deliver to all Mozillians.â€&lt;/p&gt;
- &lt;p&gt;Read the full blog &lt;a href=&quot;http://pierros.papadeas.gr/?p=447&quot;&gt;here&lt;/a&gt;!&lt;/p&gt;
- &lt;h3&gt;&lt;b&gt;There are New Ways to Bring Your Design Skills to Mozilla: &lt;/b&gt;&lt;/h3&gt;
- &lt;p&gt;Are you a passionate designer looking to contribute to Mozilla? You’ll be happy to hear there is a new way to contribute to the many design projects around Mozilla! Submit issues, find collaborators, and work on open source projects by getting involved!&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;You can check out the projects looking for help, or submit your own on the &lt;a href=&quot;https://github.com/mozilla/Community-Design/issues&quot;&gt;GitHub Repo&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://docs.google.com/a/mozilla.com/forms/d/1Tw3Mw_CMiqcIQrJF7TB1yIETGYec__NiVhaSz0CAaE8/viewform&quot;&gt;Sign-up to the mailing list&lt;/a&gt; to be added as a contributor to the Repo, added to the regular meeting list, and to get emails about GitHub trainings and more!&lt;/li&gt;
- &lt;li&gt;And read&lt;a href=&quot;http://elioqoshi.me/en/2016/01/mozilla-community-design-kickoff/&quot;&gt; a blogpost&lt;/a&gt; about the project and its first meeting.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;Learn more &lt;a href=&quot;https://discourse.mozilla-community.org/c/community-design&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
- &lt;h3&gt;&lt;b&gt;136 Volunteers Are Going to Singapore: &lt;/b&gt;&lt;/h3&gt;
- &lt;p&gt;This weekend 136 participation leaders from all over the world are&lt;a href=&quot;https://twitter.com/thephoenixbird/status/690181985222926336&quot;&gt; heading to Singapore&lt;/a&gt; to undergo two days of&lt;a href=&quot;https://wiki.mozilla.org/Participation/Global_Gatherings_2015&quot;&gt; leadership training&lt;/a&gt; to develop the skills, knowledge and attitude to lead Participation in 2016.&lt;/p&gt;
- &lt;div class=&quot;wp-caption aligncenter&quot; id=&quot;attachment_2289&quot; style=&quot;width: 609px;&quot;&gt;&lt;a href=&quot;https://blog.mozilla.org/community/files/2016/01/CZQE241WIAA6R2J.jpg&quot;&gt;&lt;img alt=&quot;Photo credit @thephoenixbird on Twitter&quot; class=&quot;wp-image-2289 size-full&quot; height=&quot;337&quot; src=&quot;https://blog.mozilla.org/community/files/2016/01/CZQE241WIAA6R2J.jpg&quot; width=&quot;599&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Photo credit @&lt;a href=&quot;https://twitter.com/thephoenixbird/status/690181985222926336&quot; target=&quot;_blank&quot;&gt;thephoenixbird&lt;/a&gt; on Twitter&lt;/p&gt;&lt;/div&gt;
- &lt;p&gt;If you know someone attending don’t forget to share your questions and goals with them, and follow along over the weekend by watching the hashtag&lt;a href=&quot;https://twitter.com/search?q=%23mozsummit&quot;&gt; #MozSummit&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Stay tuned after the event for a debrief of the weekend!&lt;/p&gt;
- &lt;h3&gt;&lt;b&gt;Friday’s Plenary from Mozlando is now public on Air Mozilla: &lt;/b&gt;&lt;/h3&gt;
- &lt;p&gt;If you’re interested in learning more about all the exciting new features, projects, and plans that were presented at Mozlando look no further! You can now watch the final plenary sessions on Air Mozilla (it’s a lot of fun so I highly recommend it!) &lt;a href=&quot;https://air.mozilla.org/channels/mozlando/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Share your questions and comments on discourse &lt;a href=&quot;https://discourse.mozilla-community.org/t/friday-plenary-from-mozlando-now-public-on-air-mozilla/6659&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;Look forward to more updates like these in the coming months!&lt;/em&gt;&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-21T17:58:33+00:00</dc:date>
- <dc:creator>Lucy Harris</dc:creator>
- </item>
- <item rdf:about="https://blog.mozilla.org/netpolicy/?p=912">
- <title>Mozilla Privacy Blog: Prioritizing privacy: Good for business</title>
- <link>https://blog.mozilla.org/netpolicy/2016/01/21/prioritizing-privacy-good-for-business/</link>
- <content:encoded>&lt;p&gt;&lt;em&gt;This was originally posted at &lt;a href=&quot;http://staysafeonline.org/blog/prioritizing-privacy-good-for-business/&quot;&gt;StaySafeOnline.org&lt;/a&gt; in advance of &lt;a href=&quot;http://www.staysafeonline.org/data-privacy-day/events/&quot;&gt;Data Privacy Day&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;Data Privacy Day – which arrives in just a week – is a day designed to raise awareness and promote best practices for privacy and data protection. It is a day that looks to the future and recognizes that we can and should do better as an industry. It reminds us that we need to focus on the importance of having the trust of our users.&lt;/p&gt;
- &lt;p&gt;We seek to build trust so we can collectively create the Web our users want – the Web we all want.&lt;/p&gt;
- &lt;p&gt;That Web is based on relationships, the same way that the offline world is. When I log in to a social media account, schedule a grocery delivery online or browse the news, I’m relying on those services to respect my data. While companies are innovating their products and services, they need to be innovating on user trust as well, which means designing to address privacy concerns – and making smart choices (early!) about how to manage data.&lt;/p&gt;
- &lt;p&gt;A &lt;a href=&quot;http://www.pewinternet.org/2016/01/14/privacy-and-information-sharing/&quot;&gt;recent survey by Pew&lt;/a&gt; highlights the thought that each user puts into their choices – and the contextual considerations in various scenarios. They concluded that many participants were annoyed and uncertain by how their information was used, and they are choosing not to interact with those services that they don’t trust. This is a clear call to businesses to foster more trust with their users, which starts by making sure that there are people empowered within your company to ask the right questions: what do your users expect? What data do you need to collect? How can you communicate about that data collection? How should you protect their data? Is holding on to data a risk, or should you delete it?&lt;/p&gt;
- &lt;p&gt;It’s crucial that users are a part of this process – consumers’ data is needed to offer cool, new experiences and a user needs to trust you in order to choose to give you their data. Pro-user innovation can’t happen in a vacuum – the system as it stands today isn’t doing a good job of aligning user interests with business incentives. Good user decisions can be good business decisions, but only if we create thoughtful user-centric products in a way that closes the feedback loop so that positive user experiences are rewarded with better business outcomes.&lt;/p&gt;
- &lt;p&gt;Not prioritizing privacy in product decisions will impact the bottom line. From the many data breaches over the last few years to increasing evidence of eroding trust in online services, data practices are proving to be the dark horse in the online economy. When a company loses user trust, whether on privacy or &lt;a href=&quot;https://medium.com/@davidamerland/the-cost-of-losing-trust-97d764a1e696&quot;&gt;anything else&lt;/a&gt;, it loses customers and the potential for growth.&lt;/p&gt;
- &lt;p&gt;Privacy means different things to different people but what’s clear is that people make decisions about the products and services that they use based on how those companies choose to treat their users. Over this time, the Internet ecosystem has evolved, as has its relationship with users – and some aspects of this evolution threaten the trust that lies at the heart of that relationship. Treating a user as a target – whether for an ad, purchase, or service – undermines the trust and relationship that a business may have with a consumer.&lt;/p&gt;
- &lt;p&gt;The solution is not to abandon the massive value that robust data can bring to users, but rather, to collect and use data leanly, productively and transparently. At Mozilla, we have created a strong set of internal data practices to ensure that data decisions align with our &lt;a href=&quot;https://www.mozilla.org/en-US/privacy/principles/&quot;&gt;privacy principles&lt;/a&gt;. As an industry, we need to keep users at the center of the product vision rather than viewing them as targets of the product – it’s the only way to stay true to consumers and deliver the best, most trusted experiences possible.&lt;/p&gt;
- &lt;p&gt;Want to hear more about how businesses can build relationships with their users by focusing on trust and privacy? We’re holding events in Washington, D.C., and &lt;a href=&quot;https://www.eventbrite.com/e/january-privacy-lab-privacy-for-startups-tickets-19849219550?aff=es2&quot;&gt;San Francisco&lt;/a&gt; with some of our partners to talk about it. Please join us!&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-21T17:42:00+00:00</dc:date>
- <dc:creator>Heather West</dc:creator>
- </item>
- <item rdf:about="https://tacticalsecret.com/tag/mozilla/rss/9c39ad13-14ae-4456-a84e-13612637d832">
- <title>J.C. Jones: Issuance Rate for Let's Encrypt</title>
- <link>https://tacticalsecret.com/issuance-rate-for-lets-encrypt/</link>
- <content:encoded>&lt;p&gt;Gathering data from &lt;a href=&quot;https://github.com/jcjones/letsencrypt_statistics&quot;&gt;Certificate Transparency logs&lt;/a&gt;, here's a snapshot in time of Let's Encrypt's certificate issuance rate per minute from 7-21 January 2016. On 20 January, DreamHost launched formal support for Let's Encrypt, which coincides with a rate increase.&lt;/p&gt;
-
- &lt;p&gt;Note: This is mostly an experimental post with embedding charts; I've more data in the queue.&lt;/p&gt;
-
- &lt;h3&gt;Let's Encrypt Issuance Rate per Minute&lt;/h3&gt;
-
- &lt;div id=&quot;rate_hours&quot;&gt;&lt;/div&gt;</content:encoded>
- <dc:date>2016-01-21T17:07:25+00:00</dc:date>
- <dc:creator>James 'J.C.' Jones</dc:creator>
- </item>
- <item rdf:about="https://air.mozilla.org/web-qa-weekly-meeting-20160121/">
- <title>Air Mozilla: Web QA Weekly Meeting, 21 Jan 2016</title>
- <link>https://air.mozilla.org/web-qa-weekly-meeting-20160121/</link>
- <content:encoded>&lt;p&gt;
- &lt;img alt=&quot;Web QA Weekly Meeting&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/f5/13/f5137857516694df0458e837c2d3a4be.png&quot; width=&quot;160&quot; /&gt;
- This is our weekly gathering of Mozilla'a Web QA team filled with discussion on our current and future projects, ideas, demos, and fun facts.
- &lt;/p&gt;</content:encoded>
- <dc:date>2016-01-21T17:00:00+00:00</dc:date>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item rdf:about="http://soledadpenades.com/?p=6379">
- <title>Soledad Penades: No more tap tap tap sounds: yay!</title>
- <link>http://soledadpenades.com/2016/01/21/no-more-tap-tap-tap-sounds-yay/</link>
- <content:encoded>&lt;p&gt;A few days ago the fantastic Fritz from the Netherlands told me that my &lt;a href=&quot;http://soledadpenades.com/files/t/2015_howa/&quot;&gt;Hands On Web Audio slides&lt;/a&gt; had stopping working and there was no sound coming out from them in Firefox.&lt;/p&gt;
- &lt;blockquote class=&quot;twitter-tweet&quot; width=&quot;550&quot;&gt;&lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;&lt;a href=&quot;https://twitter.com/supersole&quot;&gt;@supersole&lt;/a&gt; oh noes! I reopened your slides: &lt;a href=&quot;https://t.co/SO35UfljMI&quot;&gt;https://t.co/SO35UfljMI&lt;/a&gt; and it doesn't work in &lt;a href=&quot;https://twitter.com/firefox&quot;&gt;@firefox&lt;/a&gt; anymore &lt;img alt=&quot;😱&quot; class=&quot;wp-smiley&quot; src=&quot;http://s.w.org/images/core/emoji/72x72/1f631.png&quot; style=&quot;height: 1em;&quot; /&gt; (works in chrome though.. &lt;img alt=&quot;😢&quot; class=&quot;wp-smiley&quot; src=&quot;http://s.w.org/images/core/emoji/72x72/1f622.png&quot; style=&quot;height: 1em;&quot; /&gt;)&lt;/p&gt;
- &lt;p&gt;— Boring Stranger (@fritzvd) &lt;a href=&quot;https://twitter.com/fritzvd/status/686481500611735552&quot;&gt;January 11, 2016&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;&lt;/p&gt;
- &lt;p&gt;Which is pretty disappointing for a slide deck that is built to teach you about Web Audio!&lt;/p&gt;
- &lt;p&gt;I noticed that the issue was only on the introductory slide which uses a modified version of Stuart Memo’s &lt;a href=&quot;https://blog.stuartmemo.com/thx-deep-note-in-javascript/&quot;&gt;fantastic THX sound recreation&lt;/a&gt;-the rest of slides did play sound.&lt;/p&gt;
- &lt;p&gt;I built &lt;a href=&quot;http://sole.github.io/test_cases/web_audio/thx_cutting_out/&quot;&gt;an isolated test case&lt;/a&gt; &lt;small&gt;&lt;a href=&quot;https://github.com/sole/test_cases/tree/gh-pages/web_audio/thx_cutting_out&quot;&gt;(source)&lt;/a&gt;&lt;/small&gt; that used a parameter-capable version of the THX sound code, just in case the issue depended on the number of oscillators, and submitted this funnily titled bug to the Web Audio component: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1240054&quot;&gt;Entirely Web Audio generated sound cuts out after a little while, or emits random tap tap tap sounds then silence&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;I can happily confirm that the bug has been fixed in Nightly and the fix will hopefully be “uplifted†to DevEdition very soon, as it was due to a regression.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://paul.cx/&quot;&gt;Paul Adenot&lt;/a&gt; (who works in Web Audio and is a Web Audio spec editor, amongst a couple tons of other cool things) was really excited about the bug, saying it was very edge-casey! Yay! And he also explained what did actually happen in lay terms: “you’d have to have a frequency that goes down very very slowly so that the FFT code could not keep upâ€, which is what the THX sound is doing with the filter frequency automation.&lt;/p&gt;
- &lt;p&gt;I want to thank both Fritz for spotting this out and letting me know and also Stuart for sharing his THX code. It’s amazing what happens when you put stuff on the net and lots of different people use it in different ways and configurations. Together we make everything more robust &lt;img alt=&quot;:-)&quot; class=&quot;wp-smiley&quot; src=&quot;http://soledadpenades.com/wp-includes/images/smilies/simple-smile.png&quot; style=&quot;height: 1em;&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;Of course also sending thanks to Paul and Ben for identifying and fixing the issue so fast! It’s not been even a week! Woohoo!&lt;/p&gt;
- &lt;p&gt;Well done everyone! &lt;img alt=&quot;ðŸ‘&quot; class=&quot;wp-smiley&quot; src=&quot;http://s.w.org/images/core/emoji/72x72/1f44f.png&quot; style=&quot;height: 1em;&quot; /&gt;&lt;img alt=&quot;ðŸ¼&quot; class=&quot;wp-smiley&quot; src=&quot;http://s.w.org/images/core/emoji/72x72/1f3fc.png&quot; style=&quot;height: 1em;&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://soledadpenades.com/?flattrss_redirect&amp;amp;id=6379&amp;amp;md5=57babe624711830f95e4b8fbd6e52c91&quot; target=&quot;_blank&quot; title=&quot;Flattr&quot;&gt;&lt;img alt=&quot;flattr this!&quot; src=&quot;http://soledadpenades.com/wp-content/plugins/flattr/img/flattr-badge-large.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-21T15:49:05+00:00</dc:date>
- <dc:creator>sole</dc:creator>
- </item>
- <item rdf:about="http://pierros.papadeas.gr/?p=447">
- <title>Pierros Papadeas: Mozillians.org Profile Edit refresh</title>
- <link>http://pierros.papadeas.gr/?p=447</link>
- <content:encoded>&lt;p&gt;Since the start of this year, Participation Infrastructure team has a renewed focus on making mozillians.org a modern community directory to meet Mozilla’s growing needs. This will not be an one-time effort. We need to invest technically and programmatically in order to deliver a first-class product that will be the foundation for identity management across the Mozilla ecosystem.&lt;/p&gt;
- &lt;p&gt;Mozillians.org is full of functionality as it is today, but is paying the debt of being developed by 5 different teams over the past 5 years. We started simple this time. Updated all core technology pieces, did privacy and security reviews, and started the process of consolidating and modernizing many of the things we do in the site.&lt;/p&gt;
- &lt;p&gt;Our first target was Profile Edit. We chose it due to relatively self-contained nature of it, and cause many people were not happy with the current UX. After research of existing tools and applying latest best practices, we designed, coded and deployed a new profile edit interface (which by the way is renamed to Settings now) that we are happy to deliver to all Mozillians.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://pierros.papadeas.gr/wp-content/uploads/2016/01/new-profile.png&quot; rel=&quot;attachment wp-att-448&quot;&gt;&lt;img alt=&quot;new-profile&quot; class=&quot;aligncenter size-large wp-image-448&quot; height=&quot;417&quot; src=&quot;http://pierros.papadeas.gr/wp-content/uploads/2016/01/new-profile-1024x731.png&quot; width=&quot;584&quot; /&gt;&lt;/a&gt;Have a&lt;a href=&quot;https://mozillians.org/en-US/user/edit/&quot;&gt; look for yourself &lt;/a&gt;and don’t miss the chance to update your profile while you do it!&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://mozillians.org/en-US/u/comzeradd/&quot;&gt;Nikos&lt;/a&gt; (on the front-end), &lt;a href=&quot;https://mozillians.org/en-US/u/akatsoulas/&quot;&gt;Tasos&lt;/a&gt; and &lt;a href=&quot;https://mozillians.org/en-US/u/jgiannelos/&quot;&gt;Nemo&lt;/a&gt; (on the back-end) worked hard to deliver this in a speedy manner (as they are used to), and the end result is a testament to what is coming next on Mozillians.org.&lt;/p&gt;
- &lt;p&gt;Our next target? Groups. Currently it is obscure and unclear what all those settings in groups are, what is the functionality and how teams within Mozilla will be using it. We will be tackling this soon. After that, search and stats will be our attention, in an ongoing effort to fortify mozillians.org functionality. Stay tuned, and as always feel free to &lt;a href=&quot;https://bugzilla.mozilla.org/enter_bug.cgi?product=Participation%20Infrastructure&amp;amp;component=Phonebook&quot;&gt;file bugs&lt;/a&gt; and &lt;a href=&quot;https://github.com/mozilla/mozillians&quot;&gt;contribute &lt;/a&gt;in the process.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-21T11:41:39+00:00</dc:date>
- <dc:creator>Pierros Papadeas</dc:creator>
- </item>
- <item rdf:about="http://adamlofting.com/?p=1396">
- <title>Adam Lofting: Blog posts I haven’t written lately</title>
- <link>http://feedproxy.google.com/~r/adamlofting/blog/~3/DoEWpBapwiw/</link>
- <content:encoded>&lt;p&gt;Last year I joked…&lt;/p&gt;
- &lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;
- &lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;Thinking about writing a blog post listing the blog posts I’ve been meaning to write… Maybe that will save some time&lt;/p&gt;
- &lt;p&gt;— Adam Lofting (@adamlofting) &lt;a href=&quot;https://twitter.com/adamlofting/status/667657889817956352&quot;&gt;November 20, 2015&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;&lt;/p&gt;
- &lt;p&gt;Now, it has come to this.&lt;/p&gt;
- &lt;h4&gt;9 blog posts I’ve not been writing&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;Working on working on the impact of impact&lt;/li&gt;
- &lt;li&gt;Designing Games in &lt;a href=&quot;https://en.wikipedia.org/wiki/Amateur&quot; target=&quot;_blank&quot;&gt;my free time&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Moving Out (the board game)&lt;/li&gt;
- &lt;li&gt;Mozilla Foundation 2016 KPIs&lt;/li&gt;
- &lt;li&gt;Studying Network Science&lt;/li&gt;
- &lt;li&gt;Learning Analytics plans for 2016&lt;/li&gt;
- &lt;li&gt;Daily practice / you are what you do every day&lt;/li&gt;
- &lt;li&gt;Several more A/B tests to write up from &lt;a href=&quot;http://fundraising.mozilla.org/&quot;&gt;the fundraising campaign&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;CRM Progress in 2015&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;But my most requested blog by far, is an update on the status of my shed / office that I was tagging on to the end my blog posts at this time last year. Many people at Mozfest wanted to know about the shed… so here it is.&lt;/p&gt;
- &lt;p&gt;This time last year:&lt;/p&gt;
- &lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;
- Starting in the new office today. It will take time to make it *nice* but it works for now. &lt;a href=&quot;http://t.co/sWoC4kFNLc&quot;&gt;pic.twitter.com/sWoC4kFNLc&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;— Adam Lofting (@adamlofting) &lt;a href=&quot;https://twitter.com/adamlofting/status/560361913339899904&quot;&gt;January 28, 2015&lt;/a&gt;
- &lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;&lt;/p&gt;
- &lt;p&gt;Some pictures from this morning:&lt;/p&gt;
- &lt;p&gt;&lt;img alt=&quot;office1&quot; class=&quot;alignright size-large wp-image-1398&quot; height=&quot;282&quot; src=&quot;http://adamlofting.com/wp-content/uploads/2016/01/office1-750x320.jpg&quot; width=&quot;660&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;&lt;img alt=&quot;office2&quot; class=&quot;aligncenter size-large wp-image-1399&quot; height=&quot;237&quot; src=&quot;http://adamlofting.com/wp-content/uploads/2016/01/office2-750x269.jpg&quot; width=&quot;660&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;It’s a pretty nice place to work now and it doubles as useful workshop on the weekends. It needs a few finishing touches, but the law of diminishing returns means those finishing touches are lower priority than work that needs to be done elsewhere in the house and garden. So it’ll stay like this a while longer.&lt;/p&gt;
- &lt;div class=&quot;feedflare&quot;&gt;
- &lt;a href=&quot;http://feeds.feedburner.com/~ff/adamlofting/blog?a=DoEWpBapwiw:VxTJGXwqhlI:yIl2AUoC8zA&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://feeds.feedburner.com/~ff/adamlofting/blog?d=yIl2AUoC8zA&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.feedburner.com/~ff/adamlofting/blog?a=DoEWpBapwiw:VxTJGXwqhlI:qj6IDK7rITs&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://feeds.feedburner.com/~ff/adamlofting/blog?d=qj6IDK7rITs&quot; /&gt;&lt;/a&gt;
- &lt;/div&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; src=&quot;http://feeds.feedburner.com/~r/adamlofting/blog/~4/DoEWpBapwiw&quot; width=&quot;1&quot; /&gt;</content:encoded>
- <dc:date>2016-01-21T09:44:24+00:00</dc:date>
- <dc:creator>Adam</dc:creator>
- </item>
- <item rdf:about="http://blog.ziade.org/2016/01/21/a-pelican-web-editor/">
- <title>Tarek Ziadé: A Pelican web editor</title>
- <link>http://blog.ziade.org/2016/01/21/a-pelican-web-editor/</link>
- <content:encoded>&lt;p&gt;The benefit of being a father again (Freya my 3rd child, was born last week) is
- that while on paternity leave &amp;amp; between two baby bottles, I can hack on fun stuff.&lt;/p&gt;
- &lt;p&gt;A few months ago, I've built for my running club a Pelican-based website, check it out
- at : &lt;a class=&quot;reference external&quot; href=&quot;http://acr-dijon.org&quot;&gt;http://acr-dijon.org&lt;/a&gt;. Nothing's special about it, except that I am not
- the one feeding it. The content is added by people from the club that have zero
- knowledge about softwares, let alone stuff like vim or command line tools.&lt;/p&gt;
- &lt;p&gt;I set up a github-based flow for them, where they add content through the
- github UI and its minimal reStructuredText preview feature - and then a few
- of my crons update the website on the server I host.
- For images and other media, they are uploading them via FTP using FireSSH in Firefox.&lt;/p&gt;
- &lt;p&gt;For the comments, I've switched from Disqus to &lt;a class=&quot;reference external&quot; href=&quot;https://posativ.org/isso/&quot;&gt;ISSO&lt;/a&gt;
- after I got annoyed by the fact that it was impossible to display a simple Disqus
- UI for people to comment without having to log in.&lt;/p&gt;
- &lt;p&gt;I had to make my club friends go through a minimal
- reStructuredText syntax training, and things are more of less working now.&lt;/p&gt;
- &lt;p&gt;The system has a few caveats though:&lt;/p&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;it's dependent on Github. I'd rather have everything hosted on my server.&lt;/li&gt;
- &lt;li&gt;the github restTRucturedText preview will not display syntax errors and warnings
- and very often, articles get broken&lt;/li&gt;
- &lt;li&gt;the resulting reST is ugly, and it's a bit hard to force my editors to be stricter
- about details like empty lines, not using tabs etc.&lt;/li&gt;
- &lt;li&gt;adding folders or organizing articles from Github is a pain&lt;/li&gt;
- &lt;li&gt;editing the metadata tags is prone to many mistakes&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;So I've decided to build my own web editing tool with the following features:&lt;/p&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;resTructuredText cleanup&lt;/li&gt;
- &lt;li&gt;content browsing&lt;/li&gt;
- &lt;li&gt;resTructuredText web editor with live preview that shows warnings &amp;amp; errors&lt;/li&gt;
- &lt;li&gt;a little bit of wsgi glue and a few forms to create articles without
- having to worry about metadata syntax.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;section&quot; id=&quot;restructuredtext-cleanup&quot;&gt;
- &lt;h3&gt;resTructuredText cleanup&lt;/h3&gt;
- &lt;p&gt;The first step was to build a reStructuredText parser that would read some
- reStructuredText and render it back into a cleaner version.&lt;/p&gt;
- &lt;p&gt;We've imported almost 2000 articles in Pelican from the old blog, so I had
- a &lt;strong&gt;lot&lt;/strong&gt; of samples to make my parser work well.&lt;/p&gt;
- &lt;p&gt;I first tried &lt;a class=&quot;reference external&quot; href=&quot;https://github.com/benoitbryon/rst2rst&quot;&gt;rst2rst&lt;/a&gt; but that
- parser was built for a very specific use case (text wrapping) and was
- incomplete. It was not parsing all of the reStructuredText syntax.&lt;/p&gt;
- &lt;p&gt;Inspired by it, I wrote my own little parser using &lt;strong&gt;docutils&lt;/strong&gt;.&lt;/p&gt;
- &lt;p&gt;Understanding docutils is not a small task. This project is very powerfull
- but quite complex. One thing that cruelly misses in docutils parser tools
- is the ability to get the source text from any node, including its children,
- so you can render back the same source.&lt;/p&gt;
- &lt;p&gt;That's roughly what I had to add in my code. It's ugly but it does the job:
- it will parse rst files and render the same content, minus all the extraneous
- empty lines, spaces, tabs etc.&lt;/p&gt;
- &lt;/div&gt;
- &lt;div class=&quot;section&quot; id=&quot;content-browsing&quot;&gt;
- &lt;h3&gt;Content browsing&lt;/h3&gt;
- &lt;p&gt;Content browsing is pretty straightforward: my admin tool let you browse
- the Pelican &lt;em&gt;content&lt;/em&gt; directory and lists all articles, organized by categories.&lt;/p&gt;
- &lt;p&gt;In our case, each category has a top directory in &lt;em&gt;content&lt;/em&gt;. The browser
- parses the articles using my parser and displays paginated lists.&lt;/p&gt;
- &lt;p&gt;I had to add a cache system for the parser, because one of the directory
- contains over 1000 articles -- and browsing was kind of slow :)&lt;/p&gt;
- &lt;img alt=&quot;http://ziade.org/henet-browsing.png&quot; src=&quot;http://ziade.org/henet-browsing.png&quot; /&gt;
- &lt;/div&gt;
- &lt;div class=&quot;section&quot; id=&quot;restructuredtext-web-editor&quot;&gt;
- &lt;h3&gt;resTructuredText web editor&lt;/h3&gt;
- &lt;p&gt;The last big bit was the live editor. I've stumbled on a neat little tool
- called &lt;strong&gt;rsted&lt;/strong&gt;, that provides a live preview of the reStructuredText
- as you are typing it. And it includes warnings !&lt;/p&gt;
- &lt;p&gt;Check it out: &lt;a class=&quot;reference external&quot; href=&quot;http://rst.ninjs.org/&quot;&gt;http://rst.ninjs.org/&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;I've stripped it and kept what I needed, and included it in my app.&lt;/p&gt;
- &lt;img alt=&quot;http://ziade.org/henet.png&quot; src=&quot;http://ziade.org/henet.png&quot; /&gt;
- &lt;p&gt;I am quite happy with the result so far. I need to add real tests and
- a bit of documentation, and I will start to train my club friends on it.&lt;/p&gt;
- &lt;p&gt;The next features I'd like to add are:&lt;/p&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;comments management, to replace Isso (working on it now)&lt;/li&gt;
- &lt;li&gt;smart Pelican builds. e.g. if a comment is added I don't want to rebuild the whole
- blog (~1500 articles)&lt;/li&gt;
- &lt;li&gt;media management&lt;/li&gt;
- &lt;li&gt;spell checker&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;The project lives here: &lt;a class=&quot;reference external&quot; href=&quot;https://github.com/AcrDijon/henet&quot;&gt;https://github.com/AcrDijon/henet&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;I am not going to release it, but if someone finds it useful, I could.&lt;/p&gt;
- &lt;p&gt;It's built with Bottle &amp;amp; Bootstrap as well.&lt;/p&gt;
- &lt;/div&gt;</content:encoded>
- <dc:date>2016-01-21T09:40:00+00:00</dc:date>
- <dc:creator>Tarek Ziade</dc:creator>
- </item>
- <item rdf:about="http://www.ncameron.org/blog/rss/631106eb-e7b1-47d5-82f9-cb6ad210ea89">
- <title>Nick Cameron: Closures and first-class functions</title>
- <link>http://www.ncameron.org/blog/closures-and-first-class-functions/</link>
- <content:encoded>&lt;p&gt;I wrote a long and probably dull chapter on closures and first-class and higher-order functions in Rust. It goes into some detail on the implementation and some of the subtleties like higher-ranked lifetime bounds.&lt;/p&gt;
-
- &lt;p&gt;I was going to post it here too, but it is really too long. Instead, pop over to the 'Rust for C++ programmers' repo and read it &lt;a href=&quot;https://github.com/nrc/r4cppp/blob/master/closures.md&quot;&gt;there&lt;/a&gt;.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-21T08:36:21+00:00</dc:date>
- <dc:creator>Nick Cameron</dc:creator>
- </item>
- <item rdf:about="http://nickdesaulniers.github.io/blog/2016/01/20/debugging-x86-64-assembly-with-lldb-and-dtrace">
- <title>Nick Desaulniers: Intro to Debugging x86-64 Assembly</title>
- <link>http://nickdesaulniers.github.io/blog/2016/01/20/debugging-x86-64-assembly-with-lldb-and-dtrace/</link>
- <content:encoded>&lt;p&gt;I’m hacking on an assembly project, and wanted to document some of the tricks I
- was using for figuring out what was going on. This post might seem a little
- basic for folks who spend all day heads down in gdb or who do this stuff
- professionally, but I just wanted to share a quick intro to some tools that
- others may find useful.
- (&lt;a href=&quot;https://pchiusano.github.io/2014-10-11/defensive-writing.html&quot;&gt;oh god, I’m doing it&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;If your coming from gdb to lldb, there’s a few differences in commands. LLDB
- has
- &lt;a href=&quot;http://lldb.llvm.org/lldb-gdb.html&quot;&gt;great documentation&lt;/a&gt;
- on some of the differences. Everything in this post about LLDB is pretty much
- there.&lt;/p&gt;
-
- &lt;p&gt;The bread and butter commands when working with gdb or lldb are:&lt;/p&gt;
-
- &lt;ul&gt;
- &lt;li&gt;r (run the program)&lt;/li&gt;
- &lt;li&gt;s (step in)&lt;/li&gt;
- &lt;li&gt;n (step over)&lt;/li&gt;
- &lt;li&gt;finish (step out)&lt;/li&gt;
- &lt;li&gt;c (continue)&lt;/li&gt;
- &lt;li&gt;q (quit the program)&lt;/li&gt;
- &lt;/ul&gt;
-
-
- &lt;p&gt;You can hit enter if you want to run the last command again, which is really
- useful if you want to keep stepping over statements repeatedly.&lt;/p&gt;
-
- &lt;p&gt;I’ve been using LLDB on OSX. Let’s say I want to debug a program I can build,
- but is crashing or something:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo lldb ./asmttpd web_root
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Setting a breakpoint on jump to label:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; b sys_write
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Breakpoint 3: &lt;span class=&quot;nv&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;sys_write, &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00000000000029ae
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Running the program until breakpoint hit:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;8&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;9&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;10&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; r
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Process 32236 launched: &lt;span class=&quot;s1&quot;&gt;'./asmttpd'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;x86_64&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Process 32236 stopped
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;* thread &lt;span class=&quot;c&quot;&gt;#1: tid = 0xe69b9, 0x00000000000029ae asmttpd`sys_write, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#0: 0x00000000000029ae asmttpd`sys_write&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;sys_write:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;-&amp;gt; 0x29ae &amp;lt;+0&amp;gt;: pushq %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29af &amp;lt;+1&amp;gt;: pushq %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b0 &amp;lt;+2&amp;gt;: pushq %rdx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b1 &amp;lt;+3&amp;gt;: pushq %r10
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Seeing more of the current stack frame:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;8&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;9&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;10&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;11&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;12&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;13&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;14&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;15&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;16&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;17&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;18&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;19&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;20&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;21&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;22&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;23&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;24&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; d
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;sys_write:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;-&amp;gt; 0x29ae &amp;lt;+0&amp;gt;: pushq %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29af &amp;lt;+1&amp;gt;: pushq %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b0 &amp;lt;+2&amp;gt;: pushq %rdx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b1 &amp;lt;+3&amp;gt;: pushq %r10
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b3 &amp;lt;+5&amp;gt;: pushq %r8
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b5 &amp;lt;+7&amp;gt;: pushq %r9
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b7 &amp;lt;+9&amp;gt;: pushq %rbx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b8 &amp;lt;+10&amp;gt;: pushq %rcx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b9 &amp;lt;+11&amp;gt;: movq %rsi, %rdx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29bc &amp;lt;+14&amp;gt;: movq %rdi, %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29bf &amp;lt;+17&amp;gt;: movq &lt;span class=&quot;nv&quot;&gt;$0x1&lt;/span&gt;, %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29c6 &amp;lt;+24&amp;gt;: movq &lt;span class=&quot;nv&quot;&gt;$0x2000004&lt;/span&gt;, %rax
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29cd &amp;lt;+31&amp;gt;: syscall
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29cf &amp;lt;+33&amp;gt;: popq %rcx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d0 &amp;lt;+34&amp;gt;: popq %rbx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d1 &amp;lt;+35&amp;gt;: popq %r9
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d3 &amp;lt;+37&amp;gt;: popq %r8
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29 &amp;lt;+39&amp;gt;: popq %r10
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d7 &amp;lt;+41&amp;gt;: popq %rdx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d8 &amp;lt;+42&amp;gt;: popq %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d9 &amp;lt;+43&amp;gt;: popq %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29da &amp;lt;+44&amp;gt;: retq
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Getting a back trace (call stack):&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; bt
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;* thread &lt;span class=&quot;c&quot;&gt;#1: tid = 0xe69b9, 0x00000000000029ae asmttpd`sys_write, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; * frame &lt;span class=&quot;c&quot;&gt;#0: 0x00000000000029ae asmttpd`sys_write&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#1: 0x00000000000021b6 asmttpd`print_line + 16&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#2: 0x0000000000002ab3 asmttpd`start + 35&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#3: 0x00007fff9900c5ad libdyld.dylib`start + 1&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#4: 0x00007fff9900c5ad libdyld.dylib`start + 1&lt;/span&gt;
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;peeking at the upper stack frame:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; up
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;frame &lt;span class=&quot;c&quot;&gt;#1: 0x00000000000021b6 asmttpd`print_line + 16&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;print_line:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x21b6 &amp;lt;+16&amp;gt;: movabsq &lt;span class=&quot;nv&quot;&gt;$0x30cb&lt;/span&gt;, %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x21c0 &amp;lt;+26&amp;gt;: movq &lt;span class=&quot;nv&quot;&gt;$0x1&lt;/span&gt;, %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x21c7 &amp;lt;+33&amp;gt;: callq 0x29ae ; sys_write
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x21cc &amp;lt;+38&amp;gt;: popq %rcx
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;back down to the breakpoint-halted stack frame:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; down
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;frame &lt;span class=&quot;c&quot;&gt;#0: 0x00000000000029ae asmttpd`sys_write&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;sys_write:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;-&amp;gt; 0x29ae &amp;lt;+0&amp;gt;: pushq %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29af &amp;lt;+1&amp;gt;: pushq %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b0 &amp;lt;+2&amp;gt;: pushq %rdx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b1 &amp;lt;+3&amp;gt;: pushq %r10
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;dumping the values of registers:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;8&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;9&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;10&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;11&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;12&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;13&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;14&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;15&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;16&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;17&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;18&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;19&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;20&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;21&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;22&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;23&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; register &lt;span class=&quot;nb&quot;&gt;read&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;General Purpose Registers:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000002a90 asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;start
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rbx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rcx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00007fff5fbffaf8
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rdx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00007fff5fbffa40
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rdi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00000000000030cc start_text
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rsi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x000000000000000f
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rbp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00007fff5fbffa18
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rsp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00007fff5fbff9b8
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00007fff7b1670c8 atexit_mutex + 24
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00000000ffffffff
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r11&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0xffffffff00000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r12&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r13&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r14&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r15&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00000000000029ae asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;sys_write
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rflags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000246
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;cs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x000000000000002b
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;fs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;gs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;read just one register:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; register &lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rdi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00000000000030cc start_text
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;When you’re trying to figure out what system calls are made by some C code,
- using dtruss is very helpful. dtruss is available on OSX and seems to be some
- kind of wrapper around DTrace.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;8&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;9&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;10&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;11&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;12&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;13&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;14&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;15&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;16&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cat sleep.c
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;c&quot;&gt;#include &amp;lt;time.h&amp;gt;&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;int main &lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; struct timespec &lt;span class=&quot;nv&quot;&gt;rqtp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 2,
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; nanosleep&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&amp;amp;rqtp, NULL&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;clang sleep.c
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo dtruss ./a.out
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;...all kinds of fun stuff
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;__semwait_signal&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0xB03, 0x0, 0x1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; -1 Err#60
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;If you compile with &lt;code&gt;-g&lt;/code&gt; to emit debug symbols, you can use lldb’s disassemble
- command to get the equivalent assembly:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;8&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;9&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;10&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;11&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;12&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;13&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;14&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;15&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;16&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;17&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;18&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;19&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;20&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;21&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;22&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;23&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;24&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;25&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;26&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;27&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;28&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;29&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;30&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;31&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;32&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;33&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;34&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;35&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;36&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;37&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;clang sleep.c -g
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;lldb a.out
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; target create &lt;span class=&quot;s2&quot;&gt;&quot;a.out&quot;&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Current executable &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;to &lt;span class=&quot;s1&quot;&gt;'a.out'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;x86_64&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; b main
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Breakpoint 1: &lt;span class=&quot;nv&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; a.out&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;main + 16 at sleep.c:3, &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000100000f40
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; r
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Process 33213 launched: &lt;span class=&quot;s1&quot;&gt;'/Users/Nicholas/code/assembly/asmttpd/a.out'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;x86_64&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Process 33213 stopped
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;* thread &lt;span class=&quot;c&quot;&gt;#1: tid = 0xeca04, 0x0000000100000f40 a.out`main + 16 at sleep.c:3, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#0: 0x0000000100000f40 a.out`main + 16 at sleep.c:3&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 1 &lt;span class=&quot;c&quot;&gt;#include &amp;lt;time.h&amp;gt;&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 2 int main &lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;-&amp;gt; 3 struct timespec &lt;span class=&quot;nv&quot;&gt;rqtp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 4 2,
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 5 0
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 6 &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 7
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; disassemble
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;a.out&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;main:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f30 &amp;lt;+0&amp;gt;: pushq %rbp
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f31 &amp;lt;+1&amp;gt;: movq %rsp, %rbp
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f34 &amp;lt;+4&amp;gt;: subq &lt;span class=&quot;nv&quot;&gt;$0x20&lt;/span&gt;, %rsp
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f38 &amp;lt;+8&amp;gt;: leaq -0x10&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rbp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f3c &amp;lt;+12&amp;gt;: xorl %eax, %eax
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f3e &amp;lt;+14&amp;gt;: movl %eax, %esi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;-&amp;gt; 0x100000f40 &amp;lt;+16&amp;gt;: movq 0x49&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rip&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, %rcx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f47 &amp;lt;+23&amp;gt;: movq %rcx, -0x10&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rbp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f4b &amp;lt;+27&amp;gt;: movq 0x46&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rip&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, %rcx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f52 &amp;lt;+34&amp;gt;: movq %rcx, -0x8&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rbp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f56 &amp;lt;+38&amp;gt;: callq 0x100000f68 ; symbol stub &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;: nanosleep
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f5b &amp;lt;+43&amp;gt;: xorl %edx, %edx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f5d &amp;lt;+45&amp;gt;: movl %eax, -0x14&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rbp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f60 &amp;lt;+48&amp;gt;: movl %edx, %eax
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f62 &amp;lt;+50&amp;gt;: addq &lt;span class=&quot;nv&quot;&gt;$0x20&lt;/span&gt;, %rsp
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f66 &amp;lt;+54&amp;gt;: popq %rbp
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f67 &amp;lt;+55&amp;gt;: retq
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Anyways, I’ve been learning some interesting things about OSX that I’ll be
- sharing soon. If you’d like to learn more about x86-64 assembly programming,
- you should read my other posts about
- &lt;a href=&quot;http://nickdesaulniers.github.io/blog/2014/04/18/lets-write-some-x86-64/&quot;&gt;writing x86-64&lt;/a&gt;
- and a toy
- &lt;a href=&quot;http://nickdesaulniers.github.io/blog/2015/05/25/interpreter-compiler-jit/&quot;&gt;JIT for Brainfuck&lt;/a&gt;
- (&lt;a href=&quot;https://www.reddit.com/r/programming/comments/377ov9/interpreter_compiler_jit/crkkrz4&quot;&gt;the creator of Brainfuck liked it&lt;/a&gt;).&lt;/p&gt;
-
- &lt;p&gt;I should also do a post on
- &lt;a href=&quot;http://rr-project.org/&quot;&gt;Mozilla’s rr&lt;/a&gt;,
- because it can do amazing things like step backwards. Another day…&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-21T04:04:00+00:00</dc:date>
- </item>
- <item rdf:about="https://rail.merail.ca/posts/rebooting-productivity.html">
- <title>Rail Aliiev: Rebooting productivity</title>
- <link>https://rail.merail.ca/posts/rebooting-productivity.html</link>
- <content:encoded>&lt;div&gt;&lt;p&gt;Every new year gives you an opportunity to sit back, relax,
- &lt;span class=&quot;strike&quot;&gt;have some scotch&lt;/span&gt; and re-think the passed year. Holidays give
- you enough free time. Even if you decide to not take a vacation around
- the holidays, it's usually calm and peaceful.&lt;/p&gt;
- &lt;p&gt;This time, I found myself thinking mostly about productivity, being
- effective, feeling busy, overwhelmed with work and other related topics.&lt;/p&gt;
- &lt;p&gt;When I started at Mozilla (almost 6 years ago!), I tried to apply all my
- GTD and time management knowledge and techniques. Working remotely and
- in a different time zone was an advantage - I had close to zero
- interruptions. It worked perfect.&lt;/p&gt;
- &lt;p&gt;Last year I realized that my productivity skills had faded away somehow.
- 40h+ workweeks, working on weekends, delivering goals in the last week
- of quarter don't sound like good signs. Instead of being productive I
- felt busy.&lt;/p&gt;
- &lt;p&gt;&quot;Every crisis is an opportunity&quot;. Time to make a step back and reboot
- myself. Burning out at work is not a good idea. :)&lt;/p&gt;
- &lt;p&gt;Here are some ideas/tips that I wrote down for myself you may found
- useful.&lt;/p&gt;
- &lt;div class=&quot;section&quot; id=&quot;health-related&quot;&gt;
- &lt;h3&gt;Health related&lt;/h3&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;Morning exercises. A 20-minute walk will wake your brain up and
- generate enough endorphins for the first half of the day.&lt;/li&gt;
- &lt;li&gt;Meditation. 2x20min a day is ideal; 2x10min would work too. Something
- like &lt;a class=&quot;reference external&quot; href=&quot;http://www.calm.com/&quot;&gt;calm.com&lt;/a&gt; makes this a peace of cake.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;section&quot; id=&quot;concentration&quot;&gt;
- &lt;h3&gt;Concentration&lt;/h3&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;Task #1: make a daily plan. No plan - no work.&lt;/li&gt;
- &lt;li&gt;Don't start your day by reading emails. Get one (little) thing done
- first - THEN check your email.&lt;/li&gt;
- &lt;li&gt;Try to define outcomes, not tasks. &quot;Ship XYZ&quot; instead of &quot;Work on XYZ&quot;.&lt;/li&gt;
- &lt;li&gt;Meetings are time consuming, so &quot;Set a goal for each meeting&quot;.
- Consider skipping a meeting if you don't have any goal set, unless it's a
- beer-and-tell meeting! :)&lt;/li&gt;
- &lt;li&gt;Constantly ask yourself if what you're working on is important.&lt;/li&gt;
- &lt;li&gt;3-4 times a day ask yourself whether you are doing something towards
- your goal or just finding something else to keep you busy. If you want
- to look busy, take your phone and walk around the office with some
- papers in your hand. Everybody will think that you are a busy person!
- This way you can take a break and look busy at the same time!&lt;/li&gt;
- &lt;li&gt;Take breaks! &lt;a class=&quot;reference external&quot; href=&quot;https://en.wikipedia.org/wiki/Pomodoro_Technique&quot;&gt;Pomodoro technique&lt;/a&gt; has this option
- built-in. Taking breaks helps not only to avoid &lt;a class=&quot;reference external&quot; href=&quot;https://en.wikipedia.org/wiki/Repetitive_strain_injury&quot;&gt;RSI&lt;/a&gt;, but also
- keeps your brain sane and gives you time to ask yourself the questions
- mentioned above. I use &lt;a class=&quot;reference external&quot; href=&quot;http://www.workrave.org/&quot;&gt;Workrave&lt;/a&gt; on my
- laptop, but you can use a real kitchen timer instead.&lt;/li&gt;
- &lt;li&gt;Wear headphones, especially at office. Noise cancelling ones are even
- better. White noise, nature sounds, or instrumental music are your
- friends.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;section&quot; id=&quot;home-office&quot;&gt;
- &lt;h3&gt;(Home) Office&lt;/h3&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;Make sure you enjoy your work environment. Why on the earth would you
- spend your valuable time working without joy?!&lt;/li&gt;
- &lt;li&gt;De-clutter and organize your desk. Less things around - less
- distractions.&lt;/li&gt;
- &lt;li&gt;Desk, chair, monitor, keyboard, mouse, etc - don't cheap out on them.
- Your health is more important and expensive. Thanks to &lt;a class=&quot;reference external&quot; href=&quot;https://twitter.com/mhoye&quot;&gt;mhoye&lt;/a&gt; for this advice!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;section&quot; id=&quot;other&quot;&gt;
- &lt;h3&gt;Other&lt;/h3&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;Don't check email every 30 seconds. If there is an emergency, they
- will call you! :)&lt;/li&gt;
- &lt;li&gt;Reward yourself at a certain time. &quot;I'm going to have a chocolate at
- 11am&quot;, or &quot;MFBT at 4pm sharp!&quot; are good examples. Don't forget, you
- are &lt;a class=&quot;reference external&quot; href=&quot;https://en.wikipedia.org/wiki/Classical_conditioning&quot;&gt;Pavlov's dog&lt;/a&gt; too!&lt;/li&gt;
- &lt;li&gt;Don't try to read everything NOW. Save it for later and read in a
- batch.&lt;/li&gt;
- &lt;li&gt;Capture all creative ideas. You can delete them later. ;)&lt;/li&gt;
- &lt;li&gt;Prepare for next task before break. Make sure you know what's next, so
- you can think about it during the break.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;This is my list of things that I try to use everyday. Looking forward to
- see improvements!&lt;/p&gt;
- &lt;p&gt;I would appreciate your thoughts this topic. Feel free to comment or
- send a private email.&lt;/p&gt;
- &lt;p&gt;Happy Productive New Year!&lt;/p&gt;
- &lt;/div&gt;&lt;/div&gt;</content:encoded>
- <dc:date>2016-01-21T02:06:37+00:00</dc:date>
- <dc:creator>Rail Aliiev</dc:creator>
- </item>
- <item rdf:about="http://blog.rust-lang.org/2016/01/21/Rust-1.6.html">
- <title>The Rust Programming Language Blog: Announcing Rust 1.6</title>
- <link>http://blog.rust-lang.org/2016/01/21/Rust-1.6.html</link>
- <content:encoded>&lt;p&gt;Hello 2016! We’re happy to announce the first Rust release of the year, 1.6.
- Rust is a systems programming language focused on safety, speed, and
- concurrency.&lt;/p&gt;
-
- &lt;p&gt;As always, you can &lt;a href=&quot;http://www.rust-lang.org/install.html&quot;&gt;install Rust 1.6&lt;/a&gt; from the appropriate page on our
- website, and check out the &lt;a href=&quot;https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-160-2016-01-21&quot;&gt;detailed release notes for 1.6&lt;/a&gt; on GitHub.
- About 1100 patches were landed in this release.&lt;/p&gt;
-
- &lt;h3 id=&quot;what-39-s-in-1-6-stable&quot;&gt;What’s in 1.6 stable&lt;/h3&gt;
-
- &lt;p&gt;This release contains a number of small refinements, one major feature, and
- a change to &lt;a href=&quot;https://crates.io&quot;&gt;Crates.io&lt;/a&gt;.&lt;/p&gt;
-
- &lt;h4 id=&quot;libcore-stabilization&quot;&gt;libcore stabilization&lt;/h4&gt;
-
- &lt;p&gt;The largest new feature in 1.6 is that &lt;a href=&quot;http://doc.rust-lang.org/nightly/core/&quot;&gt;&lt;code&gt;libcore&lt;/code&gt;&lt;/a&gt; is now stable! Rust’s
- standard library is two-tiered: there’s a small core library, &lt;code&gt;libcore&lt;/code&gt;, and
- the full standard library, &lt;code&gt;libstd&lt;/code&gt;, that builds on top of it. &lt;code&gt;libcore&lt;/code&gt; is
- completely platform agnostic, and requires only a handful of external symbols
- to be defined. Rust’s &lt;code&gt;libstd&lt;/code&gt; builds on top of &lt;code&gt;libcore&lt;/code&gt;, adding support for
- memory allocation, I/O, and concurrency. Applications using Rust in the
- embedded space, as well as those writing operating systems, often eschew
- &lt;code&gt;libstd&lt;/code&gt;, using only &lt;code&gt;libcore&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;libcore&lt;/code&gt; being stabilized is a major step towards being able to write the
- lowest levels of software using stable Rust. There’s still future work to be
- done, however. This will allow for a library ecosystem to develop around
- &lt;code&gt;libcore&lt;/code&gt;, but &lt;em&gt;applications&lt;/em&gt; are not fully supported yet. Expect to hear more
- about this in future release notes.&lt;/p&gt;
-
- &lt;h4 id=&quot;library-stabilizations&quot;&gt;Library stabilizations&lt;/h4&gt;
-
- &lt;p&gt;About 30 library functions and methods are now stable in 1.6. Notable
- improvements include:&lt;/p&gt;
-
- &lt;p&gt;The &lt;code&gt;drain()&lt;/code&gt; family of functions on collections. These methods let you move
- elements out of a collection while allowing them to retain their backing
- memory, reducing allocation in certain situations.&lt;/p&gt;
-
- &lt;p&gt;A number of implementations of &lt;code&gt;From&lt;/code&gt; for converting between standard library
- types, mainly between various integral and floating-point types.&lt;/p&gt;
-
- &lt;p&gt;Finally, &lt;code&gt;Vec::extend_from_slice()&lt;/code&gt;, which was previously known as
- &lt;code&gt;push_all()&lt;/code&gt;. This method has a significantly faster implementation than the
- more general &lt;code&gt;extend()&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;See the &lt;a href=&quot;https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-160-2016-01-21&quot;&gt;detailed release notes&lt;/a&gt; for more.&lt;/p&gt;
-
- &lt;h4 id=&quot;crates-io-disallows-wildcards&quot;&gt;Crates.io disallows wildcards&lt;/h4&gt;
-
- &lt;p&gt;If you maintain a crate on &lt;a href=&quot;https://crates.io&quot;&gt;Crates.io&lt;/a&gt;, you might have seen
- a warning: newly uploaded crates are no longer allowed to use a wildcard when
- describing their dependencies. In other words, this is not allowed:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt;
- &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
- &lt;p&gt;Instead, you must actually specify &lt;a href=&quot;http://doc.crates.io/crates-io.html#using-cratesio-based-crates&quot;&gt;a specific version or range of
- versions&lt;/a&gt;, using one of the &lt;code&gt;semver&lt;/code&gt; crate’s various options: &lt;code&gt;^&lt;/code&gt;,
- &lt;code&gt;~&lt;/code&gt;, or &lt;code&gt;=&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;A wildcard dependency means that you work with any possible version of your
- dependency. This is highly unlikely to be true, and causes unnecessary breakage
- in the ecosystem. We’ve been advertising this change as a warning for some time;
- now it’s time to turn it into an error.&lt;/p&gt;
-
- &lt;h3 id=&quot;contributors-to-1-6&quot;&gt;Contributors to 1.6&lt;/h3&gt;
-
- &lt;p&gt;We had 132 individuals contribute to 1.6. Thank you so much!&lt;/p&gt;
-
- &lt;ul&gt;
- &lt;li&gt;Aaron Turon&lt;/li&gt;
- &lt;li&gt;Adam Badawy&lt;/li&gt;
- &lt;li&gt;Aleksey Kladov&lt;/li&gt;
- &lt;li&gt;Alexander Bulaev&lt;/li&gt;
- &lt;li&gt;Alex Burka&lt;/li&gt;
- &lt;li&gt;Alex Crichton&lt;/li&gt;
- &lt;li&gt;Alex Gaynor&lt;/li&gt;
- &lt;li&gt;Alexis Beingessner&lt;/li&gt;
- &lt;li&gt;Amanieu d'Antras&lt;/li&gt;
- &lt;li&gt;Amit Saha&lt;/li&gt;
- &lt;li&gt;Andrea Canciani&lt;/li&gt;
- &lt;li&gt;Andrew Paseltiner&lt;/li&gt;
- &lt;li&gt;androm3da&lt;/li&gt;
- &lt;li&gt;angelsl&lt;/li&gt;
- &lt;li&gt;Angus Lees&lt;/li&gt;
- &lt;li&gt;Antti Keränen&lt;/li&gt;
- &lt;li&gt;arcnmx&lt;/li&gt;
- &lt;li&gt;Ariel Ben-Yehuda&lt;/li&gt;
- &lt;li&gt;Ashkan Kiani&lt;/li&gt;
- &lt;li&gt;Barosl Lee&lt;/li&gt;
- &lt;li&gt;Benjamin Herr&lt;/li&gt;
- &lt;li&gt;Ben Striegel&lt;/li&gt;
- &lt;li&gt;Bhargav Patel&lt;/li&gt;
- &lt;li&gt;Björn Steinbrink&lt;/li&gt;
- &lt;li&gt;Boris Egorov&lt;/li&gt;
- &lt;li&gt;bors&lt;/li&gt;
- &lt;li&gt;Brian Anderson&lt;/li&gt;
- &lt;li&gt;Bruno Tavares&lt;/li&gt;
- &lt;li&gt;Bryce Van Dyk&lt;/li&gt;
- &lt;li&gt;Cameron Sun&lt;/li&gt;
- &lt;li&gt;Christopher Sumnicht&lt;/li&gt;
- &lt;li&gt;Cole Reynolds&lt;/li&gt;
- &lt;li&gt;corentih&lt;/li&gt;
- &lt;li&gt;Daniel Campbell&lt;/li&gt;
- &lt;li&gt;Daniel Keep&lt;/li&gt;
- &lt;li&gt;Daniel Rollins&lt;/li&gt;
- &lt;li&gt;Daniel Trebbien&lt;/li&gt;
- &lt;li&gt;Danilo Bargen&lt;/li&gt;
- &lt;li&gt;Devon Hollowood&lt;/li&gt;
- &lt;li&gt;Doug Goldstein&lt;/li&gt;
- &lt;li&gt;Dylan McKay&lt;/li&gt;
- &lt;li&gt;ebadf&lt;/li&gt;
- &lt;li&gt;Eli Friedman&lt;/li&gt;
- &lt;li&gt;Eric Findlay&lt;/li&gt;
- &lt;li&gt;Erik Davidson&lt;/li&gt;
- &lt;li&gt;Felix S. Klock II&lt;/li&gt;
- &lt;li&gt;Florian Hahn&lt;/li&gt;
- &lt;li&gt;Florian Hartwig&lt;/li&gt;
- &lt;li&gt;Gleb Kozyrev&lt;/li&gt;
- &lt;li&gt;Guillaume Gomez&lt;/li&gt;
- &lt;li&gt;Huon Wilson&lt;/li&gt;
- &lt;li&gt;Igor Shuvalov&lt;/li&gt;
- &lt;li&gt;Ivan Ivaschenko&lt;/li&gt;
- &lt;li&gt;Ivan Kozik&lt;/li&gt;
- &lt;li&gt;Ivan Stankovic&lt;/li&gt;
- &lt;li&gt;Jack Fransham&lt;/li&gt;
- &lt;li&gt;Jake Goulding&lt;/li&gt;
- &lt;li&gt;Jake Worth&lt;/li&gt;
- &lt;li&gt;James Miller&lt;/li&gt;
- &lt;li&gt;Jan Likar&lt;/li&gt;
- &lt;li&gt;Jean Maillard&lt;/li&gt;
- &lt;li&gt;Jeffrey Seyfried&lt;/li&gt;
- &lt;li&gt;Jethro Beekman&lt;/li&gt;
- &lt;li&gt;John KÃ¥re Alsaker&lt;/li&gt;
- &lt;li&gt;John Talling&lt;/li&gt;
- &lt;li&gt;Jonas Schievink&lt;/li&gt;
- &lt;li&gt;Jonathan S&lt;/li&gt;
- &lt;li&gt;Jose Narvaez&lt;/li&gt;
- &lt;li&gt;Josh Austin&lt;/li&gt;
- &lt;li&gt;Josh Stone&lt;/li&gt;
- &lt;li&gt;Joshua Holmer&lt;/li&gt;
- &lt;li&gt;JP Sugarbroad&lt;/li&gt;
- &lt;li&gt;jrburke&lt;/li&gt;
- &lt;li&gt;Kevin Butler&lt;/li&gt;
- &lt;li&gt;Kevin Yeh&lt;/li&gt;
- &lt;li&gt;Kohei Hasegawa&lt;/li&gt;
- &lt;li&gt;Kyle Mayes&lt;/li&gt;
- &lt;li&gt;Lee Jeffery&lt;/li&gt;
- &lt;li&gt;Manish Goregaokar&lt;/li&gt;
- &lt;li&gt;Marcell Pardavi&lt;/li&gt;
- &lt;li&gt;Markus Unterwaditzer&lt;/li&gt;
- &lt;li&gt;Martin Pool&lt;/li&gt;
- &lt;li&gt;Marvin Löbel&lt;/li&gt;
- &lt;li&gt;Matt Brubeck&lt;/li&gt;
- &lt;li&gt;Matthias Bussonnier&lt;/li&gt;
- &lt;li&gt;Matthias Kauer&lt;/li&gt;
- &lt;li&gt;mdinger&lt;/li&gt;
- &lt;li&gt;Michael Layzell&lt;/li&gt;
- &lt;li&gt;Michael Neumann&lt;/li&gt;
- &lt;li&gt;Michael Sproul&lt;/li&gt;
- &lt;li&gt;Michael Woerister&lt;/li&gt;
- &lt;li&gt;Mihaly Barasz&lt;/li&gt;
- &lt;li&gt;Mika Attila&lt;/li&gt;
- &lt;li&gt;mitaa&lt;/li&gt;
- &lt;li&gt;Ms2ger&lt;/li&gt;
- &lt;li&gt;Nicholas Mazzuca&lt;/li&gt;
- &lt;li&gt;Nick Cameron&lt;/li&gt;
- &lt;li&gt;Niko Matsakis&lt;/li&gt;
- &lt;li&gt;Ole Krüger&lt;/li&gt;
- &lt;li&gt;Oliver Middleton&lt;/li&gt;
- &lt;li&gt;Oliver Schneider&lt;/li&gt;
- &lt;li&gt;Ori Avtalion&lt;/li&gt;
- &lt;li&gt;Paul A. Jungwirth&lt;/li&gt;
- &lt;li&gt;Peter Atashian&lt;/li&gt;
- &lt;li&gt;Philipp Matthias Schäfer&lt;/li&gt;
- &lt;li&gt;pierzchalski&lt;/li&gt;
- &lt;li&gt;Ravi Shankar&lt;/li&gt;
- &lt;li&gt;Ricardo Martins&lt;/li&gt;
- &lt;li&gt;Ricardo Signes&lt;/li&gt;
- &lt;li&gt;Richard Diamond&lt;/li&gt;
- &lt;li&gt;Rizky Luthfianto&lt;/li&gt;
- &lt;li&gt;Ryan Scheel&lt;/li&gt;
- &lt;li&gt;Scott Olson&lt;/li&gt;
- &lt;li&gt;Sean Griffin&lt;/li&gt;
- &lt;li&gt;Sebastian Hahn&lt;/li&gt;
- &lt;li&gt;Sébastien Marie&lt;/li&gt;
- &lt;li&gt;Seo Sanghyeon&lt;/li&gt;
- &lt;li&gt;Simonas Kazlauskas&lt;/li&gt;
- &lt;li&gt;Simon Sapin&lt;/li&gt;
- &lt;li&gt;Stepan Koltsov&lt;/li&gt;
- &lt;li&gt;Steve Klabnik&lt;/li&gt;
- &lt;li&gt;Steven Fackler&lt;/li&gt;
- &lt;li&gt;Tamir Duberstein&lt;/li&gt;
- &lt;li&gt;Tobias Bucher&lt;/li&gt;
- &lt;li&gt;Toby Scrace&lt;/li&gt;
- &lt;li&gt;Tshepang Lekhonkhobe&lt;/li&gt;
- &lt;li&gt;Ulrik Sverdrup&lt;/li&gt;
- &lt;li&gt;Vadim Chugunov&lt;/li&gt;
- &lt;li&gt;Vadim Petrochenkov&lt;/li&gt;
- &lt;li&gt;William Throwe&lt;/li&gt;
- &lt;li&gt;xd1le&lt;/li&gt;
- &lt;li&gt;Xmasreturns&lt;/li&gt;
- &lt;/ul&gt;</content:encoded>
- <dc:date>2016-01-21T00:00:00+00:00</dc:date>
- </item>
- <item rdf:about="http://blog.mozilla.org/addons/?p=7644">
- <title>Mozilla Addons Blog: Archiving AMO Stats</title>
- <link>https://blog.mozilla.org/addons/2016/01/20/archiving-amo-stats/</link>
- <content:encoded>&lt;p&gt;One of the advantages of listing an add-on or theme on &lt;a href=&quot;https://addons.mozilla.org&quot; target=&quot;_blank&quot;&gt;addons.mozilla.org&lt;/a&gt; (AMO) is that you’ll get statistics on your add-on’s usage. These stats, which are covered by the &lt;a href=&quot;https://www.mozilla.org/privacy/&quot; target=&quot;_blank&quot;&gt;Mozilla privacy policy&lt;/a&gt;, provide add-on developers with information such as the number of downloads and daily users, among other insights.&lt;/p&gt;
- &lt;p&gt;Currently, the data that generates these statistics can go back as far as 2007, as we haven’t had an archiving policy. As a result, statistics take up the vast majority of disk space in our database and require a significant amount of processing and operations time. Statistics over a year old are very rarely accessed, and the value of their generation is very low, while the costs are increasing.&lt;/p&gt;
- &lt;p&gt;To reduce our operating and development costs, and increase the site’s reliability for developers, we are introducing an archiving policy.&lt;/p&gt;
- &lt;p&gt;In the coming weeks, statistics data &lt;strong&gt;over one year old&lt;/strong&gt; will no longer be stored in the AMO database, and reports generated from them will no longer be accessible through AMO’s add-on statistics pages. Instead, the data will be archived and maintained as plain text files, which developers can download. We will write a follow-up post when these archives become available.&lt;/p&gt;
- &lt;p&gt;If you’ve chosen to keep your add-on’s statistics private, they will remain private when stats are archived. You can check your privacy settings by going to your add-on in the &lt;a href=&quot;https://addons.mozilla.org/developers/addons&quot; target=&quot;_blank&quot;&gt;Developer Hub&lt;/a&gt;, clicking on &lt;strong&gt;Edit Listing&lt;/strong&gt;, and then &lt;strong&gt;Technical Details&lt;/strong&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://blog.mozilla.org/addons/files/2016/01/Screenshot-2016-01-20-14.52.33.png&quot;&gt;&lt;img alt=&quot;editlisting&quot; class=&quot;alignnone size-large wp-image-7645&quot; height=&quot;389&quot; src=&quot;https://blog.mozilla.org/addons/files/2016/01/Screenshot-2016-01-20-14.52.33-600x389.png&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;The total number of users and other cumulative counts on add-ons and themes will not be affected and these will continue to function.&lt;/p&gt;
- &lt;p&gt;If you have feedback or concerns, please head to our &lt;a href=&quot;https://discourse.mozilla-community.org/t/archiving-of-add-on-statistics/6573&quot; target=&quot;_blank&quot;&gt;forum post&lt;/a&gt; on this topic.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-20T23:54:09+00:00</dc:date>
- <dc:creator>Andy McKay</dc:creator>
- </item>
- <item rdf:about="https://air.mozilla.org/the-joy-of-coding-episode-41/">
- <title>Air Mozilla: The Joy of Coding - Episode 41</title>
- <link>https://air.mozilla.org/the-joy-of-coding-episode-41/</link>
- <content:encoded>&lt;p&gt;
- &lt;img alt=&quot;The Joy of Coding - Episode 41&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/cb/68/cb68b6ac48452be7e7f25ddc7b63c959.png&quot; width=&quot;160&quot; /&gt;
- mconley livehacks on real Firefox bugs while thinking aloud.
- &lt;/p&gt;</content:encoded>
- <dc:date>2016-01-20T18:00:00+00:00</dc:date>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item rdf:about="http://blog.mozilla.org/nfroyd/?p=452">
- <title>Nathan Froyd: gecko and c++ onboarding presentation</title>
- <link>https://blog.mozilla.org/nfroyd/2016/01/20/gecko-and-c-onboarding-presentation/</link>
- <content:encoded>&lt;p&gt;One of the things the Firefox team has been doing recently is having onboarding sessions for new hires. This onboarding currently covers:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;1st day setup&lt;/li&gt;
- &lt;li&gt;Bugzilla&lt;/li&gt;
- &lt;li&gt;Building Firefox&lt;/li&gt;
- &lt;li&gt;Desktop Firefox Architecture / Product&lt;/li&gt;
- &lt;li&gt;Communication and Community&lt;/li&gt;
- &lt;li&gt;Javascript and the DOM&lt;/li&gt;
- &lt;li&gt;C++ and Gecko&lt;/li&gt;
- &lt;li&gt;Shipping Software&lt;/li&gt;
- &lt;li&gt;Telemetry&lt;/li&gt;
- &lt;li&gt;Org structure and career development&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;My first day consisted of some useful HR presentations and then I was given my laptop and a pointer to a wiki page on building Firefox. Needless to say, it took me a while to get started! It would have been super convenient to have an introduction to all the stuff above.&lt;/p&gt;
- &lt;p&gt;I’ve been asked to do the C++ and Gecko session three times. All of the sessions are open to whoever wants to come, not just the new hires, and I think yesterday’s session was easily the most well-attended yet: somewhere between 10 and 20 people showed up. Yesterday’s session was the first session where I made the slides available to attendees (should have been doing that from the start…) and it seemed equally useful to make the slides available to a broader audience as well. The &lt;a href=&quot;https://docs.google.com/presentation/d/1ZHUkNzZK2TrF5_4MWd_lqEq7Ph5B6CDbNsizIkBxbnQ/edit?usp=sharing&quot;&gt;Gecko and C++ Onboarding slides&lt;/a&gt; are up now!&lt;/p&gt;
- &lt;p&gt;This presentation is a “living†presentation; it will get updated for future sessions with feedback and as I think of things that should have been in the presentation or better ways to set things up (some diagrams would be nice…). If you have feedback (good, bad, or ugly) on particular things in the slides or you have suggestions on what other things should be covered, please contact me! Next time I do this I’ll try to record the presentation so folks can watch that if they prefer.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-20T16:48:29+00:00</dc:date>
- <dc:creator>Nathan Froyd</dc:creator>
- </item>
- <item rdf:about="http://andreasgal.com/?p=573">
- <title>Andreas Gal: Brendan is back to save the Web</title>
- <link>http://andreasgal.com/2016/01/20/brendan-is-back-to-save-the-web/</link>
- <content:encoded>&lt;p class=&quot;p1&quot;&gt;Brendan is &lt;a href=&quot;https://github.com/brave&quot;&gt;back&lt;/a&gt;, and he has a &lt;a href=&quot;http://brave.com/&quot;&gt;plan&lt;/a&gt; to save the Web. Its a big and bold plan, and it may just work. I am pretty excited about this. If you have 5 minutes to read along I’ll explain why I think you should be as well.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;The Web is broken&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;Lets face it, the Web today is a mess. Everywhere we go online we are constantly inundated with annoying ads. Often pages are more ads than content, and the more ads the industry throws at us, the more we ignore them, the more obnoxious ads get, trying to catch our attention. As Brendan explains in his blog post, the browser used to be on the user’s side—we call browsers the user agent for a reason. Part of the early success of Firefox was that it blocked popup ads. But somewhere over the last 10 years of modern Web browsers, browsers lost their way and stopped being the user’s agent alone. Why?&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;Browsers aren’t free&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;Making a modern Web browser is not free. It takes hundreds of engineers to make a competitive modern browser engine. Someone has to pay for that, and that someone needs to have a reason to pay for it. Google doesn’t make Chrome for the good of mankind. Google makes Chrome so you can consume more Web and along with it, more Google ads. Each time you click on one, Google makes more money. Chrome is a billion dollar business for Google. And the same is true for pretty much every other browser. Every major browser out there is funded through advertisement. No browser maker can escape this dilemma. Maybe now you understand why no major browser ships with a builtin enabled by default ad-blocker, even though ad-blockers are by far the most popular add-ons.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;Our privacy is at stake&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;It’s not just the unregulated flood of advertisement that needs a solution. Every ad you see is often selected based on sensitive private information advertisement networks have extracted from your browsing behavior through tracking. Remember how the FBI used to track what books Americans read at the library, and it was a big scandal? Today the Googles and Facebooks of the world know almost every site you visit, everything you buy online, and they use this data to target you with advertisement. I am often puzzled why people are so afraid of the NSA spying on us but show so little concern about all the deeply personal data Google and Facebook are amassing about everyone.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;Blocking alone doesn’t scale&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;I wish the solution was as easy as just blocking all ads. There is a lot of great Web content out there: news, entertainment, educational content. It’s not free to make all this content, but we have gotten used to consuming it “for freeâ€. Banning all ads without an alternative mechanism would break the economic backbone of the Web. This dilemma has existed for many years, and the big browser vendors seem to have given up on it. It’s hard to blame them. How do you disrupt the status quo without sawing off the (ad revenue) branch you are sitting on?&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;It takes an newcomer to fix this mess&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;I think its unlikely that the incumbent browser vendors will make any bold moves to solve this mess. There is too much money at stake. I am excited to see a startup take a swipe at this problem, because they have little to lose (seed money aside). Brave is getting the user agent back into the game. Browsers have intentionally remained silent onlookers to the ad industry invading users’ privacy. With Brave, Brendan makes the user agent step up and fight for the user as it was always intended to do.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;Brave basically consists of two parts: part one blocks third party ad content and tracking signals. Instead of these Brave inserts alternative ad content. Sites can sign up to get a fair share of any ads that Brave displays for them. The big change in comparison to the status quo is that the Brave user agent is in control and can regulate what you see. It’s like a speed limit for advertisement on the Web, with the goal to restore balance and give sites a fair way to monetize while giving the user control through the user agent.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;Making money with a better Web&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;The ironic part of Brave is that its for-profit. Brave can make money by reducing obnoxious ads and protecting your privacy at the same time. If Brave succeeds, it’s going to drain money away from the crappy privacy-invasive obnoxious advertisement world we have today, and publishers and sites will start transacting in the new Brave world that is regulated by the user agent. Brave will take a cut of these transactions. And I think this is key. It aligns the incentives right. The current funding structure of major browsers encourages them to keep things as they are. Brave’s incentive is to bring down the whole diseased temple and usher in a better Web. Exciting.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;Quick update:&lt;/strong&gt; I had a chance to look over the Brave GitHub repo. It looks like the Brave Desktop browser is based on Chromium, not Gecko. Yes, you read that right. &lt;span style=&quot;text-decoration: underline;&quot;&gt;Brave is using Google’s rendering engine, not Mozilla’s.&lt;/span&gt; Much to write about this one, but it will definitely help Brave “hide†better in the large volume of Chrome users, making it harder for sites to identify and block Brave users. Brave for iOS seems to be a &lt;span style=&quot;text-decoration: underline;&quot;&gt;fork of Firefox for iOS, but it manages to block ads&lt;/span&gt; (Mozilla says they can’t).&lt;/p&gt;&lt;br /&gt;Filed under: &lt;a href=&quot;http://andreasgal.com/category/mozilla/&quot;&gt;Mozilla&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gocomments/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/godelicious/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/delicious/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gofacebook/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/facebook/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gotwitter/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/twitter/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gostumble/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/stumble/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/godigg/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/digg/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/goreddit/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/reddit/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;http://pixel.wp.com/b.gif?host=andreasgal.com&amp;amp;blog=891661&amp;amp;post=573&amp;amp;subd=andreasgal&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</content:encoded>
- <dc:date>2016-01-20T16:00:00+00:00</dc:date>
- <dc:creator>Andreas</dc:creator>
- </item>
- <item rdf:about="https://miketaylr.com/posts/2016/01/at-media-webkit-transform-three-dee.html">
- <title>Mike Taylor: 🙅 @media (-webkit-transform-3d)</title>
- <link>https://miketaylr.com/posts/2016/01/at-media-webkit-transform-three-dee.html</link>
- <content:encoded>&lt;p&gt;&lt;code&gt;@media (-webkit-transform-3d)&lt;/code&gt; is a funny thing that exists on the web.&lt;/p&gt;
-
- &lt;p&gt;It's like, a &lt;a href=&quot;https://drafts.csswg.org/mediaqueries-4/#mq-features&quot;&gt;media query feature&lt;/a&gt; in the form of a prefixed CSS property, which should tell you if your (once upon a time probably Safari-only) browser supports 3D transforms, invented back in the day before we had &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@supports&quot;&gt;&lt;code&gt;@supports&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
-
- &lt;p&gt;(According to &lt;a href=&quot;https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariCSSRef/Articles/OtherStandardCSS3Features.html#//apple_ref/doc/uid/TP40007601-SW3&quot;&gt;Apple docs&lt;/a&gt; it first appeared in Safari 4, along side the other &lt;code&gt;-webkit-transition&lt;/code&gt; and &lt;code&gt;-webkit-transform-2d&lt;/code&gt; hybrid-media-query-feature-prefixed-css-properties-things that you should immediately forget exist.)&lt;/p&gt;
-
- &lt;p&gt;Older versions of Modernizr &lt;a href=&quot;https://github.com/Modernizr/Modernizr/blob/66c694d136241d356e0d24fcbaa5c068b0b0cdae/feature-detects/css/transforms3d.js#L26-L27&quot;&gt;used this (and only this)&lt;/a&gt; to detect support for 3D transforms, and that seemed pretty OK. (They also did the polite thing and tested &lt;code&gt;@media (transform-3d)&lt;/code&gt;, but no browser has ever actually supported that, as it turns out). And because they're so consistently polite, they've since &lt;a href=&quot;https://github.com/patrickkettner/Modernizr/commit/a54308e47e269a058472854b1ef417bd54f4e616&quot;&gt;updated the test&lt;/a&gt; to prefer &lt;code&gt;@supports&lt;/code&gt; too (via a pull request from Edge developer Jacob Rossi).&lt;/p&gt;
-
- &lt;p&gt;As it turns out other browsers have been &lt;a href=&quot;http://caniuse.com/#feat=transforms3d&quot;&gt;updated to support 3D CSS transforms&lt;/a&gt;, but sites didn't go back and update their version of Modernizr. So unless you support &lt;code&gt;@media (-webkit-transform-3d)&lt;/code&gt; these sites break. Niche websites like &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1239136&quot;&gt;yahoo.com&lt;/a&gt; and &lt;a href=&quot;https://github.com/webcompat/web-bugs/issues/2151&quot;&gt;about.com&lt;/a&gt;.&lt;/p&gt;
-
- &lt;p&gt;So, anyways. I added &lt;a href=&quot;https://compat.spec.whatwg.org/#css-media-queries-webkit-transform-3d&quot;&gt;&lt;code&gt;@media (-webkit-transform-3d)&lt;/code&gt; to the Compat Standard&lt;/a&gt; and we &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1239799&quot;&gt;added support for it Firefox&lt;/a&gt; so websites stop breaking.&lt;/p&gt;
-
- &lt;p&gt;But you shouldn't ever use it—use &lt;code&gt;@supports&lt;/code&gt;. In fact, don't even share this blog post. Maybe delete it from your browser history just in case.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-20T08:00:00+00:00</dc:date>
- <dc:creator>Mike Taylor</dc:creator>
- </item>
- <item rdf:about="http://globau.wordpress.com/?p=881">
- <title>Byron Jones: happy bmo push day!</title>
- <link>https://globau.wordpress.com/2016/01/20/happy-bmo-push-day-166/</link>
- <content:encoded>&lt;p&gt;the following changes have been pushed to bugzilla.mozilla.org:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1236161&quot; target=&quot;_blank&quot;&gt;1236161&lt;/a&gt;] when converting a BMP attachment to PNG fails a zero byte attachment is created&lt;/li&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1231918&quot; target=&quot;_blank&quot;&gt;1231918&lt;/a&gt;] error handler doesn’t close multi-part responses&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;discuss these changes on &lt;a href=&quot;https://lists.mozilla.org/listinfo/tools-bmo&quot; target=&quot;_blank&quot;&gt;mozilla.tools.bmo&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;Filed under: &lt;a href=&quot;https://globau.wordpress.com/category/mozilla/bmo/&quot;&gt;bmo&lt;/a&gt;, &lt;a href=&quot;https://globau.wordpress.com/category/mozilla/&quot;&gt;mozilla&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;https://pixel.wp.com/b.gif?host=globau.wordpress.com&amp;amp;blog=25718030&amp;amp;post=881&amp;amp;subd=globau&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</content:encoded>
- <dc:date>2016-01-20T07:33:46+00:00</dc:date>
- <dc:creator>glob</dc:creator>
- </item>
- <item rdf:about="https://www.alex-johnson.net/tag/mozilla/rss/85d84c54-ed0c-4ee5-beb3-8823edb3c074">
- <title>Alex Johnson: Removing Honeycomb Code</title>
- <link>https://www.alex-johnson.net/removing-honeycomb-code/</link>
- <content:encoded>&lt;p&gt;As an effort to reduce the APK size of Firefox for Android and to remove unnecessary code, I will be helping remove the Honeycomb code throughout the Fennec project. Honeycomb will not be supported since Firefox 46, so this code is not necessary. &lt;br /&gt;
- &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1217675&quot;&gt;Bug 1217675&lt;/a&gt; will keep track of the progress. &lt;br /&gt;
- Hopefully this will help reduce the APK size some and clean up the road for &lt;a href=&quot;https://www.youtube.com/watch?v=NJ6kzW5t02Y&quot;&gt;killing Gingerbread&lt;/a&gt; hopefully sometime in the near future.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-20T04:59:34+00:00</dc:date>
- <dc:creator>Alex Johnson</dc:creator>
- </item>
- <item rdf:about="http://www.brianbondy.com/blog/id/172">
- <title>Brian R. Bondy: Brave Software</title>
- <link>http://www.brianbondy.com/blog/172/brave-software</link>
- <content:encoded>&lt;p&gt;&lt;/p&gt;&lt;p&gt;Since June of last year, I’ve been co-founding a new startup called &lt;a href=&quot;https://brave.com/&quot;&gt;Brave Software&lt;/a&gt; with &lt;a href=&quot;https://en.wikipedia.org/wiki/Brendan_Eich&quot;&gt;Brendan Eich&lt;/a&gt;.
- With our amazing team, we're developing something pretty epic.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
- &lt;p&gt;&lt;/p&gt;&lt;p&gt;We're building the next-generation of browsers for smartphones and laptops as part of our new ad-tech platform.
- Our terms of use give our users control over their personal data by blocking ad trackers and third party cookies.
- We re-integrate fewer and better ads directly into programmatic ad positions, paying revenue shares to users and publishers to support both of these essential parties in the web ecosystem.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
- &lt;p&gt;&lt;/p&gt;&lt;p&gt;Coming built in, we have new faster engines for tracking protection, ad block, HTTPS Everywhere, safe ads with rev-share, and more.
- We're seeing massive web page load time speedups.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
-
-
- &lt;p&gt;&lt;/p&gt;&lt;p&gt;We're starting to bring people in for early developer build access on all platforms.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
- &lt;p&gt;&lt;/p&gt;&lt;p&gt;I’m happy to share that the browsers we’re developing were made fully open sourced.
- We welcome contributors, and would love your help.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
- &lt;p&gt;&lt;/p&gt;&lt;p&gt;Some of the repositories include:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/brave/browser-laptop&quot;&gt;Brave OSX and Windows x64 browsers&lt;/a&gt;: Prototyped as a Gecko based browser, but now replaced with a powerful new browser built on top of the electron framework. The electron framework is the same one in use by Slack and the Atom editor. It uses the latest libchromiumcontent and Node.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/brave/link-bubble&quot;&gt;Brave for Android&lt;/a&gt;: Formerly Link Bubble, working as a background service so you can use other apps as your pages load.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/brave/browser-ios&quot;&gt;Brave for iOS&lt;/a&gt;: Originally forked from Firefox for iOS but with all of the built-in greatness described above.&lt;/li&gt;
- &lt;li&gt;And many others: Website, updater code, vault, electron fork, and others.&lt;/li&gt;
- &lt;/ul&gt;</content:encoded>
- <dc:date>2016-01-20T00:00:00+00:00</dc:date>
- <dc:creator>Brian R. Bondy</dc:creator>
- </item>
- <item rdf:about="http://coffeeonthekeyboard.com/rss/0388d8a6-fc86-477e-a161-1b356e01fe77">
- <title>James Socol: PIEfection Slides Up</title>
- <link>http://coffeeonthekeyboard.com/piefection-slides-up/</link>
- <content:encoded>&lt;p&gt;I put &lt;a href=&quot;https://github.com/jsocol/talks/tree/master/2016-01-13-manhattanjs-pie&quot;&gt;the slides for my ManhattanJS talk, &quot;PIEfection&quot;&lt;/a&gt; up on GitHub the other day (sans images, but there are links in the source for all of those).&lt;/p&gt;
-
- &lt;p&gt;I completely neglected to talk about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Maillard_reaction&quot;&gt;Maillard reaction&lt;/a&gt;, which is responsible for food tasting good, and specifically for browning pie crusts. tl;dr: Amino acid (protein) + sugar + ~300°F (~150°C) = delicious. There are innumerable and poorly understood combinations of amino acids and sugars, but this class of reaction is responsible for everything from searing stakes to browning crusts to toasting marshmallows.&lt;/p&gt;
-
- &lt;p&gt;Above ~330°F, you get caramelization, which is also a delicious part of the pie and crust, but you don't want to overdo it. Starting around ~400°F, you get pyrolysis (burning, charring, carbonization) and below 285°F the reaction won't occur (at least not quickly) so you won't get the delicious compounds.&lt;/p&gt;
-
- &lt;p&gt;(All of these are, of course, temperatures measured in the material, not in the air of the oven.)&lt;/p&gt;
-
- &lt;p&gt;So, instead of an egg wash on your top crust, try whole milk, which has more sugar to react with the gluten in the crust.&lt;/p&gt;
-
- &lt;p&gt;I also didn't get a chance to mention a rolling technique I use, that I learned from a &lt;a href=&quot;https://www.facebook.com/ellenspirerstaffing&quot;&gt;cousin of mine&lt;/a&gt;, in whose baking shadow I happily live.&lt;/p&gt;
-
- &lt;p&gt;When rolling out a crust after it's been in the fridge, first roll it out in a long stretch, then fold it in thirds; do it again; then start rolling it out into a round. Not only do you add more layer structure (mmm, flaky, delicious layers) but it'll fill in the cracks that often form if you try to roll it out directly, resulting in a stronger crust.&lt;/p&gt;
-
- &lt;p&gt;Those &lt;a href=&quot;http://www.amazon.com/Cheese-Shaker-Pepper-Perforated-Stainless/dp/B007T40P28/ref=sr_1_1?ie=UTF8&amp;amp;qid=1453236391&amp;amp;sr=8-1&amp;amp;keywords=pizza+shaker&quot;&gt;pepper flake shakers&lt;/a&gt;, filled with flour, are a great way to keep adding flour to the workspace without worrying about your buttery hands.&lt;/p&gt;
-
- &lt;p&gt;For transferring the crust to the pie plate, try rolling it up onto your rolling pin and unrolling it on the plate. &lt;a href=&quot;http://www.amazon.com/Ateco-20-Inch-Length-French-Rolling/dp/B000KESQ1G&quot;&gt;Tapered (or &quot;French&quot;) rolling pins&lt;/a&gt; (or wine bottle) are particularly good at this since they don't have moving parts.&lt;/p&gt;
-
- &lt;p&gt;Finally, thanks again to &lt;a href=&quot;https://twitter.com/renrutnnej&quot;&gt;Jenn&lt;/a&gt; for helping me get pies from one island to another. It would not have been possible without her!&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-19T20:45:34+00:00</dc:date>
- <dc:creator>James Socol</dc:creator>
- </item>
- <item rdf:about="https://air.mozilla.org/reprendre-le-controle-de-sa-vie-privee-sur-internet/">
- <title>Air Mozilla: Reprendre le contrôle de sa vie privée sur Internet</title>
- <link>https://air.mozilla.org/reprendre-le-controle-de-sa-vie-privee-sur-internet/</link>
- <content:encoded>&lt;p&gt;
- &lt;img alt=&quot;Reprendre le contrôle de sa vie privée sur Internet&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/be/f6/bef62897fb87e08dc8392fe61d10bcfa.png&quot; width=&quot;160&quot; /&gt;
- L'omniprésence des réseaux sociaux, des moteurs de recherches et de la publicité est-elle compatible avec notre droit à la vie privée ?
- &lt;/p&gt;</content:encoded>
- <dc:date>2016-01-19T18:00:00+00:00</dc:date>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item rdf:about="https://mykzilla.org/?p=245">
- <title>Myk Melez: New Year, New Blogware</title>
- <link>https://mykzilla.org/2016/01/19/new-year-new-blogware/</link>
- <content:encoded>&lt;p&gt;Four score and many moons ago, I decided to move this blog from Blogger to WordPress. The transition took longer than expected, but it’s finally done.&lt;/p&gt;
- &lt;p&gt;If you’ve been following along at the old address, &lt;a href=&quot;https://mykzilla.blogspot.com/&quot;&gt;https://mykzilla.blogspot.com/&lt;/a&gt;, now’s the time to update your address book! If you’ve been going to &lt;a href=&quot;https://mykzilla.org/&quot;&gt;https://mykzilla.org/&lt;/a&gt;, however, or you read the blog on &lt;a href=&quot;http://planet.mozilla.org/&quot;&gt;Planet Mozilla&lt;/a&gt;, then there’s nothing to do, as that’s the new address, and Planet Mozilla has been updated to syndicate posts from it.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-19T16:56:05+00:00</dc:date>
- <dc:creator>Myk Melez</dc:creator>
- </item>
- <item rdf:about="http://michaelkohler.info/?p=348">
- <title>Michael Kohler: Mozillas strategische Leitlinien für 2016 und danach</title>
- <link>https://michaelkohler.info/2016/mozillas-strategische-leitlinien-fur-2016-und-danach</link>
- <content:encoded>&lt;p&gt;Dieser Beitrag wurde zuerst im Blog auf&lt;a href=&quot;https://blog.mozilla.org/community&quot;&gt; https://blog.mozilla.org/community&lt;/a&gt; veröffentlicht. Herzlichen Dank an Aryx und Coce für die Übersetzung!&lt;/p&gt;
- &lt;p&gt;Auf der ganzen Welt arbeiten leidenschaftliche Mozillianer am Fortschritt für Mozillas Mission. Aber fragt man fünf verschiedene Mozillianer, was die Mission ist, erhält man womöglich sieben verschiedene Antworten.&lt;/p&gt;
- &lt;p&gt;Am Ende des letzten Jahres legte Mozillas CEO Chris Beard klare Vorstellungen über Mozillas Mission, Vision und Rolle dar und zeigte auf, wie unsere Produkte uns diesem Ziel in den nächsten fünf Jahren näher bringen. Das Ziel dieser strategischen Leitlinien besteht darin, für Mozilla insgesamt ein prägnantes, gemeinsames Verständnis unserer Ziele zu entwickeln, die uns als Individuen das Treffen von Entscheidungen und Erkennen von Möglichkeiten erleichtert, mit denen wir Mozilla voranbringen.&lt;/p&gt;
- &lt;p&gt;Mozillas Mission können wir nicht alleine erreichen. Die Tausenden von Mozillianern auf der ganzen Welt müssen dahinter stehen, damit wir zügig und mit lauterer Stimme als je zuvor Unglaubliches erreichen können.&lt;/p&gt;
- &lt;p&gt;Deswegen ist eine der sechs&lt;a href=&quot;https://docs.google.com/presentation/d/1A3Ma9gNawAYYGbYC2bUW0wUwcpHuvyMiZvHNiMLriw0/edit#slide=id.gdaa7a0bd0_1_0&quot;&gt; strategischen Initiativen&lt;/a&gt; des Participation Teams für die erste Jahreshälfte, möglichst viele Mozillianer über diese Leitlinien aufzuklären, damit wir 2016 den bisher wesentlichsten Einfluss erzielen können. Wir werden einen weiteren Beitrag veröffentlichen, der sich näher mit der Strategie des Participation Teams für das Jahr 2016 befassen wird.&lt;/p&gt;
- &lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;alignnone&quot; height=&quot;335&quot; src=&quot;https://ffp4g1ylyit3jdyti1hqcvtb-wpengine.netdna-ssl.com/community/files/2016/01/Screen-Shot-2015-12-18-at-2.02.07-PM-600x335.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;Das Verstehen dieser Strategie wird unabdingbar sein für jeden, der bei Mozilla in diesem Jahr etwas bewirken möchte, denn sie wird bestimmen, wofür wir eintreten, wo wir unsere Ressourcen einsetzen und auf welche Projekte wir uns 2016 konzentrieren werden.&lt;/p&gt;
- &lt;p&gt;Zu Jahresbeginn werden wir näher auf diese Strategie eingehen und weitere Details dazu bekanntgeben, wie die diversen Teams und Projekte bei Mozilla auf diese Ziele hinarbeiten.&lt;/p&gt;
- &lt;p&gt;Der aktuelle Aufruf zum Handeln besteht darin, im Kontext Ihrer Arbeit über diese Ziele nachzudenken und darüber, wie Sie im kommenden Jahr bei Mozilla mitwirken möchten. Dies hilft, Ihre Innovationen, Ambitionen und Ihren Einfluss im Jahr 2016 zu gestalten.&lt;/p&gt;
- &lt;p&gt;Wir hoffen, dass Sie mitdiskutieren und Ihre Fragen, Kommentare und Pläne für das Vorantreiben der strategischen Leitlinien im Jahr 2016&lt;a href=&quot;https://discourse.mozilla-community.org/t/mozillas-strategic-narrative-2016/6397&quot;&gt; hier&lt;/a&gt; auf Discourse teilen und Ihre Gedanken auf Twitter mit dem Hashtag &lt;a href=&quot;https://twitter.com/search?q=%23mozilla2016strategy&amp;amp;src=typd&quot;&gt;#Mozilla2016Strategy&lt;/a&gt; mitteilen.&lt;/p&gt;
- &lt;p&gt; &lt;/p&gt;
- &lt;h3&gt;Mission, Vision &amp;amp; Strategie&lt;/h3&gt;
- &lt;p&gt;&lt;b&gt;Unsere Mission&lt;/b&gt;&lt;/p&gt;
- &lt;p&gt;Dafür zu sorgen, dass das Internet eine weltweite öffentliche Ressource ist, die allen zugänglich ist.&lt;/p&gt;
- &lt;p&gt;&lt;b&gt;Unsere Vision&lt;/b&gt;&lt;/p&gt;
- &lt;p&gt;Ein Internet, für das Menschen tatsächlich an erster Stelle stehen. Ein Internet, in dem Menschen ihr eigenes Erlebnis gestalten können. Ein Internet, in dem die Menschen selbst entscheiden können sowie sicher und unabhängig sind.&lt;/p&gt;
- &lt;p&gt;&lt;b&gt;Unsere Rolle&lt;/b&gt;&lt;/p&gt;
- &lt;p&gt;Mozilla setzt sich im wahrsten Sinne des Wortes in Ihrem Online-Leben für Sie ein. Wir setzen uns für Sie ein, sowohl in Ihrem Online-Erlebnis als auch für Ihre Interessen beim Zustand des Internets.&lt;/p&gt;
- &lt;p&gt;&lt;b&gt;Unsere Arbeit&lt;/b&gt;&lt;/p&gt;
- &lt;p&gt;Unsere Säulen&lt;/p&gt;
- &lt;ol&gt;
- &lt;li&gt;&lt;b&gt;Produkte:&lt;/b&gt; Wir entwickeln Produkte mit Menschen im Mittelpunkt sowie Bildungsprogramme, mit deren Hilfe Menschen online ihr gesamtes Potential ausschöpfen können.&lt;/li&gt;
- &lt;li&gt;&lt;b&gt;Technologie:&lt;/b&gt; Wir entwickeln robuste technische Lösungen, die das Internet über verschiedene Plattformen hinweg zum Leben erwecken.&lt;/li&gt;
- &lt;li&gt;&lt;b&gt;Menschen:&lt;/b&gt; Wir entwickeln Führungspersonen und Mitwirkende in der Gemeinschaft, die das Internet erfinden, gestalten und verteidigen.&lt;/li&gt;
- &lt;/ol&gt;
- &lt;p&gt;Wir wir positive Veränderungen in Zukunft anpacken wollen&lt;/p&gt;
- &lt;p&gt;Die Arbeitsweise ist ebensowichtig wie das Ziel. Unsere Gesundheit und bleibender Einfluss hängen davon ab, wie sehr unsere Produkte und Aktivitäten:&lt;/p&gt;
- &lt;ol&gt;
- &lt;li&gt;Interoperabilität, Open Source und offene Standards fördern,&lt;/li&gt;
- &lt;li&gt;Gemeinschaften aufbauen und fördern,&lt;/li&gt;
- &lt;li&gt;Für politische Veränderungen und rechtlichen Schutz eintreten sowie&lt;/li&gt;
- &lt;li&gt;Netzbürger bilden und einbeziehen.&lt;/li&gt;
- &lt;/ol&gt;
- &lt;p&gt; &lt;/p&gt;
- &lt;img alt=&quot;&quot; height=&quot;0&quot; src=&quot;http://piwik.michaelkohler.info/piwik.php?idsite=1&amp;amp;rec=1&amp;amp;url=https%3A%2F%2Fmichaelkohler.info%2F2016%2Fmozillas-strategische-leitlinien-fur-2016-und-danach&amp;amp;action_name=Mozillas+strategische+Leitlinien+f%C3%BCr+2016+und+danach&amp;amp;urlref=https%3A%2F%2Fmichaelkohler.info%2Ffeed&quot; style=&quot;border: 0; width: 0; height: 0;&quot; width=&quot;0&quot; /&gt;</content:encoded>
- <dc:date>2016-01-19T15:27:24+00:00</dc:date>
- <dc:creator>Michael Kohler</dc:creator>
- </item>
- <item rdf:about="http://dlawrence.wordpress.com/?p=27">
- <title>David Lawrence: happy bmo push day!</title>
- <link>https://dlawrence.wordpress.com/2016/01/19/happy-bmo-push-day-3/</link>
- <content:encoded>&lt;p&gt;the following changes have been pushed to bugzilla.mozilla.org:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1238573&quot; target=&quot;_blank&quot;&gt;1238573&lt;/a&gt;] Change label of “New Bug†menu to “New/Clone Bugâ€&lt;/li&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1239065&quot; target=&quot;_blank&quot;&gt;1239065&lt;/a&gt;] Project Kickoff Form: Adjustments needed to Mozilla Infosec review portion&lt;/li&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1240157&quot; target=&quot;_blank&quot;&gt;1240157&lt;/a&gt;] Fix a typo in bug.rst&lt;/li&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1236461&quot; target=&quot;_blank&quot;&gt;1236461&lt;/a&gt;] Mass update mozilla-reps group&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;discuss these changes on &lt;a href=&quot;https://lists.mozilla.org/listinfo/tools-bmo&quot; target=&quot;_blank&quot;&gt;mozilla.tools.bmo&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gocomments/dlawrence.wordpress.com/27/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/dlawrence.wordpress.com/27/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;https://pixel.wp.com/b.gif?host=dlawrence.wordpress.com&amp;amp;blog=58816&amp;amp;post=27&amp;amp;subd=dlawrence&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</content:encoded>
- <dc:date>2016-01-19T14:49:59+00:00</dc:date>
- <dc:creator>dlawrence</dc:creator>
- </item>
- <item rdf:about="http://soledadpenades.com/?p=6335">
- <title>Soledad Penades: Hardware Hack Day @ MozLDN, 1</title>
- <link>http://soledadpenades.com/2016/01/19/hardware-hack-day-mozldn-1/</link>
- <content:encoded>&lt;p&gt;Last week we ran an internal “hack day†here at the Mozilla space in London. It was just a bunch of &lt;em&gt;software&lt;/em&gt; engineers looking at various &lt;em&gt;hardware&lt;/em&gt; boards and things and learning about them &lt;img alt=&quot;:-)&quot; class=&quot;wp-smiley&quot; src=&quot;http://soledadpenades.com/wp-includes/images/smilies/simple-smile.png&quot; style=&quot;height: 1em;&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;Here’s what we did!&lt;/p&gt;
- &lt;h3&gt;&lt;a href=&quot;http://soledadpenades.com/&quot;&gt;Sole&lt;/a&gt;&lt;/h3&gt;
- &lt;p&gt;I essentially &lt;a href=&quot;http://soledadpenades.com/2016/01/19/kind-of-bricking-an-arduino-duemilanove-by-exhausting-its-memory/&quot;&gt;kind of bricked my Arduino Duemilanove&lt;/a&gt; trying to get it working with Johnny Five, but it was fine–apparently there’s a way to recover it using another Arduino, and someone offered to help with that in the next &lt;a href=&quot;http://www.meetup.com/NodeBots-of-London/events/227890374/&quot;&gt;NodeBots&lt;/a&gt; London, which I’m going to attend.&lt;/p&gt;
- &lt;h3&gt;&lt;a href=&quot;http://ardeenelinfierno.com/&quot;&gt;Francisco&lt;/a&gt;&lt;/h3&gt;
- &lt;p&gt;Thinks he’s having issues with cables. It seems like the boards are not reset automatically by the Arduino IDE nowadays? He found the button in the board actually resets the board when pressed i.e. it’s the RESET button.&lt;/p&gt;
- &lt;p&gt;On the Raspberry Pi side of things, he was very happy to put all his old-school Linux skills in action configuring network interfaces without GUIs!&lt;/p&gt;
- &lt;h3&gt;&lt;a href=&quot;http://gu.illau.me/&quot;&gt;Guillaume&lt;/a&gt;&lt;/h3&gt;
- &lt;p&gt;Played with mDNS advertising and listening to services on Raspberry Pi.&lt;/p&gt;
- &lt;p&gt;(He was very quiet)&lt;/p&gt;
- &lt;p&gt;(He also built a very nice LEGO case for the Raspberry Pi, but I do not have a picture, so just imagine it).&lt;/p&gt;
- &lt;h3&gt;&lt;a href=&quot;http://wilsonpage.co.uk/&quot;&gt;Wilson&lt;/a&gt;&lt;/h3&gt;
- &lt;blockquote&gt;&lt;p&gt;
- Wilson: “I got my Raspberry Pi on the Wi-Fiâ€&lt;/p&gt;
- &lt;p&gt;Francisco: “Sorry?â€&lt;/p&gt;
- &lt;p&gt;Wilson: “I mean, you got my Raspberry Pi on the network. And now I’m trying to build a web app on the Pi…â€&lt;/p&gt;&lt;/blockquote&gt;
- &lt;h3&gt;&lt;a href=&quot;http://chrislord.net/&quot;&gt;Chris&lt;/a&gt;&lt;/h3&gt;
- &lt;p&gt;Exploring the Pebble with Linux. There’s a libpebble, and he managed to connect…&lt;/p&gt;
- &lt;p&gt;&lt;del datetime=&quot;2016-01-20T11:22:33+00:00&quot;&gt;&lt;em&gt;&lt;small&gt;(sorry, I had to leave early so I do not know what else did Chris do!)&lt;/small&gt;&lt;/em&gt;&lt;/del&gt;&lt;/p&gt;
- &lt;p&gt;Updated, 20 January: Chris told me he just managed to successfully connect to the Pebble watch using the bluetooth WebAPI. It requires two Gecko patches (one regression patch and one obvious logic error that he hasn’t filed yet). PROGRESS!&lt;/p&gt;
- &lt;p&gt;~~~&lt;/p&gt;
- &lt;p&gt;So as you can see we didn’t really get super far in just a day, and I even ended up with unusable hardware. BUT! we all learned something, and next time we know what NOT to do (or at least I DO KNOW what NOT to do!).&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://soledadpenades.com/?flattrss_redirect&amp;amp;id=6335&amp;amp;md5=40427d69faa3b9c2d1530732fd78e66d&quot; target=&quot;_blank&quot; title=&quot;Flattr&quot;&gt;&lt;img alt=&quot;flattr this!&quot; src=&quot;http://soledadpenades.com/wp-content/plugins/flattr/img/flattr-badge-large.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-19T13:31:55+00:00</dc:date>
- <dc:creator>sole</dc:creator>
- </item>
- <item rdf:about="http://daniel.haxx.se/blog/?p=8544">
- <title>Daniel Stenberg: “Subject: Urgent Warningâ€</title>
- <link>http://daniel.haxx.se/blog/2016/01/19/subject-urgent-warning/</link>
- <content:encoded>&lt;p&gt;Back in December I got a desperate email from this person. A woman who said her Instagram had been hacked and since she found my contact info in the app she mailed me and asked for help. I of course replied and said that I have nothing to do with her being hacked but I also have nothing to do with Instagram other than that they use software I’ve written.&lt;/p&gt;
- &lt;p&gt;Today she writes back. Clearly not convinced I told the truth before, and now she strikes back with more “evidence†of my wrongdoings.&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;Dear Daniel,&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;I had emailed you a couple months ago about my “screen dumps†aka screenshots and asked for your help with restoring my Instagram account since it had been hacked, my photos changed, and your name was included in the coding. You claimed to have no involvement whatsoever in developing a third party app for Instagram and could not help me salvage my original Instagram photos, pre-hacked, despite Instagram serving as my Photography portfolio and my career is a Photographer.&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;Since you weren’t aware that your name was attached to Instagram related hacking code, I thought you might want to know, in case you weren’t already aware, that your name is also included in Spotify terms and conditions. I came across this information using my Spotify which has also been hacked into and would love your help hacking out of Spotify. Also, I have yet to figure out how to unhack the hackers from my Instagram so if you change your mind and want to restore my Instagram to its original form as well as help me secure my account from future privacy breaches, I’d be extremely grateful. As you know, changing my passwords did nothing to resolve the problem. Please keep in mind that Facebook owns Instagram and these are big companies that you likely don’t want to have a trail of evidence that you are a part of an Instagram and Spotify hacking ring. Also, Spotify is a major partner of Spotify so you are likely familiar with the coding for all of these illegally developed third party apps. I’d be grateful for your help fixing this error immediately.&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;Thank you,&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;[name redacted]&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;P.S. Please see attached screen dump for a screen shot of your contact info included in Spotify (or what more likely seems to be a hacked Spotify developed illegally by a third party).&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_7393.png&quot; rel=&quot;attachment wp-att-8545&quot;&gt;&lt;img alt=&quot;Spotify credits screenshot&quot; class=&quot;aligncenter size-medium wp-image-8545&quot; height=&quot;450&quot; src=&quot;http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_7393-253x450.png&quot; width=&quot;253&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;Here’s the Instagram screenshot she sent me in a previous email:&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_2156.jpg&quot; rel=&quot;attachment wp-att-8546&quot;&gt;&lt;img alt=&quot;Instagram credits screenshot&quot; class=&quot;aligncenter size-medium wp-image-8546&quot; height=&quot;450&quot; src=&quot;http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_2156-253x450.jpg&quot; width=&quot;253&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;I’ve tried to respond with calm and clear reasonable logic and technical details on why she’s seeing my name there. That clearly failed. What do I try next?&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-19T08:37:32+00:00</dc:date>
- <dc:creator>Daniel Stenberg</dc:creator>
- </item>
- <item rdf:about="http://edunham.net/2016/01/19/how_much_knowledge_do_you_need_to_give_a_conference_talk.html">
- <title>Emily Dunham: How much knowledge do you need to give a conference talk?</title>
- <link>http://edunham.net/2016/01/19/how_much_knowledge_do_you_need_to_give_a_conference_talk.html</link>
- <content:encoded>&lt;h3&gt;How much knowledge do you need to give a conference talk?&lt;/h3&gt;
- &lt;p&gt;I was recently asked an excellent question when I promoted the &lt;a class=&quot;reference external&quot; href=&quot;http://www.linuxfestnorthwest.org/2016/present&quot;&gt;LFNW CFP&lt;/a&gt; on
- IRC:&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;div&gt;As someone who has never done a talk, but wants to, what kind of knowledge
- do you need about a subject to give a talk on it?&lt;/div&gt;&lt;/blockquote&gt;
- &lt;p&gt;If you answer “yes†to any of the following questions, you know enough to
- propose a talk:&lt;/p&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;Do you have a &lt;strong&gt;hobby&lt;/strong&gt; that most tech people aren’t experts on? Talk
- about applying a lesson or skill from that hobby to tech! For instance, I
- turned a habit of reading about psychology into my &lt;a class=&quot;reference external&quot; href=&quot;http://talks.edunham.net/scale13x/#1&quot;&gt;Human Hacking&lt;/a&gt; talk.&lt;/li&gt;
- &lt;li&gt;Have you ever spent a bunch of hours forcing two tools to work with each
- other, because the documentation wasn’t very helpful and Googling didn’t get
- you very far, and built something useful? “How to build ___ with ___†makes
- a catchy talk title, if the &lt;strong&gt;thing you built&lt;/strong&gt; solves a common problem.&lt;/li&gt;
- &lt;li&gt;Have you ever had a mentor sit down with you and explain a tool or
- technique, and the new understanding improved the quality of your work or
- code? Passing along useful &lt;strong&gt;lessons from your mentors&lt;/strong&gt; is a valuable talk,
- because it allows others to benefit from the knowledge without taking as
- much of your mentor’s time.&lt;/li&gt;
- &lt;li&gt;Have you seen a dozen newbies ask the same question over the course of a few
- months? When your &lt;strong&gt;answer to a common question&lt;/strong&gt; starts to feel like a
- broken record, it’s time to compose it into a talk then link the newbies to
- your slides or recording!&lt;/li&gt;
- &lt;li&gt;Have you taken a really &lt;strong&gt;interesting class&lt;/strong&gt; lately? Can you distill part of it
- into a 1-hour lesson that would appeal to nerds who don’t have the time or
- resources to take the class themselves? (thanks &lt;a class=&quot;reference external&quot; href=&quot;http://lucywyman.me/&quot;&gt;lucyw&lt;/a&gt; for adding this to
- the list!)&lt;/li&gt;
- &lt;li&gt;Have you built a cool thing that over a dozen other people use? A &lt;strong&gt;tutorial
- talk&lt;/strong&gt; can not only expand your community, but its recording can augment your
- documentation and make the project more accessible for those who prefer to
- learn directly from humans!&lt;/li&gt;
- &lt;li&gt;Did you benefit from a really great introductory talk when you were learning
- a tool? Consider doing your own tutorial! Any conference with beginners in
- their target audience needs at least one Git lesson, an IRC talk, and some
- discussions of how to use basic Unix utilities. These &lt;strong&gt;introductory talks&lt;/strong&gt;
- are actually better when given by someone who learned the technology
- relatively recently, because newer users remember what it’s like not to know
- how to use it. Just remember to have a more expert user look over your slides
- before you present, in case you made an incorrect assumption about the tool’s
- more advanced functionality.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;I personally try to propose talks I want to hear, because the dealine of a
- CFP or conference is great motivation to prioritize a cool project over
- ordinary chores.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-19T08:00:00+00:00</dc:date>
- </item>
- <item rdf:about="https://quality.mozilla.org/?p=49441">
- <title>QMO: Aurora 45.0 Testday Results</title>
- <link>https://quality.mozilla.org/2016/01/aurora-45-0-testday-results/</link>
- <content:encoded>&lt;p&gt;Howdy mozillians!&lt;/p&gt;
- &lt;p&gt;Last week – on &lt;em&gt;Friday, January 15th&lt;/em&gt; – we held &lt;a href=&quot;https://quality.mozilla.org/2016/01/firefox-45-0-aurora-testday-january-15th/&quot;&gt;Aurora 45.0 Testday&lt;/a&gt;; and, of course, it was another outstanding event!&lt;/p&gt;
- &lt;p&gt;&lt;strong&gt;Thank you&lt;/strong&gt; all – &lt;span class=&quot;author-a-oz90z4z89zz89za7qfz70zda5z87zxz85z i&quot;&gt;&lt;i&gt;Mahmoudi Dris, Iryna Thompson, Chandrakant Dhutadmal, Preethi Dhinesh, Moin Shaikh, Ilse Macías, Hossain Al Ikram, Rezaul Huque Nayeem, Tahsan Chowdhury Akash, Kazi Nuzhat Tasnem, Fahmida Noor, Tazin Ahmed, Md. Ehsanul Hassan, Mohammad Maruf Islam, Kazi Sakib Ahmad, Khalid Syfullah Zaman, Asiful Kabir, Tabassum Mehnaz, Hasibul Hasan, Saddam Hossain, Mohammad Kamran Hossain, Amlan Biswas, Fazle Rabbi, Mohammed Jawad Ibne Ishaque, Asif Mahmud Shuvo, Nazir Ahmed Sabbir, Md. Raihan Ali, Md. Almas Hossain, Sadik Khan, Md. Faysal Alam Riyad, Faisal Mahmud, Md. Oliullah Sizan, Asif Mahmud Rony, Forhad Hossain &lt;/i&gt;and&lt;i&gt; Tanvir Rahman &lt;/i&gt;&lt;/span&gt;– for the participation!&lt;/p&gt;
- &lt;p&gt;A big &lt;strong&gt;thank you&lt;/strong&gt; to all our active moderators too!&lt;/p&gt;
- &lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;font-family: 'Open Sans', sans-serif;&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;u&gt;Results:&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;font-family: 'Open Sans', sans-serif;&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;strong&gt;15&lt;/strong&gt; issues were verified: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;font-family: 'Open Sans', sans-serif;&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt; &lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1235821&quot;&gt;1235821&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1228518&quot;&gt;1228518&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1165637&quot;&gt;1165637&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1232647&quot;&gt;1232647&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1235379&quot;&gt;1235379&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=842356&quot;&gt;842356&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1222971&quot;&gt;1222971&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=915962&quot;&gt;915962&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1180761&quot;&gt;1180761&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1218455&quot;&gt;1218455&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1222747&quot;&gt;1222747&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1210752&quot;&gt;1210752&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1198450&quot;&gt;1198450&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1222820&quot;&gt;1222820&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1225514&quot;&gt;1225514&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;1&lt;/strong&gt; bug was triaged: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1230789&quot;&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;1230789&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;some failures were mentioned for &lt;i&gt;Search Refactoring &lt;/i&gt;feature in the etherpads (&lt;a href=&quot;https://public.etherpad-mozilla.org/p/testday-20160115&quot;&gt;link 1&lt;/a&gt; and &lt;a href=&quot;https://public.etherpad-mozilla.org/p/bangladesh.testday-15012016&quot;&gt;link 2&lt;/a&gt;); please feel free to add the requested details in the etherpads or, even better, join us on &lt;a href=&quot;http://widget01.mibbit.com/?server=irc.mozilla.org&amp;amp;channel=%23qa&quot; target=&quot;_blank&quot;&gt;#qa IRC channel&lt;/a&gt; and let’s figure them out&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;I &lt;strong&gt;strongly&lt;/strong&gt; advise everyone of you to reach out to us, the moderators, via &lt;a href=&quot;http://widget01.mibbit.com/?server=irc.mozilla.org&amp;amp;channel=%23qa&quot;&gt;#qa&lt;/a&gt; during the events when you encountered any kind of failures. Keep up the great work! \o/&lt;/p&gt;
- &lt;p&gt;And keep an eye on QMO for upcoming events! &lt;img alt=&quot;😉&quot; class=&quot;wp-smiley&quot; src=&quot;https://s.w.org/images/core/emoji/72x72/1f609.png&quot; style=&quot;height: 1em;&quot; /&gt;&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-19T07:51:57+00:00</dc:date>
- <dc:creator>Alexandra Lucinet</dc:creator>
- </item>
- <item rdf:about="http://blog.monotonous.org/?p=678">
- <title>Eitan Isaacson: It’s MLK Day and It’s Not Too Late to Do Something About It</title>
- <link>http://blog.monotonous.org/2016/01/18/its-mlk-day-and-its-not-too-late-to-do-something-about-it/</link>
- <content:encoded>&lt;p&gt;For the last three years I have had the opportunity to send out a reminder to Mozilla staff that Martin Luther King Jr. Day is coming up, and that U.S. employees get the day off. It has turned into my MLK Day eve ritual. I read his letters, listen to speeches, and then I compose a belabored paragraph about Dr. King with some choice quotes.&lt;/p&gt;
- &lt;p&gt;If you didn’t get a chance to celebrate Dr. King’s legacy and the movements he was a part of, you still have a chance:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;Watch &lt;a href=&quot;http://www.imdb.com/title/tt1020072/&quot; target=&quot;_blank&quot;&gt;Selma.&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Watch &lt;a href=&quot;http://www.imdb.com/title/tt1592527/&quot; target=&quot;_blank&quot;&gt;The Black Power Mixtape&lt;/a&gt; (it’s on Netflix).&lt;/li&gt;
- &lt;li&gt;Read &lt;a href=&quot;http://www.africa.upenn.edu/Articles_Gen/Letter_Birmingham.html&quot; target=&quot;_blank&quot;&gt;A Letter from a Birmingham Jail&lt;/a&gt; (it’s really really good).&lt;/li&gt;
- &lt;li&gt;Listen to his speech &lt;a href=&quot;https://www.youtube.com/watch?v=3Qf6x9_MLD0&quot; target=&quot;_blank&quot;&gt;Beyond Vietnam&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Listen to his last speech &lt;a href=&quot;https://www.youtube.com/watch?v=IDl84vusXos&quot; target=&quot;_blank&quot;&gt;I Have Been To The Mountaintop&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;&lt;br /&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gocomments/blogdotmonotonousdotorg.wordpress.com/678/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/blogdotmonotonousdotorg.wordpress.com/678/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;http://pixel.wp.com/b.gif?host=blog.monotonous.org&amp;amp;blog=34885741&amp;amp;post=678&amp;amp;subd=blogdotmonotonousdotorg&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</content:encoded>
- <dc:date>2016-01-18T23:35:19+00:00</dc:date>
- <dc:creator>Eitan</dc:creator>
- </item>
- <item rdf:about="http://www.ncameron.org/blog/rss/0e4d587c-380c-40ce-954a-7206f69bc1dd">
- <title>Nick Cameron: Libmacro</title>
- <link>http://www.ncameron.org/blog/libmacro/</link>
- <content:encoded>&lt;p&gt;As I outlined in an &lt;a href=&quot;http://ncameron.org/blog/procedural-macros-framework/&quot;&gt;earlier post&lt;/a&gt;, libmacro is a new crate designed to be used by procedural macro authors. It provides the basic API for procedural macros to interact with the compiler. I expect higher level functionality to be provided by library crates. In this post I'll go into a bit more detail about the API I think should be exposed here.&lt;/p&gt;
-
- &lt;p&gt;This is a lot of stuff. I've probably missed something. If you use syntax extensions today and do something with libsyntax that would not be possible with libmacro, please let me know!&lt;/p&gt;
-
- &lt;p&gt;I previously introduced &lt;code&gt;MacroContext&lt;/code&gt; as one of the gateways to libmacro. All procedural macros will have access to a &lt;code&gt;&amp;amp;mut MacroContext&lt;/code&gt;.&lt;/p&gt;
-
- &lt;h3&gt;Tokens&lt;/h3&gt;
-
- &lt;p&gt;I described the &lt;code&gt;tokens&lt;/code&gt; module in the last post, I won't repeat that here.&lt;/p&gt;
-
- &lt;p&gt;There are a few more things I thought of. I mentioned a &lt;code&gt;TokenStream&lt;/code&gt; which is a sequence of tokens. We should also have &lt;code&gt;TokenSlice&lt;/code&gt; which is a borrowed slice of tokens (the slice to &lt;code&gt;TokenStream&lt;/code&gt;'s &lt;code&gt;Vec&lt;/code&gt;). These should implement the standard methods for sequences, in particular they support iteration, so can be &lt;code&gt;map&lt;/code&gt;ed, etc.&lt;/p&gt;
-
- &lt;p&gt;In the earlier blog post, I talked about a token kind called &lt;code&gt;Delimited&lt;/code&gt; which contains a delimited sequence of tokens. I would like to rename that to &lt;code&gt;Sequence&lt;/code&gt; and add a &lt;code&gt;None&lt;/code&gt; variant to the &lt;code&gt;Delimiter&lt;/code&gt; enum. The &lt;code&gt;None&lt;/code&gt; option is so that we can have blocks of tokens without using delimiters. It will be used for noting unsafety and other properties of tokens. Furthermore, it is useful for macro expansion (replacing the interpolated AST tokens currently present). Although &lt;code&gt;None&lt;/code&gt; blocks do not affect scoping, they do affect precedence and parsing.&lt;/p&gt;
-
- &lt;p&gt;We should provide API for creating tokens. By default these have no hygiene information and come with a span which has no place in the source code, but shows the source of the token to be the procedural macro itself (see below for how this interacts with expansion of the current macro). I expect a &lt;code&gt;make_&lt;/code&gt; function for each kind of token. We should also have API for creating macros in a given scope (which do the same thing but with provided hygiene information). This could be considered an over-rich API, since the hygiene information could be set after construction. However, since hygiene is fiddly and annoying to get right, we should make it as easy as possible to work with.&lt;/p&gt;
-
- &lt;p&gt;There should also be a function for creating a token which is just a fresh name. This is useful for creating new identifiers. Although this can be done by interning a string and then creating a token around it, it is used frequently enough to deserve a helper function.&lt;/p&gt;
-
- &lt;h3&gt;Emitting errors and warnings&lt;/h3&gt;
-
- &lt;p&gt;Procedural macros should report errors, warnings, etc. via the &lt;code&gt;MacroContext&lt;/code&gt;. They should avoid panicking as much as possible since this will crash the compiler (once &lt;code&gt;catch_panic&lt;/code&gt; is available, we should use it to catch such panics and exit gracefully, however, they will certainly still meaning aborting compilation).&lt;/p&gt;
-
- &lt;p&gt;Libmacro will 're-export' &lt;code&gt;DiagnosticBuilder&lt;/code&gt; from &lt;a href=&quot;https://dxr.mozilla.org/rust/source/src/libsyntax/errors/mod.rs&quot;&gt;syntax::errors&lt;/a&gt;. I don't actually expect this to be a literal re-export. We will use libmacro's version of &lt;code&gt;Span&lt;/code&gt;, for example.&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;impl MacroContext {
- pub fn struct_error(&amp;amp;self, &amp;amp;str) -&amp;gt; DiagnosticBuilder;
- pub fn error(&amp;amp;self, Option&amp;lt;Span&amp;gt;, &amp;amp;str);
- }
-
- pub mod errors {
- pub struct DiagnosticBuilder { ... }
- impl DiagnosticBuilder { ... }
- pub enum ErrorLevel { ... }
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;There should be a macro &lt;code&gt;try_emit!&lt;/code&gt;, which reduces a &lt;code&gt;Result&amp;lt;T, ErrStruct&amp;gt;&lt;/code&gt; to a T or calls &lt;code&gt;emit()&lt;/code&gt; and then calls &lt;code&gt;unreachable!()&lt;/code&gt; (if the error is not fatal, then it should be upgraded to a fatal error).&lt;/p&gt;
-
- &lt;h3&gt;Tokenising and quasi-quoting&lt;/h3&gt;
-
- &lt;p&gt;The simplest function here is &lt;code&gt;tokenize&lt;/code&gt; which takes a string (&lt;code&gt;&amp;amp;str&lt;/code&gt;) and returns a &lt;code&gt;Result&amp;lt;TokenStream, ErrStruct&amp;gt;&lt;/code&gt;. The string is treated like source text. The success option is the tokenised version of the string. I expect this function must take a &lt;code&gt;MacroContext&lt;/code&gt; argument.&lt;/p&gt;
-
- &lt;p&gt;We will offer a quasi-quoting macro. This will return a &lt;code&gt;TokenStream&lt;/code&gt; (in contrast to today's quasi-quoting which returns AST nodes), to be precise a &lt;code&gt;Result&amp;lt;TokenStream, ErrStruct&amp;gt;&lt;/code&gt;. The string which is quoted may include metavariables (&lt;code&gt;$x&lt;/code&gt;), and these are filled in with variables from the environment. The type of the variables should be either a &lt;code&gt;TokenStream&lt;/code&gt;, a &lt;code&gt;TokenTree&lt;/code&gt;, or a &lt;code&gt;Result&amp;lt;TokenStream, ErrStruct&amp;gt;&lt;/code&gt; (in this last case, if the variable is an error, then it is just returned by the macro). For example,&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;fn foo(cx: &amp;amp;mut MacroContext, tokens: TokenStream) -&amp;gt; TokenStream {
- quote!(cx, fn foo() { $tokens }).unwrap()
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;The &lt;code&gt;quote!&lt;/code&gt; macro can also handle multiple tokens when the variable corresponding with the metavariable has type &lt;code&gt;[TokenStream]&lt;/code&gt; (or is dereferencable to it). In this case, the same syntax as used in macros-by-example can be used. For example, if &lt;code&gt;x: Vec&amp;lt;TokenStream&amp;gt;&lt;/code&gt; then &lt;code&gt;quote!(cx, ($x),*)&lt;/code&gt; will produce a &lt;code&gt;TokenStream&lt;/code&gt; of a comma-separated list of tokens from the elements of &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;Since the &lt;code&gt;tokenize&lt;/code&gt; function is a degenerate case of quasi-quoting, an alternative would be to always use &lt;code&gt;quote!&lt;/code&gt; and remove &lt;code&gt;tokenize&lt;/code&gt;. I believe there is utility in the simple function, and it must be used internally in any case.&lt;/p&gt;
-
- &lt;p&gt;These functions and macros should create tokens with spans and hygiene information set as described above for making new tokens. We might also offer versions which takes a scope and uses that as the context for tokenising.&lt;/p&gt;
-
- &lt;h3&gt;Parsing helper functions&lt;/h3&gt;
-
- &lt;p&gt;There are some common patterns for tokens to follow in macros. In particular those used as arguments for attribute-like macros. We will offer some functions which attempt to parse tokens into these patterns. I expect there will be more of these in time; to start with:&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod parsing {
- // Expects `(foo = &quot;bar&quot;),*`
- pub fn parse_keyed_values(&amp;amp;TokenSlice, &amp;amp;mut MacroContext) -&amp;gt; Result&amp;lt;Vec&amp;lt;(InternedString, String)&amp;gt;, ErrStruct&amp;gt;;
- // Expects `&quot;bar&quot;`
- pub fn parse_string(&amp;amp;TokenSlice, &amp;amp;mut MacroContext) -&amp;gt; Result&amp;lt;String, ErrStruct&amp;gt;;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;To be honest, given the token design in the last post, I think &lt;code&gt;parse_string&lt;/code&gt; is unnecessary, but I wanted to give more than one example of this kind of function. If &lt;code&gt;parse_keyed_values&lt;/code&gt; is the only one we end up with, then that is fine.&lt;/p&gt;
-
- &lt;h3&gt;Pattern matching&lt;/h3&gt;
-
- &lt;p&gt;The goal with the pattern matching API is to allow procedural macros to operate on tokens in the same way as macros-by-example. The pattern language is thus the same as that for macros-by-example.&lt;/p&gt;
-
- &lt;p&gt;There is a single macro, which I propose calling &lt;code&gt;matches&lt;/code&gt;. Its first argument is the name of a &lt;code&gt;MacroContext&lt;/code&gt;. Its second argument is the input, which must be a &lt;code&gt;TokenSlice&lt;/code&gt; (or dereferencable to one). The third argument is a pattern definition. The macro produces a &lt;code&gt;Result&amp;lt;T, ErrStruct&amp;gt;&lt;/code&gt; where &lt;code&gt;T&lt;/code&gt; is the type produced by the pattern arms. If the pattern has multiple arms, then each arm must have the same type. An error is produced if none of the arms in the pattern are matched.&lt;/p&gt;
-
- &lt;p&gt;The pattern language follows the language for defining macros-by-example (but is slightly stricter). There are two forms, a single pattern form and a multiple pattern form. If the first character is a &lt;code&gt;{&lt;/code&gt; then the pattern is treated as a multiple pattern form, if it starts with &lt;code&gt;(&lt;/code&gt; then as a single pattern form, otherwise an error (causes a panic with a &lt;code&gt;Bug&lt;/code&gt; error, as opposed to returning an &lt;code&gt;Err&lt;/code&gt;).&lt;/p&gt;
-
- &lt;p&gt;The single pattern form is &lt;code&gt;(pattern) =&amp;gt; { code }&lt;/code&gt;. The multiple pattern form is &lt;code&gt;{(pattern) =&amp;gt; { code } (pattern) =&amp;gt; { code } ... (pattern) =&amp;gt; { code }}&lt;/code&gt;. &lt;code&gt;code&lt;/code&gt; is any old Rust code which is executed when the corresponding pattern is matched. The pattern follows from macros-by-example - it is a series of characters treated as literals, meta-variables indicated with &lt;code&gt;$&lt;/code&gt;, and the syntax for matching multiple variables. Any meta-variables are available as variables in the righthand side, e.g., &lt;code&gt;$x&lt;/code&gt; becomes available as &lt;code&gt;x&lt;/code&gt;. These variables have type &lt;code&gt;TokenStream&lt;/code&gt; if they appear singly or &lt;code&gt;Vec&amp;lt;TokenStream&amp;gt;&lt;/code&gt; if they appear multiply (or &lt;code&gt;Vec&amp;lt;Vec&amp;lt;TokenStream&amp;gt;&amp;gt;&lt;/code&gt; and so forth).&lt;/p&gt;
-
- &lt;p&gt;Examples:&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;matches!(cx, input, (foo($x:expr) bar) =&amp;gt; {quote(cx, foo_bar($x).unwrap()}).unwrap()
-
- matches!(cx, input, {
- () =&amp;gt; {
- cx.err(&quot;No input?&quot;);
- }
- (foo($($x:ident),+ bar) =&amp;gt; {
- println!(&quot;found {} idents&quot;, x.len());
- quote!(($x);*).unwrap()
- }
- }
- })
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;Note that since we match AST items here, our backwards compatibility story is a bit complicated (though hopefully not much more so than with current macros).&lt;/p&gt;
-
- &lt;h3&gt;Hygiene&lt;/h3&gt;
-
- &lt;p&gt;The intention of the design is that the actual hygiene algorithm applied is irrelevant. Procedural macros should be able to use the same API if the hygiene algorithm changes (of course the result of applying the API might change). To this end, all hygiene objects are opaque and cannot be directly manipulated by macros.&lt;/p&gt;
-
- &lt;p&gt;I propose one module (&lt;code&gt;hygiene&lt;/code&gt;) and two types: &lt;code&gt;Context&lt;/code&gt; and &lt;code&gt;Scope&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;A &lt;code&gt;Context&lt;/code&gt; is attached to each token and contains all hygiene information about that token. If two tokens have the same &lt;code&gt;Context&lt;/code&gt;, then they may be compared syntactically. The reverse is not true - two tokens can have different &lt;code&gt;Context&lt;/code&gt;s and still be equal. &lt;code&gt;Context&lt;/code&gt;s can only be created by applying the hygiene algorithm and cannot be manipulated, only moved and stored.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;MacroContext&lt;/code&gt; has a method &lt;code&gt;fresh_hygiene_context&lt;/code&gt; for creating a new, fresh &lt;code&gt;Context&lt;/code&gt; (i.e., a &lt;code&gt;Context&lt;/code&gt; not shared with any other tokens).&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;MacroContext&lt;/code&gt; has a method &lt;code&gt;expansion_hygiene_context&lt;/code&gt; for getting the &lt;code&gt;Context&lt;/code&gt; where the macro is defined. This is equivalent to &lt;code&gt;.expansion_scope().direct_context()&lt;/code&gt;, but might be more efficient (and I expect it to be used a lot).&lt;/p&gt;
-
- &lt;p&gt;A &lt;code&gt;Scope&lt;/code&gt; provides information about a position within an AST at a certain point during macro expansion. For example,&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;fn foo() {
- a
- {
- b
- c
- }
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;&lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; will have different &lt;code&gt;Scope&lt;/code&gt;s. &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt; will have the same &lt;code&gt;Scope&lt;/code&gt;s, even if &lt;code&gt;b&lt;/code&gt; was written in this position and &lt;code&gt;c&lt;/code&gt; is due to macro expansion. However, a &lt;code&gt;Scope&lt;/code&gt; may contain more information than just the syntactic scopes, for example, it may contain information about pending scopes yet to be applied by the hygiene algorithm (i.e., information about &lt;code&gt;let&lt;/code&gt; expressions which are in scope).&lt;/p&gt;
-
- &lt;p&gt;Note that a &lt;code&gt;Scope&lt;/code&gt; means a scope in the macro hygiene sense, not the commonly used sense of a scope declared with &lt;code&gt;{}&lt;/code&gt;. In particular, each &lt;code&gt;let&lt;/code&gt; statement starts a new scope and the items and statements in a function body are in different scopes.&lt;/p&gt;
-
- &lt;p&gt;The functions &lt;code&gt;lookup_item_scope&lt;/code&gt; and &lt;code&gt;lookup_statement_scope&lt;/code&gt; take a &lt;code&gt;MacroContext&lt;/code&gt; and a path, represented as a &lt;code&gt;TokenSlice&lt;/code&gt;, and return the &lt;code&gt;Scope&lt;/code&gt; which that item defines or an error if the path does not refer to an item, or the item does not define a scope of the right kind.&lt;/p&gt;
-
- &lt;p&gt;The function &lt;code&gt;lookup_scope_for&lt;/code&gt; is similar, but returns the &lt;code&gt;Scope&lt;/code&gt; in which an item is declared.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;MacroContext&lt;/code&gt; has a method &lt;code&gt;expansion_scope&lt;/code&gt; for getting the scope in which the current macro is being expanded.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;Scope&lt;/code&gt; has a method &lt;code&gt;direct_context&lt;/code&gt; which returns a &lt;code&gt;Context&lt;/code&gt; for items declared directly (c.f., via macro expansion) in that &lt;code&gt;Scope&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;Scope&lt;/code&gt; has a method &lt;code&gt;nested&lt;/code&gt; which creates a fresh &lt;code&gt;Scope&lt;/code&gt; nested within the receiver scope.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;Scope&lt;/code&gt; has a static method &lt;code&gt;empty&lt;/code&gt; for creating an empty scope, that is one with no scope information at all (note that this is different from a top-level scope).&lt;/p&gt;
-
- &lt;p&gt;I expect the exact API around &lt;code&gt;Scope&lt;/code&gt;s and &lt;code&gt;Context&lt;/code&gt;s will need some work. &lt;code&gt;Scope&lt;/code&gt; seems halfway between an intuitive, algorithm-neutral abstraction, and the scopes from the sets of scopes hygiene algorithm. I would prefer a &lt;code&gt;Scope&lt;/code&gt; should be more abstract, on the other hand, macro authors may want fine-grained control over hygiene application.&lt;/p&gt;
-
- &lt;h4&gt;Manipulating hygiene information on tokens,&lt;/h4&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod hygiene {
- pub fn add(cx: &amp;amp;mut MacroContext, t: &amp;amp;Token, scope: &amp;amp;Scope) -&amp;gt; Token;
- // Maybe unnecessary if we have direct access to Tokens.
- pub fn set(t: &amp;amp;Token, cx: &amp;amp;Context) -&amp;gt; Token;
- // Maybe unnecessary - can use set with cx.expansion_hygiene_context().
- // Also, bad name.
- pub fn current(cx: &amp;amp;MacroContext, t: &amp;amp;Token) -&amp;gt; Token;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;&lt;code&gt;add&lt;/code&gt; adds &lt;code&gt;scope&lt;/code&gt; to any context already on &lt;code&gt;t&lt;/code&gt; (&lt;code&gt;Context&lt;/code&gt; should have a similar method). Note that the implementation is a bit complex - the nature of the &lt;code&gt;Scope&lt;/code&gt; might mean we replace the old context completely, or add to it.&lt;/p&gt;
-
- &lt;h4&gt;Applying hygiene when expanding the current macro&lt;/h4&gt;
-
- &lt;p&gt;By default, the current macro will be expanded in the standard way, having hygiene applied as expected. Mechanically, hygiene information is added to tokens when the macro is expanded. Assuming the sets of scopes algorithm, scopes (for example, for the macro's definition, and for the introduction) are added to any scopes already present on the token. A token with no hygiene information will thus behave like a token in a macro-by-example macro. Hygiene due to nested scopes created by the macro do not need to be taken into account by the macro author, this is handled at expansion time.&lt;/p&gt;
-
- &lt;p&gt;Procedural macro authors may want to customise hygiene application (it is common in Racket), for example, to introduce items that can be referred to by code in the call-site scope.&lt;/p&gt;
-
- &lt;p&gt;We must provide an option to expand the current macro without applying hygiene; the macro author must then handle hygiene. For this to work, the macro must be able to access information about the scope in which it is applied (see &lt;code&gt;MacroContext::expansion_scope&lt;/code&gt;, above) and to supply a &lt;code&gt;Scope&lt;/code&gt; indicating scopes that should be added to tokens following the macro expansion.&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod hygiene {
- pub enum ExpansionMode {
- Automatic,
- Manual(Scope),
- }
- }
-
- impl MacroContext {
- pub fn set_hygienic_expansion(hygiene::ExpansionMode);
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;We may wish to offer other modes for expansion which allow for tweaking hygiene application without requiring full manual application. One possible mode is where the author provides a &lt;code&gt;Scope&lt;/code&gt; for the macro definition (rather than using the scope where the macro is actually defined), but hygiene is otherwise applied automatically. We might wish to give the author the option of applying scopes due to the macro definition, but not the introduction scopes.&lt;/p&gt;
-
- &lt;p&gt;On a related note, might we want to affect how spans are applied when the current macro is expanded? I can't think of a use case right now, but it seems like something that might be wanted.&lt;/p&gt;
-
- &lt;p&gt;Blocks of tokens (that is a &lt;code&gt;Sequence&lt;/code&gt; token) may be marked (not sure how, exactly, perhaps using a distinguished context) such that it is expanded without any hygiene being applied or spans changed. There should be a function for creating such a &lt;code&gt;Sequence&lt;/code&gt; from a &lt;code&gt;TokenSlice&lt;/code&gt; in the &lt;code&gt;tokens&lt;/code&gt; module. The primary motivation for this is to handle the tokens representing the body on which an annotation-like macro is present. For a 'decorator' macro, these tokens will be untouched (passed through by the macro), and since they are not touched by the macro, they should appear untouched by it (in terms of hygiene and spans).&lt;/p&gt;
-
- &lt;h3&gt;Applying macros&lt;/h3&gt;
-
- &lt;p&gt;We provide functionality to expand a provided macro or to lookup and expand a macro.&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod apply {
- pub fn expand_macro(cx: &amp;amp;mut MacroContext,
- expansion_scope: Scope,
- macro: &amp;amp;TokenSlice,
- macro_scope: Scope,
- input: &amp;amp;TokenSlice)
- -&amp;gt; Result&amp;lt;(TokenStream, Scope), ErrStruct&amp;gt;;
- pub fn lookup_and_expand_macro(cx: &amp;amp;mut MacroContext,
- expansion_scope: Scope,
- macro: &amp;amp;TokenSlice,
- input: &amp;amp;TokenSlice)
- -&amp;gt; Result&amp;lt;(TokenStream, Scope), ErrStruct&amp;gt;;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;These functions apply macro hygiene in the usual way, with &lt;code&gt;expansion_scope&lt;/code&gt; dictating the scope into which the macro is expanded. Other spans and hygiene information is taken from the tokens. &lt;code&gt;expand_macro&lt;/code&gt; takes pending scopes from &lt;code&gt;macro_scope&lt;/code&gt;, &lt;code&gt;lookup_and_expand_macro&lt;/code&gt; uses the proper pending scopes. In order to apply the hygiene algorithm, the result of the macro must be parsable. The returned scope will contain pending scopes that can be applied by the macro to subsequent tokens.&lt;/p&gt;
-
- &lt;p&gt;We could provide versions that don't take an &lt;code&gt;expansion_scope&lt;/code&gt; and use &lt;code&gt;cx.expansion_scope()&lt;/code&gt;. Probably unnecessary.&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod apply {
- pub fn expand_macro_unhygienic(cx: &amp;amp;mut MacroContext,
- macro: &amp;amp;TokenSlice,
- input: &amp;amp;TokenSlice)
- -&amp;gt; Result&amp;lt;TokenStream, ErrStruct&amp;gt;;
- pub fn lookup_and_expand_macro_unhygienic(cx: &amp;amp;mut MacroContext,
- macro: &amp;amp;TokenSlice,
- input: &amp;amp;TokenSlice)
- -&amp;gt; Result&amp;lt;TokenStream, ErrStruct&amp;gt;;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;The &lt;code&gt;_unhygienic&lt;/code&gt; variants expand a macro as in the first functions, but do not apply the hygiene algorithm or change any hygiene information. Any hygiene information on tokens is preserved. I'm not sure if &lt;code&gt;_unhygienic&lt;/code&gt; are the right names - using these is not necessarily unhygienic, just that we are automatically applying the hygiene algorithm.&lt;/p&gt;
-
- &lt;p&gt;Note that all these functions are doing an eager expansion of macros, or in Scheme terms they are &lt;code&gt;local-expand&lt;/code&gt; functions. &lt;/p&gt;
-
- &lt;h3&gt;Looking up items&lt;/h3&gt;
-
- &lt;p&gt;The function &lt;code&gt;lookup_item&lt;/code&gt; takes a &lt;code&gt;MacroContext&lt;/code&gt; and a path represented as a &lt;code&gt;TokenSlice&lt;/code&gt; and returns a &lt;code&gt;TokenStream&lt;/code&gt; for the item referred to by the path, or an error if name resolution failed. I'm not sure where this function should live.&lt;/p&gt;
-
- &lt;h3&gt;Interned strings&lt;/h3&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod strings {
- pub struct InternedString;
-
- impl InternedString {
- pub fn get(&amp;amp;self) -&amp;gt; String;
- }
-
- pub fn intern(cx: &amp;amp;mut MacroContext, s: &amp;amp;str) -&amp;gt; Result&amp;lt;InternedString, ErrStruct&amp;gt;;
- pub fn find(cx: &amp;amp;mut MacroContext, s: &amp;amp;str) -&amp;gt; Result&amp;lt;InternedString, ErrStruct&amp;gt;;
- pub fn find_or_intern(cx: &amp;amp;mut MacroContext, s: &amp;amp;str) -&amp;gt; Result&amp;lt;InternedString, ErrStruct&amp;gt;;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;&lt;code&gt;intern&lt;/code&gt; interns a string and returns a fresh &lt;code&gt;InternedString&lt;/code&gt;. &lt;code&gt;find&lt;/code&gt; tries to find &lt;em&gt;an&lt;/em&gt; existing &lt;code&gt;InternedString&lt;/code&gt;.&lt;/p&gt;
-
- &lt;h3&gt;Spans&lt;/h3&gt;
-
- &lt;p&gt;A span gives information about where in the source code a token is defined. It also gives information about where the token came from (how it was generated, if it was generated code).&lt;/p&gt;
-
- &lt;p&gt;There should be a &lt;code&gt;spans&lt;/code&gt; module in libmacro, which will include a &lt;code&gt;Span&lt;/code&gt; type which can be easily inter-converted with the &lt;code&gt;Span&lt;/code&gt; defined in libsyntax. Libsyntax spans currently include information about stability, this will not be present in libmacro spans.&lt;/p&gt;
-
- &lt;p&gt;If the programmer does nothing special with spans, then they will be 'correct' by default. There are two important cases: tokens passed to the macro and tokens made fresh by the macro. The former will have the source span indicating where they were written and will include their history. The latter will have no source span and indicate they were created by the current macro. All tokens will have the history relating to expansion of the current macro added when the macro is expanded. At macro expansion, tokens with no source span will be given the macro use-site as their source.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;Span&lt;/code&gt;s can be freely copied between tokens.&lt;/p&gt;
-
- &lt;p&gt;It will probably useful to make it easy to manipulate spans. For example, rather than point at the macro's defining function, point at a helper function where the token is made. Or to set the origin to the current macro when the token was produced by another which should an implementation detail. I'm not sure what such an interface should look like (and is probably not necessary in an initial library).&lt;/p&gt;
-
- &lt;h3&gt;Feature gates&lt;/h3&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod features {
- pub enum FeatureStatus {
- // The feature gate is allowed.
- Allowed,
- // The feature gate has not been enabled.
- Disallowed,
- // Use of the feature is forbidden by the compiler.
- Forbidden,
- }
-
- pub fn query_feature(cx: &amp;amp;MacroContext, feature: Token) -&amp;gt; Result&amp;lt;FeatureStatus, ErrStruct&amp;gt;;
- pub fn query_feature_by_str(cx: &amp;amp;MacroContext, feature: &amp;amp;str) -&amp;gt; Result&amp;lt;FeatureStatus, ErrStruct&amp;gt;;
- pub fn query_feature_unused(cx: &amp;amp;MacroContext, feature: Token) -&amp;gt; Result&amp;lt;FeatureStatus, ErrStruct&amp;gt;;
- pub fn query_feature_by_str_unused(cx: &amp;amp;MacroContext, feature: &amp;amp;str) -&amp;gt; Result&amp;lt;FeatureStatus, ErrStruct&amp;gt;;
-
- pub fn used_feature_gate(cx: &amp;amp;MacroContext, feature: Token) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
- pub fn used_feature_by_str(cx: &amp;amp;MacroContext, feature: &amp;amp;str) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
-
- pub fn allow_feature_gate(cx: &amp;amp;MacroContext, feature: Token) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
- pub fn allow_feature_by_str(cx: &amp;amp;MacroContext, feature: &amp;amp;str) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
- pub fn disallow_feature_gate(cx: &amp;amp;MacroContext, feature: Token) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
- pub fn disallow_feature_by_str(cx: &amp;amp;MacroContext, feature: &amp;amp;str) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;The &lt;code&gt;query_*&lt;/code&gt; functions query if a feature gate has been set. They return an error if the feature gate does not exist. The &lt;code&gt;_unused&lt;/code&gt; variants do not mark the feature gate as used. The &lt;code&gt;used_&lt;/code&gt; functions mark a feature gate as used, or return an error if it does not exist.&lt;/p&gt;
-
- &lt;p&gt;The &lt;code&gt;allow_&lt;/code&gt; and &lt;code&gt;disallow_&lt;/code&gt; functions set a feature gate as allowed or disallowed for the current crate. These functions will only affect feature gates which take affect after parsing and expansion are complete. They do not affect feature gates which are checked during parsing or expansion.&lt;/p&gt;
-
- &lt;p&gt;Question: do we need the &lt;code&gt;used_&lt;/code&gt; functions? Could just call &lt;code&gt;query_&lt;/code&gt; and ignore the result.&lt;/p&gt;
-
- &lt;h3&gt;Attributes&lt;/h3&gt;
-
- &lt;p&gt;We need some mechanism for setting attributes as used. I don't actually know how the unused attribute checking in the compiler works, so I can't spec this area. But, I expect &lt;code&gt;MacroContext&lt;/code&gt; to make available some interface for reading attributes on a macro use and marking them as used.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-18T21:40:42+00:00</dc:date>
- <dc:creator>Nick Cameron</dc:creator>
- </item>
- <item rdf:about="http://geekyogre.com/rss/63eb682d-66b4-447d-8fb6-f4ed448019df">
- <title>Seif Lotfy: Skizze progress and REPL</title>
- <link>http://geekyogre.com/skizze-progress-and-repl/</link>
- <content:encoded>&lt;p&gt;&lt;img align=&quot;center&quot; height=&quot;190&quot; src=&quot;http://i.imgur.com/9z47NdA.png&quot; width=&quot;600&quot; /&gt; &lt;br /&gt;
- &lt;br /&gt; &lt;br /&gt;
- Over the last 3 weeks, based on feedback we proceeded fledging out the concepts and the code behind &lt;a href=&quot;https://github.com/skizzehq/skizze&quot;&gt;Skizze&lt;/a&gt;. &lt;br /&gt;
- &lt;a href=&quot;https://medium.com/@njpatel/&quot;&gt;Neil Patel&lt;/a&gt; suggested the following:&lt;/p&gt;
-
- &lt;hr /&gt;
-
- &lt;p&gt;&lt;em&gt;So I've been thinking about the server API. I think we want to choose one thing and do it as well as possible, instead of having six ways to talk to the server. I think that helps to keep things sane and simple overall.&lt;/em&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;em&gt;Thinking about usage, I can only really imagine Skizze in an environment like &lt;a href=&quot;https://xamarin.com/insights&quot;&gt;ours&lt;/a&gt;, which is high-throughput. I think that is it's 'home' and we should be optimising for that all day long.&lt;/em&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;em&gt;Taking that into account, I believe we have two options:&lt;/em&gt;&lt;/p&gt;
-
- &lt;ol&gt;
- &lt;li&gt;&lt;p&gt;&lt;em&gt;We go the gRPC route, provide .proto files and let people use the existing gRPC tooling to build support for their favourite language. That means we can happily give Ruby/Node/C#/etc devs a real way to get started up with Skizze almost immediately, piggy-backing on the gRPC docs etc.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
- &lt;li&gt;&lt;p&gt;&lt;em&gt;We absorb the Redis Protocol. It does everything we need, is very lean, and we can (mostly) easily adapt it for what we need to do. The downside is that to get support from other libs, there will have to be actual libraries for every language. This could slow adoption, or it might be easy enough if people can reuse existing REDIS code. It's hard to tell how that would end up.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
- &lt;/ol&gt;
-
- &lt;p&gt;&lt;em&gt;gRPC is interesting because it's built already for distributed systems, across bad networks, and obviously is bi-directional etc. Without us having to spend time on the protocol, gRPC let's us easily add features that require streaming. Like, imagine a client being able to listen for changes in count/size and be notified instantly. That's something that gRPC is built for right now.&lt;/em&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;em&gt;I think gRPC is a bit verbose, but I think it'll pay off for ease of third-party lib support and as things grow.&lt;/em&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;em&gt;The CLI could easily be built to work with gRPC, including adding support for streaming stuff etc. Which could be pretty exciting.&lt;/em&gt;&lt;/p&gt;
-
- &lt;hr /&gt;
-
- &lt;p&gt;That being said, we gave Skizze &lt;a href=&quot;https://github.com/skizzehq/&quot;&gt;a new home&lt;/a&gt;, where based on feedback we developed .proto files and started rewriting big chunks of the code.&lt;/p&gt;
-
- &lt;p&gt;We added a new wrapper called &quot;domain&quot; which represents a stream. It wraps around Count-Min-Log, Bloom Filter, Top-K and HyperLogLog++, so when feeding it values it feeds all the sketches. Later we intend to allow attaching and detaching sketches from &quot;domains&quot; (We need a better name).&lt;/p&gt;
-
- &lt;p&gt;We also implemented a gRPC API which should allow easy wrapper creation in other languages.&lt;/p&gt;
-
- &lt;p&gt;Special thanks go to &lt;a href=&quot;https://twitter.com/martinpintob&quot;&gt;Martin Pinto&lt;/a&gt; for helping out with unit tests and &lt;a href=&quot;http://dopeness.org&quot;&gt;Soren Macbeth&lt;/a&gt; for thorough feedback and ideas about the &quot;domain&quot; concept. &lt;br /&gt;
- Take a look at our initial REPL work there:&lt;/p&gt;
-
- &lt;p&gt;&lt;a href=&quot;http://geekyogre.com/content/images/2016/01/MBCY64aaKL.gif&quot;&gt;&lt;img alt=&quot;Link to this page&quot; border=&quot;0&quot; src=&quot;http://geekyogre.com/content/images/2016/01/skizze-1.png&quot; /&gt;&lt;/a&gt; &lt;br /&gt;
- &lt;a href=&quot;http://geekyogre.com/content/images/2016/01/MBCY64aaKL.gif&quot;&gt;click for GIF&lt;/a&gt;&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-18T17:41:43+00:00</dc:date>
- <dc:creator>Seif Lotfy</dc:creator>
- </item>
- <item rdf:about="http://dougbelshaw.com/blog/?p=39986">
- <title>Doug Belshaw: What a post-Persona landscape means for Open Badges</title>
- <link>http://dougbelshaw.com/blog/2016/01/18/open-badges-persona/</link>
- <content:encoded>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; I don’t work for Mozilla any more, so (like &lt;a href=&quot;https://www.youtube.com/watch?v=YQHsXMglC9A&quot;&gt;Adele&lt;/a&gt;) these are my thoughts ‘from the outside’…&lt;/em&gt;&lt;/p&gt;
- &lt;hr /&gt;
- &lt;h3&gt;Introduction&lt;/h3&gt;
- &lt;p&gt;&lt;a href=&quot;http://openbadges.org&quot;&gt;Open Badges&lt;/a&gt; is no longer a &lt;a href=&quot;http://mozilla.org&quot;&gt;Mozilla&lt;/a&gt; project. In fact, it hasn’t been for a while — the &lt;a href=&quot;http://badgealliance.org&quot;&gt;Badge Alliance&lt;/a&gt; was set up a couple of years ago to promote the specification on a both a technical and community basis. As I stated in a recent post, this is a &lt;strong&gt;good&lt;/strong&gt; thing and means that &lt;a href=&quot;http://dougbelshaw.com/blog/2015/11/08/bright-future-badges/&quot;&gt;the future is bright for Open Badges&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;However, Mozilla &lt;em&gt;is&lt;/em&gt; still involved with the Open Badges project: Mark Surman, Executive Director of the Mozilla Foundation, sits on the board of the Badge Alliance. Mozilla also pays for contractors to work on the &lt;a href=&quot;http://backpack.openbadges.org&quot;&gt;Open Badges backpack&lt;/a&gt; and there were badges earned at the &lt;a href=&quot;http://mozillafestival.org&quot;&gt;Mozilla Festival&lt;/a&gt; a few months ago.&lt;/p&gt;
- &lt;p&gt;Although it may seem strange for those used to corporates interested purely in profit, Mozilla creates what the open web needs at any given time. Like any organisation, sometimes it gets these wrong, either because the concept was flawed, or because the execution was poor. Other times, I’d argue, Mozilla doesn’t give ideas and concepts enough time to gain traction.&lt;/p&gt;
- &lt;h3&gt;The end of Persona at Mozilla&lt;/h3&gt;
- &lt;p&gt;Open Badges, at its very essence, is a technical specification. It allows credentials with metadata hard-coded into them to be issued, exchanged, and displayed. This is done in a secure, standardised manner.&lt;/p&gt;
- &lt;p&gt;&lt;img alt=&quot;OBI diagram&quot; class=&quot;alignnone wp-image-39987 size-full&quot; src=&quot;http://i1.wp.com/dougbelshaw.com/blog/wp-content/uploads/2016/01/obi-diagram.png?w=100%25&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;For users to be able to access their ‘backpack’ (i.e. the place they store badges) they needed a secure login system.Back in 2011 at the start of the Open Badges project it made sense to make use of Mozilla’s nascent &lt;a href=&quot;https://www.mozilla.org/en-US/persona/&quot;&gt;Persona&lt;/a&gt; project. This aimed to provide a way for users to easily sign into sites around the web without using their Facebook/Google logins. These ‘social’ sign-in methods mean that users are tracked around the web — something that Mozilla was obviously against.&lt;/p&gt;
- &lt;p&gt;By 2014, Persona wasn’t seen to be having the kind of ‘growth trajectory’ that Mozilla wanted. The project was transferred to &lt;a href=&quot;http://identity.mozilla.com/post/78873831485/transitioning-persona-to-community-ownership&quot;&gt;community ownership&lt;/a&gt; and most of the team left Mozilla in 2015. It was &lt;a href=&quot;https://groups.google.com/forum/#!msg/mozilla.dev.identity/mibOQrD6K0c/kt0NdMWbEQAJ&quot;&gt;announced&lt;/a&gt; that Persona would be shutting down as a Mozilla service in November 2016. While Persona will exist as an open source project, it won’t be hosted by Mozilla.&lt;/p&gt;
- &lt;h3&gt;What this means for Open Badges&lt;/h3&gt;
- &lt;p&gt;Although I’m not aware of an official announcement from the Badge Alliance, I think it’s worth making three points here.&lt;/p&gt;
- &lt;h5&gt;1. You can still use Persona&lt;/h5&gt;
- &lt;p&gt;If you’re a developer, you can still use Persona. It’s open source. It works.&lt;/p&gt;
- &lt;h5&gt;2. Persona is not central to the Open Badges Infrastructure&lt;/h5&gt;
- &lt;p&gt;The Open Badges backpack is &lt;em&gt;one&lt;/em&gt; place where users can store their badges. There are others, including the &lt;a href=&quot;https://openbadgepassport.com/&quot;&gt;Open Badge Passport&lt;/a&gt; and &lt;a href=&quot;https://www.openbadgeacademy.com/&quot;&gt;Open Badge Academy&lt;/a&gt;. MacArthur, who seed-funded the Open Badges ecosystem, have a new platform launching through &lt;a href=&quot;https://www.lrng.org/&quot;&gt;LRNG&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;It is up to the organisations behind these various solutions as to how they allow users to authenticate. They may choose to allow social logins. They may force users to create logins based on their email address. They may decide to use an open source version of Persona. It’s entirely up to them.&lt;/p&gt;
- &lt;h5&gt;3. A post-Persona badges system has its advantages&lt;/h5&gt;
- &lt;p&gt;The Persona authentication system runs off email addresses. This means that transitioning &lt;em&gt;from&lt;/em&gt; Persona to another system is relatively straightforward. It has, however, meant that for the past few years we’ve had a recurrent problem: what do you do with people being issued badges to multiple email addresses?&lt;/p&gt;
- &lt;p&gt;Tying badges to emails seemed like the easiest and fastest way to get to a critical mass in terms of Open Badge adoption. Now that’s worked, we need to think in a more nuanced way about allowing users to tie multiple identities to a single badge.&lt;/p&gt;
- &lt;h4&gt;Conclusion&lt;/h4&gt;
- &lt;p&gt;Persona was always a slightly awkward fit for Open Badges. Although, for a time, it made sense to use Persona for authentication to the Open Badges backpack, we’re now in a post-Persona landscape. This brings with it certain advantages.&lt;/p&gt;
- &lt;p&gt;As Nate Otto wrote in his post &lt;a href=&quot;https://medium.com/badge-alliance/open-badges-in-2016-a-look-ahead-3cfe5c3c9878#.l5mhiztwx&quot;&gt;Open Badges in 2016: A Look Ahead&lt;/a&gt;, the project is growing up. It’s time to move beyond what was expedient at the dawn of Open Badges and look to the future. I’m sad to see the decline of Persona, but I’m excited what the future holds!&lt;/p&gt;
- &lt;p style=&quot;text-align: right;&quot;&gt;&lt;em&gt;Header image CC BY-NC-SA &lt;a href=&quot;https://www.flickr.com/photos/blmiers2/6904758951/&quot;&gt;Barbara&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-18T11:34:19+00:00</dc:date>
- <dc:creator>Doug Belshaw</dc:creator>
- </item>
- <item rdf:about="tag:this-week-in-rust.org,2016-01-18:blog/2016/01/18/this-week-in-rust-114/">
- <title>This Week In Rust: This Week in Rust 114</title>
- <link>http://this-week-in-rust.org/blog/2016/01/18/this-week-in-rust-114/</link>
- <content:encoded>&lt;p&gt;Hello and welcome to another issue of &lt;em&gt;This Week in Rust&lt;/em&gt;!
- &lt;a href=&quot;http://rust-lang.org&quot;&gt;Rust&lt;/a&gt; is a systems language pursuing the trifecta:
- safety, concurrency, and speed. This is a weekly summary of its progress and
- community. Want something mentioned? Tweet us at &lt;a href=&quot;https://twitter.com/ThisWeekInRust&quot;&gt;@ThisWeekInRust&lt;/a&gt; or &lt;a href=&quot;mailto:corey@octayn.net?subject=This%20Week%20in%20Rust%20Suggestion&quot;&gt;send us an
- email&lt;/a&gt;!
- Want to get involved? &lt;a href=&quot;https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md&quot;&gt;We love
- contributions&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;This Week in Rust&lt;/em&gt; is openly developed &lt;a href=&quot;https://github.com/cmr/this-week-in-rust&quot;&gt;on GitHub&lt;/a&gt;.
- If you find any errors in this week's issue, &lt;a href=&quot;https://github.com/cmr/this-week-in-rust/pulls&quot;&gt;please submit a PR&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;This week's edition was edited by: &lt;a href=&quot;https://github.com/nasa42&quot;&gt;nasa42&lt;/a&gt;, &lt;a href=&quot;https://github.com/brson&quot;&gt;brson&lt;/a&gt;, and &lt;a href=&quot;https://github.com/llogiq&quot;&gt;llogiq&lt;/a&gt;.&lt;/p&gt;
- &lt;h3&gt;Updates from Rust Community&lt;/h3&gt;
- &lt;h4&gt;News &amp;amp; Blog Posts&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://gregchapple.com/contributing-to-the-rust-compiler/&quot;&gt;Guide: Contributing to the Rust compiler&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.ncameron.org/blog/a-type-safe-and-zero-allocation-library-for-reading-and-navigating-elf-files/&quot;&gt;A type-safe and zero-allocation library for reading and navigating ELF files&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;[podcast] &lt;a href=&quot;http://www.newrustacean.com/show_notes/e009/&quot;&gt;New Rustacean podcast episode 09&lt;/a&gt;. Getting into the nitty-gritty with Rust's traits.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://jadpole.github.io/arcaders/arcaders-1-12/&quot;&gt;ArcadeRS 1.12: Brawl, at last&lt;/a&gt;! Part of the series &lt;a href=&quot;https://jadpole.github.io/arcaders/arcaders-1-0/&quot;&gt;ArcadeRS 1.0: The project&lt;/a&gt; - a series whose objective is to explore the Rust programming language and ecosystem through the development of a simple, old-school shooter.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://blog.thiago.me/raspberry-pi-bare-metal-programming-with-rust/&quot;&gt;Raspberry Pi bare metal programming with Rust&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://blog.servo.org/2016/01/11/twis-47/&quot;&gt;This week in Servo 47&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.redox-os.org/news/this-week-in-redox-10/&quot;&gt;This week in Redox OS 10&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Notable New Crates &amp;amp; Project Updates&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/ebkalderon/amethyst&quot;&gt;Amethyst&lt;/a&gt;. Data-oriented game engine written in Rust.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust website&lt;/a&gt; has received some &lt;a href=&quot;https://www.reddit.com/r/rust/comments/40zxey/major_website_updates/&quot;&gt;major updates&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://packages.debian.org/stretch/rustc&quot;&gt;Rust&lt;/a&gt; and &lt;a href=&quot;https://packages.debian.org/stretch/cargo&quot;&gt;Cargo&lt;/a&gt; are now available in Debian stretch.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://community.particle.io/t/rust-on-particle-call-for-contributors/19090&quot;&gt;Rust on Particle: Call for contributors&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://dwrensha.github.io/capnproto-rust/2016/01/11/async-rpc.html&quot;&gt;capnp-rpc-rust rewritten to use async I/O&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/Ogeon/palette&quot;&gt;Palette&lt;/a&gt;. A Rust library for linear color calculations and conversion.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;Updates from Rust Core&lt;/h3&gt;
- &lt;p&gt;164 pull requests were &lt;a href=&quot;https://github.com/issues?q=is%3Apr+org%3Arust-lang+is%3Amerged+merged%3A2016-01-11..2016-01-18&quot;&gt;merged in the last week&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;See the &lt;a href=&quot;https://internals.rust-lang.org/t/triage-digest-tue-jan-05-2016/3052&quot;&gt;triage digest&lt;/a&gt; and &lt;a href=&quot;https://internals.rust-lang.org/t/subteam-reports-2016-01-08/3067&quot;&gt;subteam reports&lt;/a&gt; for more details.&lt;/p&gt;
- &lt;h4&gt;Notable changes&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30943&quot;&gt;std: Stabilize APIs for the 1.7 release&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/27807&quot;&gt;Refactor and improve: Arena, TypedArena&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/29498&quot;&gt;Let &lt;code&gt;str::replace&lt;/code&gt; take a pattern&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30295&quot;&gt;rustc_resolve: Fix bug in duplicate checking for extern crates&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30426&quot;&gt;Rewrite BTreeMap to use parent pointers&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30446&quot;&gt;Support generic associated consts&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30509&quot;&gt;Add an &lt;code&gt;impl&lt;/code&gt; for &lt;code&gt;Box&amp;lt;Error&amp;gt;&lt;/code&gt; from String&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30533&quot;&gt;Introduce &quot;obligation forest&quot; data structure into fulfillment to track backtraces&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30538&quot;&gt;Remove negate_unsigned feature gate&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30567&quot;&gt;llvm: Add support for vectorcall (X86_VectorCall) convention&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30676&quot;&gt;Make coherence more tolerant of error types&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30740&quot;&gt;Add fast path for ASCII in UTF-8 validation&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30753&quot;&gt;Downgrade unit struct match via S(..) warnings to errors&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30930&quot;&gt;Move const block checks before lowering step&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;New Contributors&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;Anton Blanchard&lt;/li&gt;
- &lt;li&gt;Jonas Tepe&lt;/li&gt;
- &lt;li&gt;Jörg Krause&lt;/li&gt;
- &lt;li&gt;Joshua Olson&lt;/li&gt;
- &lt;li&gt;kalita.alexey&lt;/li&gt;
- &lt;li&gt;Pierre Krieger&lt;/li&gt;
- &lt;li&gt;Sergey Veselkov&lt;/li&gt;
- &lt;li&gt;Simon Martin&lt;/li&gt;
- &lt;li&gt;Steffen&lt;/li&gt;
- &lt;li&gt;tomaka&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Approved RFCs&lt;/h4&gt;
- &lt;p&gt;Changes to Rust follow the Rust &lt;a href=&quot;https://github.com/rust-lang/rfcs#rust-rfcs&quot;&gt;RFC (request for comments)
- process&lt;/a&gt;. These
- are the RFCs that were approved for implementation this week:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1331&quot;&gt;RFC 1331: &lt;code&gt;src/grammar&lt;/code&gt; for the canonical grammar of the Rust language&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Final Comment Period&lt;/h4&gt;
- &lt;p&gt;Every week &lt;a href=&quot;https://rust-lang.org/team.html&quot;&gt;the team&lt;/a&gt; announces the
- 'final comment period' for RFCs and key PRs which are reaching a
- decision. Express your opinions now. &lt;a href=&quot;https://github.com/rust-lang/rfcs/labels/final-comment-period&quot;&gt;This week's FCPs&lt;/a&gt; are:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1462&quot;&gt;Add &lt;code&gt;[&lt;/code&gt; to the FOLLOW(ty) in macro future-proofing rules&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1457&quot;&gt;Rewrite &lt;code&gt;for&lt;/code&gt; loop desugaring to use language items&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1320&quot;&gt;Amend 1192 (RangeInclusive) to use an enum&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/243&quot;&gt;Trait-based exception handling&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1361&quot;&gt;Improve Cargo target-specific dependencies&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1129&quot;&gt;Add a &lt;code&gt;IndexAssign&lt;/code&gt; trait that allows overloading &quot;indexed assignment&quot; expressions like &lt;code&gt;a[b] = c&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1196&quot;&gt;Allow eliding more type parameters&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1296&quot;&gt;Add an &lt;code&gt;alias&lt;/code&gt; attribute to &lt;code&gt;#[link]&lt;/code&gt; and &lt;code&gt;-l&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;New RFCs&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1459&quot;&gt;Add a used attribute to prevent symbols from being discarded&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1461&quot;&gt;Move some net2 functionality into libstd&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1465&quot;&gt;Add &lt;code&gt;some!&lt;/code&gt; macro for unwrapping Option more safely&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1467&quot;&gt;Stabilize the &lt;code&gt;volatile_load&lt;/code&gt; and &lt;code&gt;volatile_store&lt;/code&gt; intrinsics as &lt;code&gt;ptr::volatile_read&lt;/code&gt; and &lt;code&gt;ptr::volatile_write&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;Upcoming Events&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/Rust-Meetup-Hamburg/events/227838367/&quot;&gt;1/19. Rust Hack and Learn Hamburg @ Ponton&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/Rust-Bay-Area/events/227841778/&quot;&gt;1/21. SF Bay Area: Rust Concurrency and Parallelism&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/opentechschool-berlin/&quot;&gt;1/27. OpenTechSchool Berlin: Rust Hack and Learn&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;If you are running a Rust event please add it to the &lt;a href=&quot;https://www.google.com/calendar/embed?src=apd9vmbc22egenmtu5l6c5jbfc%40group.calendar.google.com&quot;&gt;calendar&lt;/a&gt; to get
- it mentioned here. Email &lt;a href=&quot;mailto:erick.tryzelaar@gmail.com&quot;&gt;Erick Tryzelaar&lt;/a&gt; or &lt;a href=&quot;mailto:banderson@mozilla.com&quot;&gt;Brian
- Anderson&lt;/a&gt; for access.&lt;/p&gt;
- &lt;h3&gt;fn work(on: RustProject) -&amp;gt; Money&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://maidsafe.net/rust_engineer.html&quot;&gt;Rust Engineer&lt;/a&gt; at MaidSafe.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://careers.mozilla.org/en-US/position/ozy21fwU&quot;&gt;Research Engineer - Servo&lt;/a&gt; at Mozilla.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://careers.mozilla.org/en-US/position/o0H41fww&quot;&gt;Senior Research Engineer - Rust&lt;/a&gt; at Mozilla.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://plv.mpi-sws.org/rustbelt/&quot;&gt;PhD and postdoc positions&lt;/a&gt; at MPI-SWS.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;&lt;em&gt;Tweet us at &lt;a href=&quot;https://twitter.com/ThisWeekInRust&quot;&gt;@ThisWeekInRust&lt;/a&gt; to get your job offers listed here!&lt;/em&gt;&lt;/p&gt;
- &lt;h3&gt;Crate of the Week&lt;/h3&gt;
- &lt;p&gt;This week's Crate of the Week is &lt;a href=&quot;https://github.com/alexcrichton/toml-rs&quot;&gt;toml&lt;/a&gt;, a crate for all our configuration needs, simple yet effective.&lt;/p&gt;
- &lt;p&gt;Thanks to &lt;a href=&quot;https://users.rust-lang.org/users/stebalien&quot;&gt;Steven Allen&lt;/a&gt; for the suggestion.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://users.rust-lang.org/t/crate-of-the-week/2704&quot;&gt;Submit your suggestions for next week&lt;/a&gt;!&lt;/p&gt;
- &lt;h3&gt;Quote of the Week&lt;/h3&gt;
- &lt;blockquote&gt;
- &lt;p&gt;Borrow/lifetime errors are usually Rust compiler bugs.
- Typically, I will spend 20 minutes detailing the precise conditions of
- the bug, using language that understates my immense knowledge, while
- demonstrating sympathetic understanding of the pressures placed on a
- Rust compiler developer, who is also probably studying for several exams
- at the moment. The developer reading my bug report may not understand
- this stuff as well as I do, so I will carefully trace the lifetimes of
- each variable, where memory is allocated on the stack vs the heap, which
- struct or function owns a value at any point in time, where borrows
- begin and where they... oh yeah, actually that variable really doesn't
- live long enough.&lt;/p&gt;
- &lt;/blockquote&gt;
- &lt;p&gt;— &lt;a href=&quot;https://www.reddit.com/r/rust/comments/4084yx/my_trick_when_i_get_stuck_as_a_beginner/cysqz3s&quot;&gt;peterjoel on /r/rust&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Thanks to &lt;a href=&quot;https://users.rust-lang.org/users/WaDelma&quot;&gt;Wa Delma&lt;/a&gt; for the suggestion.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://users.rust-lang.org/t/twir-quote-of-the-week/328&quot;&gt;Submit your quotes for next week&lt;/a&gt;!&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-18T05:00:00+00:00</dc:date>
- <dc:creator>Corey Richardson</dc:creator>
- </item>
- <item rdf:about="http://nikkisquared.github.io/2016/01/17/what-does-your-work-mean-part-2.html">
- <title>Nikki Bee: Okay, But What Does Your Work Actually Mean, Nikki? Part 2: The Fetch Standard and Servo</title>
- <link>http://nikkisquared.github.io/2016/01/17/what-does-your-work-mean-part-2.html</link>
- <content:encoded>&lt;p&gt;In my previous post, I started discussing in more detail what my internship entails, by talking about my first contribution to Servo. As a refresher, my first contribution was as part of my application to Outreachy, which I later revisited during my internship after a change I introduced to the HTML Standard it relied on. I’m going to expand on that last point today- specifically, how easy it is to introduce changes in &lt;a href=&quot;https://wiki.whatwg.org/wiki/FAQ#What_is_the_WHATWG.3F&quot;&gt;WHATWG&lt;/a&gt;’s various standards. I’m also going to talk about how this accessibility to changing web standards affects how I can understand it, how I can help improve it, and my work on Servo.&lt;/p&gt;
-
- &lt;h3&gt;Two Ways To Change&lt;/h3&gt;
-
- &lt;p&gt;There are many ways to &lt;a href=&quot;https://wiki.whatwg.org/wiki/What_you_can_do&quot;&gt;get involved with WHATWG&lt;/a&gt;, but there are two that I’ve become the most familiar with: firstly, by opening a discussion about a perceived issue and asking how it should be resolved; secondly, by taking on an issue approved as needing change and making the desired change. I’ve almost entirely only done the former, and the latter only for some minor typos. Any changes that relate directly to my work, however minor, are significant for me though! Like I discussed in my previous post, I brought attention to &lt;a href=&quot;https://github.com/whatwg/html/issues/296&quot;&gt;an inconsistency&lt;/a&gt; that was resolved, giving me a new task of updating my first contribution to Servo to reflect the change in the HTML Standard. I’ve done that several times since, for the Fetch Standard.&lt;/p&gt;
-
- &lt;h3&gt;Understanding Fetch&lt;/h3&gt;
-
- &lt;p&gt;My first two weeks of my internship were spent on reading through the majority of the &lt;a href=&quot;https://fetch.spec.whatwg.org/&quot;&gt;Fetch Standard&lt;/a&gt;, primarily the various Fetch functions. I took many notes describing the steps to myself, annotated with questions I had and the answers I got from either other people on the Servo team who had worked with Fetch (including my internship mentor, of course!) or people from WHATWG who were involved in the Fetch Standard. Getting so familiar with Fetch meant a few things: I would notice minor errors (such as an out of date link) that I could submit a &lt;a href=&quot;https://github.com/whatwg/fetch/pull/173&quot;&gt;simple fix for&lt;/a&gt;, or a bigger issue that I couldn’t resolve myself.&lt;/p&gt;
-
- &lt;h3&gt;Discussions &amp;amp; Resolutions&lt;/h3&gt;
-
- &lt;p&gt;I’m going to go into more detail about some of those bigger issues. From my perspective, when I start a discussion about a piece of documentation (such as the Fetch Standard, or reading about a programming library Servo uses), I go into it thinking “Either this documentation is incorrect, or my understanding is incorrectâ€. Whichever the answer is, it doesn’t mean that the documentation is bad, or that I’m bad at reading comprehension. I understand best by building up a model of something in my head, putting that to practice, and asking a lot of questions along the way. I learn by getting things wrong and figuring out why I was wrong, and sometimes in the process I uncover a point that could be made more clear, or an inconsistency! I have good examples of both of the different outcomes I listed, which I’ll cover over the next two sections.&lt;/p&gt;
-
- &lt;h5&gt;Looking For The Big Picture&lt;/h5&gt;
-
- &lt;p&gt;Early on in my initial review of the Fetch Standard’s several protocols, I found a major step that seemed to have no use. I understood that since I was learning Fetch on a step-by-step basis, I did not have a view of the bigger picture, so I asked around what I was missing that would help me understand this. One of the people I work with on implementing Fetch agreed with me that the step seemed to have no purpose, and so we decided to &lt;a href=&quot;https://github.com/whatwg/fetch/issues/174&quot;&gt;open an issue&lt;/a&gt; asking about removing it from the standard. It turned out that I had actually missed the meaning of it, as we learned. However, instead of leaving it there, I shifted the issue into asking for some explanatory notes on why this step is needed, which was fulfilled. This meant that I would have a reference to go back to should I forget the significance of the step, and that people reading the Fetch Standard in the future would be much less likely to come to the same incorrect conclusion I had.&lt;/p&gt;
-
- &lt;h5&gt;A Confusing Order&lt;/h5&gt;
-
- &lt;p&gt;Shortly after I had first discovered that apparent issue, I found myself struggling to comprehend a sequence of actions in another Fetch protocol. The specification seemed to say that part of an early step was meant to only be done after the final step. I unfortunately don’t remember details of the discussion I had about this- if there was a reason for why it was organized like this, I forget what it was. Regardless, it was agreed that &lt;a href=&quot;https://github.com/whatwg/fetch/issues/176&quot;&gt;moving those sub-steps&lt;/a&gt; to be actually listed after the step they’re supposed to run after would be a good change. This meant that I would need to re-organize my notes to reflect the re-arranged sequence of actions, as well as have an easier time being able to follow this part of the Fetch Standard.&lt;/p&gt;
-
- &lt;h3&gt;A Living Standard&lt;/h3&gt;
-
- &lt;p&gt;Like I said at the start of this post, I’m going to talk about how changes in the Fetch Standard affects my work on Servo itself. What I’ve covered so far has mostly been how changes affect my understanding of the standard itself. A key aspect in understanding the Fetch protocols is reviewing them for updates that impact me. WHATWG labels every standard they author as a “&lt;a href=&quot;https://wiki.whatwg.org/wiki/FAQ#What_does_.22Living_Standard.22_mean.3F&quot;&gt;Living Standard&lt;/a&gt;†for good reason. It was one thing for me to learn how easy it is to introduce changes, while knowing exactly what’s going on, but it’s another for me to understand that anybody else can, and often does, make changes to the Fetch Standard!&lt;/p&gt;
-
- &lt;h5&gt;Changes Over Time&lt;/h5&gt;
-
- &lt;p&gt;When an update is made to the Fetch Standard, it’s not so difficult to deal with as one might imagine. The Fetch Standard always notes the last day it was updated at the top of the document, I follow a Twitter account that &lt;a href=&quot;https://twitter.com/fetchstandard&quot;&gt;posts about updates&lt;/a&gt;, and all the history can be &lt;a href=&quot;https://github.com/whatwg/fetch/commits&quot;&gt;seen on GitHub&lt;/a&gt; which will show me exactly what has been changed as well as some discussion on what the change does. All of these together alert me to the fact that the Fetch Standard has been modified, and I can quickly see what was revised. If it’s relevant to what I’m going to be implementing, I update my notes to match it. Occasionally, I need to change existing code to reflect the new Standard, which is also easily done by comparing my new notes to the Fetch implementation in Servo!&lt;/p&gt;
-
- &lt;h5&gt;Snapshots&lt;/h5&gt;
-
- &lt;p&gt;From all of this, it might sound like the Fetch Standard is unfinished, or unreliable/inconsistent. I don’t mean to misrepresent it- the many small improvements help make the Fetch Standard, like all of WHATWG’s standards, better and more reliable. You can think of the status of the Fetch Standard at any point in time as a single, working snapshot. If somebody implemented all of Fetch as it is now, they’d have something that works by itself correctly. A different snapshot of Fetch is just that- different. It will have an improvement or two, but that doesn’t obsolete anybody who implemented it previously. It just means if they revisit the implementation, they’ll have things to update.&lt;/p&gt;
-
- &lt;p&gt;Third post over.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-17T20:20:27+00:00</dc:date>
- </item>
- <item rdf:about="http://ngokevin.com/blog/aframe-component/">
- <title>Kevin Ngo: How to Write an A-Frame VR Component</title>
- <link>http://ngokevin.com/blog/aframe-component/</link>
- <content:encoded>&lt;img align=&quot;left&quot; hspace=&quot;5&quot; src=&quot;http://thevrjump.com/assets/img/articles/aframe-system/aframe-example.jpg&quot; width=&quot;320&quot; /&gt;Abstract representation of components by @rubenmueller of thevrjump.com.
-
- &lt;p&gt;&lt;a href=&quot;http://ngokevin.com/blog/aframe&quot;&gt;A-Frame&lt;/a&gt; is a WebVR framework that introduces the
- &lt;a href=&quot;http://ngokevin.com/blog/aframe-vs-3dml&quot;&gt;entity-component system&lt;/a&gt; (&lt;a href=&quot;http://ngokevin.com/rss/docs&quot;&gt;docs&lt;/a&gt;) to the DOM. The
- entity-component system treats every &lt;strong&gt;entity&lt;/strong&gt; in the scene as a placeholder
- object which we apply and mix &lt;strong&gt;components&lt;/strong&gt; to in order to add appearance,
- behavior, and functionality. A-Frame comes with some standard components out of
- the box like camera, geometry, material, light, or sound. However, people can
- write, publish, and register their own components to do &lt;strong&gt;whatever&lt;/strong&gt; they want
- like have entities &lt;a href=&quot;https://github.com/dmarcos/a-invaders/tree/master/js/components&quot;&gt;collide/explode/spawn&lt;/a&gt;, be controlled by
- &lt;a href=&quot;https://github.com/ngokevin/aframe-physics-components&quot;&gt;physics&lt;/a&gt;, or &lt;a href=&quot;https://jsbin.com/dasefeh/edit?html,output&quot;&gt;follow a path&lt;/a&gt;. Today, we'll be going through
- how we can write our own A-Frame components.&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;p&gt;Note that this tutorial will be covering the upcoming release of &lt;a href=&quot;https://github.com/aframevr/aframe/blob/dev/CHANGELOG.md#dev&quot;&gt;A-Frame
- 0.2.0&lt;/a&gt; which vastly improves the component API.&lt;/p&gt;
- &lt;/blockquote&gt;
- &lt;h3&gt;Table of Contents&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#what-a-component-looks-like&quot;&gt;What a Component Looks Like&lt;/a&gt;&lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#from-the-dom&quot;&gt;From the DOM&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#under-the-hood&quot;&gt;Under the Hood&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#defining-the-schema&quot;&gt;Defining the Schema&lt;/a&gt;&lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#property-types&quot;&gt;Property Types&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#single-property-schemas&quot;&gt;Single-Property Schemas&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#multiple-property-schemas&quot;&gt;Multiple-Property Schemas&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#defining-the-lifecycle-methods&quot;&gt;Defining the Lifecycle Methods&lt;/a&gt;&lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#component-init-set-up&quot;&gt;Component.init() - Set Up&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#component-update-olddata-do-the-magic&quot;&gt;Component.update(oldData) - Do the Magic&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#component-remove-tear-down&quot;&gt;Component.remove() - Tear Down&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#component-tick-time-background-behavior&quot;&gt;Component.tick() - Background Behavior&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#component-pause-and-component-play-stop-and-go&quot;&gt;Component.pause() and Component.play() - Stop and Go&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#boilerplate&quot;&gt;Boilerplate&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#examples&quot;&gt;Examples&lt;/a&gt;&lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#text-component&quot;&gt;Text Component&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#physics-components&quot;&gt;Physics Components&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#layout-component&quot;&gt;Layout Component&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;What a Component Looks Like&lt;/h3&gt;
- &lt;p&gt;A component contains a bucket of data in the form of component properties. This
- data is used to modify the entity. For example, we might have an &lt;em&gt;engine&lt;/em&gt;
- component. Possible properties might be &lt;em&gt;horsepower&lt;/em&gt; or &lt;em&gt;cylinders&lt;/em&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;http://thevrjump.com/assets/img/articles/aframe-system/aframe-system.jpg&quot; /&gt;
- &lt;/p&gt;&lt;div class=&quot;page-caption&quot;&gt;&lt;span&gt;
- Abstract representation of a component by @rubenmueller of thevrjump.com.
- &lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;
- &lt;h4&gt;From the DOM&lt;/h4&gt;
- &lt;p&gt;Let's first see what a component looks like from the DOM.&lt;/p&gt;
- &lt;p&gt;For example, the &lt;a href=&quot;https://aframe.io/docs/components/light.html&quot;&gt;light component&lt;/a&gt; has properties such as type, color,
- and intensity. In A-Frame, we register and configure a component to an entity
- using an HTML attribute and a style-like syntax:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;type: point; color: crimson; intensity: 2.5&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;This would give us a light in the scene. To demonstrate composability, we could
- give the light a spherical representation by mixing in the &lt;a href=&quot;https://aframe.io/docs/components/geometry.html&quot;&gt;geometry
- component&lt;/a&gt;.&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;primitive: sphere; radius: 5&quot;&lt;/span&gt;
- &lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;type: point; color: crimson; intensity: 2.5&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Or we can configure the position component to move the light sphere a bit to the right.&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;primitive: sphere; radius: 5&quot;&lt;/span&gt;
- &lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;type: point; color: crimson; intensity: 2.5&quot;&lt;/span&gt;
- &lt;span class=&quot;na&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;5 0 0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Given the style-like syntax and that it modifies the appearance and behavior of
- DOM nodes, component properties can be thought of as a rough analog to CSS. In
- the near future, I can imagine component property stylesheets.&lt;/p&gt;
- &lt;h4&gt;Under the Hood&lt;/h4&gt;
- &lt;p&gt;Now let's see what a component looks like &lt;strong&gt;under the hood&lt;/strong&gt;. A-Frame's most
- basic component is the &lt;a href=&quot;https://aframe.io/docs/components/position.html&quot;&gt;position component&lt;/a&gt;:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;AFRAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'position'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vec3'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
-
- &lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;object3D&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
- &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;object3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;The position component uses only a tiny subset of the component API, but what
- this does is register the component with the name &quot;position&quot;, define a &lt;code&gt;schema&lt;/code&gt;
- where the component's value with be parsed to an &lt;code&gt;{x, y, z}&lt;/code&gt; object, and when
- the component initializes or the component's data updates, set the position of
- the entity with the &lt;code&gt;update&lt;/code&gt; callback. &lt;code&gt;this.el&lt;/code&gt; is a reference from the
- component to the DOM element, or entity, and &lt;code&gt;object3D&lt;/code&gt; is the entity's
- &lt;a href=&quot;http://threejs.org/&quot;&gt;three.js&lt;/a&gt;. Note that A-Frame is built on top of three.js so many
- components will be using the three.js API.&lt;/p&gt;
- &lt;p&gt;So we see that components consist of a name and a definition, and then they can
- be registered to A-Frame. We saw the the position component definition defined
- a &lt;code&gt;schema&lt;/code&gt; and an &lt;code&gt;update&lt;/code&gt; handler. Components simply consist of the &lt;code&gt;schema&lt;/code&gt;,
- which defines the shape of the data, and several handlers for the component to
- modify the entity in reaction to different types of events.&lt;/p&gt;
- &lt;p&gt;Here is the current list of properties and methods of a component definition:&lt;/p&gt;
- &lt;table class=&quot;pure-table-striped&quot;&gt;
- &lt;tbody&gt;&lt;tr&gt;
- &lt;th&gt;Property&lt;/th&gt;
- &lt;th&gt;Description&lt;/th&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;data&lt;/td&gt;
- &lt;td&gt;Data of the component derived from the schema default values, mixins, and the entity's attributes.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;el&lt;/td&gt;
- &lt;td&gt;Reference to the &lt;a href=&quot;https://aframe.io/docs/core/entity.html&quot;&gt;entity&lt;/a&gt; element.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;schema&lt;/td&gt;
- &lt;td&gt;Names, types, and default values of the component property value(s)&lt;/td&gt;
- &lt;/tr&gt;
- &lt;/tbody&gt;&lt;/table&gt;
-
- &lt;table class=&quot;pure-table-striped&quot;&gt;
- &lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;init&lt;/td&gt;
- &lt;td&gt;Called once when the component is initialized.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;update&lt;/td&gt;
- &lt;td&gt;Called both when the component is initialized and whenever the component's data changes (e.g, via &lt;i&gt;setAttribute&lt;/i&gt;).&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;remove&lt;/td&gt;
- &lt;td&gt;Called when the component detaches from the element (e.g., via &lt;i&gt;removeAttribute&lt;/i&gt;).&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;tick&lt;/td&gt;
- &lt;td&gt;Called on each render loop or tick of the scene.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;play&lt;/td&gt;
- &lt;td&gt;Called whenever the scene or entity plays to add any background or dynamic behavior.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;pause&lt;/td&gt;
- &lt;td&gt;Called whenever the scene or entity pauses to remove any background or dynamic behavior.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;/tbody&gt;&lt;/table&gt;
-
- &lt;h3&gt;Defining the Schema&lt;/h3&gt;
- &lt;p&gt;The component's schema defines what type of data it takes. A component can
- either be single-property or consist of multiple properties. And properties
- have &lt;em&gt;property types&lt;/em&gt;. Note that single-property schemas and property types are
- being released in A-Frame &lt;code&gt;v0.2.0&lt;/code&gt;.&lt;/p&gt;
- &lt;p&gt;A property might look like:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'int'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;And a schema consisting of multiple properties might look like:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#FFF'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'selector'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;uv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1 1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Since components in the entity-component system are just buckets of data that
- are used to affect the appearance or behavior of the entity, the schema plays a
- crucial role in the definition of the component.&lt;/p&gt;
- &lt;h4&gt;Property Types&lt;/h4&gt;
- &lt;p&gt;A-Frame comes with several built-in property types such as &lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;,
- &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;selector&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, or &lt;code&gt;vec3&lt;/code&gt;. Every single property is assigned a
- type, whether explicitly through the &lt;code&gt;type&lt;/code&gt; key or implictly via inferring the
- value. And each type is used to assign &lt;code&gt;parse&lt;/code&gt; and &lt;code&gt;stringify&lt;/code&gt; functions. The
- parser deserializes the incoming string value from the DOM to be put into the
- component's data object. The stringifier is used when using &lt;code&gt;setAttribute&lt;/code&gt; to
- serialize back to the DOM.&lt;/p&gt;
- &lt;p&gt;We can actually define and register our own property types:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;AFRAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerPropertyType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'radians'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
-
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
-
- &lt;span class=&quot;c1&quot;&gt;// Default stringify is .toString().&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;h4&gt;Single-Property Schemas&lt;/h4&gt;
- &lt;p&gt;If a component has only one property, then it must either have a &lt;code&gt;type&lt;/code&gt; or a
- &lt;code&gt;default&lt;/code&gt; value. If the type is defined, then the type is used to parse and
- coerce the string retrieved from the DOM (e.g., &lt;code&gt;getAttribute&lt;/code&gt;). Or if the
- default value is defined, the default value is used to infer the type.&lt;/p&gt;
- &lt;p&gt;Take for instance the &lt;a href=&quot;https://aframe.io/docs/components/visible.html&quot;&gt;visible component&lt;/a&gt;. The schema property
- definition implicitly defines it as a boolean:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;AFRAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'visible'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;c1&quot;&gt;// Type will be inferred to be boolean.&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
-
- &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Or the &lt;a href=&quot;https://aframe.io/docs/components/rotation.html&quot;&gt;rotation component&lt;/a&gt; which explicitly defines the value as a &lt;code&gt;vec3&lt;/code&gt;:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;AFRAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rotation'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;c1&quot;&gt;// Default value will be 0, 0, 0 as defined by the vec3 property type.&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vec3'&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
-
- &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Using these defined property types, schemas are processed by
- &lt;code&gt;registerComponent&lt;/code&gt; to inject default values, parsers, and stringifiers for
- each property. So if a default value is not defined, the default value will be
- whatever the property type defines as the &quot;default default value&quot;.&lt;/p&gt;
- &lt;h4&gt;Multiple-Property Schemas&lt;/h4&gt;
- &lt;p&gt;If a component has multiple properties (or one named property), then it consists of
- one or more property definitions, in the form described above, in an object keyed by
- property name. For instance, a physics body component might define a schema:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;AFRAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'physics-body'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;boundingBox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vec3'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;mass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;velocity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vec3'&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Having multiple properties is what makes the component take the syntax in the
- form of &lt;code&gt;physics=&quot;mass: 2; velocity: 1 1 1&quot;&lt;/code&gt;.&lt;/p&gt;
- &lt;p&gt;With the schema defined, all data coming into the component will be passed
- through the schema for parsing. Then in the lifecycle methods, the component
- has access to &lt;code&gt;this.data&lt;/code&gt; which in a single-property schema is a value and in a
- multiple-propery schema is an object.&lt;/p&gt;
- &lt;h3&gt;Defining the Lifecycle Methods&lt;/h3&gt;
- &lt;h4&gt;Component.init() - Set Up&lt;/h4&gt;
- &lt;p&gt;&lt;code&gt;init&lt;/code&gt; is called once in the component's lifecycle when it is mounted to the
- entity. &lt;code&gt;init&lt;/code&gt; is generally used to set up variables or members that may used
- throughout the component or to set up state. Though not every component will
- need to define an &lt;code&gt;init&lt;/code&gt; handler. Sort of like the component-equivalent method
- to &lt;code&gt;createdCallback&lt;/code&gt; or &lt;code&gt;React.ComponentDidMount&lt;/code&gt;.&lt;/p&gt;
- &lt;p&gt;For example, the &lt;code&gt;look-at&lt;/code&gt; component's &lt;code&gt;init&lt;/code&gt; handler sets up some variables:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target3D&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Vector3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
-
- &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;h4&gt;Component.update(oldData) - Do the Magic&lt;/h4&gt;
- &lt;p&gt;The &lt;code&gt;update&lt;/code&gt; handler is called both at the beginning of the component's
- lifecycle with the initial &lt;code&gt;this.data&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; every time the component's data
- changes (generally during the entity's &lt;code&gt;attributeChangedCallback&lt;/code&gt; like with a
- &lt;code&gt;setAttribute&lt;/code&gt;). The update handler gets access to the previous state of the
- component data passed in through &lt;code&gt;oldData&lt;/code&gt;. The previous state of the component
- can be used to tell exactly which properties changed to do more granular
- updates.&lt;/p&gt;
- &lt;p&gt;The update handler uses &lt;code&gt;this.data&lt;/code&gt; to modify the entity, usually interacting
- with three.js APIs. One of the simplest update handlers is the
- &lt;a href=&quot;https://aframe.io/docs/components/visible.html&quot;&gt;visible&lt;/a&gt; component's:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;A slightly more complex update handler might be the &lt;a href=&quot;https://aframe.io/docs/components/light.html&quot;&gt;light&lt;/a&gt; component's,
- which we'll show via abbreviated code:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;oldData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diffData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oldData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{});&lt;/span&gt;
-
- &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'type'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diffData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;c1&quot;&gt;// If there is an existing light and the type hasn't changed, update light.&lt;/span&gt;
- &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;diffData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diffData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;c1&quot;&gt;// No light exists yet or the type of light has changed, create a new light.&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
-
- &lt;span class=&quot;c1&quot;&gt;// Register the object3D of type `light` to the entity.&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setObject3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'light'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;The entity's &lt;code&gt;object3D&lt;/code&gt; is a plain THREE.Object3D. Other three.js object types
- such as meshes, lights, and cameras can be set with &lt;code&gt;setObject3D&lt;/code&gt; where they
- will be appeneded to the entity's &lt;code&gt;object3D&lt;/code&gt;.&lt;/p&gt;
- &lt;h4&gt;Component.remove() - Tear Down&lt;/h4&gt;
- &lt;p&gt;The &lt;code&gt;remove&lt;/code&gt; handler is called when the component detaches from the entity such
- as with &lt;code&gt;removeAttribute&lt;/code&gt;. This is generally used to remove all modifications,
- listeners, and behaviors to the entity that the component added.&lt;/p&gt;
- &lt;p&gt;For example, when the &lt;a href=&quot;https://aframe.io/docs/components/light.html&quot;&gt;light component&lt;/a&gt; detaches, it removes the light
- it previously attached from the entity and thus the scene:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeObject3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'light'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;h4&gt;Component.tick(time) - Background Behavior&lt;/h4&gt;
- &lt;p&gt;The &lt;code&gt;tick&lt;/code&gt; handler is called on every single tick or render loop of the scene.
- So expect it to run on the order of 60-120 times for second. The global uptime of
- the scene in seconds is passed into the tick handler.&lt;/p&gt;
- &lt;p&gt;For example, the &lt;a href=&quot;https://aframe.io/docs/components/look-at.html&quot;&gt;look-at&lt;/a&gt; component, which instructs an entity to
- look at another target entity, uses the tick handler to update the rotation in
- case the target entity changes its position:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;c1&quot;&gt;// target3D and vector are set from the update handler.&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lookAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setFromMatrixPosition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;matrixWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;h4&gt;Component.pause() and Component.play() - Stop and Go&lt;/h4&gt;
- &lt;p&gt;To support pause and play, just as with a video game or to toggle entities for
- performance, components can implement &lt;code&gt;play&lt;/code&gt; and &lt;code&gt;pause&lt;/code&gt; handlers. These are
- invoked when the component's entity runs its &lt;code&gt;play&lt;/code&gt; or &lt;code&gt;pause&lt;/code&gt; method. When an
- entity plays or pauses, all of its child entities are also played or paused.&lt;/p&gt;
- &lt;p&gt;Components should implement play or pause handlers if they register any
- dynamic, asynchronous, or background behavior such as animations, event
- listeners, or tick handlers.&lt;/p&gt;
- &lt;p&gt;For example, the &lt;code&gt;look-controls&lt;/code&gt; component simply removes its event listeners
- such that the camera does not move when the scene is paused, and it adds its
- event listeners when the scene starts playing or is resumed:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;pause&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeEventListeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
-
- &lt;span class=&quot;nx&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addEventListeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;h3&gt;Boilerplate&lt;/h3&gt;
- &lt;p&gt;I suggest that people start off with my &lt;a href=&quot;https://github.com/ngokevin/aframe-component-boilerplate&quot;&gt;component boilerplate&lt;/a&gt;,
- even hardcore tool junkies. This will get you straight into building a
- component and comes with everything you will need to publish your component
- into the wild. The boilerplate handles creating a stubbed component, build
- steps for both NPM and browser distribution files, and publishing to Github
- Pages.&lt;/p&gt;
- &lt;p&gt;Generally with boilerplates, it is better to start from scratch and build your
- own boilerplate, but the A-Frame component boilerplate contains a lot of tribal
- inside knowledge about A-Frame and is updated frequently to reflect new things
- landing on A-Frame. The only possibly opinionated pieces about the boilerplate
- is the development tools it internally uses that are hidden away by NPM
- scripts.&lt;/p&gt;
- &lt;h3&gt;Examples&lt;/h3&gt;
- &lt;p&gt;Under construction. Stay tuned!&lt;/p&gt;
- &lt;h4&gt;Text Component&lt;/h4&gt;
- &lt;p&gt;&lt;a href=&quot;https://github.com/ngokevin/aframe-text-component&quot;&gt;Text component&lt;/a&gt;&lt;/p&gt;
- &lt;h4&gt;Physics Components&lt;/h4&gt;
- &lt;p&gt;&lt;a href=&quot;https://github.com/ngokevin/aframe-physics-components&quot;&gt;Physics components&lt;/a&gt;&lt;/p&gt;
- &lt;h4&gt;Layout Component&lt;/h4&gt;
- &lt;p&gt;&lt;a href=&quot;https://github.com/ngokevin/aframe-layout-component&quot;&gt;Layout component&lt;/a&gt;&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-17T00:00:00+00:00</dc:date>
- </item>
- <item rdf:about="http://blog.gerv.net/?p=3527">
- <title>Gervase Markham: Convenient… and Creepy</title>
- <link>http://feedproxy.google.com/~r/HackingForChrist/~3/DN054t04_dE/</link>
- <content:encoded>&lt;p&gt;The last Mozilla All-Hands was at one of the hotels in the Walt Disney World Resort in Florida. Every attendee was issued with one of these (although their use was optional):&lt;br /&gt;
- &lt;a href=&quot;http://blog.gerv.net/files/2016/01/Disneys_MagicBand.jpg&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-3530&quot; src=&quot;http://blog.gerv.net/files/2016/01/Disneys_MagicBand-1024x832.jpg&quot; width=&quot;292&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;It’s called a “Magic Bandâ€. You register it online and connect it to your Disney account, and then it can be used for park entry, entry to pre-booked rides so you don’t have to queue (called “FastPass+â€), payment, picking up photos, as your room key, and all sorts of other convenient features. Note that it has no UI whatsoever – no lights, no buttons. Not even a battery compartment. (It does contain a battery, but it’s not replaceable.) These are specific design decisions – the aim is for ultra-simple convenience.&lt;/p&gt;
- &lt;p&gt;One of the talks we had at the All Hands was from one of the Magic Band team. The audience reactions to some of the things he said was really interesting. He gave the example of Cinderella wishing you a Happy Birthday as you walk round the park. “Cinderella just knowsâ€, he said. Of course, in fact, her costume’s tech prompts her when it silently reads your Magic Band from a distance. This got some initial impressed applause, but it was noticeable that after a few moments, it wavered – people were thinking “Cool… er, but creepy?â€&lt;/p&gt;
- &lt;p&gt;The Magic Band also has range sufficient that Disney can track you around the park. This enables some features which are good for both customers and Disney – for example, they can use it for load balancing. If one area of the park seems to be getting overcrowded, have some characters pop up in a neighbouring area to try and draw people away. But it means that they always know where you are and where you’ve been.&lt;/p&gt;
- &lt;p&gt;My take-away from learning about the Magic Band is that it’s really hard to have a technical solution to this kind of requirement which allows all the Convenient features but not the Creepy features. Disney does offer an RFID-card-based solution for the privacy-conscious which does some of these things, but not all of them. And it’s easier to lose. It seems to me that the only way to distinguish the two types of feature, and get one and not the other, is policy – either the policy of the organization, or external restrictions on them (e.g. from a watchdog body’s code of conduct they sign up to, or from law). And it’s often not in the organization’s interest to limit themselves in this way.&lt;/p&gt;
- &lt;img alt=&quot;&quot; height=&quot;1&quot; src=&quot;http://feeds.feedburner.com/~r/HackingForChrist/~4/DN054t04_dE&quot; width=&quot;1&quot; /&gt;</content:encoded>
- <dc:date>2016-01-16T12:18:38+00:00</dc:date>
- <dc:creator>gerv</dc:creator>
- </item>
- <item rdf:about="https://www.christianheilmann.com/?p=4957">
- <title>Christian Heilmann: Don’t tell me what my browser can’t do!</title>
- <link>https://www.christianheilmann.com/2016/01/16/dont-tell-me-what-my-browser-cant-do/</link>
- <content:encoded>&lt;p&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;Chances are, your guess is wrong!&lt;/em&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;you are obviously in the wrong place&quot; src=&quot;https://d262ilb51hltx0.cloudfront.net/max/800/1*l9jPbOyAl00kjPhyNYA-IQ.jpeg&quot; width=&quot;100%&quot; /&gt;Arrogance towards possible customers never pays out – as shown in “Pretty Womanâ€&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;There is nothing more frustrating than being capable of something and not getting a chance to do it. The same goes for being blocked out from something although you are capable of consuming it. Or you’re even willing to put some extra effort or even money in and you still don’t get to consume it.&lt;/p&gt;
-
- &lt;p&gt;For example, I’d happily pay $50 a month to get access to Netflix’s world-wide library from any country I’m in. But the companies Netflix get their content from won’t go for that. Movies and TV show are budgeted by predicted revenue in different geographical markets with month-long breaks in between the releases. A world-wide network capable of delivering content in real time? Preposterous — let’s shut that down.&lt;/p&gt;
-
- &lt;p&gt;On a less “let’s break a 100 year old monopoly†scale of annoyance, &lt;a href=&quot;https://twitter.com/codepo8/status/687616620529844224&quot;&gt;I tweeted yesterday something glib and apparently cruel&lt;/a&gt;:&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;“Sorry, but your browser does not support WebGL!†– sorry, you are a shit coder.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;strong&gt;And I stand by this&lt;/strong&gt;. I went to a web site that promised me some cute, pointless animation and technological demo. I was using Firefox Nightly — a WebGL capable browser. I also went there with Microsoft Edge — another WebGL capable browser. Finally, using Chrome, I was able to delight in seeing an animation.&lt;/p&gt;
-
- &lt;p&gt;&lt;strong&gt;I’m not saying the creators of that thing lack in development capabilities&lt;/strong&gt;. The demo was slick, beautiful and well coded. They still do lack in two things developers of &lt;em&gt;web products &lt;/em&gt;(and I count apps into that) should have: empathy for the end user and an understanding that they are not in control.&lt;/p&gt;
-
- &lt;p&gt;Now, I am a pretty capable technical person. When you tell me that I might be lacking WebGL, I know what you mean. I don’t lack WebGL. I was blocked out because the web site did browser sniffing instead of capability testing. But I know what could be the problem.&lt;/p&gt;
-
- &lt;p&gt;A normal user of the web has no idea what WebGL is and — if you’re lucky — will try to find it on an app store. If you’re not lucky all you did is confuse a person. A person who went through the effort to click a link, open a browser and wait for your thing to load. A person that feels stupid for using your product as they have no clue what WebGL is and won’t ask. Humans hate feeling stupid and we do anything not to appear it or show it.&lt;/p&gt;
-
- &lt;p&gt;This is what I mean by empathy for the end user. Our problems should never become theirs.&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;A cryptic error message telling the user that they lack some technology helps nobody and is sloppy development at best, sheer arrogance at worst.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;The web is, sadly enough, littered with unhelpful error messages and assumptions that it is the user’s fault when they can’t consume the thing we built.&lt;/p&gt;
-
- &lt;p&gt;Here’s a reality check — this is what our users should have to do to consume the things we build:&lt;/p&gt;
-
- &lt;p&gt;&lt;img alt=&quot;&quot; height=&quot;600&quot; src=&quot;https://d262ilb51hltx0.cloudfront.net/max/800/1*DXtRIWTu-UzRb0YB-h8SmA.png&quot; width=&quot;10&quot; /&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;strong&gt;That’s right. Nothing&lt;/strong&gt;. This is the web. Everybody is invited to consume, contribute and create. This is what made it the success it is. This is what will make it outlive whatever other platform threatens it with shiny impressive interactions. Interactions at that time impossible to achieve with web technologies.&lt;/p&gt;
-
- &lt;p&gt;Whenever I mention this, the knee-jerk reaction is the same:&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote class=&quot;graf--blockquote graf-after--p&quot; id=&quot;79d6&quot; name=&quot;79d6&quot;&gt;How can you expect us to build delightful experiences close to magic (and whatever other soundbites were in the last Apple keynote) if we keep having to support old browsers and users with terrible setups?&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;You don’t have to support old browsers and terrible setups. But you are not allowed to block them out. It is a simple matter of giving a usable interface to end users. A button that does nothing when you click it is not a good experience. Test if the functionality is available, then create or show the button. &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;This is as simple as it is.&lt;/strong&gt;&lt;/p&gt;
-
- &lt;p&gt;If you really have to rely on some technology then show people what they are missing out on and tell them how to upgrade. A screenshot or a video of a WebGL animation is still lovely to see. A message telling me I have no WebGL less so.&lt;/p&gt;
-
- &lt;p&gt;Even more on the black and white scale, what the discussion boils down to is in essence:&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote class=&quot;graf--blockquote graf-after--p&quot; id=&quot;a775&quot; name=&quot;a775&quot;&gt;But it is 2016 — surely we can expect people to have JavaScript enabled — it is after all “the assembly language of the webâ€&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;Despite the cringe-worthy &lt;a href=&quot;http://www.hanselman.com/blog/JavaScriptIsAssemblyLanguageForTheWebSematicMarkupIsDeadCleanVsMachinecodedHTML.aspx&quot;&gt;misquote of the assembly language&lt;/a&gt; thing, here is a harsh truth:&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;You can absolutely expect JavaScript to be available on your end users computers in 2016. At the same time it is painfully &lt;strong&gt;naive&lt;/strong&gt; to expect it to work under all circumstances.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;strong&gt;JavaScript is brittle&lt;/strong&gt;. &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; both are &lt;em&gt;fault tolerant&lt;/em&gt;. If something goes wrong in &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, browsers either display the content of the element or try to fix minor issues like unclosed elements for you. &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; skips lines of code it can’t understand and merrily goes on its way to show the rest of it. JavaScript breaks on errors and tells you that something went wrong. It will not execute the rest of the script, but throws in the towel and tells you to get your house in order first.&lt;/p&gt;
-
- &lt;p&gt;There &lt;a href=&quot;http://kryogenix.org/code/browser/everyonehasjs.html&quot;&gt;are many outside influences&lt;/a&gt; that will interfere with the execution of your JavaScript. That’s why a non-naive and non-arrogant — a dedicated and seasoned web developer — will never rely on it. Instead, you treat it as an enhancement and in an almost paranoid fashion test for the availability of everything before you access it.&lt;/p&gt;
-
- &lt;p&gt;&lt;strong&gt;Sorry (not sorry) — this will never go away&lt;/strong&gt;. This is the nature of JavaScript. And it is a good thing. It means we can access new features of the language as they come along instead of getting stuck in a certain state. It means we have to think about using it every time instead of relying on libraries to do the work for us. It means that we need to keep evolving with the web — a living and constantly changing medium, and not a software platform. That’s just part of it.&lt;/p&gt;
-
- &lt;p&gt;This is why the whole discussion about JavaScript enabled or disabled is a massive waste of time. It is not the availability of JavaScript we need to worry about. It is our products breaking in perfectly capable environments because we rely on perfect execution instead of writing defensive code. A tumblr like &lt;a class=&quot;markup--anchor markup--p-anchor&quot; href=&quot;http://sighjavascript.tumblr.com/&quot; rel=&quot;nofollow&quot;&gt;Sigh, JavaScript&lt;/a&gt; is fun, but is pithy finger-pointing.&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;There is nothing wrong with using JavaScript to build things. Just be aware that the error handling is your responsibility.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;Any message telling the user that they have to turn on JavaScript to use a certain product is a proof that you care more about your developer convenience than your users.&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;It is damn hard these days to turn off JavaScript – you are complaining about a almost non-existent issue and tell the confused user to do something they don’t know how to.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;The chance that something in the JavaScript execution of any of your dozens of dependencies went wrong is much higher – and this is your job to fix. This is why advice like &lt;a href=&quot;http://webdesign.tutsplus.com/tutorials/quick-tip-dont-forget-the-noscript-element--cms-25498&quot;&gt;using noscript to provide alternative content&lt;/a&gt; is terrible. It means you double your workload instead of enhancing what works. Who knows? If you start with something not JavaScript dependent (or running it server side) you might find that you don’t need the complex solution you started with in the first place. Faster, smaller, easier. Sounds good, right?&lt;/p&gt;
-
- &lt;p&gt;So, please, stop sniffing my browser, you will fail and tell me lies. Stop pretending that working with a brittle technology is the user’s fault when something goes wrong.&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;As web developers we work in the service industry. We deliver products to people. And keeping these people happy and non-worried is our job. Nothing more, nothing less.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;Without users, your product is nothing. Sure, we are better paid and well educated and we are not flipping burgers. But we have no right whatsoever to be arrogant and not understanding that our mistakes are not the fault of our end users.&lt;/p&gt;
-
- &lt;p&gt;Our demeanor when complaining about how stupid our end users and their terrible setups are reminds me of &lt;a href=&quot;https://www.youtube.com/watch?v=CSj5stmFkQ0&quot;&gt;this Mitchell and Webb sketch&lt;/a&gt;.&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Don’t be that person. &lt;/strong&gt;Our job is to enable people to consume, participate and create the web. This is magic. This is beautiful. This is incredibly rewarding. The next markets we should care about are ready to be as excited about the web as we were when we first encountered it. Browsers are good these days. Use what they offer after testing for it and enjoy what you can achieve. Don’t tell the user when things go wrong – they can not fix what you messed up.&lt;/p&gt;
-
-
- &lt;img alt=&quot;&quot; height=&quot;1&quot; src=&quot;http://feeds.feedburner.com/~r/chrisheilmann/~4/vqtqgcNQXy8&quot; width=&quot;1&quot; /&gt;</content:encoded>
- <dc:date>2016-01-16T11:28:10+00:00</dc:date>
- <dc:creator>Chris Heilmann</dc:creator>
- </item>
- <item rdf:about="http://glandium.org/blog/?p=3510">
- <title>Mike Hommey: Announcing git-cinnabar 0.3.1</title>
- <link>http://glandium.org/blog/?p=3510</link>
- <content:encoded>&lt;p&gt;This is a brown paper bag release. It turns out I managed to break the upgrade&lt;br /&gt;
- path only 10 commits before the release.&lt;/p&gt;
- &lt;h3&gt;What’s new since 0.3.0?&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;code&gt;git cinnabar fsck&lt;/code&gt; doesn’t fail to upgrade metadata.&lt;/li&gt;
- &lt;li&gt;The &lt;code&gt;remote.$remote.cinnabar-draft&lt;/code&gt; config works again.&lt;/li&gt;
- &lt;li&gt;Don’t fail to clone an empty repository.&lt;/li&gt;
- &lt;li&gt;Allow to specify mercurial configuration items in a .git/hgrc file.&lt;/li&gt;
- &lt;/ul&gt;</content:encoded>
- <dc:date>2016-01-16T11:26:45+00:00</dc:date>
- <dc:creator>glandium</dc:creator>
- </item>
- <item rdf:about="http://edunham.net/2016/01/16/buildbot_and_eoferror.html">
- <title>Emily Dunham: Buildbot and EOFError</title>
- <link>http://edunham.net/2016/01/16/buildbot_and_eoferror.html</link>
- <content:encoded>&lt;h3&gt;Buildbot and EOFError&lt;/h3&gt;
- &lt;p&gt;More SEO-bait, after tracking down an poorly documented problem:&lt;/p&gt;
- &lt;div class=&quot;highlight-python&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;# buildbot start master
- Following twistd.log until startup finished..
- 2016-01-17 04:35:49+0000 [-] Log opened.
- 2016-01-17 04:35:49+0000 [-] twistd 14.0.2 (/usr/bin/python 2.7.6) starting up.
- 2016-01-17 04:35:49+0000 [-] reactor class: twisted.internet.epollreactor.EPollReactor.
- 2016-01-17 04:35:49+0000 [-] Starting BuildMaster -- buildbot.version: 0.8.12
- 2016-01-17 04:35:49+0000 [-] Loading configuration from '/home/user/buildbot/master/master.cfg'
- 2016-01-17 04:35:53+0000 [-] error while parsing config file:
- Traceback (most recent call last):
- File &quot;/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py&quot;, line 577, in _runCallbacks
- current.result = callback(current.result, *args, **kw)
- File &quot;/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py&quot;, line 1155, in gotResult
- _inlineCallbacks(r, g, deferred)
- File &quot;/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py&quot;, line 1099, in _inlineCallbacks
- result = g.send(result)
- File &quot;/usr/local/lib/python2.7/dist-packages/buildbot/master.py&quot;, line 189, in startService
- self.configFileName)
- --- &amp;lt;exception caught here&amp;gt; ---
- File &quot;/usr/local/lib/python2.7/dist-packages/buildbot/config.py&quot;, line 156, in loadConfig
- exec f in localDict
- File &quot;/home/user/buildbot/master/master.cfg&quot;, line 415, in &amp;lt;module&amp;gt;
- extra_post_params={'secret': HOMU_BUILDBOT_SECRET},
- File &quot;/usr/local/lib/python2.7/dist-packages/buildbot/status/status_push.py&quot;, line 404, in __init__
- secondaryQueue=DiskQueue(path, maxItems=maxDiskItems))
- File &quot;/usr/local/lib/python2.7/dist-packages/buildbot/status/persistent_queue.py&quot;, line 286, in __init__
- self.secondaryQueue.popChunk(self.primaryQueue.maxItems()))
- File &quot;/usr/local/lib/python2.7/dist-packages/buildbot/status/persistent_queue.py&quot;, line 208, in popChunk
- ret.append(self.unpickleFn(ReadFile(path)))
- exceptions.EOFError:
-
- 2016-01-17 04:35:53+0000 [-] Configuration Errors:
- 2016-01-17 04:35:53+0000 [-] error while parsing config file: (traceback in logfile)
- 2016-01-17 04:35:53+0000 [-] Halting master.
- 2016-01-17 04:35:53+0000 [-] Main loop terminated.
- 2016-01-17 04:35:53+0000 [-] Server Shut Down.
- &lt;/pre&gt;&lt;/div&gt;
- &lt;/div&gt;
- &lt;p&gt;This happened after the buildmaster’s disk filled up and a bunch of stuff was
- manually deleted. There were no changes to master.cfg since it worked
- perfectly.&lt;/p&gt;
- &lt;p&gt;The fix was to examine &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;master.cfg&lt;/span&gt;&lt;/span&gt; to see &lt;a class=&quot;reference external&quot; href=&quot;https://github.com/servo/saltfs/blob/master/buildbot/master/master.cfg#L413&quot;&gt;where the HttpStatusPush was
- created&lt;/a&gt;,
- of the form:&lt;/p&gt;
- &lt;div class=&quot;highlight-python&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'status'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HttpStatusPush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;serverUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://build.servo.org:54856/buildbot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;extra_post_params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'secret'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HOMU_BUILDBOT_SECRET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
- &lt;/div&gt;
- &lt;p&gt;Digging in the Buildbot source reveals that &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;persistent_queue.py&lt;/span&gt;&lt;/span&gt; wants to
- unpickle a cache file from &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;/events_build.servo.org/-1&lt;/span&gt;&lt;/span&gt; if there was nothing
- in &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;/events_build.servo.org/&lt;/span&gt;&lt;/span&gt;. To fix this the right way, create that file
- and make sure Buildbot has &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;+rwx&lt;/span&gt;&lt;/span&gt; on it.&lt;/p&gt;
- &lt;p&gt;Alternately, you can give up on writing your status push cache to disk
- entirely by adding the line &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;maxDiskItems=0&lt;/span&gt;&lt;/span&gt; to the creation of the
- HttpStatusPush, giving you:&lt;/p&gt;
- &lt;div class=&quot;highlight-python&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'status'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HttpStatusPush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;serverUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://build.servo.org:54856/buildbot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;maxDiskItems&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;extra_post_params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'secret'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HOMU_BUILDBOT_SECRET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
- &lt;/div&gt;
- &lt;p&gt;The real moral of the story is “remember to use &lt;a class=&quot;reference external&quot; href=&quot;http://www.linuxcommand.org/man_pages/logrotate8.html&quot;&gt;logrotate&lt;/a&gt;.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-16T08:00:00+00:00</dc:date>
- </item>
- <item rdf:about="urn:md5:41d039bb28fb15c761578cba0b1454fa">
- <title>Daniel Glazman: Ebook pagination and CSS</title>
- <link>http://www.glazman.org/weblog/dotclear/index.php?post/2016/01/16/Ebook-pagination-and-CSS</link>
- <content:encoded>&lt;p&gt;Let's suppose you have a rather long document, for instance a book chapter, and you want to render it in your browser &lt;em&gt;à la&lt;/em&gt; iBooks/Kindle. That's rather easy with just a dash of CSS:&lt;/p&gt;
- &lt;pre&gt;body {
- height: calc(100vh - 24px);
- column-width: 45vw;
- overflow: hidden;
- margin-left: calc(-50vw * attr(currentpage integer));
- }&lt;/pre&gt;
- &lt;p&gt;Yes, yes, I know that no browser implements that &lt;code&gt;attr()&lt;/code&gt;extended syntax. So put an inline style on your body for &lt;code&gt;margin-left: calc(-50vw * &lt;em&gt;&amp;lt;n&amp;gt;&lt;/em&gt;)&lt;/code&gt; where &lt;em&gt;&lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt;&lt;/em&gt; is the page number you want minus 1.&lt;/p&gt;
- &lt;p&gt;Then add the fixed positioned controls you need to let user change page, plus gesture detection. Add a transition on margin-left to make it nicer. Done. Works perfectly in Firefox, Safari, Chrome and Opera. I don't have a Windows box handy so I can't test on Edge.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-16T03:43:00+00:00</dc:date>
- <dc:creator>glazou</dc:creator>
- </item>
- <item rdf:about="https://repeer.org/?p=48">
- <title>Nicolas Mandil: Mozilla cultural revolution: from ‘radical participation’ to ‘radical user-centric’</title>
- <link>https://repeer.org/2016/01/16/mozilla-cultural-revolution-from-radical-participation-to-radical-user-centric/</link>
- <content:encoded>&lt;p&gt;This post has been written about the &lt;a href=&quot;http://marksurman.commons.ca/2015/12/21/mofo2020/&quot;&gt;Mozilla Foundation (MoFo) 2020 strategy&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;The ideas developed in this post are in different levels: some are global, some focus on particular points of the proposed draft. But in my point of view, they all carry a transversal meaning: articulation (as piece connected to a structure allowing movement) with others and consistency with our mission.&lt;/p&gt;
- &lt;h3&gt;Summary&lt;/h3&gt;
- &lt;p&gt;On the way to &lt;a href=&quot;http://marksurman.commons.ca/2015/01/09/what-is-radical-participation/&quot;&gt;radical participation&lt;/a&gt;, Mozilla should be radical &lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;https://repeer.org/tag/mozilla/feed/#fn-48-1&quot; id=&quot;fnref-48-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; user-centric. Mozilla should not go against the social understanding of the (tech and whole society) situation because it’s what is massively shared and what polarizes the prism of understanding of the society. &lt;strong&gt;We should built solutions for it and transform (develop and change) it on the way. Our responsibility is to build &lt;em&gt;inclusivity&lt;/em&gt; (inclusion strengths) everywhere, to gather for multiplying our impact.&lt;/strong&gt; We must build (progressive) victories instead of battles (of static positions and postures).&lt;br /&gt;
- If we don’t do it, we go against users self-perceived need: use. We value our differences more than our commonalities and &lt;strong&gt;consider ethic more as an absolute objective than a concrete process&lt;/strong&gt;: we divide, separate, compete. Our solutions get irrelevant, we get rejected and marginalized, we reject compromises that improve the current situation for the ideal, we loose influence and therefore impact on the definition of the present and future. We already done it for the good and the bad in the past (H.264+Daala, pocket integration, Hello login, no Firefox for iOS, Google fishing vs Disconnect, FxOS Notes app which sync is evernote only, …).&lt;br /&gt;
- To get a consistent and impactful ability to integrate and transform the social understanding, there are four domains where we can take and articulate (connected structure allowing movement) action:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;People&lt;/strong&gt;: identity is the key to grow consciousness, understanding, skills, voice, representation and to articulate global/local, personal/common. &lt;strong&gt;[Activate]&lt;/strong&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;Technology&lt;/strong&gt;: universality is key for a platform (for resilience) with interfaces (for modularity) where services, features and front-ends can plug-in and communicate to provide (inter)active support ; Decouple conditions of fulfillment with execution (content/appearance/policy ; material/immaterial) to support remix (policy continuity, consistency thought providers, …). &lt;strong&gt;[Unlock]&lt;/strong&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;Product&lt;/strong&gt;: persona and (current and emerging) use via user-agents are the keys. Be on all major platforms depending on use, ethical alignment and opportunities, emerging newness to provide continuity (task, device) to users and leading on new practices. Features should be about products parity and opening new possibilities carrying our values to the action at a massive scale. &lt;strong&gt;[Build]&lt;/strong&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;Organizations/institutions&lt;/strong&gt;: sociological innovation for participation is the key. Research on historical (evolution) and sociological (human organizations, social institutions and social behaviors) analysis based on social networks (link as social interactions), in the perspective of producing commons. &lt;strong&gt;[Drive]&lt;/strong&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;Our front has two sides: &lt;strong&gt;propose and protect&lt;/strong&gt;. But each of them are connected and can have different strategic expressions, if our actions generate improving (progressive) curves:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;For the &lt;strong&gt;action taking&lt;/strong&gt;: consciousness, understanding, symbolic actions, behavior change, behavior advocacy (evangelism)&lt;/li&gt;
- &lt;li&gt;For the &lt;strong&gt;action mode&lt;/strong&gt;: promotion (spreading the idea), incitement (giving a competitive advantage to people involved), collaboration (open interactions to make a win-win exchange; process-centric), contractualization (formalize domains where a win-win exchange is made; object-centric), coercion (giving a competitive disadvantage to people not involved).&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;Social history is a history of social values.&lt;strong&gt; The way we understand and tell the problem determine the solution we can create&lt;/strong&gt;: we need, all the way long, a shared understanding. Tools and technologies are not tied, bound forever to their social value, which depends on people’s social representations that evolve over time.&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;The social behavior&lt;/strong&gt; is a first key. It is the narrative, and therefore its &lt;strong&gt;inclusion in the social history that we make, which converges the product with the values that it stands for&lt;/strong&gt;. Here is the articulation of product with people and technology, of product with leadership network and advocacy engine (it could be less persistent and inclusive: marketing).&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;The social organization&lt;/strong&gt; is a second key. It is about how the process, the tools, the architecture, the governance and the opportunities/constraints have changed for Mozilla (org) and Mozillians (people). &lt;strong&gt;Here comes the question of being open&lt;/strong&gt;. It is not enough because it is about availability (passive) and not inclusivity (active). The high level of automation coming is a challenge. We should level-up the meaning to differentiate from others: &lt;strong&gt;Mozilla should activate and unlock societal progress to build fair technical progress&lt;/strong&gt;. Mozilla need to &lt;strong&gt;identify its resilient backbone&lt;/strong&gt; (not only a technology, the web, but something that articulate people, technology and products) and make it more universal (through people and products). But our goals can’t be absolutely achieved because they have to be considered in a dynamic context. However, the brand engagement is persistent, if it’s included in the product, visible, and centered on easing the user’s action.&lt;br /&gt;
- Linked to the ‘being open’ question, the advocacy engine could be a thing to unlock societal progress. People are satisfied of narrow hills of choice until they understand it’s not socially neutral. It’s the case with technology: they accept things about technology to be build top-down. &lt;strong&gt;A successful advocacy, even one about technology, is always built bottom-up&lt;/strong&gt;, as its function is to give back the voice to the people, to get them involved, not to make them fulfill our predefined aims. The top-down method is too organization centric and administrative content centric: it can’t massively drive people that are not already committed to the org. It’s usually named advertisement or propaganda. &lt;strong&gt;If we want to have an impact, we should listen to people needs, not tell them to listen to ours&lt;/strong&gt;. People want (first) to be empowered, not to empower an org. We need to have content and user centric (not org and it’s process) tools/platform for advocates and leaders: let’s build the technology advocacy plan together. Yes it’s slower, but much more massive, inclusive and persistent. The impact will be higher because it will carry a meaning for people and it wont be too org centric. So it will be qualitatively better: not just an amount, &lt;strong&gt;accumulation is not our goal, but impact, that comes from articulation&lt;/strong&gt;. Likewise we should be careful to not use best practice as absolute solutions, but as solutions in a context, if we want to transpose them massively: when we unify we should avoid to homogenize. On the narrative side, our preoccupation should be about building short, medium and long term narrative to get action.&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;The social institutions&lt;/strong&gt; are the third key. Here is the articulation of the leadership network with the advocacy engine. &lt;strong&gt;Leaders build new solutions (products) and Advocates new voices (rallying), they are both about personal development and empower commons.&lt;/strong&gt; Leadership=learn+create and advocacy=teach+spread commons. Leaders are projects/orgs leaders, the ones that traduce DNA (values) in products (concrete ability and availability). Advocates are values advocates, the ones that traduce DNA (values) in actions (behavior). As they are both targeting commons, they both produce the same social organization (collaboration instead of competition). They are both involved in creating (different) representations (institutions) and organizations (foundation/firms) but &lt;strong&gt;with a different DNA (values) processing&lt;/strong&gt;: from public good to personal benefit or from personal interest to public benefit. If Mozilla cares about public good resilience, &lt;strong&gt;the articulation of their domains of values is critical&lt;/strong&gt;. So, on the social organization side, their articulation’s expression and the revision process must be said and clear: from hierarchy or contract or different autonomy levels (internal incubation and external advocacy), or … to criteria to start a revision. About the narrative, and hence about the social behavior side, leaders carry a lot of legitimacy and avoid the stay-experimental or non-massive (unique) thoughts. And we need legitimacy to get impact. But this legitimacy is already present if we&lt;strong&gt; make clear that our actions are about commons&lt;/strong&gt;. We should name them creators (compositors or managers) to make it clear that the creative process is a collaboration, made by a team and that the public good do not have the same role in the process and outcome. Full circle.&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;The social networks&lt;/strong&gt; are the keystone. Let’s shortly take an example based on social networks (link as social interactions) with the perspective of producing people, technological and product commons. &lt;strong&gt;We need better tools for collaboration and participation&lt;/strong&gt;: tools that merge discussion channels, capitalize on the discussion and preview the results to build a plan. From evolving the wiki discussion page to feature document production into peer-to-peer discussion.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;An analysis of the creation process is another way to the articulation of product with people and technology.&lt;br /&gt;
- Platforms move closer to strict ‘walled garden’ ecosystems. We need bridges from lab to home that carry different mix of customization and reliability to support the emancipation curve. We need to build pathways thought audiences and thought IT layers (content, software, hardware, distant service). &lt;strong&gt;We should find a convergence between customization&lt;/strong&gt; (dev code patch to users add-ons) &lt;strong&gt;and reliability&lt;/strong&gt; (self made to mass product), &lt;strong&gt;between first time experience, support and add-ons thought all our users’ persona by building bridges, pathways&lt;/strong&gt;. Mozilla should find ways to &lt;strong&gt;integrate learning&lt;/strong&gt; in its products, in-content, as we have code comment on code: on-boarding levels, progression from simple to high level techniques, reproducible/universal next task/skill building.&lt;/p&gt;
- &lt;h3&gt;Detailed discussion content&lt;/h3&gt;
- &lt;p&gt;Here are the developed ideas, with more reference to our allies and detractors’ products.&lt;/p&gt;
- &lt;h4&gt;People, the sociological side&lt;/h4&gt;
- &lt;h5&gt;From focused to systemic action&lt;/h5&gt;
- &lt;p&gt;First of all, I think &lt;strong&gt;the strategy move Mozilla is doing is the right one&lt;/strong&gt; as it embraces more our real life. People are not defined by one characteristic, we are complex: ex. we can be pedestrian, car driver, biker, Public Transport user… we think and do simultaneously. So why Mozilla should restrict its strategy by targeting people on skills, through education, thought better material only (the Mozilla Academy program). Education, even popular education, can’t do everything for the people to build change. &lt;strong&gt;We need a plan that balance intellectual and practical (abstraction/action, think/do) integrating progressive paths to massively scale so we get an impact: build change.&lt;/strong&gt;&lt;/p&gt;
- &lt;h5&gt;Real life: Social history, individuals and institutions as an articulation founding the action.&lt;/h5&gt;
- &lt;p&gt;Let’s start by some definitions based on my understanding of some &lt;a href=&quot;https://fr.wikipedia.org/wiki/Sociologie&quot;&gt;Wikipedia articles&lt;/a&gt;. Sociology is the study of the evolution of societies: human organizations and social institutions. It is about &lt;strong&gt;the impact of the social dimension on humans representations (ways of thinking) and behaviors (ways of acting)&lt;/strong&gt;. It allows to study the conceptions of social relations according to fundamental criteria (structuralism, functionalism, conventionalism, etc.) and the hooks to reality (interactionism, institutionalism, regulationisme, actionism, etc.), to think and shape the modernity. Currently (and this is key for Mozilla’s positioning), the combination of models replace the models’ unity, which aims to assume the multidimensionality. There are three major sociological paradigms, including one emerging:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;The holistic paradigm&lt;/strong&gt;: Society is a whole that is greater than the sum of its parts, it exists before the individual and individuals are governed by it. In this context, the Society includes the individual and the individual consciousness is seen only as a fragment of the collective consciousness. The emphasis is on the social fact, whose cause must be sought in earlier social facts. The social fact is part of a system of interlocking institutions that govern individuals. It is external to the individual and constraint it. Sociology is then the science of institutional invariants in which are the observable phenomenas.&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;The atomistic paradigm&lt;/strong&gt;: each individual is a social atom. The atoms act according to self motives, interests, emotions and are linked to other atoms. A system of constant interaction between atoms produces and reproduces Society. The emphasis is on the cause of social actions and the meaning given by individuals to their actions. A horizon of meanings serve as reference instead of the arrangements of institutions. The institution is there but it serves the motives and interests of agents. Sociology is then the study of the social action.&lt;/li&gt;
- &lt;li&gt;The recent emergence of a sociological analysis based on &lt;strong&gt;social networks&lt;/strong&gt; (which are a collection of individuals or organizations connected by regular social interactions) suggest lines of research &lt;strong&gt;beyond the opposition between the holistic and the atomistic approaches&lt;/strong&gt;. The theory of social networks conceives social relationships in terms of nodes and links. The nodes are usually social actors in the network but can also represent institutions, and links are the relationships between these nodes. There may be several kinds of links between nodes and their analysis determines social capital of the social actors.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;Consequently, Mozilla should build its strategy on &lt;strong&gt;historical&lt;/strong&gt; (evolution) and &lt;strong&gt;sociological&lt;/strong&gt; (human organizations, social institutions and social behaviors) analysis based on &lt;strong&gt;social networks&lt;/strong&gt; (links as social interactions), in the perspective of producing &lt;strong&gt;commons&lt;/strong&gt;. That is to say as an &lt;strong&gt;engine of transition from a model of value&lt;/strong&gt; on its last leg (rarity capitalism) to the emerging one (new articulation of the individual and the collective: commons).&lt;br /&gt;
- It is important and strategic to propose a sociological articulation supporting our mission and its purpose (commons) since &lt;strong&gt;the sociological concept (the paradigm) reveals an ideological characteristic&lt;/strong&gt;: because it participates in societal movements made in the Society, it serves an ideal. The societal domain, what’s making society, a political object, should be a stake for Mozilla.&lt;/p&gt;
- &lt;h5&gt;Build on a basement: current tech challenge articulated with current social meaning/perception&lt;/h5&gt;
- &lt;p&gt;&lt;strong&gt;We should articulate ‘our real life’ with the nowadays tech challenge&lt;/strong&gt;: how to get back control over our data at the time of IoT, cloud, big data, convergence (multi-devices/form factor)? From a user point of view, we have devices and want them convenient, easy and nice. The big moves in the tech industry (IoT, cloud, big data, convergence) free us for somethings and lock us for others. The lock key is that our devices don’t compute anymore our data that are in silos. From a developer point of view, the innovation is going very fast and it’s hard to have a complete open source toolbox that we can share, mostly because we don’t lead: Open has turn to be more open-releasing.&lt;br /&gt;
- We should articulate our new strategy with the tech industry moves: for example, &lt;strong&gt;as a user, how can I get (email) encryption on all my devices?&lt;/strong&gt; Should I follow (fragmented) different kind of howtos/tools/apps to achieve that? How do I know these are consistent together? How can I be sure it won’t brake my continuous workflow? (app silo? social silo? level of trust and reliability?)&lt;br /&gt;
- Mozilla have the skills to answer this as we already faced and solved some of these issues on particular points: like how to ease the installation of Firefox for Android for Firefox desktop users, open and discoverable choice of search engines, synchronization across devices, …&lt;br /&gt;
- &lt;strong&gt;Mozilla’s challenge is to not be marginalized by the change of practices. Having an impact is embracing the new practice and give it an alternative.&lt;/strong&gt; Mozilla already made that move by saying « &lt;em&gt;Firefox will go where users are&lt;/em&gt;« , by trying to balance the advertisement practice between adds companies and users, by integrating H.264 and developing Daala. But &lt;strong&gt;Mozilla never stated that clearly as a strategy&lt;/strong&gt;.&lt;/p&gt;
- &lt;h5&gt;A backbone to make our mission resilient in it expressions&lt;/h5&gt;
- &lt;p&gt;If we think about the &lt;strong&gt;Facebook’s strategy, they first built a network of people whiling to share&lt;/strong&gt; (no matter what they share) and then use this &lt;strong&gt;transversal backbone to power vertical business segments&lt;/strong&gt; (search, donation, local market selling, …). Google with its search engine and its open source policy have a similar (in a way) strategy. The difference here is that the backbone is people’s data and control over digital formats. In both cases, the level of use (of the social network, search engine, mobile OS, …) is the key (with fast innovation) to have an impact. And that’s a major obstacle to build successful alternatives.&lt;br /&gt;
- The proposed Mozilla’s strategy is built in the opposite way, and that’s questioning. &lt;strong&gt;We try to build people network depending on some shared matters&lt;/strong&gt;. Then, is our strategy able to scale enough to compete against GAFAM, or are we trying to build a third way ?&lt;br /&gt;
- For the products, the Mozilla’s strategy is still (and has always been) inclusive: everybody can use the product and then benefit of its open web values. A good product that answer people needs, plus giving people back/new power (allow new use) build a big community. For the network, should we build our global force of people based on concentric circles (of shared matters) or based on a (Mozilla own) transversal backbone (matter agnostic)? It seems to me the actual presentation of the strategy do not answer clearly enough this big question: &lt;strong&gt;which &lt;em&gt;inclusivity&lt;/em&gt; (inclusion strengths) mechanism in the strategy?&lt;/strong&gt;&lt;br /&gt;
- And that &lt;strong&gt;call back to our product strategy&lt;/strong&gt;: build a community that shares values, that is used to spread outcomes (product) OR build a community that shares a product, that is used to spread values. This is not a question on what matters more (product VS values) but on the strategy to get to a point, an objective (many web citizens). Shouldn’t we use our product to built a people network backbone ? Back to GAFAM: what can we learn from the Google try with Google+?&lt;br /&gt;
- If our core is not enough transversal (the backbone), more new web/tech market there will be, more we will be marginalized, because focused on our circles center not taking in account that the war front (the context) have changed. &lt;strong&gt;Mozilla have to be resilient: mutability of the means, stability in the objectives.&lt;/strong&gt;&lt;br /&gt;
- The document is the MoFo strategy, and so it doesn’t say anything about ‘build Firefox’ (aka the product strategy) and so don’t articulate our main product (Firefox) with our main people network building effort and values sharing engine. We should do it: at a strategic scale and a particular scale (articulating the agenda-setting with main product features).&lt;/p&gt;
- &lt;h5&gt;Brand engagement, a psychological backbone on the user side ?&lt;/h5&gt;
- &lt;p&gt;It seems that our GAFAM challengers get big and have impact by not educating (that much) people, and that’s what makes them not involved in the web citizenship. Or only when they are pushed by their customers. At the opposite, making people aware about web citizenship at first, makes it hard to have that much people involved and so to have impact. However, there is &lt;strong&gt;an other prism that drive people: the brand perceived values&lt;/strong&gt;. Google is seen as a tech pioneer innovator and doing the good because of its open policy, free model, fast innovation… Facebook is seen as really cool firm trying to help people by connecting them…&lt;br /&gt;
- Is the increase of marketing of Mozilla doing good enough to gains back users ? Is this resilient compared to the next-tech-thing coming ?&lt;br /&gt;
- Most of the time when I meet Goggle Chrome users and ask then why they use it and don’t switch to Firefox, they answer about use allowed (sync thought devices, apps everywhere that run only on GC, …). Sometimes, they argue that they make effort on other areas, and that they want to keep they digital life simple. They &lt;strong&gt;experience is not centered in a product/brand, but more on the person&lt;/strong&gt;: on that Google Chrome with its Person (with one click ‘auto-login’ to all Google services) is far superior than Firefox.&lt;/p&gt;
- &lt;h5&gt;User-agent or products ?&lt;/h5&gt;
- &lt;p&gt;A user-agent is an intermediary acting on behalf of a supplier. As a representative, it is the contact point with customers; It’s role is to manage, to administer the affairs; it is entrusted with a mission by one or more persons; it both acts and produce an effect.&lt;br /&gt;
- So, the user-agent can be describe with three criteria. It is: an intermediate (user/technology) ; a tool (used to manage and administrate depending on the user’s skills) ; a representative (mission bearer, values vector, for a group of people). It exceeds partly the contradiction between being active and passive.&lt;br /&gt;
- A &lt;strong&gt;user-agent articulate personal-identity with technology-identity&lt;/strong&gt; and give informations about available skills over these domains. It’s much more universal than a product that is about featuring a user-agent. &lt;strong&gt;If we target resilience, user-agent should be the target&lt;/strong&gt;.&lt;/p&gt;
- &lt;h4&gt;Social history, marketing: how we understand things to make choices&lt;/h4&gt;
- &lt;h5&gt;History of the social value&lt;/h5&gt;
- &lt;p&gt;The way we look at the past and current facts shape our understanding and determine if we open new ways to solve the issues identified. That’s the way to understand the challenges that come on the way and to agree on an adaptation of the strategy instead of splitting things. The way we understand and tell the problem determine the solution we can create: we need, all the way long, &lt;strong&gt;a shared understanding.&lt;/strong&gt;&lt;br /&gt;
- &lt;strong&gt;Tools and technologies are not necessarily tied to their social value, which depends on social representations. The social value can be built upstream and evolve downstream.&lt;/strong&gt; It also depends on the perspective in which we look at it, on the understanding of the action and therefore on past or current history. Example: the social value of a weapon can be a potential danger or defense, creative (liberating) or destructive. The nuclear bomb is a weapon of mass destruction (negative), whose social value was (ingeniously built as) freedom (positive).&lt;/p&gt;
- &lt;h5&gt;Impact in our strategy: a missing root&lt;/h5&gt;
- &lt;p&gt;To engage the public, before to « &lt;em&gt;Focus on creative campaigns that use media + software to engage the public.&lt;/em&gt; » we need to step back, in our speeding world, for understanding together the big picture and the big movement.&lt;br /&gt;
- Mozilla want to fuel a movement and propose a strong and consistent strategy. However, I think &lt;strong&gt;this plan miss a key point, a root point: build a common (hi)story.&lt;/strong&gt; This should be an objective, not just an action.&lt;br /&gt;
- Also, that’s maybe a missing root for the State of the web report: how do we understand what we want to evaluate? But it’s not only a missing root for an (annual?) report (a ‘Reporters without borders’ Press-Freedom like?), it’s a missing root for a new grow of our products’ market share.&lt;br /&gt;
- For example, I do think that most users don’t know and understand that Mozilla is a foundation, Firefox build by a community as a product to keep the web healthy: &lt;strong&gt;they don’t imagine any meaning about technology&lt;/strong&gt;, because they see it as a neutral tool at its root, so as a tool that should just fit they producing needs.&lt;br /&gt;
- Firefox, its technologies and its features are not bound for ever. It is the narrative, and therefore their inclusion in the social history that we make, which converges Firefox with the values that it stand for. &lt;strong&gt;Stoping or changing the deep narrative means cutting the source of common understanding and making stronger other consistencies captured by other objects, turning as centrifugal forces for Firefox.&lt;/strong&gt;&lt;br /&gt;
- Marketing is a way to change what we socially say about things: that’s why Google Chrome marketing campaign (and consistent features maturity) has been the decreasing starting point of Firefox. &lt;strong&gt;Our message has been scrambled.&lt;/strong&gt;&lt;/p&gt;
- &lt;h4&gt;From participation to emancipation: values, people and org relationships&lt;/h4&gt;
- &lt;p&gt;How to emancipate people in the digital world ?&lt;/p&gt;
- &lt;h5&gt;Keeping the open open&lt;/h5&gt;
- &lt;p&gt;Being open is not a thing we can achieve, it’s a constant process. « &lt;em&gt;Mozilla needs to engage on both fronts, tackling the big problems but also fuelling the next wave of open.&lt;/em&gt; » Yes, but &lt;strong&gt;Mozilla should say too how the next wave of open can stay under people’s control and rally new people&lt;/strong&gt;. Not only open code, but open participation, open governance, open organization. Being open is not a releasing policy about objects, it’s a mutation to participation process: a metamorphosis. It’s not reached by expanding, but by shifting. It’s not only about an amount, but about values: it’s qualitative.&lt;br /&gt;
- Maybe &lt;strong&gt;open is not enough&lt;/strong&gt;, because it doesn’t say enough about who control and how, about the governance, and says too much about &lt;strong&gt;availability (passive)&lt;/strong&gt; and not enough &lt;strong&gt;about &lt;em&gt;inclusivity&lt;/em&gt; (active ; inclusion strengths)&lt;/strong&gt;. It doesn’t say how the power is organized and articulated to the people (ex. think about how closed is the open Android). We may need to change the wording: indie web, the web that fuel autonomy, is a try, but it doesn’t say enough about &lt;em&gt;inclusivity&lt;/em&gt; compared to openness &amp;amp; opportunity. Emancipation is the concept. It’s strategic because it says what is aligned to what, especially how to articulate values and uses. It’s important because it tells what are the sufficient conditions of realization to ‘open/indie’. That’s key to get ‘open/indie at small and large scales, from Internet people to Internet institutions, thought all ‘open/indie’ detractors in the always-current situation: a resilient ecosystem.&lt;br /&gt;
- My intuition is that &lt;strong&gt;the leadership network and advocacy engine promoting open will be efficient if we clarify ‘open’ while keeping it universal&lt;/strong&gt;. We can do it by looking back at the raw material that we have worked for years, our DNA in action. Because after all, we are experts about it and wish others to become experts too. It does not mean to essentialize it (opposing its nature and its culture), &lt;strong&gt;but to define its conditions of continuous achievement in our social context&lt;/strong&gt;.&lt;/p&gt;
- &lt;h5&gt;Starting point: exemplary projects that tell a lot about the evolution of our DNA in action&lt;/h5&gt;
- &lt;p&gt;Clarifying the idea of ‘open’ is strategic to our action because it outlines the constitution of ‘open’, its high ‘rules’, like with laws in political regimes. It clarifies for all, if you are part of it or not, and it tells you what to change to get in. It can reinforce the brand by differentiating from the big players that are the GAFAM: &lt;strong&gt;it’s a way to drive, not to be driven by others lowering the meaning to catch the social impact. We should say that ‘open’ at Mozilla means more than ‘open’ at GAFAM&lt;/strong&gt;. I wish Mozilla to speak about its openness, not as an ‘equal in opportunity’ but as an ‘equal in participation’, because it fits openness not only for a moment (on boarding) or for a person, but during the whole process of people’s interaction.&lt;br /&gt;
- &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; and &lt;a href=&quot;https://servo.org/&quot;&gt;Servo&lt;/a&gt; or &lt;a href=&quot;https://firefoxos.mozilla.community/&quot;&gt;Firefox OS&lt;/a&gt; (since the Mozilla’s shift to radical participation) seem to be very good examples of projects with participation &amp;amp; impact centric rules, tools, process (RFC, new team and owners, …). Think about how Rust and &lt;a href=&quot;http://arc.applause.com/2015/03/27/google-dart-virtual-machine-chrome/&quot;&gt;Dart emerged and are evolving&lt;/a&gt;. Think about how stronger has been the locked-open Android with partnership than the open-locked FxOS. We should tell those stories, not as recipes that can be reproduced, but as process based on a Constitution (inclusive rules) that make a political regime (open) and define a mode of government (participation). That’s key to social understanding and therefore to transpose and advocate for it.&lt;br /&gt;
- As projects&lt;strong&gt; compared to ‘original Mozilla’, Rust, Servo and FxOS could say a lot&lt;/strong&gt; about how different they implemented learning/interaction/participation at the roots of the project. How the process, the tools, the architecture, the governance and the opportunities/constraints have changed for Mozilla and participants. This could definitely help to setup our curriculum resources, database and workshop at a personal (e.g., “How to teach / facilitate / organize / lead in the open like Mozilla.â€) and orgs levels, with personal and orgs policies.&lt;/p&gt;
- &lt;h5&gt;Spreading the high meanings in our strategy to consolidate it consistency&lt;/h5&gt;
- &lt;p&gt;Clarifying the constitution of ‘open’ calls to clarify other related wordings.&lt;br /&gt;
- I’m satisfied to read back (social) ‘movement’ instead of ‘community’, because it means that our goal can’t be achieve forever (is static), but we should protect it by acting. And it seems more inclusive, less ‘folds on itself’ and less ‘build the alternative beside’ than ‘community’: the alternative can be everywhere the actual system is. It can make a system. It can get global, convergent, continuous, … all at the same time. Because it’s roots are decentralized _and_ consistent, collaborating, …&lt;/p&gt;
- &lt;p&gt;About participation, we should think too (again) about engagement VS contribute VS participate: how much am I engaged ? Free about defining and receiving cost/gains? What is the impact of my actions ? … &lt;strong&gt;These different words carry different ideas about how we connect the ‘open’&lt;/strong&gt;: spread is not enough because it diffuses, _be_ everywhere is more permanent. Applied to Mozilla’s own actions, &lt;strong&gt;funding open projects and leaders, is maybe not enough and there should be others areas where we can connect&lt;/strong&gt; inside products, technology, people and organizations that build emancipation. So that say something about getting control (who, how, …).&lt;/p&gt;
- &lt;h5&gt;IA: a challenge for ‘open’&lt;/h5&gt;
- &lt;p&gt;IA is first developed to help us by improving our interactions. However, this seems to start to shift into taking decisions instead of us. This is problematic because these are indirect and direct ways for us to loose control, to be locked. And that can be as far as computers smarter than humans. The problem is that technical progress is made without any consideration of the societal progress it should made.&lt;br /&gt;
- That’s an other point, why open is not enough: automation should be build-in with superior humanization. &lt;strong&gt;Mozilla should activate and unlock societal progress to build fair technical progress.&lt;/strong&gt;&lt;/p&gt;
- &lt;h5&gt;Digital integration &amp;amp; democracy&lt;/h5&gt;
- &lt;p&gt;The digital (&amp;amp; virtual) world is gaining control over the physical world in many domains of our society (economy to finance, mail to email, automatic car, voting machine, …). It’s getting more and more integrated to our lives without getting back our (imperfect) democracy integrated into them. Public benefit and public good are turning ‘self benefit’ and ‘own sake’ because citizens don’t have control over private companies. &lt;strong&gt;We should build a digital democracy if we don’t want to loose at all the democratic governing of society.&lt;/strong&gt; We must overcome the poses and postures battles about private and public. We need to build.&lt;/p&gt;
- &lt;h4&gt;‘Leader’ &amp;amp; ‘Leadership’ need a clarification&lt;/h4&gt;
- &lt;h5&gt;Why a clarification?&lt;/h5&gt;
- &lt;p&gt;At some level, I’m not the only one to ask this question:&lt;/p&gt;
- &lt;blockquote&gt;&lt;p&gt;How do CRM requirements for Leadership and Advocacy overlap / differ? What’s our email management / communications platform for Leadership?&lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;Connect leaders to lead what ? How ? To whose benefit ? Do we want to connect leaders or initiatives (people or orgs) ? Will the leaders be emerging ones (building new networks) or established ones (use they influence to rally more people)? Are Leaders leaders of something part of Mozilla (like can be Reps) or outside of Mozilla (leaders of project, companies, newspaper: tech leaders, news leaders, …) ? This is especially important depending on what is the desire for the leaders to become in the future. &lt;strong&gt;The MoFo’s document should be more precise&lt;/strong&gt; about this and go forward than « &lt;em&gt;Mozilla must attract, develop, and support a global network of diverse leaders who use their expertise to collaboratively advance points-of-view, policies and practices that maintain the overall health of the Internet.&lt;/em&gt; »&lt;br /&gt;
- We should do it because &lt;strong&gt;the confusion about the leadership impact the advocacy engine&lt;/strong&gt;: « &lt;em&gt;The shared themes also provide explicit opportunities for our Leadership and Advocacy efforts to work together.&lt;/em&gt; » Regarding Mozilla, is the leaders role to be advocacy leaders ? It seems as they share themes and key initiatives (even if not worded the same sometimes). Or in other words, who Drives the Advocacy engine?&lt;/p&gt;
- &lt;h5&gt;Iterations with the actual definition: creators&lt;/h5&gt;
- &lt;p&gt;Here are my iterations on the definition of ‘Leaders’:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;The Leaders could be the people platform (the community) and the advocacy engine the tool/themes/actions platform (the product).&lt;/li&gt;
- &lt;li&gt;Leaders could build at the end new solutions (products) and Advocates new voices (rallying), that could be translated in a learning area divided like Leadership=learn+create and advocacy=teach+spread.&lt;/li&gt;
- &lt;li&gt;Leadership: personal development to produce (turn into) new commons or add new facets to commons. Advocacy: personal development to protect established/identified commons.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;With these definitions, then Leaders are maybe more a Lab, R&amp;amp;D place, incubation tool (if we think about start-up incubators, then it shows a tool-set that we will need to inspire for the future). But if we want to keep the emphasis on people, &lt;strong&gt;we could name them ‘creators’&lt;/strong&gt; (compositors or managers ; not commoners, because leaders and advocates are commoners ; yes, traditionally creators are craftspersons and intellectual designers). This make sens with the examples given in the MoFo 2020 strategy 0.8 document, where all persona are involved in a building-something-new process.&lt;/p&gt;
- &lt;p&gt;However, it’s interesting to understand why we choose at first ‘Leaders’. &lt;strong&gt;Leaders build new solutions (products) and Advocates new voices (rallying), they are both about personal development and empower commons.&lt;/strong&gt; Leadership=learn+create and advocacy=teach+spread commons. Leaders are projects/orgs leaders, the ones that traduce DNA (values) in products (concrete ability and availability). Advocates are values advocates, the ones that traduce DNA (values) in actions (behavior). As they are both targeting commons, they both produce the same social organization (collaboration instead of competition). They are both involved to create (different) representation (institutions) and organization (foundation/firms) but &lt;strong&gt;with a different DNA (values) processing&lt;/strong&gt;: from public good to personal interest or the opposite. If Mozilla cares about public good resilience, &lt;strong&gt;the articulation of they domains of values is critical. So their articulation’s expression and the revision process must be said and clear&lt;/strong&gt;: from hierarchy vs contract vs different autonomy levels (internal incubation and external advocacy), vs … to criteria to start a revision.&lt;/p&gt;
- &lt;h5&gt;The network effect&lt;/h5&gt;
- &lt;p&gt;Another argument for the switch from Leader to Creator is that the Leader word it too much tight to a single-person-made innovation. &lt;strong&gt;Creator make more clear that the innovation is possible not because of one genius, but because of a team&lt;/strong&gt;, a group, a collective: personS (where there could also be genius). The value is made by the collaboration of people (especially in an open project, especially in a network).&lt;br /&gt;
- That’s important because that could impact how well we do the convening part: not self-promoting, not-advertising, but sharing skills and knowledge for people and catalysing projects.&lt;br /&gt;
- &lt;strong&gt;The same for the wording ‘talent’&lt;/strong&gt;: alone, a talent can do nothing that has an impact. At least, we need two talents, a team (plus some assistants at some point).&lt;/p&gt;
- &lt;h5&gt;The cultural prism&lt;/h5&gt;
- &lt;p&gt;Again, this seems to be an open question:&lt;/p&gt;
- &lt;blockquote&gt;&lt;p&gt;Define and articulate “leadership.†Hone our story, ethos and definition for what we mean by “leadership development†(including cultural / localization aspects).&lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;In my culture, Leader carry positive (take action) and negative (dominate) meanings. That’s another reason why I prefer another naming.&lt;br /&gt;
- I understand too that it carries a lot of legitimacy (ex. market leader) in our societies and it avoids the stay-experimental or non-massive (unique) thoughts. And we need legitimacy to get impact.&lt;br /&gt;
- But the way Mozilla has an impact thought all cultures, its &lt;strong&gt;legitimacy, is by creating or expanding a common&lt;/strong&gt;. To do this, depending on the maturity, Mozilla could follow the market proposing an alternative with superior usability OR opening a new market by adding a vertical segment.&lt;/p&gt;
- &lt;h5&gt;Existing tool-set opportunities&lt;/h5&gt;
- &lt;p&gt;If Leadership is « &lt;em&gt;a year-round MozFest + Lab&lt;/em&gt;« , so it’s a social network + an incubation place. Then, we already have a social network for people involved with Mozilla: Which kind of link should have the leadership network with &lt;strong&gt;mozillians.org&lt;/strong&gt; ? What can we learn from this project and other specialized social network projects (linkedin, viadeo, …) to build the leadership network ?&lt;/p&gt;
- &lt;h4&gt;Advocacy engine: make it clear&lt;/h4&gt;
- &lt;h5&gt;What it is &amp;amp; how it works&lt;/h5&gt;
- &lt;p&gt;Mozilla is doing a great effort to build its advocacy engine on collaboration (« &lt;em&gt;Develop new partnerships and build on current partnerships&lt;/em&gt;« , « &lt;em&gt;begin collaboration&lt;/em&gt;« , « &lt;em&gt;build alliances with similar orgs&lt;/em&gt;« ) but at the same time affirms that Mozilla should be « &lt;em&gt;Part of a broader movement, be the boldest, loudest and most effective advocates&lt;/em&gt; » that could be seen as too centralized, too exclusive.&lt;br /&gt;
- While this can be consistent (or contradictory), &lt;strong&gt;the consistency has to be explained&lt;/strong&gt; looking at orgs and people, global and local, abstract and real, with a complementarity/competitive grid.&lt;br /&gt;
- First, &lt;strong&gt;the articulation with other orgs has to be explained&lt;/strong&gt;. What about others orgs doing things global (&lt;a href=&quot;https://eff.org/&quot;&gt;EFF&lt;/a&gt;, &lt;a href=&quot;https://fsf.org/&quot;&gt;FSF&lt;/a&gt;, …) and local (&lt;a href=&quot;http://www.laquadrature.net/&quot;&gt;Quadrature du net&lt;/a&gt;, CCC, …) ? What about the value they give and that Mozilla doesn’t have (juridic expertise for example) ? What about other advocate engines (&lt;a href=&quot;https://change.org/&quot;&gt;change.org&lt;/a&gt;, &lt;a href=&quot;https://secure.avaaz.org/&quot;&gt;Avaaz&lt;/a&gt;…) ? That should not be at an administrative level only like « &lt;em&gt;Develop an affiliate policy. Defining what MoFo does / does not offer to effectively govern relationships w. affiliated partners and networks (e.g., for issues like branding, fundraising, incentives, participation guidelines, in-kind resources.)&lt;/em&gt; »&lt;br /&gt;
- Second, this is key for users to understand and &lt;strong&gt;articulate the global level of the brand engagement and their local preoccupations and engagement&lt;/strong&gt;. How the engine will be used for local (non-US) battles ? In the past Mozilla totally involved against PIPA, SOPA by taking action, and hesitate a lot to take position and just published a blog post (and too late to gain traction and get impact) against French spying law for example.&lt;br /&gt;
- Third, &lt;strong&gt;the articulation ‘action(own agenda)/reaction’ should be clarified&lt;/strong&gt; in the objectives and functioning of the advocacy engine. Especially because other orgs, allies or detractors, try to to setup the social agenda. It’s important because it can change the social perception of our narrative (alternative promotion/issue fighting) and therefore people’s contributions.&lt;br /&gt;
- People think the technology is socially neutral. People are satisfied of narrow hills of choice (not the meaning, the aim, but only the ability to show your favorite avatar). &lt;strong&gt;People don’t want to feel guilty or oppressed&lt;/strong&gt;, they don’t want new constraints, they are looking for solution only: they want to use, not to do more, they want they things to be done. Part of the problem is about understanding (literacy, education), part of it is about the personal/common duality, part of it is about being hopeless about having an impact, part of it is about expressing change as a positive goal and a new possible way (alternative), not a fight against an issue. About the advocacy engine, I think &lt;strong&gt;our preoccupation should be people-centric and the aim to give them a short, medium and long term narrative to get action without being individuals-centric&lt;/strong&gt;.&lt;/p&gt;
- &lt;h5&gt;How we build it ?&lt;/h5&gt;
- &lt;p&gt;How to build a social movement ? How it has been built in the past ? Is it the same today ? Can it be transposed to the digital domain from others social domains ? How strong are the cultural differences between nations? These are the main questions we should answer, and our pivot era gives us many examples in diverse domains (climate change advocates, Syriza &amp;amp; Podemos, NSA &amp;amp; surveillance services in Europe, empowered syndicates in Venezuela, &lt;a href=&quot;http://blogs.valvesoftware.com/economics/why-valve-or-what-do-we-need-corporations-for-and-how-does-valves-management-structure-fit-into-todays-corporate-world/#more-252&quot;&gt;Valve corp. internal organization&lt;/a&gt;…) to set a search terrain. However, I will go strait to my intuitive understanding below.&lt;br /&gt;
- I’m kind of worried that it’s imagined to build the advocacy engine themes by a top-down method. &lt;strong&gt;I think a successful advocacy is always built bottom-up&lt;/strong&gt;, as its function is to give back the voice to the people, to get them involved, not to make them fulfill our predefined aims. The top-down method is too organization centric: it can’t massively drive people that are not already committed to the org. It’s usually named advertisement or propaganda. If we want to have impact, &lt;strong&gt;we should listen to people needs, not tell them to listen to ours. People want (first) to be empowered, not to empower an org&lt;/strong&gt;. So let’s organize the infrastructure, set the agenda and draw the horizon (strategic understanding) participative: make people fill them with content of their experience. It seems to me it is the only way, the only successful method, if we want to build a movement, and not just a shifting moment (that could be built by the top, with a good press campaign locally relayed for example ; that’s what happen in old style politics: the aim is short term, to cleave).&lt;br /&gt;
- &lt;strong&gt;Isn’t the advocacy engine a new Drumbeat ?&lt;/strong&gt; We shifted from Drumbeat to Webmaker+web literacy to Mozilla Academy and now to Leadership plus advocacy: it could be good to tell that story now that we are shifting again and learn from it.&lt;br /&gt;
- &lt;strong&gt;Mozilla should support, behave as a platform&lt;/strong&gt;, not define, not focus. Letting the people set the agenda makes them more involved and is a good way to build a network of shared aims with other orgs, that is not invasive or alienating, but a support relationship in a win-win move. The strength comes from the all agendas sewed. So at an org level, let’s on-board allies organizations as soon as plan building-time (now), to build it together. Yes it’s slower, but much more massive, inclusive and persistent.&lt;/p&gt;
- &lt;h5&gt;How we evaluate it: cultural bias &amp;amp; qualitative analysis&lt;/h5&gt;
- &lt;p&gt;First, about the agenda-setting KPI for 2016, should these KPI be an evaluation of the inclusion and rank in others strategic agendas, governance systems and productions (outcome/products) ? Others org could be from different domains: political, social, economy orgs.&lt;br /&gt;
- Then, as a wide size audience KPI, Mozilla wants « &lt;em&gt;celebration of our campaigns with ‘headline KPIs’ including number of actions, and number of advocates.&lt;/em&gt;« . While doing this could be the right thing to do for some cultures, it could be the worst for others. I think that these KPI don’t carry a meaning for people and are too org centric. In a way, they are to generic: it’s just an amount. &lt;strong&gt;Accumulation is not our goal: we want impact that is the grow of articulated actions&lt;/strong&gt; made by diverse people toward the same aim. &lt;strong&gt;We need our massive KPI to be more qualitative&lt;/strong&gt;, or at least find a way to present them in a more qualitative way: interactive map ? a global to local prism that engages people for the next step ?&lt;/p&gt;
- &lt;h5&gt;Best practices &amp;amp; massive impact&lt;/h5&gt;
- &lt;p&gt;Selecting best practices are an appealing method when we want to have a fast and strong impact in a wide area. However, &lt;strong&gt;when we unify we should avoid to homogenize&lt;/strong&gt;. The gain in area by scaling-up is always at the cost of loosing local impact because it is not corresponding to local specificities, hence to local expectations. Federating instead of scaling-up is a way to solve this challenge. So we should be careful to not &lt;strong&gt;use best practice as absolute solutions, but as solutions in a context&lt;/strong&gt; if we want to transpose them massively.&lt;/p&gt;
- &lt;h5&gt;Tools &amp;amp; platform balanced between user-centric and org-centric outcomes&lt;/h5&gt;
- &lt;p&gt;It’s good to hear that we will build a advocacy platform. As we ‘had’ bugzilla+svn then mercurial (hg)+… and are going to the &lt;strong&gt;integrated&lt;/strong&gt;, &lt;strong&gt;pluggable&lt;/strong&gt; and &lt;strong&gt;content-centric&lt;/strong&gt; (but non-free; admin tools are closed source) github (targeting more coder than users, but with a lower entry price for users still), we need to be able to have the same kind of tool for advocates and leaders. Something inspired maybe at some levels by the remixing tools we built in Webmakers for web users.&lt;/p&gt;
- &lt;h4&gt;From experiment to production: support (self made to mass product) + modularity (dev code patch to users add-ons).&lt;/h4&gt;
- &lt;p&gt;&lt;strong&gt;We need pathways from lab to home that carry different mix of customization and reliability to support the emancipation curve.&lt;/strong&gt;&lt;br /&gt;
- Users want things to work, because they want to use it. Geeks want to be able to modify a lot and accept to put their hands in the engine to build growing reliability. Advanced users want to customize their experience and keep control and understanding on working status. They want to be able to fix the reliability at a medium/low technical cost. They are OK to gain more control at these prices. Users want to use things to do what they need and want to trust a reliability maintained for them. They are OK to gain control at a no technical cost. Depending on the matter we all have different skill levels, so we are all geeks, advanced users and users depending on our position or on the moment. And depending on our aspirations, we all want to be able to move from one category to an other. That’s what we need to build: we don’t just need to « &lt;em&gt;better articulate the value to our audiences&lt;/em&gt;« , &lt;strong&gt;we need to build pathways thought audiences and thought IT layers&lt;/strong&gt; (content, software, hardware, distant service). &lt;strong&gt;We should find a convergence between customization and reliability, between first time experience, support and add-ons thought all our users’ persona by building bridges, pathways&lt;/strong&gt;. So, « &lt;em&gt;better articulate the value to our audiences&lt;/em&gt; » should not be restrained in our minds to the Mozilla Leadership Network.&lt;br /&gt;
- &lt;strong&gt;Part of this is being done in other projects outside of Mozilla in the commons movement.&lt;/strong&gt; There are many, but let’s take just one example, the &lt;a href=&quot;https://www.fairphone.com/&quot;&gt;Fairphone&lt;/a&gt; project: modularity, howtos, … all this help to break the product-to-use walls and drive appropriation/emancipation. &lt;strong&gt;Products are less product and brand centric and more people/user centric&lt;/strong&gt;.&lt;br /&gt;
- Part of this has been done inside Mozilla, like integrating learning in our products, in-content, as we have code comment on code. I think &lt;strong&gt;the &lt;a href=&quot;https://wiki.mozilla.org/Firefox_OS/Spark&quot;&gt;Spark&lt;/a&gt; project on Firefox OS is on a promising path&lt;/strong&gt;, even if maybe immature: it maybe has not been released mainstream because it misses bridges/pathways (on-boarding levels, progression from simple to high level techniques, and no or not enough reproducible/universal next task/skill building).&lt;br /&gt;
- So some solutions start to emerge, the direction is here, but has never been conceived and implemented that globally, as there isn’t integrated pathways with choice and opportunity and a strategy embracing all products and technologies (platform, tools, …).&lt;/p&gt;
- &lt;h4&gt;Better tools for collaboration and participation: task-centric to process-centric (use) infrastructure&lt;/h4&gt;
- &lt;p&gt;&lt;strong&gt;The open community should definitely improve the collaboration tools and infrastructure to ease participation.&lt;/strong&gt;&lt;br /&gt;
- &lt;strong&gt;&lt;a href=&quot;http://www.discourse.org&quot;&gt;Discourse&lt;/a&gt; ‘merged’ discussion channels&lt;/strong&gt;: email+forum(+instant, messaging, … and others peer-to-peer discussion?). &lt;strong&gt;&lt;a href=&quot;http://stackexchange.com&quot;&gt;Stack exchange&lt;/a&gt; merged the questioning/solving process&lt;/strong&gt; and added a vote mechanism to rank answers: it eased the collaboration on editing the statement and the results while staying synchronous with the discussion and keeping the discussion history. We need such kind of possibilities with discourse: &lt;strong&gt;capitalize on the discussion and preview the results to build a plan.&lt;/strong&gt;&lt;br /&gt;
- This exist in document oriented software (that added collaboration editing tools), but not that much in collaboration software (that don’t produce documents). For example, while discussing the future plan for Fx/FxOS be supported to keep track on a doc about the proposals plans + criteria &amp;amp; dependencies. In action, it is from &lt;a href=&quot;https://mail.mozilla.org/pipermail/firefox-dev/2015-July/003063.html&quot;&gt;this&lt;/a&gt; plus all the discussion taking place to &lt;a href=&quot;https://mail.mozilla.org/pipermail/firefox-dev/2015-July/003119.html&quot;&gt;that&lt;/a&gt;.&lt;br /&gt;
- This is maybe something like integrating Discourse+Wiki, maybe with the need to have competing and ranked (both for content and underlaying meaning of content=strategy?) plan/page proposals. &lt;strong&gt;From evolving the wiki discussion page to featuring document production into peer-to-peer discussion.&lt;/strong&gt;&lt;/p&gt;
- &lt;h4&gt;A recovering strategy: from fail to win&lt;/h4&gt;
- &lt;p&gt;There is maybe one thing that is in the shadow in this plan: &lt;strong&gt;what do we do when/if we (partially) fail ?&lt;/strong&gt;&lt;br /&gt;
- I think at least we should say that &lt;strong&gt;we document&lt;/strong&gt; (keep research going on) to be able to outline and spread the outcomes of what we tried to fight against. So we still try to built consciousness to be ready for the next round.&lt;/p&gt;
- &lt;p&gt; &lt;/p&gt;
- &lt;p&gt;&lt;em&gt;If you see some contradiction in my thoughts, let’s say it’s my state of thinking right now: please voice them so we can go forward.&lt;/em&gt;&lt;br /&gt;
- &lt;em&gt; The same for thoughts that are voiced definitive (like users are): take it as a first attempt with my bias: let’s state these bias to go forward.&lt;/em&gt;&lt;/p&gt;
- &lt;div class=&quot;footnotes&quot; id=&quot;footnotes-48&quot;&gt;
- &lt;div class=&quot;footnotedivider&quot;&gt;&lt;/div&gt;
- &lt;ol&gt;
- &lt;li id=&quot;fn-48-1&quot;&gt; ‘&lt;em&gt;Radical&lt;/em&gt;‘ can be in some cultures an euphemism to ‘&lt;em&gt;violent&lt;/em&gt;‘. Let’s be clear that the change by increasing violence is done to make a popular uprising of some part against others. While it does not help the majority to magically understand that the minority is right, it stigmatize the radical-violent-changers and in the way it discredits the alternative proposed. &lt;span class=&quot;footnotereverse&quot;&gt;&lt;a href=&quot;https://repeer.org/tag/mozilla/feed/#fnref-48-1&quot;&gt;↩&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
- &lt;/ol&gt;
- &lt;/div&gt;</content:encoded>
- <dc:date>2016-01-16T00:27:13+00:00</dc:date>
- <dc:creator>Nicolas</dc:creator>
- </item>
- <item rdf:about="http://bluesock.org/%7Ewillkg/blog/pyvideo/status_20160115.html">
- <title>Will Kahn-Greene: pyvideo status: January 15th, 2016</title>
- <link>http://bluesock.org/%7Ewillkg/blog/pyvideo/status_20160115.html</link>
- <content:encoded>&lt;div class=&quot;section&quot; id=&quot;what-is-pyvideo-org&quot;&gt;
- &lt;h3&gt;What is pyvideo.org&lt;/h3&gt;
- &lt;p&gt;&lt;a class=&quot;reference external&quot; href=&quot;http://pyvideo.org/&quot;&gt;pyvideo.org&lt;/a&gt; is an index of Python-related conference and user-group videos on
- the Internet. Saw a session you liked and want to share it? It's likely you can
- find it, watch it, and share it with pyvideo.org.&lt;/p&gt;
- &lt;p&gt;This is the latest status report for all things happening on the site.&lt;/p&gt;
- &lt;p&gt;It's also an announcement about the end.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://bluesock.org/~willkg/blog/pyvideo/status_20160115.html&quot;&gt;Read more…&lt;/a&gt; (5 mins to read)&lt;/p&gt;&lt;/div&gt;</content:encoded>
- <dc:date>2016-01-15T23:30:00+00:00</dc:date>
- <dc:creator>Will Kahn-Greene</dc:creator>
- </item>
- <item rdf:about="http://coopcoopbware.tumblr.com/post/137371863755">
- <title>Chris Cooper: RelEng &amp; RelOps Weekly Highlights - January 15, 2016</title>
- <link>http://coopcoopbware.tumblr.com/post/137371863755</link>
- <content:encoded>&lt;p&gt;One of releng’s big goals for Q1 is to deliver a beta via &lt;a href=&quot;https://bugzil.la/release-promotion&quot; target=&quot;_blank&quot;&gt;build promotion&lt;/a&gt;. It was great to have some tangible progress there this week with bouncer submission.&lt;/p&gt;
-
- &lt;p&gt;Lots of other stuff in-flight, more details below!
- &lt;/p&gt;&lt;p&gt;&lt;b&gt;Modernize infrastructure&lt;/b&gt;:&lt;/p&gt;
-
- &lt;p&gt;Dustin worked with Armen and Joel Maher to run Firefox tests in TaskCluster on an older EC2 instance type where the tests seem to fail less often, perhaps because they are single-CPU or slower.&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Improve CI pipeline&lt;/b&gt;:&lt;/p&gt;
-
- &lt;p&gt;We turned off automation for b2g 2.2 builds this week, which allowed us to remove some code, reduce some complexity, and regain some small amount of capacity. Thanks to Vlad and Alin on buildduty for helping to land those patches. (&lt;a href=&quot;https://bugzil.la/1236835&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1236835&lt;/a&gt; and &lt;a href=&quot;https://bugzil.la/1237985&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1237985&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;In a similar vein, Callek landed code to disable all b2g desktop builds and tests on all trees. Another win for increased capacity and reduced complexity! (&lt;a href=&quot;https://bugzil.la/1236835&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1236835&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Release&lt;/b&gt;:&lt;/p&gt;
-
- &lt;p&gt;Kim finished integrating bouncer submission with our release promotion project. That’s one more blocker out of the way! (&lt;a href=&quot;https://bugzil.la/1215204&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1215204&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;Ben landed several enhancements to our update server: adding aliases to update rules (&lt;a href=&quot;https://bugzil.la/1067402&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1067402&lt;/a&gt;), and allowing fallbacks for rules with whitelists (&lt;a href=&quot;https://bugzil.la/1235073&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1235073&lt;/a&gt;).&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Operational&lt;/b&gt;:&lt;/p&gt;
- &lt;p&gt;There was some excitement last Sunday when all the trees were closed due to timeouts connectivity issues between our SCL3 datacentre and AWS. (&lt;a href=&quot;https://bugzil.la/238369&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/238369&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Build config&lt;/b&gt;:&lt;/p&gt;
-
- &lt;p&gt;Mike released v0.7.4 of &lt;a href=&quot;http://gittup.org/tup/&quot; target=&quot;_blank&quot;&gt;tup&lt;/a&gt;, and is working on generating the tup backend from moz.build. We hope to offer tup as an alternative build backend sometime soon.&lt;/p&gt;
-
- &lt;p&gt;See you all next week!&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-15T22:44:13+00:00</dc:date>
- </item>
- <item rdf:about="https://air.mozilla.org/webdev-beer-and-tell-january-2016/">
- <title>Air Mozilla: Webdev Beer and Tell: January 2016</title>
- <link>https://air.mozilla.org/webdev-beer-and-tell-january-2016/</link>
- <content:encoded>&lt;p&gt;
- &lt;img alt=&quot;Webdev Beer and Tell: January 2016&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/35/0f/350f246037ead3bab95fdbd4c2b77484.png&quot; width=&quot;160&quot; /&gt;
- Once a month web developers across the Mozilla community get together (in person and virtually) to share what cool stuff we've been working on in...
- &lt;/p&gt;</content:encoded>
- <dc:date>2016-01-15T22:00:00+00:00</dc:date>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item rdf:about="http://blog.mozilla.org/sumo/?p=3665">
- <title>Support.Mozilla.Org: What’s up with SUMO – 15th January</title>
- <link>https://blog.mozilla.org/sumo/2016/01/15/whats-up-with-sumo-15th-january/</link>
- <content:encoded>&lt;p&gt;&lt;strong&gt;Hello, SUMO Nation!&lt;/strong&gt;&lt;/p&gt;
- &lt;p&gt;The second post of the year is here. Have you had a good time in 2016 so far? Let us know in the comments!&lt;/p&gt;
- &lt;p&gt;Now, let’s get going with the updates and activity summaries. It will be brief today, I promise.&lt;/p&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-name&quot;&gt;Welcome, new contributors!&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li class=&quot;author&quot;&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;a class=&quot;username&quot; href=&quot;https://support.mozilla.org/en-US/user/Andy.Yang&quot;&gt;Andy.Yang&lt;/a&gt;&lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;author&quot;&gt;After the massive influx over the last few weeks, we only had Andy introducing himself recently – the warmer the welcome for him!&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;If you just joined us, don’t hesitate – come over and &lt;a href=&quot;https://support.mozilla.org/forums/buddies&quot; target=&quot;_blank&quot;&gt;say “hi†in the forums!&lt;/a&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;
- &lt;h3&gt;&lt;strong&gt;Contributors of the week&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://blog.mozilla.org/sumo/2016/01/08/whats-up-with-sumo-8th-january/&quot; target=&quot;_blank&quot;&gt;All the people who joined us in the winter season so far!&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid64&quot;&gt;
- &lt;p&gt;&lt;strong&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;We salute you!&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
- &lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;Don’t forget that if you are new to SUMO and someone helped you get started in a nice way you can &lt;a href=&quot;https://support.mozilla.org/forums/buddies/711364?last=65670&quot; target=&quot;_blank&quot;&gt;nominate them for the Buddy of the Month!&lt;/a&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;/div&gt;
- &lt;/div&gt;
- &lt;h3&gt;&lt;strong&gt;Most recent SUMO Community meeting&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-2016-01-11&quot; target=&quot;_blank&quot;&gt;You can read the notes here&lt;/a&gt; and see the video on our &lt;a href=&quot;https://www.youtube.com/channel/UCaiposaIhA7HfMqH2NIciyA/videos&quot; target=&quot;_blank&quot;&gt;YouTube channel&lt;/a&gt; and &lt;a href=&quot;https://air.mozilla.org/search/?q=sumo&quot; target=&quot;_blank&quot;&gt;at AirMozilla&lt;/a&gt;.&lt;del&gt; &lt;/del&gt;&lt;del&gt;&lt;br /&gt;
- &lt;/del&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;IMPORTANT: We are considering changing the way the meetings work. Help us figure out what’s best for you – join the discussion on the forums in this thread: &lt;a href=&quot;https://support.mozilla.org/en-US/forums/contributors/711752?last=67873&quot;&gt;(Monday) Community Meetings in 2016&lt;/a&gt;.&lt;/strong&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong&gt;The next SUMO Community meeting… &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;is happening on &lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-2016-01-18&quot; target=&quot;_blank&quot;&gt;Monday the 18th – join us&lt;/a&gt;!&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Reminder: if you want to add a discussion topic to the upcoming meeting agenda:&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;Start a thread in the &lt;a href=&quot;https://support.mozilla.org/forums/contributors&quot; target=&quot;_blank&quot;&gt;Community Forums&lt;/a&gt;, so that everyone in the community can see what will be discussed and voice their opinion here before Monday (this will make it easier to have an efficient meeting).&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;Please do so as soon as you can before the meeting, so that people have time to read, think, and reply (and also add it to the agenda).&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;If you can, please attend the meeting in person (or via IRC), so we can follow up on your discussion topic during the meeting with your feedback.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-g-ivsra51ph44x461i&quot;&gt;Developers&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;The new version of the Ask A Question page is here!&lt;/li&gt;
- &lt;li&gt;The 2.0 version of the KPI dashboard is in the works.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://edwin.mozilla.io/t/sumo&quot; target=&quot;_blank&quot;&gt;You can see the current state of the backlog our developers are working on here&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-p-2016-01-14&quot; target=&quot;_blank&quot;&gt;The latest SUMO Platform meeting notes can be found here&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Interested in learning how Kitsune (the engine behind SUMO) works? &lt;a href=&quot;http://kitsune.readthedocs.org/&quot; target=&quot;_blank&quot;&gt;Read more about it here&lt;/a&gt; and &lt;a href=&quot;https://github.com/mozilla/kitsune/&quot; target=&quot;_blank&quot;&gt;fork it on GitHub&lt;/a&gt;!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong&gt;Community&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Our awesome Bangladesh SUMO Warriors are on the road again! Follow their adventures on Twitter under this tag: &lt;a href=&quot;https://twitter.com/search?q=%23sumotourctg&quot; target=&quot;_blank&quot;&gt;#sumotourctg&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711729?last=67763&quot;&gt;Reminder: take a look at our Work Week Summary for Mozlando. We need your feedback for a few things there.&lt;/a&gt;&lt;/div&gt;
- &lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;Ongoing reminder: if you think you can benefit from getting &lt;a href=&quot;https://wiki.mozilla.org/Community_Hardware&quot; target=&quot;_blank&quot;&gt;a second-hand device&lt;/a&gt; to help you with contributing to SUMO, you know where to find us.&lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong class=&quot;user-chip&quot; title=&quot;adriel0415&quot;&gt;Support Forum&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Say hello to the new people on the forums!
- &lt;ul&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/Tomi55&quot; target=&quot;_blank&quot;&gt;Tomi55&lt;/a&gt; (Hungarian)&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/jdc20181&quot; target=&quot;_blank&quot;&gt;jdc20181&lt;/a&gt; (English)&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/andexi&quot; target=&quot;_blank&quot;&gt;andexi&lt;/a&gt; (Spanish)&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/Qantas94Heavy&quot; target=&quot;_blank&quot;&gt;Qantas94Heavy&lt;/a&gt; (English)&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/samuelms79&quot; target=&quot;_blank&quot;&gt;samuelms79&lt;/a&gt; (Brazilian-PT)&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/jorgecomun&quot; target=&quot;_blank&quot;&gt;jorgecomun&lt;/a&gt; (Spanish)&lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;&quot;&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-g-ivsra51ph44x461i&quot;&gt;Knowledge Base&lt;/strong&gt;&lt;/h3&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid90&quot;&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid82&quot;&gt;
- &lt;ul class=&quot;list-bullet1&quot;&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zjz80zxwjz85z4z65zytdpz68zoz69z&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/forums/knowledge-base-articles/711304#post-65289&quot; target=&quot;_blank&quot;&gt;Thanks to everyone who took part in the most recent KB Day!&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;Version 44 updates should be live now.&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-w2dz70zaz70z7z89zqz78ziz69zz78zz85zz90zj&quot;&gt;&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1lkpRPJp9P1P5MRU-c9dwbDC0w5bMmrMdu-BNMp1xe8w/edit#gid=6&quot; target=&quot;_blank&quot;&gt;Ongoing reminder: learn more about upcoming English article updates by clicking here&lt;/a&gt;&lt;/span&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;Ongoing reminder #2:&lt;a href=&quot;https://support.mozilla.org/forums/knowledge-base-articles/&quot; target=&quot;_blank&quot;&gt; do you have ideas about improving the KB guidelines and training materials? Let us know in the forums&lt;/a&gt;!&lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid83&quot;&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-g-ivsra51ph44x461i&quot;&gt;Localization&lt;/strong&gt;&lt;/h3&gt;
- &lt;/div&gt;
- &lt;/div&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid95&quot;&gt;
- &lt;ul&gt;
- &lt;li&gt;Thanks to everyone writing in with problems, ideas, reports of bugs – all your feedback matters!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid75&quot;&gt;
- &lt;h3&gt;&lt;strong&gt;Firefox&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for Android&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711712?last=67653&quot;&gt;Learn more about Firefox 43 for Android from the official thread with release notes / issues / discussions&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711718?last=67822&quot;&gt;Reminder: Roland is sharing Firefox 44 for Android release notes / issues / discussions&lt;/a&gt; with everyone in the forum.&lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for Desktop&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li&gt;The &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1238620&quot; target=&quot;_blank&quot;&gt;uploading issues reported by many users are being tracked here.&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/questions/firefox?tagged=bug1208145&amp;amp;show=all&quot; target=&quot;_blank&quot;&gt;The “show passwords†button has been removed from the password manager for the Beta of Version 44&lt;/a&gt;. The developers are looking into &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208145&quot; target=&quot;_blank&quot;&gt;last minute fixes for that in this bug&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Also in Version 44, the &lt;span class=&quot;author-a-kz88zz80zhz89z6hlz81znytez70zz66zz68z&quot;&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=606655&quot; target=&quot;_blank&quot;&gt;“ask me everytime†option for cookies will be removed from the privacy panel.&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for iOS&lt;/strong&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid85&quot;&gt;
- &lt;ul class=&quot;list-bullet1&quot;&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-107uz69zz81zhz78z0z78zz84zz66zz76zz82zz77zj&quot;&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/ios/1.4/releasenotes/&quot; target=&quot;_blank&quot;&gt;Firefox for iOS 1.4 primarily with features for China is here&lt;/a&gt;.&lt;br /&gt;
- &lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid86&quot;&gt;
- &lt;ul class=&quot;list-bullet1&quot;&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-107uz69zz81zhz78z0z78zz84zz66zz76zz82zz77zj&quot;&gt;Firefox for iOS 2.0 is after 1.4 and hopefully sometime this quarter!&lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;p&gt;Not that many updates this week, since we’re coming out of our winter slumber (even though winter will be here for a while, still) and plotting an awesome 2016 with you and for you. Take it easy, have a great weekend and see you around SUMO.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-15T19:38:51+00:00</dc:date>
- <dc:creator>Michał</dc:creator>
- </item>
- <item rdf:about="https://air.mozilla.org/paris-firefox-os-hackathon-presentations/">
- <title>Air Mozilla: Paris Firefox OS Hackathon Presentations</title>
- <link>https://air.mozilla.org/paris-firefox-os-hackathon-presentations/</link>
- <content:encoded>&lt;p&gt;
- &lt;img alt=&quot;Paris Firefox OS Hackathon Presentations&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/35/83/358305bfa246fff07d707061082134aa.png&quot; width=&quot;160&quot; /&gt;
- As an introduction to this weekend's Firefox OS Hackathon in Paris we'll have two presentations: - Guillaume Marty will talk about the current state of...
- &lt;/p&gt;</content:encoded>
- <dc:date>2016-01-15T18:00:00+00:00</dc:date>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item rdf:about="https://tacticalsecret.com/tag/mozilla/rss/db7fec0c-34d3-4633-9904-79b98aab34e7">
- <title>J.C. Jones: Renewing Let's Encrypt Certs (Nginx)</title>
- <link>https://tacticalsecret.com/renewing-lets-encrypt-certs-nginx/</link>
- <content:encoded>&lt;p&gt;All the first &lt;a href=&quot;https://crt.sh/?id=10172479&quot;&gt;Let's Encrypt certs for my websites&lt;/a&gt; from the LE private beta began expiring last week, so it was time to work through the renewal tooling. I wanted a script that:&lt;/p&gt;
-
- &lt;ol&gt;
- &lt;li&gt;Would be okay to run daily, so there'd be plenty of retries if something went wrong, &lt;/li&gt;
- &lt;li&gt;Wouldn't require extra config for me to forget about if I add a new site, &lt;/li&gt;
- &lt;li&gt;Would only renew certificates expiring in the next few weeks.&lt;/li&gt;
- &lt;/ol&gt;
-
- &lt;p&gt;The official Let's Encrypt client team is hard at work producing a great renew tool to handle all this, but it's not released yet. Of course I could use &lt;a href=&quot;https://caddyserver.com/&quot;&gt;Caddy Server&lt;/a&gt; that &lt;a href=&quot;https://www.youtube.com/watch?v=nk4EWHvvZtI&quot;&gt;just handles all this&lt;/a&gt;, but I have a lot invested in Nginx here.&lt;/p&gt;
-
- &lt;p&gt;So I wrote a short script and &lt;a href=&quot;https://gist.github.com/jcjones/432eeaa6a2bf25e2c746&quot;&gt;put it up in a Gist&lt;/a&gt;. &lt;/p&gt;
-
- &lt;p&gt;The script is designed to run daily, with a random start between 00:00 and 02:00 to protect against load spikes at Let's Encrypt's infrastructure. It doesn't do any real reporting, though, except to maintain &lt;code&gt;/var/log/letsencrypt/renew.log&lt;/code&gt; as the most-recent failure if one fails.&lt;/p&gt;
-
- &lt;p&gt;It's written to handle Nginx with Upstart's &lt;code&gt;service&lt;/code&gt; command. It's pretty modular though; you could make this operate any webserver, or use the webroot method quite easily. Feel free to use the OpenSSL SubjectAlternativeName processing code for whatever purposes you have.&lt;/p&gt;
-
- &lt;p&gt;Happy renewing!&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-15T16:01:19+00:00</dc:date>
- <dc:creator>James 'J.C.' Jones</dc:creator>
- </item>
- <item rdf:about="http://firefoxmania.uci.cu/?p=15521">
- <title>Yunier José Sosa Vázquez: Conoce los complementos destacados para enero</title>
- <link>http://firefoxmania.uci.cu/conoce-los-complementos-destacados-para-enero-2016/</link>
- <content:encoded>&lt;p style=&quot;text-align: left;&quot;&gt;Comenzó un nuevo año y con él, te traemos nuevos e interesantes complementos para tu navegador preferido que mejoran con creces tu experiencia de navegación. Durante los próximos 6 meses estará trabajando nuevos miembros en el Add-ons Board Team, en la próxima selección desde Firefoxmanía te avisaremos.&lt;/p&gt;
- &lt;h3 style=&quot;text-align: left;&quot;&gt;Elección del mes: uMatrix&lt;/h3&gt;
- &lt;p&gt;uMatrix es muy parecido a un &lt;em&gt;firewall&lt;/em&gt; y desde una ventana fácilmente podrás controlar todos los lugares a donde tu navegador tiene permitido conectarse, qué tipo de datos pueden descargarse y cual puede ejecutar.&lt;/p&gt;
- &lt;blockquote&gt;&lt;p&gt;Esta puede ser la extensión perfecta para el control avanzado de los usuarios.&lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;&lt;span id=&quot;more-15521&quot;&gt;&lt;/span&gt;&lt;/p&gt;
-
- &lt;a href=&quot;http://firefoxmania.uci.cu/conoce-los-complementos-destacados-para-enero-2016/umatrix/&quot;&gt;&lt;img alt=&quot;Interfaz principal de uMatrix&quot; class=&quot;attachment-thumbnail size-thumbnail&quot; height=&quot;160&quot; src=&quot;http://firefoxmania.uci.cu/wp-content/uploads/2016/01/uMatrix-160x160.png&quot; width=&quot;160&quot; /&gt;&lt;/a&gt;
- &lt;a href=&quot;http://firefoxmania.uci.cu/conoce-los-complementos-destacados-para-enero-2016/umatrix2/&quot;&gt;&lt;img alt=&quot;Opciones de configuración de uMatrix&quot; class=&quot;attachment-thumbnail size-thumbnail&quot; height=&quot;160&quot; src=&quot;http://firefoxmania.uci.cu/wp-content/uploads/2016/01/uMatrix2-160x160.png&quot; width=&quot;160&quot; /&gt;&lt;/a&gt;
-
- &lt;p&gt;&lt;em&gt;&lt;a href=&quot;http://addons.firefoxmania.uci.cu/umatrix/&quot; target=&quot;_blank&quot;&gt;Instalar uMatrix »&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
- &lt;h3&gt;También te recomendamos&lt;/h3&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;http://addons.firefoxmania.uci.cu/https-everywhere/&quot; target=&quot;_blank&quot;&gt;⇒ HTTPS Everywhere&lt;/a&gt; por &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/user/eff-technologists/&quot; title=&quot;EFF Technologists&quot;&gt;EFF Technologists&lt;/a&gt;&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;Protege tus comunicaciones habilitando la encriptación HTTPS automáticamente en los sitios conocidos que la soportan, incluso cuando navegas mediante sitios que no incluyen el prefijo “https†en la URL.&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;http://addons.firefoxmania.uci.cu/add-to-search-bar/&quot; target=&quot;_blank&quot;&gt;⇒ Add to Search Bar&lt;/a&gt; por &lt;a href=&quot;https://addons.mozilla.org/firefox/user/dr-evil/&quot; target=&quot;_blank&quot; title=&quot;AdblockLite&quot;&gt;Dr. Evil&lt;/a&gt;&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;Hace posible que cualquier página con un formulario de búsqueda disponible pueda ser añadido fácilmente a la barra de búsqueda de Firefox.&lt;/p&gt;
- &lt;div class=&quot;wp-caption aligncenter&quot; id=&quot;attachment_15528&quot; style=&quot;width: 262px;&quot;&gt;&lt;a href=&quot;http://firefoxmania.uci.cu/wp-content/uploads/2016/01/add_to_search_bar.png&quot; rel=&quot;attachment wp-att-15528&quot;&gt;&lt;img alt=&quot;add_to_search_bar&quot; class=&quot;wp-image-15528 size-medium&quot; height=&quot;226&quot; src=&quot;http://firefoxmania.uci.cu/wp-content/uploads/2016/01/add_to_search_bar-252x226.png&quot; width=&quot;252&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Añadiendo la búsqueda de un sitio web a la barra de búsqueda&lt;/p&gt;&lt;/div&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;http://addons.firefoxmania.uci.cu/duplicate-tabs-closer/&quot; target=&quot;_blank&quot;&gt;⇒ Duplicate Tabs Closer&lt;/a&gt; por &lt;a href=&quot;https://addons.mozilla.org/firefox/user/peuj/&quot; target=&quot;_blank&quot; title=&quot;The 1-Click YouTube Video Download Team&quot;&gt;Peuj&lt;/a&gt;&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;Detecta las pestañas duplicadas en tu navegador y automáticamente las cierra.&lt;/p&gt;
- &lt;h3 style=&quot;text-align: left;&quot;&gt;Nomina tus complementos favoritos&lt;/h3&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;A nosotros nos encantaría que &lt;strong&gt;fueras parte del proceso&lt;/strong&gt; de seleccionar los mejores complementos para Firefox y nos gustaría escucharte. &lt;em&gt;¿No sabes cómo?&lt;/em&gt; Sólo tienes que &lt;em&gt;enviar un correo electrónico&lt;/em&gt; a la dirección &lt;strong&gt;amo-featured@mozilla.org&lt;/strong&gt; con el nombre del complemento o el archivo de instalación y los miembros evaluarán tu recomendación.&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Fuente:&lt;/strong&gt; &lt;a href=&quot;https://blog.mozilla.org/addons/2016/01/01/january-2016-featured-add-ons/&quot; target=&quot;_blank&quot;&gt;Mozilla Add-ons Blog&lt;/a&gt;&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-15T15:10:26+00:00</dc:date>
- <dc:creator>Yunier J</dc:creator>
- </item>
- <item rdf:about="https://timtaubert.de/blog/2016/01/build-your-own-signal-desktop">
- <title>Tim Taubert: Build Your Own Signal Desktop</title>
- <link>https://timtaubert.de/blog/2016/01/build-your-own-signal-desktop/</link>
- <content:encoded>&lt;p&gt;The Signal Private Messenger is great. &lt;strong&gt;Use it.&lt;/strong&gt; It’s probably the best secure
- messenger on the market. When recently a desktop app was announced people were
- eager to join the beta and even happier when an invite finally showed up in
- their inbox. So was I, it’s a great app and works surprisingly well for an early
- version.&lt;/p&gt;
-
- &lt;p&gt;The only problem is that it’s a Chrome App. Apart from excluding folks with
- other browsers it’s also a shitty user experience. If you too want your
- messaging app not tied to a browser then let’s just build our own standalone
- variant of Signal Desktop.&lt;/p&gt;
-
- &lt;h3&gt;NW.js beta with Chrome App support&lt;/h3&gt;
-
- &lt;p&gt;Signal Desktop is a Chrome App, so the easiest way to turn it into a standalone
- app is to use &lt;a href=&quot;http://nwjs.io/&quot;&gt;NW.js&lt;/a&gt;. Conveniently, their next release v0.13
- will ship with Chrome App support and is available for download as a beta
- version.&lt;/p&gt;
-
- &lt;p&gt;First, make sure you have &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt; installed. Then open a terminal and
- prepare a temporary build directory to which we can download a few things and
- where we can build the app:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ mkdir signal-build
- $ cd signal-build
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;h3&gt;[OS X] Packaging Signal and NW.js&lt;/h3&gt;
-
- &lt;p&gt;Download the latest beta of NW.js and &lt;code&gt;unzip&lt;/code&gt; it. We’ll extract the application
- and use it as a template for our Signal clone. The NW.js project does
- unfortunately not seem to provide a secure source (or at least hashes)
- for their downloads.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ wget http://dl.nwjs.io/v0.13.0-beta3/nwjs-sdk-v0.13.0-beta3-osx-x64.zip
- $ unzip nwjs-sdk-v0.13.0-beta3-osx-x64.zip
- $ cp -r nwjs-sdk-v0.13.0-beta3-osx-x64/nwjs.app SignalPrivateMessenger.app
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Next, clone the Signal repository and use NPM to install the necessary modules.
- Run the &lt;code&gt;grunt&lt;/code&gt; automation tool to build the application.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ git clone https://github.com/WhisperSystems/Signal-Desktop.git
- $ cd Signal-Desktop/
- $ npm install
- $ node_modules/grunt-cli/bin/grunt
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Finally, simply to copy the &lt;code&gt;dist&lt;/code&gt; folder containing all the juicy Signal files
- into the application template we created a few moments ago.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ cp -r dist ../SignalPrivateMessenger.app/Contents/Resources/app.nw
- $ open ..
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;The last command opens a Finder window. Move &lt;code&gt;SignalPrivateMessenger.app&lt;/code&gt; to
- your Applications folder and launch it as usual. You should now see a welcome
- page!&lt;/p&gt;
-
- &lt;h3&gt;[Linux] Packaging Signal and NW.js&lt;/h3&gt;
-
- &lt;p&gt;The build instructions for Linux aren’t too different but I’ll write them down,
- if just for convenience. Start by cloning the Signal Desktop repository and
- build.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ git clone https://github.com/WhisperSystems/Signal-Desktop.git
- $ cd Signal-Desktop/
- $ npm install
- $ node_modules/grunt-cli/bin/grunt
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;The &lt;code&gt;dist&lt;/code&gt; folder contains the app, ready to be launched. &lt;code&gt;zip&lt;/code&gt; it and place
- the resulting package somewhere handy.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ cd dist
- $ zip -r ../../package.nw *
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Back to the top. Download the NW.js binary, extract it, and change into the
- newly created directory. Move the &lt;code&gt;package.nw&lt;/code&gt; file we created earlier next to
- the &lt;code&gt;nw&lt;/code&gt; binary and we’re done. The &lt;code&gt;nwjs-sdk-v0.13.0-beta3-linux-x64&lt;/code&gt; folder
- does now contain the standalone Signal app.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ cd ../..
- $ wget http://dl.nwjs.io/v0.13.0-beta3/nwjs-sdk-v0.13.0-beta3-linux-x64.tar.gz
- $ tar xfz nwjs-sdk-v0.13.0-beta3-linux-x64.tar.gz
- $ cd nwjs-sdk-v0.13.0-beta3-linux-x64
- $ mv ../package.nw .
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Finally, launch NW.js. You should see a welcome page!&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ ./nw
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;h3&gt;If you see something, file something&lt;/h3&gt;
-
- &lt;p&gt;Our standalone Signal clone mostly works, but it’s far from perfect. We’re
- pulling from master and that might bring breaking changes that weren’t
- sufficiently tested.&lt;/p&gt;
-
- &lt;p&gt;We don’t have the right icons. The app crashes when you click a media message.
- It opens a blank popup when you click a link. It’s quite big because also NW.js
- has bugs and so we have to use the SDK build for now. In the future it would be
- great to have automatic updates, and maybe even signed builds.&lt;/p&gt;
-
- &lt;p&gt;Remember, Signal Desktop is beta, and completely untested with NW.js. If you
- want to help file bugs, but only after checking that those affect the Chrome
- App too. If you want to fix a bug only occurring in the standalone version
- it’s probably best to file a pull request and cross fingers.&lt;/p&gt;
-
- &lt;h3&gt;Is this secure?&lt;/h3&gt;
-
- &lt;p&gt;Great question! I don’t know. I would love to get some more insights from people
- that know more about the NW.js security model and whether it comes with all the
- protections Chromium can offer. Another interesting question is whether bundling
- Signal Desktop with NW.js is in any way worse (from a security perspective) than
- installing it as a Chrome extension. If you happen to have an opinion about
- that, I would love to hear it.&lt;/p&gt;
-
- &lt;p&gt;Another important thing to keep in mind is that when building Signal on your
- own you will possibly miss automatic and signed security updates from the
- Chrome Web Store. Keep an eye on the repository and rebuild your app from
- time to time to not fall behind too much.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-15T14:00:00+00:00</dc:date>
- </item>
- <item rdf:about="http://glandium.org/blog/?p=3579">
- <title>Mike Hommey: Announcing git-cinnabar 0.3.0</title>
- <link>http://glandium.org/blog/?p=3579</link>
- <content:encoded>&lt;p&gt;Git-cinnabar is a git remote helper to interact with mercurial repositories. It allows to clone, pull and push from/to mercurial remote repositories, using git.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://github.com/glandium/git-cinnabar&quot;&gt;Get it on github&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;These release notes are also &lt;a href=&quot;https://github.com/glandium/git-cinnabar/wiki/Release-Notes:-0.3.0&quot;&gt;available on the git-cinnabar wiki&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Development had been stalled for a few months, with many improvements in the&lt;br /&gt;
- &lt;code&gt;next&lt;/code&gt; branch without any new release. I used some time during the new year&lt;br /&gt;
- break and after in order to straighten things up in order to create a new&lt;br /&gt;
- release, delaying many of the originally planned changes to a future 0.4.0&lt;br /&gt;
- release.&lt;/p&gt;
- &lt;h3&gt;What’s new since 0.2.2?&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Speed and memory usage were improved when doing &lt;code&gt;git push&lt;/code&gt;.&lt;/li&gt;
- &lt;li&gt;Now works on Windows, at least to some extent. See &lt;a href=&quot;http://glandium.org/blog/Windows-Support&quot;&gt;details&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Support for pre-0.1.0 git-cinnabar repositories was removed. You must first&lt;br /&gt;
- use a git-cinnabar version between 0.1.0 and 0.2.2 to upgrade its metadata.&lt;/li&gt;
- &lt;li&gt;It is now possible to attach/graft git-cinnabar metadata to existing commits&lt;br /&gt;
- matching mercurial changesets. This allows to migrate from some other&lt;br /&gt;
- hg-to-git tool to git-cinnabar while preserving the existing git commits.&lt;br /&gt;
- See &lt;a href=&quot;http://glandium.org/blog/Mozilla%3A-Using-a-git-clone-of-gecko%E2%80%90dev-to-push-to-mercurial&quot;&gt;an example of how this works with the git clone of the Gecko mercurial&lt;br /&gt;
- repository&lt;/a&gt;
- &lt;/li&gt;
- &lt;li&gt;Avoid mercurial printing its progress bar, messing up with git-cinnabar’s&lt;br /&gt;
- output.&lt;/li&gt;
- &lt;li&gt;It is now possible to fetch from an incremental mercurial bundle (without&lt;br /&gt;
- a root changeset).&lt;/li&gt;
- &lt;li&gt;It is now possible to push to a new mercurial repository without &lt;code&gt;-f&lt;/code&gt;.&lt;/li&gt;
- &lt;li&gt;By default, reject pushing a new root to a mercurial repository.&lt;/li&gt;
- &lt;li&gt;Make the connection to a mercurial repository through ssh respect the&lt;br /&gt;
- &lt;code&gt;GIT_SSH&lt;/code&gt; and &lt;code&gt;GIT_SSH_COMMAND&lt;/code&gt; environment variables.&lt;/li&gt;
- &lt;li&gt;
- &lt;code&gt;git cinnabar&lt;/code&gt; now has a proper argument parser for all its subcommands.&lt;/li&gt;
- &lt;li&gt;
- &lt;/li&gt;
- &lt;li&gt;A new &lt;code&gt;git cinnabar python&lt;/code&gt; command allows to run python scripts or open a&lt;br /&gt;
- python shell with the right sys.path to import the cinnabar module.&lt;/li&gt;
- &lt;li&gt;All git-cinnabar metadata is now kept under a single ref (although for&lt;br /&gt;
- convenience, other refs are created, but they can be derived if necessary).&lt;/li&gt;
- &lt;li&gt;Consequently, a new &lt;code&gt;git cinnabar rollback&lt;/code&gt; command allows to roll back to&lt;br /&gt;
- previous metadata states.&lt;/li&gt;
- &lt;li&gt;git-cinnabar metadata now tracks the manifests DAG.&lt;/li&gt;
- &lt;li&gt;A new &lt;code&gt;git cinnabar bundle&lt;/code&gt; command allows to create mercurial bundles,&lt;br /&gt;
- mostly for debugging purposes, without requiring to hit a mercurial server.&lt;/li&gt;
- &lt;li&gt;Updated git to 2.7.0 for the native helper.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;Development process changes&lt;/h3&gt;
- &lt;p&gt;Up to before this release closing in, the &lt;code&gt;master&lt;/code&gt; branch was dedicated to&lt;br /&gt;
- releases, and development was happening on the &lt;code&gt;next&lt;/code&gt; branch, until a new&lt;br /&gt;
- release happens.&lt;/p&gt;
- &lt;p&gt;From now on, the &lt;code&gt;release&lt;/code&gt; branch will take dot-release fixes and new&lt;br /&gt;
- releases, while the &lt;code&gt;master&lt;/code&gt; branch will receive all changes that are&lt;br /&gt;
- validated through testing (currently semi-automatically tested with&lt;br /&gt;
- out-of-tree tests based on four real-life mercurial repositories, with&lt;br /&gt;
- some automated CI based on in-tree tests used in the future).&lt;/p&gt;
- &lt;p&gt;The &lt;code&gt;next&lt;/code&gt; branch will receive changes to be tested in CI when things&lt;br /&gt;
- will be hooked up, and may have rewritten history as a consequence of&lt;br /&gt;
- wanting passing tests on every commit on &lt;code&gt;master&lt;/code&gt;.&lt;/p&gt;</content:encoded>
- <dc:date>2016-01-15T08:56:40+00:00</dc:date>
- <dc:creator>glandium</dc:creator>
- </item>
- <item rdf:about="https://air.mozilla.org/web-qa-weekly-meeting-20160114/">
- <title>Air Mozilla: Web QA Weekly Meeting, 14 Jan 2016</title>
- <link>https://air.mozilla.org/web-qa-weekly-meeting-20160114/</link>
- <content:encoded>&lt;p&gt;
- &lt;img alt=&quot;Web QA Weekly Meeting&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/f5/13/f5137857516694df0458e837c2d3a4be.png&quot; width=&quot;160&quot; /&gt;
- This is our weekly gathering of Mozilla'a Web QA team filled with discussion on our current and future projects, ideas, demos, and fun facts.
- &lt;/p&gt;</content:encoded>
- <dc:date>2016-01-14T17:00:00+00:00</dc:date>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
-
-</rdf:RDF>
diff --git a/mobile/android/tests/background/junit4/resources/feed_rss20_planetmozilla.xml b/mobile/android/tests/background/junit4/resources/feed_rss20_planetmozilla.xml
deleted file mode 100644
index a3447ab8a..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_rss20_planetmozilla.xml
+++ /dev/null
@@ -1,3853 +0,0 @@
-<?xml version="1.0"?>
-<rss version="2.0"
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:atom="http://www.w3.org/2005/Atom"
- >
-
- <channel>
- <title>Planet Mozilla</title>
- <link>http://planet.mozilla.org/</link>
- <language>en</language>
- <description>Planet Mozilla - http://planet.mozilla.org/</description>
- <atom:link rel="self" href="http://planet.mozilla.org/rss20.xml" type="application/rss+xml"/>
-
- <item>
- <title>Aaron Klotz: Announcing Mozdbgext</title>
- <guid isPermaLink="false">http://dblohm7.ca/blog/2016/01/26/announcing-mozdbgext</guid>
- <link>http://dblohm7.ca/blog/2016/01/26/announcing-mozdbgext/</link>
- <description>&lt;p&gt;A well-known problem at Mozilla is that, while most of our desktop users run
- Windows, most of Mozilla’s developers do not. There are a lot of problems that
- result from that, but one of the most frustrating to me is that sometimes
- those of us that actually use Windows for development find ourselves at a
- disadvantage when it comes to tooling or other productivity enhancers.&lt;/p&gt;
-
- &lt;p&gt;In many ways this problem is also a Catch-22: People don’t want to use Windows
- for many reasons, but tooling is big part of the problem. OTOH, nobody is
- motivated to improve the tooling situation if nobody is actually going to
- use them.&lt;/p&gt;
-
- &lt;p&gt;A couple of weeks ago my frustrations with the situation boiled over when I
- learned that our &lt;code&gt;Cpp&lt;/code&gt; unit test suite could not log symbolicated call stacks,
- resulting in my filing of &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1238305&quot; title=&quot;cppunittests do not look up breakpad symbols for logged stack traces&quot;&gt;bug 1238305&lt;/a&gt; and &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1240605&quot; title=&quot;Set _NT_SYMBOL_PATH on Windows test machines&quot;&gt;bug 1240605&lt;/a&gt;. Not only could we
- not log those stacks, in many situations we could not view them in a debugger
- either.&lt;/p&gt;
-
- &lt;p&gt;Due to the fact that PDB files consume a large amount of disk space, we don’t
- keep those when building from integration or try repositories. Unfortunately
- they are be quite useful to have when there is a build failure. Most of our
- integration builds, however, do include breakpad symbols. Developers may also
- explicitly &lt;a href=&quot;https://wiki.mozilla.org/ReleaseEngineering/TryServer#Getting_debug_symbols&quot;&gt;request symbols&lt;/a&gt;
- for their try builds.&lt;/p&gt;
-
- &lt;p&gt;A couple of years ago I had begun working on a WinDbg debugger extension that
- was tailored to Mozilla development. It had mostly bitrotted over time, but I
- decided to resurrect it for a new purpose: to help WinDbg&lt;sup&gt;&lt;a href=&quot;http://dblohm7.ca/atom.xml#fn1&quot; id=&quot;r1&quot;&gt;*&lt;/a&gt;&lt;/sup&gt;
- grok breakpad.&lt;/p&gt;
-
- &lt;h3&gt;Enter mozdbgext&lt;/h3&gt;
-
- &lt;p&gt;&lt;a href=&quot;https://github.com/dblohm7/mozdbgext&quot;&gt;&lt;code&gt;mozdbgext&lt;/code&gt;&lt;/a&gt; is the result. This extension
- adds a few commands that makes Win32 debugging with breakpad a little bit easier.&lt;/p&gt;
-
- &lt;p&gt;The original plan was that I wanted &lt;code&gt;mozdbgext&lt;/code&gt; to load breakpad symbols and then
- insert them into the debugger’s symbol table via the &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/windows/hardware/ff537943%28v=vs.85%29.aspx&quot;&gt;&lt;code&gt;IDebugSymbols3::AddSyntheticSymbol&lt;/code&gt;&lt;/a&gt;
- API. Unfortunately the design of this API is not well equipped for bulk loading
- of synthetic symbols: each individual symbol insertion causes the debugger to
- re-sort its entire symbol table. Since &lt;code&gt;xul.dll&lt;/code&gt;’s quantity of symbols is in the
- six-figure range, using this API to load that quantity of symbols is
- prohibitively expensive. I tweeted a Microsoft PM who works on Debugging Tools
- for Windows, asking if there would be any improvements there, but it sounds like
- this is not going to be happening any time soon.&lt;/p&gt;
-
- &lt;p&gt;My original plan would have been ideal from a UX perspective: the breakpad
- symbols would look just like any other symbols in the debugger and could be
- accessed and manipulated using the same set of commands. Since synthetic symbols
- would not work for me in this case, I went for “Plan B:†Extension commands that
- are separate from, but analagous to, regular WinDbg commands.&lt;/p&gt;
-
- &lt;p&gt;I plan to continuously improve the commands that are available. Until I have a
- proper README checked in, I’ll introduce the commands here.&lt;/p&gt;
-
- &lt;h4&gt;Loading the Extension&lt;/h4&gt;
-
- &lt;ol&gt;
- &lt;li&gt;Use the &lt;code&gt;.load&lt;/code&gt; command: &lt;code&gt;.load &amp;lt;path_to_mozdbgext_dll&amp;gt;&lt;/code&gt;&lt;/li&gt;
- &lt;/ol&gt;
-
-
- &lt;h4&gt;Loading the Breakpad Symbols&lt;/h4&gt;
-
- &lt;ol&gt;
- &lt;li&gt;Extract the breakpad symbols into a directory.&lt;/li&gt;
- &lt;li&gt;In the debugger, enter &lt;code&gt;!bploadsyms &amp;lt;path_to_breakpad_symbol_directory&amp;gt;&lt;/code&gt;&lt;/li&gt;
- &lt;li&gt;Note that this command will take some time to load all the relevant symbols.&lt;/li&gt;
- &lt;/ol&gt;
-
-
- &lt;h4&gt;Working with Breakpad Symbols&lt;/h4&gt;
-
- &lt;p&gt;&lt;strong&gt;Note: You must have successfully run the &lt;code&gt;!bploadsyms&lt;/code&gt; command first!&lt;/strong&gt;&lt;/p&gt;
-
- &lt;p&gt;As a general guide, I am attempting to name each breakpad command similarly to
- the native WinDbg command, except that the command name is prefixed by &lt;code&gt;!bp&lt;/code&gt;.&lt;/p&gt;
-
- &lt;ul&gt;
- &lt;li&gt;Stack trace: &lt;code&gt;!bpk&lt;/code&gt;&lt;/li&gt;
- &lt;li&gt;Find nearest symbol to address: &lt;code&gt;!bpln &amp;lt;address&amp;gt;&lt;/code&gt; where &lt;em&gt;address&lt;/em&gt; is specified
- as a hexadecimal value.&lt;/li&gt;
- &lt;/ul&gt;
-
-
- &lt;h4&gt;Downloading windbgext&lt;/h4&gt;
-
- &lt;p&gt;I have pre-built a &lt;a href=&quot;https://github.com/dblohm7/mozdbgext/blob/master/bin/mozdbgext.dll?raw=true&quot;&gt;32-bit binary&lt;/a&gt;
- (which obviously requires 32-bit WinDbg). I have not built a 64-bit binary yet,
- but the code should be source compatible.&lt;/p&gt;
-
- &lt;p&gt;Note that there are several other commands that are “roughed-in†at this point
- and do not work correctly yet. Please stick to the documented commands at this
- time.&lt;/p&gt;
-
- &lt;hr /&gt;
-
- &lt;p&gt;&lt;sup&gt;&lt;a href=&quot;http://dblohm7.ca/atom.xml#r1&quot; id=&quot;fn1&quot;&gt;*&lt;/a&gt;&lt;/sup&gt; When I write “WinDbgâ€, I am really
- referring to any debugger in the &lt;em&gt;Debugging Tools for Windows&lt;/em&gt; package,
- including &lt;code&gt;cdb&lt;/code&gt;.&lt;/p&gt;</description>
- <pubDate>Tue, 26 Jan 2016 19:45:00 +0000</pubDate>
- </item>
- <item>
- <title>Yunier José Sosa Vázquez: Soporte para WebM/VP9, más seguridad y nuevas herramientas para desarrolladores en el nuevo Firefox</title>
- <guid isPermaLink="false">http://firefoxmania.uci.cu/?p=15548</guid>
- <link>http://firefoxmania.uci.cu/soporte-para-webmvp9-mas-seguridad-y-nuevas-herramientas-para-desarrolladores-en-el-nuevo-firefox/</link>
- <description>&lt;p style=&quot;text-align: left;&quot;&gt;¡Como pasa el tiempo amigos! Casi sin darnos cuenta han transcurrido 6 semanas y hasta hemos comenzado un año nuevo, un año en el que Mozilla prepara nuevas funcionalidades que harán de Firefox un mejor como por ejemplo: la &lt;a href=&quot;http://firefoxmania.uci.cu/como-se-hace-activar-electrolysis-en-firefox/&quot; target=&quot;_blank&quot;&gt;separación de procesos&lt;/a&gt;, el uso de vías alternas para &lt;a href=&quot;http://firefoxmania.uci.cu/el-futuro-de-los-plugins-npapi-en-firefox/&quot; target=&quot;_blank&quot;&gt;ejecutar plugins&lt;/a&gt; y la nueva API para desarrollar &lt;a href=&quot;http://firefoxmania.uci.cu/el-futuro-de-los-complementos-en-firefox/&quot; target=&quot;_blank&quot;&gt;complementos “multi navegadorâ€&lt;/a&gt;.&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;Desde el anuncio en 2010 del formato de video WebM, &lt;a href=&quot;https://blog.mozilla.org/blog/2010/05/19/open-web-open-video-and-webm/&quot; target=&quot;_blank&quot;&gt;Mozilla ha mostrado un especial interés&lt;/a&gt; al ser una alternativa potente frente a los formatos propietarios del mercado que existían en aquel momento y de esta forma mejorar la experiencia de los usuarios al reproducir videos en la web. Con esta liberación se ha habilitado el &lt;strong&gt;soporte para WebM/VP9 en aquellos sistemas que no soportan MP4/H.264&lt;/strong&gt;.&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;Desde algunas versiones atrás, Firefox incluye el plugin &lt;a href=&quot;http://andreasgal.com/2014/10/14/openh264-now-in-firefox/&quot; target=&quot;_blank&quot;&gt;OpenH264 proveído por Cisco&lt;/a&gt; para cumplir las especificaciones de WebRTC y habilitar las llamadas con dispositivos que lo requieran. Ahora, si el &lt;strong&gt;decodificador de H.264 está disponible&lt;/strong&gt; en el sistema, entonces se habilita este codec de video.&lt;span id=&quot;more-15548&quot;&gt;&lt;/span&gt;&lt;/p&gt;
- &lt;h3 style=&quot;text-align: left;&quot;&gt;&lt;em&gt;Novedades para desarrolladores&lt;/em&gt;&lt;/h3&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;En esta oportunidad, los desarrolladores podrán contar con herramientas de animación y filtros CSS, informes sobre consumo de memoria, depuración de WebSocket y más. Todo esto puedes leerlo en &lt;a href=&quot;https://www.mozilla-hispano.org/edicion-para-desarrolladores-44-editor-visual-manejo-de-memoria/&quot; target=&quot;_blank&quot;&gt;el blog de Labs&lt;/a&gt; de Mozilla Hispano.&lt;/p&gt;
- &lt;h3 style=&quot;text-align: left;&quot;&gt;&lt;em&gt;Novedades en Android&lt;/em&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Los usuarios pueden elegir la página de inicio a mostrar, en vez de los sitios más visitados.&lt;/li&gt;
- &lt;li&gt;El servicio de impresión de Android permite activar la impresión en la nube.&lt;/li&gt;
- &lt;li&gt;Al &lt;a href=&quot;https://developer.chrome.com/multidevice/android/intents&quot; target=&quot;_blank&quot;&gt;intentar abrir una URIs&lt;/a&gt;, se le pregunta al usuario si desea abrirla en una pestaña privada.&lt;/li&gt;
- &lt;li&gt;Adicionado el soporte para ejecutar URIs con el protocolo mms.&lt;/li&gt;
- &lt;li&gt;Fácil acceso a la configuración de la búsqueda mientras buscamos en Internet.&lt;/li&gt;
- &lt;li&gt;Ahora se muestran las sugerencias del historial de búsqueda.&lt;/li&gt;
- &lt;li&gt;La página Cuentas Firefox ahora está basada en la web.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;em&gt;Otras novedades&lt;/em&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;El soporte para el algoritmo criptográfico RC4 ha sido removido.&lt;/li&gt;
- &lt;li&gt;Soporte para el formato de compresión brotli cuando se usa HTTPS.&lt;/li&gt;
- &lt;li&gt;Uso de un certificado de firmado SHA256 para las versiones de Windows en aras de adaptarse a los nuevos requerimientos.&lt;/li&gt;
- &lt;li&gt;Para soportar el descriptor unicode-range de las fuentes web, el algoritmo de concordancia en Linux usa el mismo código como en las demás plataformas.&lt;/li&gt;
- &lt;li&gt;Firefox no confiará más en la autoridad de certificación Equifax Secure Certificate Authority 1024-bit root o UTN – DATACorp SGC para validar &lt;a href=&quot;https://support.mozilla.org/ta/kb/secure-website-certificate&quot; target=&quot;_blank&quot;&gt;certificados web seguros&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;El soporte para el teclado en pantalla ha sido temporalmente desactivado en Windows 8 y 8.1.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;Si deseas conocer más, puedes leer las &lt;a href=&quot;http://www.mozilla.org/en-US/firefox/44.0/releasenotes/&quot; target=&quot;_blank&quot;&gt;notas de lanzamiento&lt;/a&gt; (en inglés) para conocer más novedades.&lt;/p&gt;
- &lt;p&gt;&lt;strong&gt;Aclaración para la versión móvil.&lt;/strong&gt;&lt;/p&gt;
- &lt;p&gt;En las descargas se pueden encontrar 3 versiones para Android. El archivo que contiene &lt;strong&gt;i386&lt;/strong&gt; es para los dispositivos que tengan la &lt;strong&gt;arquitectura de Intel&lt;/strong&gt;. Mientras que en los nombrados &lt;strong&gt;arm&lt;/strong&gt;, el que dice &lt;strong&gt;api11 funciona con Honeycomb (3.0) o superior&lt;/strong&gt; y el de &lt;strong&gt;api9 es para Gingerbread (2.3)&lt;/strong&gt;.&lt;/p&gt;
- &lt;p&gt;Puedes obtener esta versión desde nuestra &lt;a href=&quot;http://firefoxmania.uci.cu/download/&quot; target=&quot;_blank&quot;&gt;zona de Descargas&lt;/a&gt; en español e inglés para Linux, Mac, Windows y Android. Recuerda que para navegar a través de servidores proxy debes modificar la preferencia &lt;strong&gt;network.auth.force-generic-ntlm&lt;/strong&gt; a &lt;code&gt;true&lt;/code&gt; desde &lt;a target=&quot;_blank&quot;&gt;about:config&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Si te ha gustado, por favor comparte con tus amigos esta noticia en las redes sociales. No dudes en dejarnos un comentario.&lt;/p&gt;</description>
- <pubDate>Tue, 26 Jan 2016 18:56:54 +0000</pubDate>
- <dc:creator>Yunier J</dc:creator>
- </item>
- <item>
- <title>QMO: Firefox 45.0 Beta 3 Testday, February 5th</title>
- <guid isPermaLink="false">https://quality.mozilla.org/?p=49454</guid>
- <link>https://quality.mozilla.org/2016/01/firefox-45-0-beta-3-testday-february-5th/</link>
- <description>&lt;p&gt;Hello Mozillians,&lt;/p&gt;
- &lt;p&gt;We are happy to announce that &lt;strong&gt;Friday, February 5th&lt;/strong&gt;, we are organizing &lt;strong&gt;Firefox 45.0 Beta 3 Testday&lt;/strong&gt;. We will be focusing our testing on the following features: &lt;em&gt;Search Refactoring, Synced Tabs Menu, Text to Speech and Grouped Tabs Migration&lt;/em&gt;. Check out the detailed instructions via &lt;a href=&quot;https://public.etherpad-mozilla.org/p/testday-20160205&quot; target=&quot;_blank&quot;&gt;this etherpad&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;No previous testing experience is required, so feel free to join us on &lt;strong&gt;&lt;a href=&quot;http://widget01.mibbit.com/?server=irc.mozilla.org&amp;amp;channel=%23qa&quot;&gt;#qa IRC channel&lt;/a&gt;&lt;/strong&gt; where our moderators will offer you guidance and answer your questions.&lt;/p&gt;
- &lt;p&gt;Join us and help us make Firefox better! See you on &lt;strong&gt;Friday&lt;/strong&gt;!&lt;/p&gt;</description>
- <pubDate>Tue, 26 Jan 2016 14:40:55 +0000</pubDate>
- <dc:creator>vasilica.mihasca</dc:creator>
- </item>
- <item>
- <title>David Lawrence: Happy BMO Push Day!</title>
- <guid isPermaLink="false">http://dlawrence.wordpress.com/?p=29</guid>
- <link>https://dlawrence.wordpress.com/2016/01/26/happy-bmo-push-day-4/</link>
- <description>&lt;p&gt;the following changes have been pushed to bugzilla.mozilla.org:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1240575&quot; target=&quot;_blank&quot;&gt;1240575&lt;/a&gt;] Update form.reps.budget&lt;/li&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1226028&quot; target=&quot;_blank&quot;&gt;1226028&lt;/a&gt;] API for batching MozReview requests&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;discuss these changes on &lt;a href=&quot;https://lists.mozilla.org/listinfo/tools-bmo&quot; target=&quot;_blank&quot;&gt;mozilla.tools.bmo&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gocomments/dlawrence.wordpress.com/29/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/dlawrence.wordpress.com/29/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;https://pixel.wp.com/b.gif?host=dlawrence.wordpress.com&amp;amp;blog=58816&amp;amp;post=29&amp;amp;subd=dlawrence&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</description>
- <pubDate>Tue, 26 Jan 2016 14:27:50 +0000</pubDate>
- <dc:creator>dlawrence</dc:creator>
- </item>
- <item>
- <title>Tanvi Vyas: Updated Firefox Security Indicators</title>
- <guid isPermaLink="false">http://blog.mozilla.org/tanvi/?p=198</guid>
- <link>https://blog.mozilla.org/tanvi/2016/01/26/updated-firefox-security-indicators/</link>
- <description>&lt;p&gt;&lt;em&gt;This article has been coauthored by Aislinn Grigas, Senior Interaction Designer, Firefox Desktop&lt;/em&gt;&lt;br /&gt;
- &lt;em&gt;Cross posting with &lt;a href=&quot;https://blog.mozilla.org/security/2015/11/03/updated-firefox-security-indicators-2/&quot;&gt;Mozilla’s Security Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;November 3, 2015&lt;/p&gt;
- &lt;p&gt;Over the past few months, Mozilla has been improving the user experience of our privacy and security features in Firefox. One specific initiative has focused on the feedback shown in our address bar around a site’s security. The major changes are highlighted below along with the rationale behind each change.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://blog.mozilla.org/security/files/2015/10/combo-graph21.png&quot;&gt;&lt;img alt=&quot;&quot; class=&quot;alignnone wp-image-2045 size-full&quot; height=&quot;914&quot; src=&quot;https://blog.mozilla.org/security/files/2015/10/combo-graph21.png&quot; width=&quot;1518&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;h3&gt;Change to DV Certificate treatment in the address bar&lt;/h3&gt;
- &lt;p&gt;Color and iconography is commonly used today to communicate to users when a site is secure. The most widely used patterns are coloring a lock icon and parts of the address bar green. This treatment has a straightforward rationale given green = good in most cultures. Firefox has historically used two different color treatments for the lock icon – a gray lock for &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-validated_certificate&quot;&gt;Domain-validated (DV) certificates&lt;/a&gt; and a green lock for &lt;a href=&quot;https://en.wikipedia.org/wiki/Extended_Validation_Certificate&quot;&gt;Extended Validation (EV) certificates&lt;/a&gt;. The average user is likely not going to understand this color distinction between EV and DV certificates. The overarching message we want users to take from both certificate states is that their connection to the site is secure. We’re therefore updating the color of the lock when a DV certificate is used to match that of an EV certificate.&lt;/p&gt;
- &lt;p&gt;Although the same green icon will be used, the UI for a site using EV certificates will continue to differ from a site using a DV certificate. Specifically, EV certificates are used when &lt;a href=&quot;https://en.wikipedia.org/wiki/Certificate_authority&quot;&gt;Certificate Authorities (CA)&lt;/a&gt; verify the owner of a domain. Hence, we will continue to include the organization name verified by the CA in the address bar.&lt;/p&gt;
- &lt;h3&gt;Changes to Mixed Content Blocker UI on HTTPS sites&lt;/h3&gt;
- &lt;p&gt;A second change we’re introducing addresses what happens when a page served over a secure connection contains &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Security/MixedContent&quot;&gt;Mixed Content&lt;/a&gt;. Firefox’s Mixed Content Blocker proactively blocks &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Security/MixedContent#Mixed_active_content&quot;&gt;Mixed Active Content&lt;/a&gt; by default. Users historically saw a &lt;a href=&quot;https://people.mozilla.org/~tvyas/FigureA.jpg&quot;&gt;shield icon&lt;/a&gt; when Mixed Active Content was blocked and were given the option to disable the protection.&lt;/p&gt;
- &lt;p&gt;Since the Mixed Content state is closely tied to site security, the information should be communicated in one place instead of having two separate icons. Moreover, we have seen that the &lt;a href=&quot;https://telemetry.mozilla.org/new-pipeline/dist.html#!cumulative=0&amp;amp;end_date=2015-09-17&amp;amp;keys=__none__!__none__!__none__&amp;amp;max_channel_version=beta%252F41&amp;amp;measure=MIXED_CONTENT_UNBLOCK_COUNTER&amp;amp;min_channel_version=null&amp;amp;product=Firefox&amp;amp;sanitize=1&amp;amp;sort_keys=submissions&amp;amp;start_date=2015-08-11&amp;amp;table=0&amp;amp;trim=1&amp;amp;use_submission_date=0&quot;&gt;number of times users override mixed content protection&lt;/a&gt; is slim, and hence the need for dedicated mixed content iconography is diminishing. Firefox is also using the shield icon for another feature in &lt;a href=&quot;https://support.mozilla.org/en-US/kb/private-browsing-use-firefox-without-history&quot;&gt;Private Browsing Mode&lt;/a&gt; and we want to avoid making the iconography ambiguous.&lt;/p&gt;
- &lt;p&gt;The updated design that ships with Firefox 42 combines the lock icon with a warning sign which represents Mixed Content. When Firefox blocks Mixed Active Content, we retain the green lock since the HTTP content is blocked and hence the site remains secure.&lt;/p&gt;
- &lt;p&gt;For users who want to learn more about a site’s security state, we have added an informational panel to further explain differences in page security. This panel appears anytime a user clicks on the lock icon in the address bar.&lt;/p&gt;
- &lt;p&gt;Previously users could &lt;a href=&quot;https://people.mozilla.org/~tvyas/FigureB.jpg&quot;&gt;click on the shield icon&lt;/a&gt; in the rare case they needed to override mixed content protection. With this new UI, users can still do this by clicking the arrow icon to expose more information about the site security, along with a disable protection button.&lt;/p&gt;
- &lt;div class=&quot;wp-caption alignnone&quot; id=&quot;attachment_2034&quot; style=&quot;width: 557px;&quot;&gt;&lt;a href=&quot;https://blog.mozilla.org/security/files/2015/10/mixed-active-content-click-and-subpanel.png&quot;&gt;&lt;img alt=&quot;mixed active content click and subpanel&quot; class=&quot;wp-image-2034 &quot; height=&quot;176&quot; src=&quot;https://blog.mozilla.org/security/files/2015/10/mixed-active-content-click-and-subpanel.png&quot; width=&quot;547&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Users can click the lock with warning icon and proceed to disable Mixed Content Protection.&lt;/p&gt;&lt;/div&gt;
- &lt;h3&gt;&lt;/h3&gt;
- &lt;h3&gt;Loading Mixed Passive Content on HTTPS sites&lt;/h3&gt;
- &lt;p&gt;There is a second category of Mixed Content called &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Security/MixedContent#Mixed_passivedisplay_content&quot;&gt;Mixed Passive Content&lt;/a&gt;. Firefox does not block Mixed Passive Content by default. However, when it is loaded on an HTTPS page, we let the user know with iconography and text. In previous versions of Firefox, we used a gray warning sign to reflect this case.&lt;/p&gt;
- &lt;p&gt;We have updated this iconography in Firefox 42 to a gray lock with a yellow warning sign. We degrade the lock from green to gray to emphasize that the site is no longer completely secure. In addition, we use a vibrant color for the warning icon to amplify that there is something wrong with the security state of the page.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://blog.mozilla.org/security/files/2015/10/mixed-passive-click1.png&quot;&gt;&lt;img alt=&quot;&quot; class=&quot;alignnone wp-image-2042 &quot; height=&quot;100&quot; src=&quot;https://blog.mozilla.org/security/files/2015/10/mixed-passive-click1-600x221.png&quot; width=&quot;268&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;We also use this iconography when the certificate or TLS connection used by the website relies on deprecated cryptographic algorithms.&lt;/p&gt;
- &lt;p&gt;The above changes will be rolled out in Firefox 42. Overall, the design improvements make it simpler for our users to understand whether or not their interactions with a site are secure.&lt;/p&gt;
- &lt;h3&gt;Firefox Mobile&lt;/h3&gt;
- &lt;p&gt;We have made similar changes to the site security indicators in Firefox for Android, which you can learn more about &lt;a href=&quot;https://support.mozilla.org/en-US/kb/mixed-content-blocker-firefox-android#w_how-do-i-know-if-a-page-has-mixed-content&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</description>
- <pubDate>Tue, 26 Jan 2016 05:58:29 +0000</pubDate>
- <dc:creator>Tanvi Vyas</dc:creator>
- </item>
- <item>
- <title>The Mozilla Blog: Firefox Can Now Get Push Notifications From Your Favorite Sites</title>
- <guid isPermaLink="false">https://blog.mozilla.org/?p=9166</guid>
- <link>https://blog.mozilla.org/blog/2016/01/25/firefox-can-now-get-push-notifications-from-your-favorite-sites/</link>
- <description>&lt;p&gt;UPDATED TO CLARIFY HOW TO MANAGE PUSH NOTIFICATIONS&lt;/p&gt;
- &lt;p&gt;Firefox for Windows, Mac and Linux now lets you choose to receive push notifications from websites if you give them permission. This is similar to Web notifications, except now you can receive notifications for websites even when they’re not loaded in a tab. This is super useful for websites like email, weather, social networks and shopping, which you might check frequently for updates.&lt;/p&gt;
- &lt;p&gt;You can manage your notifications in the Control Center by clicking the green lock icon on the left side of the address bar. You can learn more about how to manage push notifications&lt;a href=&quot;https://support.mozilla.org/en-US/kb/push-notifications-firefox?as=u&amp;amp;utm_source=inproduct#w_upgraded-notifications&quot;&gt; here&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;b&gt;Push Notifications for Web Developers&lt;/b&gt;&lt;br /&gt;
- To make this functionality possible, Mozilla helped establish the Web Push W3C standard that’s gaining momentum across the Web. We also continue to explore the new design pattern known as&lt;a href=&quot;https://blog.mozilla.org/futurereleases/2015/11/17/extending-the-webs-capabilities-in-firefox-and-beyond/&quot;&gt; Progressive Web Apps&lt;/a&gt;. If you’re a developer who wants to implement push notifications on your site, you can learn more in this&lt;a href=&quot;https://hacks.mozilla.org/2016/01/web-push-arrives-in-firefox-44/&quot;&gt; Hacks blog post&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;b&gt;More information:&lt;/b&gt;&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;Download&lt;a href=&quot;https://www.mozilla.org/firefox/new/&quot;&gt; Firefox for Windows, Mac, Linux&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Release Notes for&lt;a href=&quot;https://www.mozilla.org/firefox/44.0/releasenotes/&quot;&gt; Firefox for Windows, Mac, Linux&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Download&lt;a href=&quot;https://play.google.com/store/apps/details?id=org.mozilla.firefox&amp;amp;referrer=utm_source%3Dmozilla%26utm_medium&quot;&gt; Firefox for Android&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Release Notes for&lt;a href=&quot;https://www.mozilla.org/firefox/android/44.0/releasenotes/&quot;&gt; Firefox for Android&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;</description>
- <pubDate>Tue, 26 Jan 2016 01:56:50 +0000</pubDate>
- <dc:creator>Mozilla</dc:creator>
- </item>
- <item>
- <title>Benoit Girard: Using RecordReplay to investigate intermittent oranges</title>
- <guid isPermaLink="false">http://benoitgirard.wordpress.com/?p=651</guid>
- <link>https://benoitgirard.wordpress.com/2016/01/25/using-recordreplay-to-investigate-intermittent-oranges/</link>
- <description>&lt;p&gt;This is a quick write up to summarize my, and Jeff’s, experience, using RR to debug a &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1226748&quot;&gt;fairly rare intermittent reftest failure&lt;/a&gt;. There’s still a lot of be learned about how to use RR effectively so I’m hoping sharing this will help others.&lt;/p&gt;
- &lt;h3&gt;Finding the root of the bad pixel&lt;/h3&gt;
- &lt;p&gt;First given a offending pixel I was able to set a breakpoint on it using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Hacking_Tips#rr_with_reftest&quot;&gt;these instructions&lt;/a&gt;. Next using &lt;a href=&quot;https://github.com/jrmuizel/rr-dataflow&quot;&gt;rr-dataflow&lt;/a&gt; I was able to step from the offending bad pixel to the display item responsible for this pixel. Let me emphasize this for a second since it’s incredibly impressive. rr + rr-dataflow allows you to go from a buffer, through an intermediate surface, to the compositor on another thread, through another intermediate surface, back to the main thread and eventually back to the relevant display item. All of this was automated except for when the two pixels are blended together which is logically ambiguous. The speed at which rr was able to reverse continue through this execution was very impressive!&lt;/p&gt;
- &lt;p&gt;Here’s the trace of this part: &lt;a href=&quot;https://gist.github.com/bgirard/e707e9b97556b500d9ae&quot;&gt;rr-trace-reftest-pixel-origin&lt;/a&gt;&lt;/p&gt;
- &lt;h3&gt;Understanding the decoding step&lt;/h3&gt;
- &lt;p&gt;From here I started comparing a replay of a failing test and a non failing step and it was clear that the DisplayList was different. In one we have a nsDisplayBackgroundColor in the other we don’t. From here I was able to step through the decoder and compare the sequence. This was very useful in ruling out possible theories. It was easy to step forward and backwards in the good and bad replay debugging sessions to test out various theories about race conditions and understanding at which part of the decode process the image was rejected. It turned out that we sent two decodes, one for the metadata that is used to sized the frame tree and the other one for the image data itself.&lt;/p&gt;
- &lt;h3&gt;Comparing the frame tree&lt;/h3&gt;
- &lt;p&gt;In hindsight, it would have been more effective to start debugging this test by looking at the frame tree (and I imagine for other tests looking at the display list and layer tree) first would have been a quicker start. It works even better if you have a good and a bad trace to compare the difference in the frame tree. From here, I found that the difference in the layer tree came from a change hint that wasn’t guaranteed to come in before the draw.&lt;/p&gt;
- &lt;p&gt;The problem is now well understood: When we do a sync decode on reftest draw, if there’s an image error we wont flush the style hints since we’re already too deep in the painting pipeline.&lt;/p&gt;
- &lt;h3&gt;Take away&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Finding the root cause of a bad pixel is very easy, and fast, to do using rr-dataflow.&lt;/li&gt;
- &lt;li&gt;However it might be better to look for obvious frame tree/display list/layer tree difference(s) first.&lt;/li&gt;
- &lt;li&gt;Debugging a replay is a lot simpler then debugging against non-determinist re-runs and a lot less frustrating too.&lt;/li&gt;
- &lt;li&gt;rr is really useful for race conditions, especially rare ones.&lt;/li&gt;
- &lt;/ul&gt;&lt;br /&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gocomments/benoitgirard.wordpress.com/651/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/benoitgirard.wordpress.com/651/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;https://pixel.wp.com/b.gif?host=benoitgirard.wordpress.com&amp;amp;blog=12112851&amp;amp;post=651&amp;amp;subd=benoitgirard&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</description>
- <pubDate>Mon, 25 Jan 2016 22:16:01 +0000</pubDate>
- <dc:creator>benoitgirard</dc:creator>
- </item>
- <item>
- <title>The Servo Blog: These Weeks In Servo 48</title>
- <guid isPermaLink="true">http://blog.servo.org/2016/01/25/twis-48/</guid>
- <link>http://blog.servo.org/2016/01/25/twis-48/</link>
- <description>&lt;p&gt;In the &lt;a href=&quot;https://github.com/pulls?page=1&amp;amp;q=is%3Apr+is%3Amerged+closed%3A2016-01-11..2016-01-25+user%3Aservo&quot;&gt;last two weeks&lt;/a&gt;, we landed 130 PRs in the Servo organization’s repositories.&lt;/p&gt;
-
- &lt;p&gt;After months of work by vlad and many others, Windows support &lt;a href=&quot;https://github.com/servo/servo/pull/9385&quot;&gt;landed&lt;/a&gt;! Thanks to everyone who contributed fixes, tests, reviews, and even encouragement (or impatience!) to help us make this happen.&lt;/p&gt;
-
- &lt;h3 id=&quot;notable-additions&quot;&gt;Notable Additions&lt;/h3&gt;
-
- &lt;ul&gt;
- &lt;li&gt;nikki &lt;a href=&quot;https://github.com/servo/servo/pull/9391&quot;&gt;added&lt;/a&gt; tests and support for checking the Fetch redirect count&lt;/li&gt;
- &lt;li&gt;glennw &lt;a href=&quot;https://github.com/servo/servo/pull/9359&quot;&gt;implemented&lt;/a&gt; horizontal scrolling with arrow keys&lt;/li&gt;
- &lt;li&gt;simon &lt;a href=&quot;https://github.com/servo/servo/pull/9333&quot;&gt;created&lt;/a&gt; a script that parses all of the CSS properties parsed by Servo&lt;/li&gt;
- &lt;li&gt;ms2ger &lt;a href=&quot;https://github.com/servo/servo/pull/9293&quot;&gt;removed&lt;/a&gt; the legacy reftest framework&lt;/li&gt;
- &lt;li&gt;fernando &lt;a href=&quot;https://github.com/servo/crowbot/pull/33&quot;&gt;made&lt;/a&gt; crowbot able to rejoin IRC after it accidentally floods the channel&lt;/li&gt;
- &lt;li&gt;jack &lt;a href=&quot;https://github.com/servo/saltfs/pull/193&quot;&gt;added&lt;/a&gt; testing the &lt;code&gt;geckolib&lt;/code&gt; target to our CI&lt;/li&gt;
- &lt;li&gt;antrik &lt;a href=&quot;https://github.com/servo/ipc-channel/pull/25&quot;&gt;fixed&lt;/a&gt; transfer corruption in ipc-channel on 32-bit&lt;/li&gt;
- &lt;li&gt;valentin &lt;a href=&quot;https://github.com/servo/rust-url/pull/119&quot;&gt;added&lt;/a&gt; and simon &lt;a href=&quot;https://github.com/servo/rust-url/pull/152&quot;&gt;extended&lt;/a&gt; IDNA support in rust-url, which is required for both web and Gecko compatibility&lt;/li&gt;
- &lt;/ul&gt;
-
- &lt;h3 id=&quot;new-contributors&quot;&gt;New Contributors&lt;/h3&gt;
-
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/Chandler&quot;&gt;Chandler Abraham&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/DarinM223&quot;&gt;Darin Minamoto&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/coder543&quot;&gt;Josh Leverette&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/shssoichiro&quot;&gt;Joshua Holmer&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/therealkbhat&quot;&gt;Kishor Bhat&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/MonsieurLanza&quot;&gt;Lanza&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/mattkuo&quot;&gt;Matthew Kuo&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/waterlink&quot;&gt;Oleksii Fedorov&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/stspyder&quot;&gt;St.Spyder&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/vvuk&quot;&gt;Vladimir Vukicevic&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/apopiak&quot;&gt;apopiak&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/askalski&quot;&gt;askalski&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
-
- &lt;h3 id=&quot;screenshot&quot;&gt;Screenshot&lt;/h3&gt;
-
- &lt;p&gt;Screencast of this post being upvoted on reddit… from Windows!&lt;/p&gt;
-
- &lt;p&gt;&lt;img alt=&quot;(screencast)&quot; src=&quot;http://blog.servo.org/images/upvote-windows.gif&quot; title=&quot;Screencast of upvoting on Reddit on Windows.&quot; /&gt;&lt;/p&gt;
-
- &lt;h3 id=&quot;meetings&quot;&gt;Meetings&lt;/h3&gt;
-
- &lt;p&gt;We had a &lt;a href=&quot;https://github.com/servo/servo/wiki/Meeting-2016-01-11&quot;&gt;meeting&lt;/a&gt; on some CI-related woes, documenting tags and mentoring, and dependencies for the style subsystem.&lt;/p&gt;</description>
- <pubDate>Mon, 25 Jan 2016 20:30:00 +0000</pubDate>
- </item>
- <item>
- <title>Air Mozilla: Mozilla Weekly Project Meeting, 25 Jan 2016</title>
- <guid isPermaLink="true">https://air.mozilla.org/mozilla-weekly-project-meeting-20160125/</guid>
- <link>https://air.mozilla.org/mozilla-weekly-project-meeting-20160125/</link>
- <description>&lt;p&gt;
- &lt;img alt=&quot;Mozilla Weekly Project Meeting&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/e9/4f/e94fbd7f8df916c75a60e63a85b9168c.png&quot; width=&quot;160&quot; /&gt;
- The Monday Project Meeting
- &lt;/p&gt;</description>
- <pubDate>Mon, 25 Jan 2016 19:00:00 +0000</pubDate>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item>
- <title>About:Community: Firefox 44 new contributors</title>
- <guid isPermaLink="false">http://blog.mozilla.org/community/?p=2292</guid>
- <link>http://blog.mozilla.org/community/2016/01/25/firefox-44-new-contributors/</link>
- <description>&lt;p&gt;With the release of Firefox 44, we are pleased to welcome the &lt;strong&gt;28 developers&lt;/strong&gt; who contributed their first code change to Firefox in this release, &lt;strong&gt;23&lt;/strong&gt; of whom were brand new volunteers! Please join us in thanking each of these diligent and enthusiastic individuals, and take a look at their contributions:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;mkm: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208124&quot;&gt;1208124&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Aditya Motwani: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1209087&quot;&gt;1209087&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Aniket Vyas: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1197309&quot;&gt;1197309&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1197315&quot;&gt;1197315&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Chirath R: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1216941&quot;&gt;1216941&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Christiane Ruetten: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1209091&quot;&gt;1209091&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Fernando Campo: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1199815&quot;&gt;1199815&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Grisha Pushkov: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=994555&quot;&gt;994555&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Guang-De Lin: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1150305&quot;&gt;1150305&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Hassen ben tanfous: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1074804&quot;&gt;1074804&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Helen V. Holmes: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1205046&quot;&gt;1205046&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Henrik Tjäder: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1161698&quot;&gt;1161698&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1209912&quot;&gt;1209912&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Johann Hofmann: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1192432&quot;&gt;1192432&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1198405&quot;&gt;1198405&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1204072&quot;&gt;1204072&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Kapeel Sable: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1212171&quot;&gt;1212171&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Manav Batra: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1202618&quot;&gt;1202618&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1212280&quot;&gt;1212280&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1214626&quot;&gt;1214626&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Manuel Casas Barrado: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1172662&quot;&gt;1172662&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1193674&quot;&gt;1193674&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1200693&quot;&gt;1200693&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1203298&quot;&gt;1203298&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1205684&quot;&gt;1205684&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1212331&quot;&gt;1212331&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1212338&quot;&gt;1212338&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1214582&quot;&gt;1214582&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Matt Howell: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208626&quot;&gt;1208626&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Matthew Turnbull: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1213620&quot;&gt;1213620&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Olivier Yiptong: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1210936&quot;&gt;1210936&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1210940&quot;&gt;1210940&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1213078&quot;&gt;1213078&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Piotr Tworek: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1209446&quot;&gt;1209446&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Rocik: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1070719&quot;&gt;1070719&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Roland Sako: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1207733&quot;&gt;1207733&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Ronald Claveau: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1207266&quot;&gt;1207266&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Sanchit Nevgi: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1205181&quot;&gt;1205181&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Shaif Chowdhury: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1185606&quot;&gt;1185606&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208121&quot;&gt;1208121&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Shubham Jain: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208470&quot;&gt;1208470&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208705&quot;&gt;1208705&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Stanislas Daniel Claude Dolcini: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1147197&quot;&gt;1147197&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Stephanie Ouillon: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1178533&quot;&gt;1178533&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1201626&quot;&gt;1201626&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Tim Huang: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1181489&quot;&gt;1181489&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;simplyblue24: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1218204&quot;&gt;1218204&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;</description>
- <pubDate>Mon, 25 Jan 2016 16:21:33 +0000</pubDate>
- <dc:creator>Josh Matthews</dc:creator>
- </item>
- <item>
- <title>Doug Belshaw: 3 things to consider when designing a digital skills framework</title>
- <guid isPermaLink="false">tag:literaci.es,2014:Post/digital-skills-curriculum</guid>
- <link>http://literaci.es/digital-skills-curriculum</link>
- <description>&lt;p&gt;&lt;img alt=&quot;Learning to credential&quot; src=&quot;http://bryanmmathers.com/wp-content/uploads/2016/01/learning-to-credential.png&quot; /&gt;&lt;/p&gt;
-
- &lt;p&gt;The image above was created by &lt;a href=&quot;http://bryanmmathers.com/learning-to-credential&quot; rel=&quot;nofollow&quot;&gt;Bryan Mathers&lt;/a&gt; for our &lt;a href=&quot;https://goo.gl/QqwUKP&quot; rel=&quot;nofollow&quot;&gt;presentation&lt;/a&gt; at &lt;a href=&quot;http://bettshow.com&quot; rel=&quot;nofollow&quot;&gt;BETT&lt;/a&gt; last week. It shows the way that, in broad brushstrokes, learning design &lt;em&gt;should&lt;/em&gt; happen. Before microcredentials such as &lt;a href=&quot;http://openbadges.org&quot; rel=&quot;nofollow&quot;&gt;Open Badges&lt;/a&gt; this was a difficult thing to do as both the credential and the assessment are usually given to educators. The flow tends to go &lt;em&gt;backwards&lt;/em&gt; from credentials instead of forwards from what we want people to learn.&lt;/p&gt;
-
- &lt;p&gt;But what if you really &lt;em&gt;were&lt;/em&gt; starting from scratch? How could you design a digital skills framework that contains knowledge, skills, and behaviours worth learning? Having written my &lt;a href=&quot;http://neverendingthesis.com&quot; rel=&quot;nofollow&quot;&gt;thesis&lt;/a&gt; on digital literacies and led Mozilla’s &lt;a href=&quot;https://teach.mozilla.org/activities/web-literacy/&quot; rel=&quot;nofollow&quot;&gt;Web Literacy Map&lt;/a&gt; for a couple of years, I’ve got some suggestions. &lt;/p&gt;
- &lt;h3&gt;
- &lt;a class=&quot;head_anchor&quot; href=&quot;http://literaci.es/feed#1-define-your-audience&quot; name=&quot;1-define-your-audience&quot; rel=&quot;nofollow&quot;&gt; &lt;/a&gt;1. Define your audience&lt;/h3&gt;
- &lt;p&gt;One of the most important things to define is who your audience is for your digital skills framework. Is it for learners to read? Who are they? How old are they? Are you excluding anyone on purpose? Why / why not?&lt;/p&gt;
-
- &lt;p&gt;You might want to do some research and work around &lt;a href=&quot;https://en.wikipedia.org/wiki/Persona_(user_experience)&quot; rel=&quot;nofollow&quot;&gt;user personas&lt;/a&gt; as part of a user-centred design approach. This ensures you’re designing for real people instead of figments of your imagination (or, worse still, in line with your prejudices).&lt;/p&gt;
-
- &lt;p&gt;It’s also good practice to make the language used in the skills framework as precise as possible. Jargon is technical language used for the sake of it. There may be times when it’s impossible not to use a word (e.g. ’&lt;a href=&quot;https://en.wikipedia.org/wiki/Meme&quot; rel=&quot;nofollow&quot;&gt;meme&lt;/a&gt;’). If you do this then link to a definition or include a glossary. It’s also useful to check the ‘reading level’ of your framework and, if you really want a challenge, try using &lt;a href=&quot;http://splasho.com/upgoer5/&quot; rel=&quot;nofollow&quot;&gt;Up-Goer Five&lt;/a&gt; language.&lt;/p&gt;
- &lt;h3&gt;
- &lt;a class=&quot;head_anchor&quot; href=&quot;http://literaci.es/feed#2-focus-on-verbs&quot; name=&quot;2-focus-on-verbs&quot; rel=&quot;nofollow&quot;&gt; &lt;/a&gt;2. Focus on verbs&lt;/h3&gt;
- &lt;p&gt;It’s extremely easy, when creating a framework for learning, to fall into the 'knowledge trap’. Our aim when creating the raw materials from which someone can build a curriculum is to focus on &lt;em&gt;action&lt;/em&gt;. Knowledge should make a difference in practice.&lt;/p&gt;
-
- &lt;p&gt;One straightforward way to ensure that you’re focusing on action rather than head knowledge is to use &lt;strong&gt;verbs&lt;/strong&gt; when constructing your digital skills framework. If you’re familiar with &lt;a href=&quot;https://en.wikipedia.org/wiki/Bloom%27s_taxonomy&quot; rel=&quot;nofollow&quot;&gt;Bloom’s Taxonomy&lt;/a&gt;, then you may find &lt;a href=&quot;http://byrdseed.com/differentiator/&quot; rel=&quot;nofollow&quot;&gt;The Differentiator&lt;/a&gt; useful. This pairs verbs with the various levels of Bloom’s.&lt;/p&gt;
- &lt;h3&gt;
- &lt;a class=&quot;head_anchor&quot; href=&quot;http://literaci.es/feed#3-add-version-numbers&quot; name=&quot;3-add-version-numbers&quot; rel=&quot;nofollow&quot;&gt; &lt;/a&gt;3. Add version numbers&lt;/h3&gt;
- &lt;p&gt;A framework needs to be a living, breathing thing. It should be subject to revision and updated often. For this reason, you should add version numbers to your documentation. Ideally, the latest version should be at a canonical URL and you should archive previous versions to static URLs. &lt;/p&gt;
-
- &lt;p&gt;I would also advise releasing the first version of your framework not as 'version 1.0’ but as 'v0.1’. This shows that you’re willing for others to provide input, that there will be further versions, and that you know you haven’t got it right first time (and forevermore). &lt;/p&gt;
-
- &lt;hr /&gt;
-
- &lt;p&gt;&lt;strong&gt;Questions? Comments?&lt;/strong&gt; Ask me on Twitter (&lt;a href=&quot;http://twitter.com/dajbelshaw&quot; rel=&quot;nofollow&quot;&gt;@dajbelshaw&lt;/a&gt;). I also consult around this kind of thing, so hit me up on &lt;a href=&quot;http://literaci.es/hello@dynamicskillset.com&quot; rel=&quot;nofollow&quot;&gt;hello@dynamicskillset.com&lt;/a&gt;&lt;/p&gt;</description>
- <pubDate>Mon, 25 Jan 2016 14:46:34 +0000</pubDate>
- </item>
- <item>
- <title>Mozilla Fundraising: Why did you decide to donate today?</title>
- <guid isPermaLink="false">https://fundraising.mozilla.org/?p=800</guid>
- <link>https://fundraising.mozilla.org/why-did-you-decide-to-donate-today/</link>
- <description>This year, we asked some of our donors why they decided to donate to our end of year fundraising campaign. The Survey The Audience The survey was shown to a random sample of donors whose browser language was set to … &lt;a class=&quot;go&quot; href=&quot;https://fundraising.mozilla.org/why-did-you-decide-to-donate-today/&quot;&gt;Continue reading&lt;/a&gt;</description>
- <pubDate>Mon, 25 Jan 2016 13:31:34 +0000</pubDate>
- <dc:creator>Adam Lofting</dc:creator>
- </item>
- <item>
- <title>Andy McKay: Robbie Burns</title>
- <guid isPermaLink="false">http://www.agmweb.ca/robbie-burns</guid>
- <link>http://www.agmweb.ca/2016-01-25-robbie-burns/</link>
- <description>&lt;p&gt;Tonight is Robbie Burns night, in honour of that great Scottish poet. But tonight had me thinking about another night in my past.&lt;/p&gt;
-
- &lt;p&gt;It was about 5 years ago, maybe less, I struggle to remember now. I was in the UK visiting family and my Dad was sick. Cancer and it's treatment is tough, you have good weeks, you have bad weeks and you have really fucking bad weeks. This was a good week and for some reason I was in the UK.&lt;/p&gt;
-
- &lt;p&gt;Myself, my brother and my sister-in-law went down to see him that night. It was Robbie Burns night and that meant an excuse for haggis, really, truly terrible scotch, Scottish dancing and all that. There are many times when I look back at time with my Dad in those last few years. This was definitely one of those times. He was my Dad at his best, cracking jokes and having fun. Living life to the absolute fullest, while you still have that chance.&lt;/p&gt;
-
- &lt;p&gt;We had a great night. That ended way too soon.&lt;/p&gt;
-
- &lt;p&gt;Not long after that the cancer came back and that was that.&lt;/p&gt;
-
- &lt;p&gt;But suddenly tonight, in a bar in Portland I had these memories of my Dad in a waistcoat cracking jokes and having fun on Robbie Burns night. No-one else in the bar seemed to know what night it was. You'd think Robbie Burns night might get a little bit more appreciation, but hey.&lt;/p&gt;
-
- &lt;p&gt;In the many years I've been running this blog I've never written about my Dad passing away. Here's the first time. I miss him.&lt;/p&gt;
-
- &lt;p&gt;Hey Robbie Burns? Thanks for making me remember that night.&lt;/p&gt;</description>
- <pubDate>Mon, 25 Jan 2016 08:00:00 +0000</pubDate>
- </item>
- <item>
- <title>This Week In Rust: This Week in Rust 115</title>
- <guid isPermaLink="false">tag:this-week-in-rust.org,2016-01-25:blog/2016/01/25/this-week-in-rust-115/</guid>
- <link>http://this-week-in-rust.org/blog/2016/01/25/this-week-in-rust-115/</link>
- <description>&lt;p&gt;Hello and welcome to another issue of &lt;em&gt;This Week in Rust&lt;/em&gt;!
- &lt;a href=&quot;http://rust-lang.org&quot;&gt;Rust&lt;/a&gt; is a systems language pursuing the trifecta:
- safety, concurrency, and speed. This is a weekly summary of its progress and
- community. Want something mentioned? Tweet us at &lt;a href=&quot;https://twitter.com/ThisWeekInRust&quot;&gt;@ThisWeekInRust&lt;/a&gt; or &lt;a href=&quot;mailto:corey@octayn.net?subject=This%20Week%20in%20Rust%20Suggestion&quot;&gt;send us an
- email&lt;/a&gt;!
- Want to get involved? &lt;a href=&quot;https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md&quot;&gt;We love
- contributions&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;This Week in Rust&lt;/em&gt; is openly developed &lt;a href=&quot;https://github.com/cmr/this-week-in-rust&quot;&gt;on GitHub&lt;/a&gt;.
- If you find any errors in this week's issue, &lt;a href=&quot;https://github.com/cmr/this-week-in-rust/pulls&quot;&gt;please submit a PR&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;This week's edition was edited by: &lt;a href=&quot;https://github.com/nasa42&quot;&gt;nasa42&lt;/a&gt;, &lt;a href=&quot;https://github.com/brson&quot;&gt;brson&lt;/a&gt;, and &lt;a href=&quot;https://github.com/llogiq&quot;&gt;llogiq&lt;/a&gt;.&lt;/p&gt;
- &lt;h3&gt;Updates from Rust Community&lt;/h3&gt;
- &lt;h4&gt;News &amp;amp; Blog Posts&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;img alt=&quot;balloon&quot; class=&quot;emoji&quot; src=&quot;https://cdn.discourse.org/business/images/emoji/emoji_one/balloon.png?v=0&quot; title=&quot;:balloon:&quot; /&gt;&lt;img alt=&quot;tada&quot; class=&quot;emoji&quot; src=&quot;https://cdn.discourse.org/business/images/emoji/emoji_one/tada.png?v=0&quot; title=&quot;:tada:&quot; /&gt; &lt;a href=&quot;http://blog.rust-lang.org/2016/01/21/Rust-1.6.html&quot;&gt;Announcing Rust 1.6&lt;/a&gt;. &lt;img alt=&quot;tada&quot; class=&quot;emoji&quot; src=&quot;https://cdn.discourse.org/business/images/emoji/emoji_one/tada.png?v=0&quot; title=&quot;:tada:&quot; /&gt;&lt;img alt=&quot;balloon&quot; class=&quot;emoji&quot; src=&quot;https://cdn.discourse.org/business/images/emoji/emoji_one/balloon.png?v=0&quot; title=&quot;:balloon:&quot; /&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.poumeyrol.fr/2016/01/15/Awkward-zone/&quot;&gt;Rust, BigData and my laptop&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;[pdf]&lt;a href=&quot;https://cdn.rawgit.com/Gankro/thesis/master/thesis.pdf&quot;&gt;You can't spell trust without Rust&lt;/a&gt;. Analysis of the semantics and expressiveness of Rust’s type system.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.ncameron.org/blog/libmacro/&quot;&gt;Libmacro - an API for procedural macros to interact with the compiler&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.jonathanturner.org/2016/01/rust-and-blub-paradox.html&quot;&gt;Rust and the Blub Paradox&lt;/a&gt;. And the &lt;a href=&quot;http://www.jonathanturner.org/2016/01/rethinking-the-blub-paradox.html&quot;&gt;follow-up&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;[video] &lt;a href=&quot;https://www.youtube.com/channel/UC4mpLlHn0FOekNg05yCnkzQ/videos&quot;&gt;Ferris Makes Emulators&lt;/a&gt;. Live stream of Ferris developing a N64 emulator in Rust (also on &lt;a href=&quot;http://www.twitch.tv/ferrisstreamsstuff/profile&quot;&gt;Twitch&lt;/a&gt;).&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Notable New Crates &amp;amp; Project Updates&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://areweconcurrentyet.com/&quot;&gt;Are we concurrent yet&lt;/a&gt;?&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/gfx-rs/gfx&quot;&gt;GFX&lt;/a&gt; epic rewrite for the Pipeline State Objects paradigm has &lt;a href=&quot;https://github.com/gfx-rs/gfx/pull/828&quot;&gt;landed&lt;/a&gt;, described &lt;a href=&quot;http://gfx-rs.github.io/2016/01/22/pso.html&quot;&gt;on the blog&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/mcarton/rust-herbie-lint&quot;&gt;Herbie&lt;/a&gt;. A rustc plugin to check for numerical instability.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://blog.piston.rs/2016/01/23/dynamo/&quot;&gt;Dynamo&lt;/a&gt;. A rusty dynamically typed scripting language.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/whitequark/rust-vnc&quot;&gt;rust-vnc&lt;/a&gt;. An implementation of VNC protocol, client state machine and a client.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;Updates from Rust Core&lt;/h3&gt;
- &lt;p&gt;129 pull requests were &lt;a href=&quot;https://github.com/issues?q=is%3Apr+org%3Arust-lang+is%3Amerged+merged%3A2016-01-18..2016-01-25&quot;&gt;merged in the last week&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;See the &lt;a href=&quot;https://internals.rust-lang.org/t/triage-digest-mon-jan-25-2016/3111&quot;&gt;triage digest&lt;/a&gt; and &lt;a href=&quot;https://internals.rust-lang.org/t/subteam-reports-2016-01-22/3106&quot;&gt;subteam reports&lt;/a&gt; for more details.&lt;/p&gt;
- &lt;h4&gt;Notable changes&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30872&quot;&gt;Implement RFC 1252 expanding the OpenOptions structure&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/book/pull/58&quot;&gt;Book: First draft of 'ownership'&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/cargo/pull/2205&quot;&gt;Cargo: Add convenience syntax to install current crate&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/cargo/pull/2196&quot;&gt;Cargo: Introduce cargo metadata subcommand&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/cargo/pull/2081&quot;&gt;Cargo: Implement &lt;code&gt;cargo init&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/cargo/pull/2270&quot;&gt;Cargo: Emit a warning when manifest specifies empty dependency constraints&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/29520&quot;&gt;Change name when outputting staticlibs on Windows&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30998&quot;&gt;Make &lt;code&gt;btree_set::{IntoIter, Iter, Range}&lt;/code&gt; covariant&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30917&quot;&gt;Avoid bounds checking at &lt;code&gt;slice::binary_search&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30894&quot;&gt;&lt;code&gt;std::sync::mpsc&lt;/code&gt;: Add &lt;code&gt;fmt::Debug&lt;/code&gt; stubs&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30882&quot;&gt;resolve: Fix variant namespacing&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;New Contributors&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;Adrian Heine&lt;/li&gt;
- &lt;li&gt;Andrea Bedini&lt;/li&gt;
- &lt;li&gt;Guillaume Bonnet&lt;/li&gt;
- &lt;li&gt;Kamal Marhubi&lt;/li&gt;
- &lt;li&gt;Keith Yeung&lt;/li&gt;
- &lt;li&gt;Marc Bowes&lt;/li&gt;
- &lt;li&gt;Martin&lt;/li&gt;
- &lt;li&gt;mopp&lt;/li&gt;
- &lt;li&gt;Olaf Buddenhagen&lt;/li&gt;
- &lt;li&gt;Paul Dicker&lt;/li&gt;
- &lt;li&gt;Peter Kolloch&lt;/li&gt;
- &lt;li&gt;Stephen (Ziyun) Li&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Approved RFCs&lt;/h4&gt;
- &lt;p&gt;Changes to Rust follow the Rust &lt;a href=&quot;https://github.com/rust-lang/rfcs#rust-rfcs&quot;&gt;RFC (request for comments)
- process&lt;/a&gt;. These
- are the RFCs that were approved for implementation this week:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1462&quot;&gt;Amendment to RFC 550: Add &lt;code&gt;[&lt;/code&gt; to the FOLLOW(ty) in macro future-proofing rules&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1320&quot;&gt;Amendment to RFC 1192: Amend &lt;code&gt;RangeInclusive&lt;/code&gt; to use an enum&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Final Comment Period&lt;/h4&gt;
- &lt;p&gt;Every week &lt;a href=&quot;https://rust-lang.org/team.html&quot;&gt;the team&lt;/a&gt; announces the
- 'final comment period' for RFCs and key PRs which are reaching a
- decision. Express your opinions now. &lt;a href=&quot;https://github.com/rust-lang/rfcs/labels/final-comment-period&quot;&gt;This week's FCPs&lt;/a&gt; are:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/243&quot;&gt;Trait-based exception handling&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1361&quot;&gt;Improve Cargo target-specific dependencies&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1129&quot;&gt;Add a &lt;code&gt;IndexAssign&lt;/code&gt; trait that allows overloading &quot;indexed assignment&quot; expressions like &lt;code&gt;a[b] = c&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1196&quot;&gt;Allow eliding more type parameters&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1296&quot;&gt;Add an &lt;code&gt;alias&lt;/code&gt; attribute to &lt;code&gt;#[link]&lt;/code&gt; and &lt;code&gt;-l&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;New RFCs&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1477&quot;&gt;Add compiler support for generic atomic operations&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1478&quot;&gt;Translate undefined generic intrinsics to an LLVM &lt;code&gt;unreachable&lt;/code&gt; and a lint&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;Upcoming Events&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/opentechschool-berlin/&quot;&gt;1/27. OpenTechSchool Berlin: Rust Hack and Learn&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/Tokyo-Rust-Meetup/events/227871840/&quot;&gt;1/28. Tokyo Rust Meetup #2&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/Rust-Berlin/events/227321071/&quot;&gt;2/3. Rust Berlin: Leaf and Collenchyma&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/de/Rust-Cologne-Bonn/events/227534456/&quot;&gt;2/3. Rust Meetup in Cologne / Germany&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://www.eventbrite.com/e/mozilla-rust-seattle-meetup-tickets-12222326307?aff=erelexporg&quot;&gt;2/8. Seattle Rust Meetup&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/de-DE/Rust-Rhein-Main/events/228170051/&quot;&gt;2/12. Embedded Rust Workshop Frankfurt&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;If you are running a Rust event please add it to the &lt;a href=&quot;https://www.google.com/calendar/embed?src=apd9vmbc22egenmtu5l6c5jbfc%40group.calendar.google.com&quot;&gt;calendar&lt;/a&gt; to get
- it mentioned here. Email &lt;a href=&quot;mailto:erick.tryzelaar@gmail.com&quot;&gt;Erick Tryzelaar&lt;/a&gt; or &lt;a href=&quot;mailto:banderson@mozilla.com&quot;&gt;Brian
- Anderson&lt;/a&gt; for access.&lt;/p&gt;
- &lt;h3&gt;fn work(on: RustProject) -&amp;gt; Money&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://maidsafe.net/rust_engineer.html&quot;&gt;Rust Engineer&lt;/a&gt; at MaidSafe.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://careers.mozilla.org/en-US/position/ozy21fwU&quot;&gt;Research Engineer - Servo&lt;/a&gt; at Mozilla.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://careers.mozilla.org/en-US/position/o0H41fww&quot;&gt;Senior Research Engineer - Rust&lt;/a&gt; at Mozilla.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://plv.mpi-sws.org/rustbelt/&quot;&gt;PhD and postdoc positions&lt;/a&gt; at MPI-SWS.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;&lt;em&gt;Tweet us at &lt;a href=&quot;https://twitter.com/ThisWeekInRust&quot;&gt;@ThisWeekInRust&lt;/a&gt; to get your job offers listed here!&lt;/em&gt;&lt;/p&gt;
- &lt;h3&gt;Crate of the Week&lt;/h3&gt;
- &lt;p&gt;This week's Crate of the Week is &lt;a href=&quot;https://github.com/phildawes/racer&quot;&gt;racer&lt;/a&gt; which powers code completion in all Rust development environments.&lt;/p&gt;
- &lt;p&gt;Thanks to &lt;a href=&quot;https://users.rust-lang.org/users/stebalien&quot;&gt;Steven Allen&lt;/a&gt; for the suggestion.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://users.rust-lang.org/t/crate-of-the-week/2704&quot;&gt;Submit your suggestions for next week&lt;/a&gt;!&lt;/p&gt;
- &lt;h3&gt;Quote of the Week&lt;/h3&gt;
- &lt;blockquote&gt;
- &lt;p&gt;Memory errors are fundamentally state errors, and Rust's move semantics, borrowing, and aliasing XOR mutating help enormously for me to reason about how my program changes state as it executes, to avoid accidental shared state and side effects at a distance. Rust more than any other language I know enables me to do compiler driven design. And internalizing its rules has helped me design better systems, even in other languages.&lt;/p&gt;
- &lt;/blockquote&gt;
- &lt;p&gt;— &lt;a href=&quot;https://www.reddit.com/r/rust/comments/4275gz/rust_and_the_blub_paradox/cz8akv9&quot;&gt;desiringmachines on /r/rust&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Thanks to &lt;a href=&quot;https://users.rust-lang.org/users/dikaiosune&quot;&gt;dikaiosune&lt;/a&gt; for the suggestion.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://users.rust-lang.org/t/twir-quote-of-the-week/328&quot;&gt;Submit your quotes for next week&lt;/a&gt;!&lt;/p&gt;</description>
- <pubDate>Mon, 25 Jan 2016 05:00:00 +0000</pubDate>
- <dc:creator>Corey Richardson</dc:creator>
- </item>
- <item>
- <title>Cameron Kaiser: 38.6.0 available</title>
- <guid isPermaLink="false">tag:blogger.com,1999:blog-1015214236289077798.post-7056349209464984020</guid>
- <link>http://tenfourfox.blogspot.com/2016/01/3860-available.html</link>
- <description>TenFourFox 38.6.0 is available for testing (&lt;a href=&quot;https://sourceforge.net/projects/tenfourfox/files/38.6.0/&quot;&gt;downloads&lt;/a&gt;, &lt;a href=&quot;https://github.com/classilla/tenfourfox/wiki/Hashes&quot;&gt;hashes&lt;/a&gt;, &lt;a href=&quot;https://github.com/classilla/tenfourfox/wiki/ZZReleaseNotes3860&quot;&gt;release notes&lt;/a&gt;). I'm sorry it's been so quiet around here; I'm in the middle of a backbreaking Master's course, my last one before I'm finally done with the lousy thing, and I haven't had any time to start on 45 so far. 38.6 does have some other fixes in it, though: I think I found the last place where bookmark backups were being mistakenly saved in LZ4 based on Chris Trusch's report, and the problematic fonts on the iCloud login page are now blacklisted, so you should be able to login again. I can't do much more testing than that, however, since I don't use iCloud personally, so other lapses in font functionality will require the font URL and I'll add them to the blacklist in 38.7. The browser will go live Monday Pacific time as usual. (The temporary workaround is to set &lt;tt&gt;gfx.downloadable_fonts.enabled&lt;/tt&gt; to &lt;tt&gt;false&lt;/tt&gt;, and switch the setting back when you don't need it anymore.) &lt;p&gt;Speaking of, downloadable fonts were exactly the same problem on the Sun Ultra-3 laptop I've been refurbishing; Oracle still provides a free Solaris 10 build of 38ESR, but it crashes on web fonts for reasons I have yet to diagnose, so I just have them turned off. Yes, it really is a SPARC laptop, a rebranded Tadpole Viper, and I think the fastest one ever made in this form factor (a 1.2GHz UltraSPARC IIIi). It's pretty much what I expected the PowerBook G5 would have been -- hot, overthrottled and power-hungry -- but Tadpole actually built the thing and it's not a disaster, relatively speaking. There's no JIT in this Firefox build, the brand new battery gets only 70 minutes of runtime even with the CPU clock-skewed to hell, it stands a very good chance of rendering me sterile and/or medium rare if I actually use it in my lap and it had at least one sudden overtemp shutdown and pooped all over the filesystem, but between Firefox, Star Office and &lt;tt&gt;pkgsrc&lt;/tt&gt; I can actually use it. More on that for laughs in a future post. &lt;/p&gt;&lt;p&gt;It has been pointed out to me that Leopard Webkit has not made an update in over three months, so hopefully Tobias is still doing okay with his port.&lt;/p&gt;</description>
- <pubDate>Sat, 23 Jan 2016 06:02:00 +0000</pubDate>
- <author>noreply@blogger.com (ClassicHasClass)</author>
- </item>
- <item>
- <title>Mozilla Privacy Blog: Addressing the Chilling Effect of Patent Damages</title>
- <guid isPermaLink="false">https://blog.mozilla.org/netpolicy/?p=907</guid>
- <link>https://blog.mozilla.org/netpolicy/2016/01/22/addressing-the-chilling-effect-of-patent-damages/</link>
- <description>&lt;p&gt;Last year, we unveiled the &lt;a href=&quot;https://www.mozilla.org/about/patents/license/&quot;&gt;Mozilla Open Software Patent License&lt;/a&gt; as part of our &lt;a href=&quot;https://www.mozilla.org/about/patents/&quot;&gt;Initiative&lt;/a&gt; to help limit the negative impacts that patents have on open source software. While those were an important first step for us, we continue to do more. This past Wednesday, Mozilla joined several other tech and software companies in filing an &lt;a href=&quot;https://blog.mozilla.org/netpolicy/files/2016/01/Halo-Stryker-Internet-Companies-brief.pdf&quot;&gt;amicus brief&lt;/a&gt; with the Supreme Court of the United States in the &lt;i&gt;Halo&lt;/i&gt; and &lt;i&gt;Stryker&lt;/i&gt; cases.&lt;/p&gt;
- &lt;p&gt;In the brief, we urge the Court to limit the availability of treble damages. Treble damages are significant because they greatly increase the amount of money owed if a defendant is found to “willfully infringe†a patent. As a result, many open source projects and technology companies will refuse to look into or engage in discussions about patents, in order to avoid even a remote possibility of willful infringement. This makes it very hard to address the chilling effects that patents can have on open source software development, open innovation, and collaborative efforts.&lt;/p&gt;
- &lt;p&gt;We hope that our brief will help the Court see how this legal standard has affected technology companies and persuade the Court to limit treble damages.&lt;/p&gt;</description>
- <pubDate>Sat, 23 Jan 2016 00:17:34 +0000</pubDate>
- <dc:creator>Elvin Lee</dc:creator>
- </item>
- <item>
- <title>Mozilla Addons Blog: Add-on Signing Update</title>
- <guid isPermaLink="false">http://blog.mozilla.org/addons/?p=7640</guid>
- <link>https://blog.mozilla.org/addons/2016/01/22/add-on-signing-update/</link>
- <description>&lt;p&gt;In Firefox 43, we made it a default requirement for add-ons to be signed. This requirement can be disabled by &lt;a href=&quot;https://wiki.mozilla.org/Addons/Extension_Signing#FAQ&quot;&gt;toggling a preference&lt;/a&gt; that was originally scheduled to be removed in Firefox 44 for release and beta versions (this preference will continue to be available in the Nightly, Developer, and ESR Editions of Firefox for the foreseeable future). &lt;/p&gt;
- &lt;p&gt;We are delaying the removal of this preference to Firefox 46 for a couple of reasons: We’re adding a feature in Firefox 45 that allows &lt;a href=&quot;https://blog.mozilla.org/addons/2015/12/23/loading-temporary-add-ons/&quot;&gt;temporarily loading unsigned restartless add-ons&lt;/a&gt; in release, which will allow developers of those add-ons to use Firefox for testing, and we’d like this option to be available when we remove the preference. We also want to ensure that developers have adequate time to finish the transition to signed add-ons. &lt;/p&gt;
- &lt;p&gt;The &lt;a href=&quot;https://wiki.mozilla.org/Addons/Extension_Signing#Timeline&quot;&gt;updated timeline&lt;/a&gt; is available on the signing wiki, and you can look up &lt;a href=&quot;https://wiki.mozilla.org/RapidRelease/Calendar&quot;&gt;release dates for Firefox versions&lt;/a&gt; on the releases wiki. Signing will be mandatory in the beta and release versions of Firefox from 46 onwards, at which point unbranded builds based on beta and release will be provided for testing.&lt;/p&gt;</description>
- <pubDate>Fri, 22 Jan 2016 22:40:59 +0000</pubDate>
- <dc:creator>Kev Needham</dc:creator>
- </item>
- <item>
- <title>Chris Cooper: RelEng &amp; RelOps Weekly Highlights - January 22, 2016</title>
- <guid isPermaLink="true">http://coopcoopbware.tumblr.com/post/137832199980</guid>
- <link>http://coopcoopbware.tumblr.com/post/137832199980</link>
- <description>&lt;p&gt;&lt;/p&gt;&lt;figure class=&quot;alignright&quot;&gt;&lt;a href=&quot;https://www.flickr.com/photos/proud2bcan8dn/1150097247/in/faves-19934681@N00/&quot; target=&quot;_blank&quot; title=&quot;wine-and-pies&quot;&gt;&lt;img alt=&quot;wine-and-pies&quot; src=&quot;https://farm2.staticflickr.com/1216/1150097247_2f11cb4c2d_z.jpg?zz=1&quot; width=&quot;200px&quot; /&gt;&lt;/a&gt;Releng: drinkin’ wine and makin’ pies.&lt;/figure&gt;It’s encouraging to see more progress this week on both the build/release promotion and TaskCluster migration fronts, our two major efforts for this quarter.&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Modernize infrastructure:&lt;/b&gt;&lt;/p&gt;
- &lt;p&gt;In a continuing effort to enable faster, more reliable, and more easily-run tests for TaskCluster components, Dustin landed support for an in-memory, credential-free mock of Azure Table Storage in the &lt;a href=&quot;https://www.npmjs.com/package/azure-entities&quot; target=&quot;_blank&quot;&gt;azure-entities&lt;/a&gt; package. Together with the fake mock support he added to &lt;a href=&quot;https://github.com/djmitche/taskcluster-lib-testing&quot; target=&quot;_blank&quot;&gt;taskcluster-lib-testing&lt;/a&gt;, this allows tests for components like taskcluster-hooks to run without network access and without the need for any credentials, substantially decreasing the barrier to external contributions.&lt;/p&gt;
-
- &lt;p&gt;All release promotion tasks are now signed by default. Thanks to Rail for his work here to help improve verifiability and chain-of-custody in our upcoming release process. (&lt;a href=&quot;https://bugzil.la/1239682&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1239682&lt;/a&gt;)
- Beetmover has been spotted in the wild! Jordan has been working on this new tool as part of our release promotion project. Beetmover helps move build artifacts from one place to another (generally between S3 buckets these days), but can also be extended to perform validation actions inline, e.g. checksums and anti-virus. (&lt;a href=&quot;https://bugzil.la/1225899&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1225899&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;Dustin configured the “desktop-test†and “desktop-build†docker images to build automatically on push. That means that you can modify the Dockerfile under `testing/docker`, push to try, and have the try job run in the resulting image, all without pushing any images. This should enable much quicker iteration on tweaks to the docker images. Note, however, that updates to the base OS images (ubuntu1204-build and centos6-build) still require manual pushes.&lt;/p&gt;
-
- &lt;p&gt;Mark landed Puppet code for base windows 10 support including secrets and ssh keys management.&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Improve CI pipeline:&lt;/b&gt;&lt;/p&gt;
-
- &lt;p&gt;Vlad and Amy repurposed 10 Windows XP machines as Windows 7 to improve the wait times in that test pool (&lt;a href=&quot;https://bugzil.la/1239785&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1239785&lt;/a&gt;)
- Armen and Joel have been working on porting the Gecko tests to run under TaskCluster, and have narrowed the failures down to the single digits. This puts us on-track to enable Linux debug builds and tests in TaskCluster as the canonical build/test process.&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Release:&lt;/b&gt;&lt;/p&gt;
-
- &lt;p&gt;Ben finished up work on enhanced Release Blob validation in Balrog (&lt;a href=&quot;https://bugzil.la/703040&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/703040&lt;/a&gt;), which makes it much more difficult to enter bad data into our update server.&lt;/p&gt;
-
- &lt;p&gt;You may recall Mihai, our former intern who &lt;a href=&quot;http://coopcoopbware.tumblr.com/post/133490693210/welcome-back-mihai&quot; target=&quot;_blank&quot;&gt;we just hired back in November&lt;/a&gt;. Shortly after joining the team, he jumped into the &lt;a href=&quot;https://wiki.mozilla.org/ReleaseEngineering/Releaseduty&quot; target=&quot;_blank&quot;&gt;releaseduty&lt;/a&gt; rotation to provide much-needed extra bandwidth. The learning curve here is steep, but over the course of the Firefox 44 release cycle, he’s taken on more and more responsibility. He’s even volunteered to do releaseduty for the Firefox 45 release cycle as well. Perhaps the most impressive thing is that he’s also taken the time to update (or write) the releaseduty docs so that the next person who joins the rotation will be that much further ahead of the game. Thanks for your hard work here, Mihai!&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Operational:&lt;/b&gt;&lt;/p&gt;
-
- &lt;p&gt;Hal did some cleanup work to remove unused mozharness configs and directories from the build mercurial repos. These resources have long-since moved into the main mozilla-central tree. Hopefully this will make it easier for contributors to find the canonical copy! (&lt;a href=&quot;https://bugzil.la/1239003&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1239003&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Hiring:&lt;/b&gt;&lt;/p&gt;
-
- &lt;p&gt;We’re still hiring for a full-time &lt;a href=&quot;https://careers.mozilla.org/position/oi8b2fwn&quot; target=&quot;_blank&quot;&gt;Build &amp;amp; Release Engineer&lt;/a&gt;, and we are still accepting applications for &lt;a href=&quot;https://careers.mozilla.org/position/ofA51fwF&quot; target=&quot;_blank&quot;&gt;interns for 2016&lt;/a&gt;. Come join us!&lt;/p&gt;
-
- &lt;p&gt;Well, I don’t know about you, but all that hard work makes me hungry for pie. See you next week!&lt;/p&gt;</description>
- <pubDate>Fri, 22 Jan 2016 20:49:38 +0000</pubDate>
- </item>
- <item>
- <title>Air Mozilla: Foundation Demos January 22 2016</title>
- <guid isPermaLink="true">https://air.mozilla.org/foundation-demos-january-22-2016/</guid>
- <link>https://air.mozilla.org/foundation-demos-january-22-2016/</link>
- <description>&lt;p&gt;
- &lt;img alt=&quot;Foundation Demos January 22 2016&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/1c/a0/1ca0b9b2609cdd4e6e3577a8c3df8cfc.jpg&quot; width=&quot;160&quot; /&gt;
- Mozilla Foundation Demos January 22 2016
- &lt;/p&gt;</description>
- <pubDate>Fri, 22 Jan 2016 18:00:00 +0000</pubDate>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item>
- <title>Support.Mozilla.Org: What’s up with SUMO – 22nd January</title>
- <guid isPermaLink="false">http://blog.mozilla.org/sumo/?p=3667</guid>
- <link>https://blog.mozilla.org/sumo/2016/01/22/whats-up-with-sumo-22nd-january/</link>
- <description>&lt;p&gt;&lt;strong&gt;Hello, SUMO Nation!&lt;/strong&gt;&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://blog.mozilla.org/sumo/files/2016/01/sumo_logo.png&quot;&gt;&lt;img alt=&quot;sumo_logo&quot; class=&quot;aligncenter size-full wp-image-3670&quot; height=&quot;387&quot; src=&quot;http://blog.mozilla.org/sumo/files/2016/01/sumo_logo.png&quot; width=&quot;383&quot; /&gt;&lt;/a&gt;The third week of the new year is already behind us. Time flies when you’re not paying attention… What are you going to do this weekend? Let us know in the comments, if you feel like sharing :-) I hope to be in the mountains, getting some fresh (bracing) air, and enjoying nature.&lt;/p&gt;
- &lt;h3&gt;&lt;strong class=&quot;username&quot;&gt;Welcome, new contributors!&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li class=&quot;author&quot;&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;a class=&quot;username&quot; href=&quot;https://support.mozilla.org/user/johnmwc2&quot; target=&quot;_blank&quot;&gt;johnmwc2&lt;/a&gt;&lt;/div&gt;
- &lt;/li&gt;
- &lt;li class=&quot;author&quot;&gt;&lt;a class=&quot;author-name&quot; href=&quot;https://support.mozilla.org/user/myanesp&quot; target=&quot;_blank&quot;&gt;myanesp&lt;/a&gt;&lt;/li&gt;
- &lt;li class=&quot;author&quot;&gt;&lt;a class=&quot;author-name&quot; href=&quot;https://support.mozilla.org/user/Harish.A&quot; target=&quot;_blank&quot;&gt;Harish.A&lt;/a&gt;&lt;/li&gt;
- &lt;li class=&quot;author&quot;&gt;&lt;a class=&quot;author-name&quot; href=&quot;https://support.mozilla.org/user/hoolibob&quot; target=&quot;_blank&quot;&gt;hoolibob&lt;/a&gt;&lt;/li&gt;
- &lt;li class=&quot;author&quot;&gt;&lt;a class=&quot;author-name&quot; href=&quot;https://support.mozilla.org/user/Meteoro890&quot; target=&quot;_blank&quot;&gt;Meteoro890&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;author&quot;&gt;If you just joined us, don’t hesitate – come over and &lt;a href=&quot;https://support.mozilla.org/forums/buddies&quot; target=&quot;_blank&quot;&gt;say “hi†in the forums!&lt;/a&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;
- &lt;h3&gt;&lt;strong&gt;Contributors of the week&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z74z1rz89z69z76zbz72zz69zz67z9z82zniz71z&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/safwan.rahman&quot; target=&quot;_blank&quot;&gt;Safwan&lt;/a&gt; for his work on the &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=619284&quot; target=&quot;_blank&quot;&gt;draft feature for l10n / KB editing&lt;/a&gt; – rock on!&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/user/artist&quot; target=&quot;_blank&quot;&gt;Artist&lt;/a&gt; and &lt;a href=&quot;https://support.mozilla.org/user/pollti&quot; target=&quot;_blank&quot;&gt;Pollti&lt;/a&gt; for their the work on updating important articles for Focus with limited time – woot!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid64&quot;&gt;
- &lt;p&gt;&lt;strong&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;We salute you!&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
- &lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;Don’t forget that if you are new to SUMO and someone helped you get started in a nice way you can &lt;a href=&quot;https://support.mozilla.org/forums/buddies/711364?last=65670&quot; target=&quot;_blank&quot;&gt;nominate them for the Buddy of the Month!&lt;/a&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;/div&gt;
- &lt;/div&gt;
- &lt;h3&gt;&lt;strong&gt;Most recent SUMO Community meeting&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-2016-01-18&quot; target=&quot;_blank&quot;&gt;You can read the notes here&lt;/a&gt; (most of the staff members were AFK due to MLK Day in the US) and see the video on our &lt;a href=&quot;https://www.youtube.com/channel/UCaiposaIhA7HfMqH2NIciyA/videos&quot; target=&quot;_blank&quot;&gt;YouTube channel&lt;/a&gt; and &lt;a href=&quot;https://air.mozilla.org/search/?q=sumo&quot; target=&quot;_blank&quot;&gt;at AirMozilla&lt;/a&gt;.&lt;del&gt; &lt;/del&gt;&lt;del&gt;&lt;br /&gt;
- &lt;/del&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;IMPORTANT: We are considering changing the way the meetings work. Help us figure out what’s best for you – join the discussion on the forums in this thread: &lt;a href=&quot;https://support.mozilla.org/en-US/forums/contributors/711752?last=67873&quot;&gt;(Monday) Community Meetings in 2016&lt;/a&gt;.&lt;/strong&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong&gt;The next SUMO Community meeting… &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;is happening on &lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-2016-01-25&quot; target=&quot;_blank&quot;&gt;Monday the 25th – join us&lt;/a&gt;!&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Reminder: if you want to add a discussion topic to the upcoming meeting agenda:&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;Start a thread in the &lt;a href=&quot;https://support.mozilla.org/forums/contributors&quot; target=&quot;_blank&quot;&gt;Community Forums&lt;/a&gt;, so that everyone in the community can see what will be discussed and voice their opinion here before Monday (this will make it easier to have an efficient meeting).&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;Please do so as soon as you can before the meeting, so that people have time to read, think, and reply (and also add it to the agenda).&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;If you can, please attend the meeting in person (or via IRC), so we can follow up on your discussion topic during the meeting with your feedback.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-g-ivsra51ph44x461i&quot;&gt;Developers&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://edwin.mozilla.io/t/sumo&quot; target=&quot;_blank&quot;&gt;You can see the current state of the backlog our developers are working on here&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-p-2016-01-21&quot; target=&quot;_blank&quot;&gt;The latest SUMO Platform meeting notes can be found here&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Interested in learning how Kitsune (the engine behind SUMO) works? &lt;a href=&quot;http://kitsune.readthedocs.org/&quot; target=&quot;_blank&quot;&gt;Read more about it here&lt;/a&gt; and &lt;a href=&quot;https://github.com/mozilla/kitsune/&quot; target=&quot;_blank&quot;&gt;fork it on GitHub&lt;/a&gt;!&lt;/li&gt;
- &lt;li&gt;We have a new link for promoting contributions to Kitsune’s code. Please use &lt;strong&gt;http://mzl.la/SUMOdev&lt;/strong&gt; whenever you want to show interested people to see what Kitsune is all about – thanks!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;&lt;a href=&quot;http://blog.mozilla.org/sumo/files/2016/01/mission_developers.png&quot;&gt;&lt;img alt=&quot;mission_developers&quot; class=&quot;aligncenter size-full wp-image-3668&quot; height=&quot;406&quot; src=&quot;http://blog.mozilla.org/sumo/files/2016/01/mission_developers.png&quot; width=&quot;437&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;h3&gt;&lt;strong&gt;Social&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Next week, there will be a kick-off meeting for the rethinking of Mozilla’s general support strategy through social networks. &lt;a href=&quot;https://support.mozilla.org/user/Madasan&quot; target=&quot;_blank&quot;&gt;Are you interested in taking part? Let Madalina know!&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong&gt;Community&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;The NDA process and list is currently being reworked under the leadership of the Participation Team. Expect to see messaging on this subject in the coming days.&lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711729?last=67763&quot;&gt;IMPORTANT: take a look at our Work Week Summary for Mozlando. We need your feedback for a few things there.&lt;/a&gt;&lt;/strong&gt;&lt;/div&gt;
- &lt;/li&gt;
- &lt;li&gt;Are you going to FOSDEM next week? Would you like to have a small SUMO-meetup? &lt;a href=&quot;https://support.mozilla.org/user/vesper&quot; target=&quot;_blank&quot;&gt;Let me know&lt;/a&gt;!&lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;Ongoing reminder: if you think you can benefit from getting &lt;a href=&quot;https://wiki.mozilla.org/Community_Hardware&quot; target=&quot;_blank&quot;&gt;a second-hand device&lt;/a&gt; to help you with contributing to SUMO, you know where to find us.&lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;&lt;a href=&quot;http://blog.mozilla.org/sumo/files/2016/01/hero_support.png&quot;&gt;&lt;img alt=&quot;hero_support&quot; class=&quot;aligncenter size-full wp-image-3669&quot; height=&quot;383&quot; src=&quot;http://blog.mozilla.org/sumo/files/2016/01/hero_support.png&quot; width=&quot;367&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;div class=&quot;&quot;&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid83&quot;&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-g-ivsra51ph44x461i&quot;&gt;Localization&lt;/strong&gt;&lt;/h3&gt;
- &lt;/div&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid95&quot;&gt;
- &lt;ul&gt;
- &lt;li&gt;You can &lt;a href=&quot;https://support.mozilla.org/forums/l10n-forum/711781&quot; target=&quot;_blank&quot;&gt;read more about the recent “infrequent contributor survey†in this thread&lt;/a&gt;. In short: the good news is that we’re doing a good job at making it easy enough for everyone to contribute. The bad news – we’re not doing enough to make sure they know what to do after their first contribution. Expect some changes in the messaging for first-time contributors to the KB :-)&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1012384&quot; target=&quot;_blank&quot;&gt;Our magical l10n dashboards keep being magical&lt;/a&gt; ;-) Thank you for your patience. If you see any discrepancies between the number of localized articles and the percentage shown in the bar, file a bug!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid75&quot;&gt;
- &lt;h3&gt;&lt;strong&gt;Firefox&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for Android&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711712?last=67653&quot;&gt;Learn more about Firefox 43 for Android from the official thread with release notes / issues / discussions&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711718?last=67822&quot;&gt;Reminder: Roland is sharing Firefox 44 for Android release notes / issues / discussions&lt;/a&gt; with everyone in the forum.&lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for Desktop&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li&gt;Heads up – next week should be release week! Keep your eyes peeled ;-)&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for iOS&lt;/strong&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid85&quot;&gt;
- &lt;ul class=&quot;list-bullet1&quot;&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-107uz69zz81zhz78z0z78zz84zz66zz76zz82zz77zj&quot;&gt;No news from the world of Firefox for iOS this week.&lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;p&gt;Thank you for reading all the way down here… More to come next week! You know where to find us, so see you around – keep rocking the open &amp;amp; helpful web!&lt;/p&gt;</description>
- <pubDate>Fri, 22 Jan 2016 17:43:56 +0000</pubDate>
- <dc:creator>Michał</dc:creator>
- </item>
- <item>
- <title>Air Mozilla: Bay Area Rust Meetup January 2016</title>
- <guid isPermaLink="true">https://air.mozilla.org/bay-area-rust-meetup-january-2016/</guid>
- <link>https://air.mozilla.org/bay-area-rust-meetup-january-2016/</link>
- <description>&lt;p&gt;
- &lt;img alt=&quot;Bay Area Rust Meetup January 2016&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/87/4f/874f4abef76f55213d50e43d6417ed99.png&quot; width=&quot;160&quot; /&gt;
- Bay Area Rust meetup for January 2016. Topics TBD.
- &lt;/p&gt;</description>
- <pubDate>Fri, 22 Jan 2016 03:00:00 +0000</pubDate>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item>
- <title>Mitchell Baker: Honored to Participate in New UN Panel on Women’s Economic Empowerment</title>
- <guid isPermaLink="false">https://blog.lizardwrangler.com/?p=3953</guid>
- <link>http://blog.lizardwrangler.com/2016/01/22/honored-to-participate-in-new-un-panel-on-womens-economic-empowerment/</link>
- <description>Women’s economic empowerment is necessary for many reasons. It is necessary to bring health, safety and opportunity to half of humanity. It is necessary to bring investment and health to families and communities. It is necessary to unlock economic growth and build more stable societies. Today the UN Secretary General Ban Ki-moon launched the first […]</description>
- <pubDate>Fri, 22 Jan 2016 02:45:58 +0000</pubDate>
- <dc:creator>Mitchell Baker</dc:creator>
- </item>
- <item>
- <title>Mozilla WebDev Community: Beer and Tell – January 2016</title>
- <guid isPermaLink="false">https://blog.mozilla.org/webdev/?p=4082</guid>
- <link>https://blog.mozilla.org/webdev/2016/01/21/beer-and-tell-january-2016/</link>
- <description>&lt;p&gt;Once a month, web developers from across the Mozilla Project get together to talk about our side projects and drink, an occurrence we like to call “Beer and Tellâ€.&lt;/p&gt;
- &lt;p&gt;There’s a &lt;a href=&quot;https://wiki.mozilla.org/Webdev/Beer_And_Tell/January_2016&quot;&gt;wiki page available&lt;/a&gt; with a list of the presenters, as well as links to their presentation materials. There’s also a &lt;a href=&quot;https://air.mozilla.org/webdev-beer-and-tell-january-2016/&quot;&gt;recording available&lt;/a&gt; courtesy of Air Mozilla.&lt;/p&gt;
- &lt;h3&gt;shobson: CSS-Only Disco Ball&lt;/h3&gt;
- &lt;p&gt;First up was &lt;a href=&quot;https://mozillians.org/en-US/u/stephaniehobson/&quot;&gt;shobson&lt;/a&gt; with a cool demo of an &lt;a href=&quot;http://codepen.io/stephaniehobson/pen/ZGZBVW?editors=110&quot;&gt;animated disco ball made entirely with CSS&lt;/a&gt;. The demo uses a repeated radial gradient for the background, and linear gradients plus a border radius for the disco ball itself. The demo was made for use in shobson’s &lt;a href=&quot;https://www.youtube.com/watch?v=7poVasAQjos&quot;&gt;WordCamp talk&lt;/a&gt; about debugging CSS. A &lt;a href=&quot;http://stephaniehobson.ca/wordpress/2015/08/15/how-to-debug-css/&quot;&gt;blog post&lt;/a&gt; with notes from the talk is available as well.&lt;/p&gt;
- &lt;h3&gt;craigcook: Proton – A CSS Framework for Prototyping&lt;/h3&gt;
- &lt;p&gt;Next was &lt;a href=&quot;https://mozillians.org/en-US/u/craigcook/&quot;&gt;craigcook&lt;/a&gt;, who presented &lt;a href=&quot;http://craigcook.github.io/proton/&quot;&gt;Proton&lt;/a&gt;. It’s a CSS framework that is intentionally ugly to encourage use for prototypes only. Unlike other CSS frameworks, the temptation to reuse the classes from the framework in your final page doesn’t occur, which helps avoid the presentational classes that plague sites built using a framework normally.&lt;/p&gt;
- &lt;p&gt;Proton’s website includes an overview of the layout and components provided, as well as examples of prototypes made using the framework.&lt;/p&gt;
- &lt;hr /&gt;
- &lt;p&gt;If you’re interested in attending the next Beer and Tell, sign up for the &lt;a href=&quot;https://lists.mozilla.org/listinfo/dev-webdev&quot;&gt;dev-webdev@lists.mozilla.org mailing list&lt;/a&gt;. An email is sent out a week beforehand with connection details. You could even add yourself to the wiki and show off your side-project!&lt;/p&gt;
- &lt;p&gt;See you next month!&lt;/p&gt;</description>
- <pubDate>Thu, 21 Jan 2016 18:56:46 +0000</pubDate>
- <dc:creator>Michael Kelly</dc:creator>
- </item>
- <item>
- <title>About:Community: This Month at Mozilla</title>
- <guid isPermaLink="false">http://blog.mozilla.org/community/?p=2287</guid>
- <link>http://blog.mozilla.org/community/2016/01/21/this-month-at-mozilla/</link>
- <description>&lt;p style=&quot;text-align: center;&quot;&gt;&lt;em&gt;A lot of exciting things are happening with Participation at Mozilla this month. Here’s a quick round-up of some of the things that are going on!&lt;/em&gt;&lt;/p&gt;
- &lt;h3&gt;&lt;b&gt;Mozillians Profiles Got a Facelift: &lt;/b&gt;&lt;/h3&gt;
- &lt;p&gt;Since the start of this year, the Participation Infrastructure team has had a renewed focus on making mozillians.org a modern community directory to meet Mozilla’s growing needs.&lt;/p&gt;
- &lt;p&gt;Their first target for 2016 was to improve the UX on the profile edit interface.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://blog.mozilla.org/community/files/2016/01/new-profile-768x548.png&quot;&gt;&lt;img alt=&quot;new-profile-768x548&quot; class=&quot;aligncenter wp-image-2288 size-large&quot; height=&quot;428&quot; src=&quot;https://blog.mozilla.org/community/files/2016/01/new-profile-768x548-600x428.png&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
- â€We chose it due to relatively self-contained nature of it, and cause many people were not happy with the current UX. After research of existing tools and applying latest best practices, we designed, coded and deployed a new profile edit interface (which by the way is renamed to Settings now) that we are happy to deliver to all Mozillians.â€&lt;/p&gt;
- &lt;p&gt;Read the full blog &lt;a href=&quot;http://pierros.papadeas.gr/?p=447&quot;&gt;here&lt;/a&gt;!&lt;/p&gt;
- &lt;h3&gt;&lt;b&gt;There are New Ways to Bring Your Design Skills to Mozilla: &lt;/b&gt;&lt;/h3&gt;
- &lt;p&gt;Are you a passionate designer looking to contribute to Mozilla? You’ll be happy to hear there is a new way to contribute to the many design projects around Mozilla! Submit issues, find collaborators, and work on open source projects by getting involved!&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;You can check out the projects looking for help, or submit your own on the &lt;a href=&quot;https://github.com/mozilla/Community-Design/issues&quot;&gt;GitHub Repo&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://docs.google.com/a/mozilla.com/forms/d/1Tw3Mw_CMiqcIQrJF7TB1yIETGYec__NiVhaSz0CAaE8/viewform&quot;&gt;Sign-up to the mailing list&lt;/a&gt; to be added as a contributor to the Repo, added to the regular meeting list, and to get emails about GitHub trainings and more!&lt;/li&gt;
- &lt;li&gt;And read&lt;a href=&quot;http://elioqoshi.me/en/2016/01/mozilla-community-design-kickoff/&quot;&gt; a blogpost&lt;/a&gt; about the project and its first meeting.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;Learn more &lt;a href=&quot;https://discourse.mozilla-community.org/c/community-design&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
- &lt;h3&gt;&lt;b&gt;136 Volunteers Are Going to Singapore: &lt;/b&gt;&lt;/h3&gt;
- &lt;p&gt;This weekend 136 participation leaders from all over the world are&lt;a href=&quot;https://twitter.com/thephoenixbird/status/690181985222926336&quot;&gt; heading to Singapore&lt;/a&gt; to undergo two days of&lt;a href=&quot;https://wiki.mozilla.org/Participation/Global_Gatherings_2015&quot;&gt; leadership training&lt;/a&gt; to develop the skills, knowledge and attitude to lead Participation in 2016.&lt;/p&gt;
- &lt;div class=&quot;wp-caption aligncenter&quot; id=&quot;attachment_2289&quot; style=&quot;width: 609px;&quot;&gt;&lt;a href=&quot;https://blog.mozilla.org/community/files/2016/01/CZQE241WIAA6R2J.jpg&quot;&gt;&lt;img alt=&quot;Photo credit @thephoenixbird on Twitter&quot; class=&quot;wp-image-2289 size-full&quot; height=&quot;337&quot; src=&quot;https://blog.mozilla.org/community/files/2016/01/CZQE241WIAA6R2J.jpg&quot; width=&quot;599&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Photo credit @&lt;a href=&quot;https://twitter.com/thephoenixbird/status/690181985222926336&quot; target=&quot;_blank&quot;&gt;thephoenixbird&lt;/a&gt; on Twitter&lt;/p&gt;&lt;/div&gt;
- &lt;p&gt;If you know someone attending don’t forget to share your questions and goals with them, and follow along over the weekend by watching the hashtag&lt;a href=&quot;https://twitter.com/search?q=%23mozsummit&quot;&gt; #MozSummit&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Stay tuned after the event for a debrief of the weekend!&lt;/p&gt;
- &lt;h3&gt;&lt;b&gt;Friday’s Plenary from Mozlando is now public on Air Mozilla: &lt;/b&gt;&lt;/h3&gt;
- &lt;p&gt;If you’re interested in learning more about all the exciting new features, projects, and plans that were presented at Mozlando look no further! You can now watch the final plenary sessions on Air Mozilla (it’s a lot of fun so I highly recommend it!) &lt;a href=&quot;https://air.mozilla.org/channels/mozlando/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Share your questions and comments on discourse &lt;a href=&quot;https://discourse.mozilla-community.org/t/friday-plenary-from-mozlando-now-public-on-air-mozilla/6659&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;Look forward to more updates like these in the coming months!&lt;/em&gt;&lt;/p&gt;</description>
- <pubDate>Thu, 21 Jan 2016 17:58:33 +0000</pubDate>
- <dc:creator>Lucy Harris</dc:creator>
- </item>
- <item>
- <title>Mozilla Privacy Blog: Prioritizing privacy: Good for business</title>
- <guid isPermaLink="false">https://blog.mozilla.org/netpolicy/?p=912</guid>
- <link>https://blog.mozilla.org/netpolicy/2016/01/21/prioritizing-privacy-good-for-business/</link>
- <description>&lt;p&gt;&lt;em&gt;This was originally posted at &lt;a href=&quot;http://staysafeonline.org/blog/prioritizing-privacy-good-for-business/&quot;&gt;StaySafeOnline.org&lt;/a&gt; in advance of &lt;a href=&quot;http://www.staysafeonline.org/data-privacy-day/events/&quot;&gt;Data Privacy Day&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;Data Privacy Day – which arrives in just a week – is a day designed to raise awareness and promote best practices for privacy and data protection. It is a day that looks to the future and recognizes that we can and should do better as an industry. It reminds us that we need to focus on the importance of having the trust of our users.&lt;/p&gt;
- &lt;p&gt;We seek to build trust so we can collectively create the Web our users want – the Web we all want.&lt;/p&gt;
- &lt;p&gt;That Web is based on relationships, the same way that the offline world is. When I log in to a social media account, schedule a grocery delivery online or browse the news, I’m relying on those services to respect my data. While companies are innovating their products and services, they need to be innovating on user trust as well, which means designing to address privacy concerns – and making smart choices (early!) about how to manage data.&lt;/p&gt;
- &lt;p&gt;A &lt;a href=&quot;http://www.pewinternet.org/2016/01/14/privacy-and-information-sharing/&quot;&gt;recent survey by Pew&lt;/a&gt; highlights the thought that each user puts into their choices – and the contextual considerations in various scenarios. They concluded that many participants were annoyed and uncertain by how their information was used, and they are choosing not to interact with those services that they don’t trust. This is a clear call to businesses to foster more trust with their users, which starts by making sure that there are people empowered within your company to ask the right questions: what do your users expect? What data do you need to collect? How can you communicate about that data collection? How should you protect their data? Is holding on to data a risk, or should you delete it?&lt;/p&gt;
- &lt;p&gt;It’s crucial that users are a part of this process – consumers’ data is needed to offer cool, new experiences and a user needs to trust you in order to choose to give you their data. Pro-user innovation can’t happen in a vacuum – the system as it stands today isn’t doing a good job of aligning user interests with business incentives. Good user decisions can be good business decisions, but only if we create thoughtful user-centric products in a way that closes the feedback loop so that positive user experiences are rewarded with better business outcomes.&lt;/p&gt;
- &lt;p&gt;Not prioritizing privacy in product decisions will impact the bottom line. From the many data breaches over the last few years to increasing evidence of eroding trust in online services, data practices are proving to be the dark horse in the online economy. When a company loses user trust, whether on privacy or &lt;a href=&quot;https://medium.com/@davidamerland/the-cost-of-losing-trust-97d764a1e696&quot;&gt;anything else&lt;/a&gt;, it loses customers and the potential for growth.&lt;/p&gt;
- &lt;p&gt;Privacy means different things to different people but what’s clear is that people make decisions about the products and services that they use based on how those companies choose to treat their users. Over this time, the Internet ecosystem has evolved, as has its relationship with users – and some aspects of this evolution threaten the trust that lies at the heart of that relationship. Treating a user as a target – whether for an ad, purchase, or service – undermines the trust and relationship that a business may have with a consumer.&lt;/p&gt;
- &lt;p&gt;The solution is not to abandon the massive value that robust data can bring to users, but rather, to collect and use data leanly, productively and transparently. At Mozilla, we have created a strong set of internal data practices to ensure that data decisions align with our &lt;a href=&quot;https://www.mozilla.org/en-US/privacy/principles/&quot;&gt;privacy principles&lt;/a&gt;. As an industry, we need to keep users at the center of the product vision rather than viewing them as targets of the product – it’s the only way to stay true to consumers and deliver the best, most trusted experiences possible.&lt;/p&gt;
- &lt;p&gt;Want to hear more about how businesses can build relationships with their users by focusing on trust and privacy? We’re holding events in Washington, D.C., and &lt;a href=&quot;https://www.eventbrite.com/e/january-privacy-lab-privacy-for-startups-tickets-19849219550?aff=es2&quot;&gt;San Francisco&lt;/a&gt; with some of our partners to talk about it. Please join us!&lt;/p&gt;</description>
- <pubDate>Thu, 21 Jan 2016 17:42:00 +0000</pubDate>
- <dc:creator>Heather West</dc:creator>
- </item>
- <item>
- <title>J.C. Jones: Issuance Rate for Let's Encrypt</title>
- <guid isPermaLink="false">https://tacticalsecret.com/tag/mozilla/rss/9c39ad13-14ae-4456-a84e-13612637d832</guid>
- <link>https://tacticalsecret.com/issuance-rate-for-lets-encrypt/</link>
- <description>&lt;p&gt;Gathering data from &lt;a href=&quot;https://github.com/jcjones/letsencrypt_statistics&quot;&gt;Certificate Transparency logs&lt;/a&gt;, here's a snapshot in time of Let's Encrypt's certificate issuance rate per minute from 7-21 January 2016. On 20 January, DreamHost launched formal support for Let's Encrypt, which coincides with a rate increase.&lt;/p&gt;
-
- &lt;p&gt;Note: This is mostly an experimental post with embedding charts; I've more data in the queue.&lt;/p&gt;
-
- &lt;h3&gt;Let's Encrypt Issuance Rate per Minute&lt;/h3&gt;
-
- &lt;div id=&quot;rate_hours&quot;&gt;&lt;/div&gt;</description>
- <pubDate>Thu, 21 Jan 2016 17:07:25 +0000</pubDate>
- <dc:creator>James 'J.C.' Jones</dc:creator>
- </item>
- <item>
- <title>Air Mozilla: Web QA Weekly Meeting, 21 Jan 2016</title>
- <guid isPermaLink="true">https://air.mozilla.org/web-qa-weekly-meeting-20160121/</guid>
- <link>https://air.mozilla.org/web-qa-weekly-meeting-20160121/</link>
- <description>&lt;p&gt;
- &lt;img alt=&quot;Web QA Weekly Meeting&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/f5/13/f5137857516694df0458e837c2d3a4be.png&quot; width=&quot;160&quot; /&gt;
- This is our weekly gathering of Mozilla'a Web QA team filled with discussion on our current and future projects, ideas, demos, and fun facts.
- &lt;/p&gt;</description>
- <pubDate>Thu, 21 Jan 2016 17:00:00 +0000</pubDate>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item>
- <title>Soledad Penades: No more tap tap tap sounds: yay!</title>
- <guid isPermaLink="false">http://soledadpenades.com/?p=6379</guid>
- <link>http://soledadpenades.com/2016/01/21/no-more-tap-tap-tap-sounds-yay/</link>
- <description>&lt;p&gt;A few days ago the fantastic Fritz from the Netherlands told me that my &lt;a href=&quot;http://soledadpenades.com/files/t/2015_howa/&quot;&gt;Hands On Web Audio slides&lt;/a&gt; had stopping working and there was no sound coming out from them in Firefox.&lt;/p&gt;
- &lt;blockquote class=&quot;twitter-tweet&quot; width=&quot;550&quot;&gt;&lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;&lt;a href=&quot;https://twitter.com/supersole&quot;&gt;@supersole&lt;/a&gt; oh noes! I reopened your slides: &lt;a href=&quot;https://t.co/SO35UfljMI&quot;&gt;https://t.co/SO35UfljMI&lt;/a&gt; and it doesn't work in &lt;a href=&quot;https://twitter.com/firefox&quot;&gt;@firefox&lt;/a&gt; anymore &lt;img alt=&quot;😱&quot; class=&quot;wp-smiley&quot; src=&quot;http://s.w.org/images/core/emoji/72x72/1f631.png&quot; style=&quot;height: 1em;&quot; /&gt; (works in chrome though.. &lt;img alt=&quot;😢&quot; class=&quot;wp-smiley&quot; src=&quot;http://s.w.org/images/core/emoji/72x72/1f622.png&quot; style=&quot;height: 1em;&quot; /&gt;)&lt;/p&gt;
- &lt;p&gt;— Boring Stranger (@fritzvd) &lt;a href=&quot;https://twitter.com/fritzvd/status/686481500611735552&quot;&gt;January 11, 2016&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;&lt;/p&gt;
- &lt;p&gt;Which is pretty disappointing for a slide deck that is built to teach you about Web Audio!&lt;/p&gt;
- &lt;p&gt;I noticed that the issue was only on the introductory slide which uses a modified version of Stuart Memo’s &lt;a href=&quot;https://blog.stuartmemo.com/thx-deep-note-in-javascript/&quot;&gt;fantastic THX sound recreation&lt;/a&gt;-the rest of slides did play sound.&lt;/p&gt;
- &lt;p&gt;I built &lt;a href=&quot;http://sole.github.io/test_cases/web_audio/thx_cutting_out/&quot;&gt;an isolated test case&lt;/a&gt; &lt;small&gt;&lt;a href=&quot;https://github.com/sole/test_cases/tree/gh-pages/web_audio/thx_cutting_out&quot;&gt;(source)&lt;/a&gt;&lt;/small&gt; that used a parameter-capable version of the THX sound code, just in case the issue depended on the number of oscillators, and submitted this funnily titled bug to the Web Audio component: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1240054&quot;&gt;Entirely Web Audio generated sound cuts out after a little while, or emits random tap tap tap sounds then silence&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;I can happily confirm that the bug has been fixed in Nightly and the fix will hopefully be “uplifted†to DevEdition very soon, as it was due to a regression.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://paul.cx/&quot;&gt;Paul Adenot&lt;/a&gt; (who works in Web Audio and is a Web Audio spec editor, amongst a couple tons of other cool things) was really excited about the bug, saying it was very edge-casey! Yay! And he also explained what did actually happen in lay terms: “you’d have to have a frequency that goes down very very slowly so that the FFT code could not keep upâ€, which is what the THX sound is doing with the filter frequency automation.&lt;/p&gt;
- &lt;p&gt;I want to thank both Fritz for spotting this out and letting me know and also Stuart for sharing his THX code. It’s amazing what happens when you put stuff on the net and lots of different people use it in different ways and configurations. Together we make everything more robust &lt;img alt=&quot;:-)&quot; class=&quot;wp-smiley&quot; src=&quot;http://soledadpenades.com/wp-includes/images/smilies/simple-smile.png&quot; style=&quot;height: 1em;&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;Of course also sending thanks to Paul and Ben for identifying and fixing the issue so fast! It’s not been even a week! Woohoo!&lt;/p&gt;
- &lt;p&gt;Well done everyone! &lt;img alt=&quot;ðŸ‘&quot; class=&quot;wp-smiley&quot; src=&quot;http://s.w.org/images/core/emoji/72x72/1f44f.png&quot; style=&quot;height: 1em;&quot; /&gt;&lt;img alt=&quot;ðŸ¼&quot; class=&quot;wp-smiley&quot; src=&quot;http://s.w.org/images/core/emoji/72x72/1f3fc.png&quot; style=&quot;height: 1em;&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://soledadpenades.com/?flattrss_redirect&amp;amp;id=6379&amp;amp;md5=57babe624711830f95e4b8fbd6e52c91&quot; target=&quot;_blank&quot; title=&quot;Flattr&quot;&gt;&lt;img alt=&quot;flattr this!&quot; src=&quot;http://soledadpenades.com/wp-content/plugins/flattr/img/flattr-badge-large.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
- <pubDate>Thu, 21 Jan 2016 15:49:05 +0000</pubDate>
- <dc:creator>sole</dc:creator>
- </item>
- <item>
- <title>Pierros Papadeas: Mozillians.org Profile Edit refresh</title>
- <guid isPermaLink="true">http://pierros.papadeas.gr/?p=447</guid>
- <link>http://pierros.papadeas.gr/?p=447</link>
- <description>&lt;p&gt;Since the start of this year, Participation Infrastructure team has a renewed focus on making mozillians.org a modern community directory to meet Mozilla’s growing needs. This will not be an one-time effort. We need to invest technically and programmatically in order to deliver a first-class product that will be the foundation for identity management across the Mozilla ecosystem.&lt;/p&gt;
- &lt;p&gt;Mozillians.org is full of functionality as it is today, but is paying the debt of being developed by 5 different teams over the past 5 years. We started simple this time. Updated all core technology pieces, did privacy and security reviews, and started the process of consolidating and modernizing many of the things we do in the site.&lt;/p&gt;
- &lt;p&gt;Our first target was Profile Edit. We chose it due to relatively self-contained nature of it, and cause many people were not happy with the current UX. After research of existing tools and applying latest best practices, we designed, coded and deployed a new profile edit interface (which by the way is renamed to Settings now) that we are happy to deliver to all Mozillians.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://pierros.papadeas.gr/wp-content/uploads/2016/01/new-profile.png&quot; rel=&quot;attachment wp-att-448&quot;&gt;&lt;img alt=&quot;new-profile&quot; class=&quot;aligncenter size-large wp-image-448&quot; height=&quot;417&quot; src=&quot;http://pierros.papadeas.gr/wp-content/uploads/2016/01/new-profile-1024x731.png&quot; width=&quot;584&quot; /&gt;&lt;/a&gt;Have a&lt;a href=&quot;https://mozillians.org/en-US/user/edit/&quot;&gt; look for yourself &lt;/a&gt;and don’t miss the chance to update your profile while you do it!&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://mozillians.org/en-US/u/comzeradd/&quot;&gt;Nikos&lt;/a&gt; (on the front-end), &lt;a href=&quot;https://mozillians.org/en-US/u/akatsoulas/&quot;&gt;Tasos&lt;/a&gt; and &lt;a href=&quot;https://mozillians.org/en-US/u/jgiannelos/&quot;&gt;Nemo&lt;/a&gt; (on the back-end) worked hard to deliver this in a speedy manner (as they are used to), and the end result is a testament to what is coming next on Mozillians.org.&lt;/p&gt;
- &lt;p&gt;Our next target? Groups. Currently it is obscure and unclear what all those settings in groups are, what is the functionality and how teams within Mozilla will be using it. We will be tackling this soon. After that, search and stats will be our attention, in an ongoing effort to fortify mozillians.org functionality. Stay tuned, and as always feel free to &lt;a href=&quot;https://bugzilla.mozilla.org/enter_bug.cgi?product=Participation%20Infrastructure&amp;amp;component=Phonebook&quot;&gt;file bugs&lt;/a&gt; and &lt;a href=&quot;https://github.com/mozilla/mozillians&quot;&gt;contribute &lt;/a&gt;in the process.&lt;/p&gt;</description>
- <pubDate>Thu, 21 Jan 2016 11:41:39 +0000</pubDate>
- <dc:creator>Pierros Papadeas</dc:creator>
- </item>
- <item>
- <title>Adam Lofting: Blog posts I haven’t written lately</title>
- <guid isPermaLink="false">http://adamlofting.com/?p=1396</guid>
- <link>http://feedproxy.google.com/~r/adamlofting/blog/~3/DoEWpBapwiw/</link>
- <description>&lt;p&gt;Last year I joked…&lt;/p&gt;
- &lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;
- &lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;Thinking about writing a blog post listing the blog posts I’ve been meaning to write… Maybe that will save some time&lt;/p&gt;
- &lt;p&gt;— Adam Lofting (@adamlofting) &lt;a href=&quot;https://twitter.com/adamlofting/status/667657889817956352&quot;&gt;November 20, 2015&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;&lt;/p&gt;
- &lt;p&gt;Now, it has come to this.&lt;/p&gt;
- &lt;h4&gt;9 blog posts I’ve not been writing&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;Working on working on the impact of impact&lt;/li&gt;
- &lt;li&gt;Designing Games in &lt;a href=&quot;https://en.wikipedia.org/wiki/Amateur&quot; target=&quot;_blank&quot;&gt;my free time&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Moving Out (the board game)&lt;/li&gt;
- &lt;li&gt;Mozilla Foundation 2016 KPIs&lt;/li&gt;
- &lt;li&gt;Studying Network Science&lt;/li&gt;
- &lt;li&gt;Learning Analytics plans for 2016&lt;/li&gt;
- &lt;li&gt;Daily practice / you are what you do every day&lt;/li&gt;
- &lt;li&gt;Several more A/B tests to write up from &lt;a href=&quot;http://fundraising.mozilla.org/&quot;&gt;the fundraising campaign&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;CRM Progress in 2015&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;But my most requested blog by far, is an update on the status of my shed / office that I was tagging on to the end my blog posts at this time last year. Many people at Mozfest wanted to know about the shed… so here it is.&lt;/p&gt;
- &lt;p&gt;This time last year:&lt;/p&gt;
- &lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;
- Starting in the new office today. It will take time to make it *nice* but it works for now. &lt;a href=&quot;http://t.co/sWoC4kFNLc&quot;&gt;pic.twitter.com/sWoC4kFNLc&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;— Adam Lofting (@adamlofting) &lt;a href=&quot;https://twitter.com/adamlofting/status/560361913339899904&quot;&gt;January 28, 2015&lt;/a&gt;
- &lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;&lt;/p&gt;
- &lt;p&gt;Some pictures from this morning:&lt;/p&gt;
- &lt;p&gt;&lt;img alt=&quot;office1&quot; class=&quot;alignright size-large wp-image-1398&quot; height=&quot;282&quot; src=&quot;http://adamlofting.com/wp-content/uploads/2016/01/office1-750x320.jpg&quot; width=&quot;660&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;&lt;img alt=&quot;office2&quot; class=&quot;aligncenter size-large wp-image-1399&quot; height=&quot;237&quot; src=&quot;http://adamlofting.com/wp-content/uploads/2016/01/office2-750x269.jpg&quot; width=&quot;660&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;It’s a pretty nice place to work now and it doubles as useful workshop on the weekends. It needs a few finishing touches, but the law of diminishing returns means those finishing touches are lower priority than work that needs to be done elsewhere in the house and garden. So it’ll stay like this a while longer.&lt;/p&gt;
- &lt;div class=&quot;feedflare&quot;&gt;
- &lt;a href=&quot;http://feeds.feedburner.com/~ff/adamlofting/blog?a=DoEWpBapwiw:VxTJGXwqhlI:yIl2AUoC8zA&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://feeds.feedburner.com/~ff/adamlofting/blog?d=yIl2AUoC8zA&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.feedburner.com/~ff/adamlofting/blog?a=DoEWpBapwiw:VxTJGXwqhlI:qj6IDK7rITs&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://feeds.feedburner.com/~ff/adamlofting/blog?d=qj6IDK7rITs&quot; /&gt;&lt;/a&gt;
- &lt;/div&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; src=&quot;http://feeds.feedburner.com/~r/adamlofting/blog/~4/DoEWpBapwiw&quot; width=&quot;1&quot; /&gt;</description>
- <pubDate>Thu, 21 Jan 2016 09:44:24 +0000</pubDate>
- <dc:creator>Adam</dc:creator>
- </item>
- <item>
- <title>Tarek Ziadé: A Pelican web editor</title>
- <guid isPermaLink="true">http://blog.ziade.org/2016/01/21/a-pelican-web-editor/</guid>
- <link>http://blog.ziade.org/2016/01/21/a-pelican-web-editor/</link>
- <description>&lt;p&gt;The benefit of being a father again (Freya my 3rd child, was born last week) is
- that while on paternity leave &amp;amp; between two baby bottles, I can hack on fun stuff.&lt;/p&gt;
- &lt;p&gt;A few months ago, I've built for my running club a Pelican-based website, check it out
- at : &lt;a class=&quot;reference external&quot; href=&quot;http://acr-dijon.org&quot;&gt;http://acr-dijon.org&lt;/a&gt;. Nothing's special about it, except that I am not
- the one feeding it. The content is added by people from the club that have zero
- knowledge about softwares, let alone stuff like vim or command line tools.&lt;/p&gt;
- &lt;p&gt;I set up a github-based flow for them, where they add content through the
- github UI and its minimal reStructuredText preview feature - and then a few
- of my crons update the website on the server I host.
- For images and other media, they are uploading them via FTP using FireSSH in Firefox.&lt;/p&gt;
- &lt;p&gt;For the comments, I've switched from Disqus to &lt;a class=&quot;reference external&quot; href=&quot;https://posativ.org/isso/&quot;&gt;ISSO&lt;/a&gt;
- after I got annoyed by the fact that it was impossible to display a simple Disqus
- UI for people to comment without having to log in.&lt;/p&gt;
- &lt;p&gt;I had to make my club friends go through a minimal
- reStructuredText syntax training, and things are more of less working now.&lt;/p&gt;
- &lt;p&gt;The system has a few caveats though:&lt;/p&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;it's dependent on Github. I'd rather have everything hosted on my server.&lt;/li&gt;
- &lt;li&gt;the github restTRucturedText preview will not display syntax errors and warnings
- and very often, articles get broken&lt;/li&gt;
- &lt;li&gt;the resulting reST is ugly, and it's a bit hard to force my editors to be stricter
- about details like empty lines, not using tabs etc.&lt;/li&gt;
- &lt;li&gt;adding folders or organizing articles from Github is a pain&lt;/li&gt;
- &lt;li&gt;editing the metadata tags is prone to many mistakes&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;So I've decided to build my own web editing tool with the following features:&lt;/p&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;resTructuredText cleanup&lt;/li&gt;
- &lt;li&gt;content browsing&lt;/li&gt;
- &lt;li&gt;resTructuredText web editor with live preview that shows warnings &amp;amp; errors&lt;/li&gt;
- &lt;li&gt;a little bit of wsgi glue and a few forms to create articles without
- having to worry about metadata syntax.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;section&quot; id=&quot;restructuredtext-cleanup&quot;&gt;
- &lt;h3&gt;resTructuredText cleanup&lt;/h3&gt;
- &lt;p&gt;The first step was to build a reStructuredText parser that would read some
- reStructuredText and render it back into a cleaner version.&lt;/p&gt;
- &lt;p&gt;We've imported almost 2000 articles in Pelican from the old blog, so I had
- a &lt;strong&gt;lot&lt;/strong&gt; of samples to make my parser work well.&lt;/p&gt;
- &lt;p&gt;I first tried &lt;a class=&quot;reference external&quot; href=&quot;https://github.com/benoitbryon/rst2rst&quot;&gt;rst2rst&lt;/a&gt; but that
- parser was built for a very specific use case (text wrapping) and was
- incomplete. It was not parsing all of the reStructuredText syntax.&lt;/p&gt;
- &lt;p&gt;Inspired by it, I wrote my own little parser using &lt;strong&gt;docutils&lt;/strong&gt;.&lt;/p&gt;
- &lt;p&gt;Understanding docutils is not a small task. This project is very powerfull
- but quite complex. One thing that cruelly misses in docutils parser tools
- is the ability to get the source text from any node, including its children,
- so you can render back the same source.&lt;/p&gt;
- &lt;p&gt;That's roughly what I had to add in my code. It's ugly but it does the job:
- it will parse rst files and render the same content, minus all the extraneous
- empty lines, spaces, tabs etc.&lt;/p&gt;
- &lt;/div&gt;
- &lt;div class=&quot;section&quot; id=&quot;content-browsing&quot;&gt;
- &lt;h3&gt;Content browsing&lt;/h3&gt;
- &lt;p&gt;Content browsing is pretty straightforward: my admin tool let you browse
- the Pelican &lt;em&gt;content&lt;/em&gt; directory and lists all articles, organized by categories.&lt;/p&gt;
- &lt;p&gt;In our case, each category has a top directory in &lt;em&gt;content&lt;/em&gt;. The browser
- parses the articles using my parser and displays paginated lists.&lt;/p&gt;
- &lt;p&gt;I had to add a cache system for the parser, because one of the directory
- contains over 1000 articles -- and browsing was kind of slow :)&lt;/p&gt;
- &lt;img alt=&quot;http://ziade.org/henet-browsing.png&quot; src=&quot;http://ziade.org/henet-browsing.png&quot; /&gt;
- &lt;/div&gt;
- &lt;div class=&quot;section&quot; id=&quot;restructuredtext-web-editor&quot;&gt;
- &lt;h3&gt;resTructuredText web editor&lt;/h3&gt;
- &lt;p&gt;The last big bit was the live editor. I've stumbled on a neat little tool
- called &lt;strong&gt;rsted&lt;/strong&gt;, that provides a live preview of the reStructuredText
- as you are typing it. And it includes warnings !&lt;/p&gt;
- &lt;p&gt;Check it out: &lt;a class=&quot;reference external&quot; href=&quot;http://rst.ninjs.org/&quot;&gt;http://rst.ninjs.org/&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;I've stripped it and kept what I needed, and included it in my app.&lt;/p&gt;
- &lt;img alt=&quot;http://ziade.org/henet.png&quot; src=&quot;http://ziade.org/henet.png&quot; /&gt;
- &lt;p&gt;I am quite happy with the result so far. I need to add real tests and
- a bit of documentation, and I will start to train my club friends on it.&lt;/p&gt;
- &lt;p&gt;The next features I'd like to add are:&lt;/p&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;comments management, to replace Isso (working on it now)&lt;/li&gt;
- &lt;li&gt;smart Pelican builds. e.g. if a comment is added I don't want to rebuild the whole
- blog (~1500 articles)&lt;/li&gt;
- &lt;li&gt;media management&lt;/li&gt;
- &lt;li&gt;spell checker&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;The project lives here: &lt;a class=&quot;reference external&quot; href=&quot;https://github.com/AcrDijon/henet&quot;&gt;https://github.com/AcrDijon/henet&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;I am not going to release it, but if someone finds it useful, I could.&lt;/p&gt;
- &lt;p&gt;It's built with Bottle &amp;amp; Bootstrap as well.&lt;/p&gt;
- &lt;/div&gt;</description>
- <pubDate>Thu, 21 Jan 2016 09:40:00 +0000</pubDate>
- <dc:creator>Tarek Ziade</dc:creator>
- </item>
- <item>
- <title>Nick Cameron: Closures and first-class functions</title>
- <guid isPermaLink="false">http://www.ncameron.org/blog/rss/631106eb-e7b1-47d5-82f9-cb6ad210ea89</guid>
- <link>http://www.ncameron.org/blog/closures-and-first-class-functions/</link>
- <description>&lt;p&gt;I wrote a long and probably dull chapter on closures and first-class and higher-order functions in Rust. It goes into some detail on the implementation and some of the subtleties like higher-ranked lifetime bounds.&lt;/p&gt;
-
- &lt;p&gt;I was going to post it here too, but it is really too long. Instead, pop over to the 'Rust for C++ programmers' repo and read it &lt;a href=&quot;https://github.com/nrc/r4cppp/blob/master/closures.md&quot;&gt;there&lt;/a&gt;.&lt;/p&gt;</description>
- <pubDate>Thu, 21 Jan 2016 08:36:21 +0000</pubDate>
- <dc:creator>Nick Cameron</dc:creator>
- </item>
- <item>
- <title>Nick Desaulniers: Intro to Debugging x86-64 Assembly</title>
- <guid isPermaLink="false">http://nickdesaulniers.github.io/blog/2016/01/20/debugging-x86-64-assembly-with-lldb-and-dtrace</guid>
- <link>http://nickdesaulniers.github.io/blog/2016/01/20/debugging-x86-64-assembly-with-lldb-and-dtrace/</link>
- <description>&lt;p&gt;I’m hacking on an assembly project, and wanted to document some of the tricks I
- was using for figuring out what was going on. This post might seem a little
- basic for folks who spend all day heads down in gdb or who do this stuff
- professionally, but I just wanted to share a quick intro to some tools that
- others may find useful.
- (&lt;a href=&quot;https://pchiusano.github.io/2014-10-11/defensive-writing.html&quot;&gt;oh god, I’m doing it&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;If your coming from gdb to lldb, there’s a few differences in commands. LLDB
- has
- &lt;a href=&quot;http://lldb.llvm.org/lldb-gdb.html&quot;&gt;great documentation&lt;/a&gt;
- on some of the differences. Everything in this post about LLDB is pretty much
- there.&lt;/p&gt;
-
- &lt;p&gt;The bread and butter commands when working with gdb or lldb are:&lt;/p&gt;
-
- &lt;ul&gt;
- &lt;li&gt;r (run the program)&lt;/li&gt;
- &lt;li&gt;s (step in)&lt;/li&gt;
- &lt;li&gt;n (step over)&lt;/li&gt;
- &lt;li&gt;finish (step out)&lt;/li&gt;
- &lt;li&gt;c (continue)&lt;/li&gt;
- &lt;li&gt;q (quit the program)&lt;/li&gt;
- &lt;/ul&gt;
-
-
- &lt;p&gt;You can hit enter if you want to run the last command again, which is really
- useful if you want to keep stepping over statements repeatedly.&lt;/p&gt;
-
- &lt;p&gt;I’ve been using LLDB on OSX. Let’s say I want to debug a program I can build,
- but is crashing or something:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo lldb ./asmttpd web_root
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Setting a breakpoint on jump to label:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; b sys_write
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Breakpoint 3: &lt;span class=&quot;nv&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;sys_write, &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00000000000029ae
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Running the program until breakpoint hit:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;8&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;9&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;10&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; r
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Process 32236 launched: &lt;span class=&quot;s1&quot;&gt;'./asmttpd'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;x86_64&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Process 32236 stopped
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;* thread &lt;span class=&quot;c&quot;&gt;#1: tid = 0xe69b9, 0x00000000000029ae asmttpd`sys_write, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#0: 0x00000000000029ae asmttpd`sys_write&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;sys_write:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;-&amp;gt; 0x29ae &amp;lt;+0&amp;gt;: pushq %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29af &amp;lt;+1&amp;gt;: pushq %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b0 &amp;lt;+2&amp;gt;: pushq %rdx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b1 &amp;lt;+3&amp;gt;: pushq %r10
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Seeing more of the current stack frame:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;8&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;9&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;10&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;11&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;12&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;13&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;14&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;15&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;16&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;17&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;18&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;19&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;20&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;21&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;22&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;23&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;24&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; d
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;sys_write:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;-&amp;gt; 0x29ae &amp;lt;+0&amp;gt;: pushq %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29af &amp;lt;+1&amp;gt;: pushq %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b0 &amp;lt;+2&amp;gt;: pushq %rdx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b1 &amp;lt;+3&amp;gt;: pushq %r10
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b3 &amp;lt;+5&amp;gt;: pushq %r8
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b5 &amp;lt;+7&amp;gt;: pushq %r9
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b7 &amp;lt;+9&amp;gt;: pushq %rbx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b8 &amp;lt;+10&amp;gt;: pushq %rcx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b9 &amp;lt;+11&amp;gt;: movq %rsi, %rdx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29bc &amp;lt;+14&amp;gt;: movq %rdi, %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29bf &amp;lt;+17&amp;gt;: movq &lt;span class=&quot;nv&quot;&gt;$0x1&lt;/span&gt;, %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29c6 &amp;lt;+24&amp;gt;: movq &lt;span class=&quot;nv&quot;&gt;$0x2000004&lt;/span&gt;, %rax
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29cd &amp;lt;+31&amp;gt;: syscall
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29cf &amp;lt;+33&amp;gt;: popq %rcx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d0 &amp;lt;+34&amp;gt;: popq %rbx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d1 &amp;lt;+35&amp;gt;: popq %r9
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d3 &amp;lt;+37&amp;gt;: popq %r8
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29 &amp;lt;+39&amp;gt;: popq %r10
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d7 &amp;lt;+41&amp;gt;: popq %rdx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d8 &amp;lt;+42&amp;gt;: popq %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29d9 &amp;lt;+43&amp;gt;: popq %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29da &amp;lt;+44&amp;gt;: retq
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Getting a back trace (call stack):&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; bt
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;* thread &lt;span class=&quot;c&quot;&gt;#1: tid = 0xe69b9, 0x00000000000029ae asmttpd`sys_write, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; * frame &lt;span class=&quot;c&quot;&gt;#0: 0x00000000000029ae asmttpd`sys_write&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#1: 0x00000000000021b6 asmttpd`print_line + 16&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#2: 0x0000000000002ab3 asmttpd`start + 35&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#3: 0x00007fff9900c5ad libdyld.dylib`start + 1&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#4: 0x00007fff9900c5ad libdyld.dylib`start + 1&lt;/span&gt;
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;peeking at the upper stack frame:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; up
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;frame &lt;span class=&quot;c&quot;&gt;#1: 0x00000000000021b6 asmttpd`print_line + 16&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;print_line:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x21b6 &amp;lt;+16&amp;gt;: movabsq &lt;span class=&quot;nv&quot;&gt;$0x30cb&lt;/span&gt;, %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x21c0 &amp;lt;+26&amp;gt;: movq &lt;span class=&quot;nv&quot;&gt;$0x1&lt;/span&gt;, %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x21c7 &amp;lt;+33&amp;gt;: callq 0x29ae ; sys_write
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x21cc &amp;lt;+38&amp;gt;: popq %rcx
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;back down to the breakpoint-halted stack frame:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; down
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;frame &lt;span class=&quot;c&quot;&gt;#0: 0x00000000000029ae asmttpd`sys_write&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;sys_write:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;-&amp;gt; 0x29ae &amp;lt;+0&amp;gt;: pushq %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29af &amp;lt;+1&amp;gt;: pushq %rsi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b0 &amp;lt;+2&amp;gt;: pushq %rdx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x29b1 &amp;lt;+3&amp;gt;: pushq %r10
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;dumping the values of registers:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;8&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;9&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;10&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;11&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;12&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;13&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;14&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;15&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;16&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;17&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;18&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;19&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;20&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;21&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;22&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;23&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; register &lt;span class=&quot;nb&quot;&gt;read&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;General Purpose Registers:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000002a90 asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;start
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rbx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rcx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00007fff5fbffaf8
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rdx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00007fff5fbffa40
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rdi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00000000000030cc start_text
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rsi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x000000000000000f
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rbp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00007fff5fbffa18
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rsp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00007fff5fbff9b8
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00007fff7b1670c8 atexit_mutex + 24
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00000000ffffffff
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r11&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0xffffffff00000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r12&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r13&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r14&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;r15&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00000000000029ae asmttpd&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;sys_write
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rflags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000246
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;cs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x000000000000002b
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;fs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;gs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000000000
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;read just one register:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; register &lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;nv&quot;&gt;rdi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x00000000000030cc start_text
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;When you’re trying to figure out what system calls are made by some C code,
- using dtruss is very helpful. dtruss is available on OSX and seems to be some
- kind of wrapper around DTrace.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;8&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;9&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;10&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;11&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;12&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;13&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;14&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;15&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;16&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cat sleep.c
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;c&quot;&gt;#include &amp;lt;time.h&amp;gt;&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;int main &lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; struct timespec &lt;span class=&quot;nv&quot;&gt;rqtp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 2,
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; nanosleep&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&amp;amp;rqtp, NULL&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;clang sleep.c
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo dtruss ./a.out
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;...all kinds of fun stuff
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;__semwait_signal&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0xB03, 0x0, 0x1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; -1 Err#60
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;If you compile with &lt;code&gt;-g&lt;/code&gt; to emit debug symbols, you can use lldb’s disassemble
- command to get the equivalent assembly:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&quot;line-number&quot;&gt;1&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;2&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;3&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;4&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;5&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;6&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;7&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;8&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;9&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;10&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;11&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;12&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;13&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;14&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;15&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;16&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;17&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;18&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;19&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;20&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;21&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;22&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;23&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;24&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;25&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;26&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;27&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;28&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;29&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;30&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;31&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;32&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;33&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;34&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;35&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;36&lt;/span&gt;
- &lt;span class=&quot;line-number&quot;&gt;37&lt;/span&gt;
- &lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;clang sleep.c -g
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;lldb a.out
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; target create &lt;span class=&quot;s2&quot;&gt;&quot;a.out&quot;&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Current executable &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;to &lt;span class=&quot;s1&quot;&gt;'a.out'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;x86_64&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; b main
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Breakpoint 1: &lt;span class=&quot;nv&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; a.out&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;main + 16 at sleep.c:3, &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000100000f40
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; r
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Process 33213 launched: &lt;span class=&quot;s1&quot;&gt;'/Users/Nicholas/code/assembly/asmttpd/a.out'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;x86_64&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;Process 33213 stopped
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;* thread &lt;span class=&quot;c&quot;&gt;#1: tid = 0xeca04, 0x0000000100000f40 a.out`main + 16 at sleep.c:3, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; frame &lt;span class=&quot;c&quot;&gt;#0: 0x0000000100000f40 a.out`main + 16 at sleep.c:3&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 1 &lt;span class=&quot;c&quot;&gt;#include &amp;lt;time.h&amp;gt;&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 2 int main &lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;-&amp;gt; 3 struct timespec &lt;span class=&quot;nv&quot;&gt;rqtp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 4 2,
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 5 0
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 6 &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 7
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lldb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; disassemble
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;a.out&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;main:
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f30 &amp;lt;+0&amp;gt;: pushq %rbp
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f31 &amp;lt;+1&amp;gt;: movq %rsp, %rbp
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f34 &amp;lt;+4&amp;gt;: subq &lt;span class=&quot;nv&quot;&gt;$0x20&lt;/span&gt;, %rsp
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f38 &amp;lt;+8&amp;gt;: leaq -0x10&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rbp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, %rdi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f3c &amp;lt;+12&amp;gt;: xorl %eax, %eax
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f3e &amp;lt;+14&amp;gt;: movl %eax, %esi
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt;-&amp;gt; 0x100000f40 &amp;lt;+16&amp;gt;: movq 0x49&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rip&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, %rcx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f47 &amp;lt;+23&amp;gt;: movq %rcx, -0x10&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rbp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f4b &amp;lt;+27&amp;gt;: movq 0x46&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rip&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, %rcx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f52 &amp;lt;+34&amp;gt;: movq %rcx, -0x8&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rbp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f56 &amp;lt;+38&amp;gt;: callq 0x100000f68 ; symbol stub &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;: nanosleep
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f5b &amp;lt;+43&amp;gt;: xorl %edx, %edx
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f5d &amp;lt;+45&amp;gt;: movl %eax, -0x14&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%rbp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f60 &amp;lt;+48&amp;gt;: movl %edx, %eax
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f62 &amp;lt;+50&amp;gt;: addq &lt;span class=&quot;nv&quot;&gt;$0x20&lt;/span&gt;, %rsp
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f66 &amp;lt;+54&amp;gt;: popq %rbp
- &lt;/span&gt;&lt;span class=&quot;line&quot;&gt; 0x100000f67 &amp;lt;+55&amp;gt;: retq
- &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Anyways, I’ve been learning some interesting things about OSX that I’ll be
- sharing soon. If you’d like to learn more about x86-64 assembly programming,
- you should read my other posts about
- &lt;a href=&quot;http://nickdesaulniers.github.io/blog/2014/04/18/lets-write-some-x86-64/&quot;&gt;writing x86-64&lt;/a&gt;
- and a toy
- &lt;a href=&quot;http://nickdesaulniers.github.io/blog/2015/05/25/interpreter-compiler-jit/&quot;&gt;JIT for Brainfuck&lt;/a&gt;
- (&lt;a href=&quot;https://www.reddit.com/r/programming/comments/377ov9/interpreter_compiler_jit/crkkrz4&quot;&gt;the creator of Brainfuck liked it&lt;/a&gt;).&lt;/p&gt;
-
- &lt;p&gt;I should also do a post on
- &lt;a href=&quot;http://rr-project.org/&quot;&gt;Mozilla’s rr&lt;/a&gt;,
- because it can do amazing things like step backwards. Another day…&lt;/p&gt;</description>
- <pubDate>Thu, 21 Jan 2016 04:04:00 +0000</pubDate>
- </item>
- <item>
- <title>Rail Aliiev: Rebooting productivity</title>
- <guid isPermaLink="true">https://rail.merail.ca/posts/rebooting-productivity.html</guid>
- <link>https://rail.merail.ca/posts/rebooting-productivity.html</link>
- <description>&lt;div&gt;&lt;p&gt;Every new year gives you an opportunity to sit back, relax,
- &lt;span class=&quot;strike&quot;&gt;have some scotch&lt;/span&gt; and re-think the passed year. Holidays give
- you enough free time. Even if you decide to not take a vacation around
- the holidays, it's usually calm and peaceful.&lt;/p&gt;
- &lt;p&gt;This time, I found myself thinking mostly about productivity, being
- effective, feeling busy, overwhelmed with work and other related topics.&lt;/p&gt;
- &lt;p&gt;When I started at Mozilla (almost 6 years ago!), I tried to apply all my
- GTD and time management knowledge and techniques. Working remotely and
- in a different time zone was an advantage - I had close to zero
- interruptions. It worked perfect.&lt;/p&gt;
- &lt;p&gt;Last year I realized that my productivity skills had faded away somehow.
- 40h+ workweeks, working on weekends, delivering goals in the last week
- of quarter don't sound like good signs. Instead of being productive I
- felt busy.&lt;/p&gt;
- &lt;p&gt;&quot;Every crisis is an opportunity&quot;. Time to make a step back and reboot
- myself. Burning out at work is not a good idea. :)&lt;/p&gt;
- &lt;p&gt;Here are some ideas/tips that I wrote down for myself you may found
- useful.&lt;/p&gt;
- &lt;div class=&quot;section&quot; id=&quot;health-related&quot;&gt;
- &lt;h3&gt;Health related&lt;/h3&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;Morning exercises. A 20-minute walk will wake your brain up and
- generate enough endorphins for the first half of the day.&lt;/li&gt;
- &lt;li&gt;Meditation. 2x20min a day is ideal; 2x10min would work too. Something
- like &lt;a class=&quot;reference external&quot; href=&quot;http://www.calm.com/&quot;&gt;calm.com&lt;/a&gt; makes this a peace of cake.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;section&quot; id=&quot;concentration&quot;&gt;
- &lt;h3&gt;Concentration&lt;/h3&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;Task #1: make a daily plan. No plan - no work.&lt;/li&gt;
- &lt;li&gt;Don't start your day by reading emails. Get one (little) thing done
- first - THEN check your email.&lt;/li&gt;
- &lt;li&gt;Try to define outcomes, not tasks. &quot;Ship XYZ&quot; instead of &quot;Work on XYZ&quot;.&lt;/li&gt;
- &lt;li&gt;Meetings are time consuming, so &quot;Set a goal for each meeting&quot;.
- Consider skipping a meeting if you don't have any goal set, unless it's a
- beer-and-tell meeting! :)&lt;/li&gt;
- &lt;li&gt;Constantly ask yourself if what you're working on is important.&lt;/li&gt;
- &lt;li&gt;3-4 times a day ask yourself whether you are doing something towards
- your goal or just finding something else to keep you busy. If you want
- to look busy, take your phone and walk around the office with some
- papers in your hand. Everybody will think that you are a busy person!
- This way you can take a break and look busy at the same time!&lt;/li&gt;
- &lt;li&gt;Take breaks! &lt;a class=&quot;reference external&quot; href=&quot;https://en.wikipedia.org/wiki/Pomodoro_Technique&quot;&gt;Pomodoro technique&lt;/a&gt; has this option
- built-in. Taking breaks helps not only to avoid &lt;a class=&quot;reference external&quot; href=&quot;https://en.wikipedia.org/wiki/Repetitive_strain_injury&quot;&gt;RSI&lt;/a&gt;, but also
- keeps your brain sane and gives you time to ask yourself the questions
- mentioned above. I use &lt;a class=&quot;reference external&quot; href=&quot;http://www.workrave.org/&quot;&gt;Workrave&lt;/a&gt; on my
- laptop, but you can use a real kitchen timer instead.&lt;/li&gt;
- &lt;li&gt;Wear headphones, especially at office. Noise cancelling ones are even
- better. White noise, nature sounds, or instrumental music are your
- friends.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;section&quot; id=&quot;home-office&quot;&gt;
- &lt;h3&gt;(Home) Office&lt;/h3&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;Make sure you enjoy your work environment. Why on the earth would you
- spend your valuable time working without joy?!&lt;/li&gt;
- &lt;li&gt;De-clutter and organize your desk. Less things around - less
- distractions.&lt;/li&gt;
- &lt;li&gt;Desk, chair, monitor, keyboard, mouse, etc - don't cheap out on them.
- Your health is more important and expensive. Thanks to &lt;a class=&quot;reference external&quot; href=&quot;https://twitter.com/mhoye&quot;&gt;mhoye&lt;/a&gt; for this advice!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;section&quot; id=&quot;other&quot;&gt;
- &lt;h3&gt;Other&lt;/h3&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;Don't check email every 30 seconds. If there is an emergency, they
- will call you! :)&lt;/li&gt;
- &lt;li&gt;Reward yourself at a certain time. &quot;I'm going to have a chocolate at
- 11am&quot;, or &quot;MFBT at 4pm sharp!&quot; are good examples. Don't forget, you
- are &lt;a class=&quot;reference external&quot; href=&quot;https://en.wikipedia.org/wiki/Classical_conditioning&quot;&gt;Pavlov's dog&lt;/a&gt; too!&lt;/li&gt;
- &lt;li&gt;Don't try to read everything NOW. Save it for later and read in a
- batch.&lt;/li&gt;
- &lt;li&gt;Capture all creative ideas. You can delete them later. ;)&lt;/li&gt;
- &lt;li&gt;Prepare for next task before break. Make sure you know what's next, so
- you can think about it during the break.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;This is my list of things that I try to use everyday. Looking forward to
- see improvements!&lt;/p&gt;
- &lt;p&gt;I would appreciate your thoughts this topic. Feel free to comment or
- send a private email.&lt;/p&gt;
- &lt;p&gt;Happy Productive New Year!&lt;/p&gt;
- &lt;/div&gt;&lt;/div&gt;</description>
- <pubDate>Thu, 21 Jan 2016 02:06:37 +0000</pubDate>
- <dc:creator>Rail Aliiev</dc:creator>
- </item>
- <item>
- <title>The Rust Programming Language Blog: Announcing Rust 1.6</title>
- <guid isPermaLink="true">http://blog.rust-lang.org/2016/01/21/Rust-1.6.html</guid>
- <link>http://blog.rust-lang.org/2016/01/21/Rust-1.6.html</link>
- <description>&lt;p&gt;Hello 2016! We’re happy to announce the first Rust release of the year, 1.6.
- Rust is a systems programming language focused on safety, speed, and
- concurrency.&lt;/p&gt;
-
- &lt;p&gt;As always, you can &lt;a href=&quot;http://www.rust-lang.org/install.html&quot;&gt;install Rust 1.6&lt;/a&gt; from the appropriate page on our
- website, and check out the &lt;a href=&quot;https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-160-2016-01-21&quot;&gt;detailed release notes for 1.6&lt;/a&gt; on GitHub.
- About 1100 patches were landed in this release.&lt;/p&gt;
-
- &lt;h3 id=&quot;what-39-s-in-1-6-stable&quot;&gt;What’s in 1.6 stable&lt;/h3&gt;
-
- &lt;p&gt;This release contains a number of small refinements, one major feature, and
- a change to &lt;a href=&quot;https://crates.io&quot;&gt;Crates.io&lt;/a&gt;.&lt;/p&gt;
-
- &lt;h4 id=&quot;libcore-stabilization&quot;&gt;libcore stabilization&lt;/h4&gt;
-
- &lt;p&gt;The largest new feature in 1.6 is that &lt;a href=&quot;http://doc.rust-lang.org/nightly/core/&quot;&gt;&lt;code&gt;libcore&lt;/code&gt;&lt;/a&gt; is now stable! Rust’s
- standard library is two-tiered: there’s a small core library, &lt;code&gt;libcore&lt;/code&gt;, and
- the full standard library, &lt;code&gt;libstd&lt;/code&gt;, that builds on top of it. &lt;code&gt;libcore&lt;/code&gt; is
- completely platform agnostic, and requires only a handful of external symbols
- to be defined. Rust’s &lt;code&gt;libstd&lt;/code&gt; builds on top of &lt;code&gt;libcore&lt;/code&gt;, adding support for
- memory allocation, I/O, and concurrency. Applications using Rust in the
- embedded space, as well as those writing operating systems, often eschew
- &lt;code&gt;libstd&lt;/code&gt;, using only &lt;code&gt;libcore&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;libcore&lt;/code&gt; being stabilized is a major step towards being able to write the
- lowest levels of software using stable Rust. There’s still future work to be
- done, however. This will allow for a library ecosystem to develop around
- &lt;code&gt;libcore&lt;/code&gt;, but &lt;em&gt;applications&lt;/em&gt; are not fully supported yet. Expect to hear more
- about this in future release notes.&lt;/p&gt;
-
- &lt;h4 id=&quot;library-stabilizations&quot;&gt;Library stabilizations&lt;/h4&gt;
-
- &lt;p&gt;About 30 library functions and methods are now stable in 1.6. Notable
- improvements include:&lt;/p&gt;
-
- &lt;p&gt;The &lt;code&gt;drain()&lt;/code&gt; family of functions on collections. These methods let you move
- elements out of a collection while allowing them to retain their backing
- memory, reducing allocation in certain situations.&lt;/p&gt;
-
- &lt;p&gt;A number of implementations of &lt;code&gt;From&lt;/code&gt; for converting between standard library
- types, mainly between various integral and floating-point types.&lt;/p&gt;
-
- &lt;p&gt;Finally, &lt;code&gt;Vec::extend_from_slice()&lt;/code&gt;, which was previously known as
- &lt;code&gt;push_all()&lt;/code&gt;. This method has a significantly faster implementation than the
- more general &lt;code&gt;extend()&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;See the &lt;a href=&quot;https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-160-2016-01-21&quot;&gt;detailed release notes&lt;/a&gt; for more.&lt;/p&gt;
-
- &lt;h4 id=&quot;crates-io-disallows-wildcards&quot;&gt;Crates.io disallows wildcards&lt;/h4&gt;
-
- &lt;p&gt;If you maintain a crate on &lt;a href=&quot;https://crates.io&quot;&gt;Crates.io&lt;/a&gt;, you might have seen
- a warning: newly uploaded crates are no longer allowed to use a wildcard when
- describing their dependencies. In other words, this is not allowed:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;*&quot;&lt;/span&gt;
- &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
- &lt;p&gt;Instead, you must actually specify &lt;a href=&quot;http://doc.crates.io/crates-io.html#using-cratesio-based-crates&quot;&gt;a specific version or range of
- versions&lt;/a&gt;, using one of the &lt;code&gt;semver&lt;/code&gt; crate’s various options: &lt;code&gt;^&lt;/code&gt;,
- &lt;code&gt;~&lt;/code&gt;, or &lt;code&gt;=&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;A wildcard dependency means that you work with any possible version of your
- dependency. This is highly unlikely to be true, and causes unnecessary breakage
- in the ecosystem. We’ve been advertising this change as a warning for some time;
- now it’s time to turn it into an error.&lt;/p&gt;
-
- &lt;h3 id=&quot;contributors-to-1-6&quot;&gt;Contributors to 1.6&lt;/h3&gt;
-
- &lt;p&gt;We had 132 individuals contribute to 1.6. Thank you so much!&lt;/p&gt;
-
- &lt;ul&gt;
- &lt;li&gt;Aaron Turon&lt;/li&gt;
- &lt;li&gt;Adam Badawy&lt;/li&gt;
- &lt;li&gt;Aleksey Kladov&lt;/li&gt;
- &lt;li&gt;Alexander Bulaev&lt;/li&gt;
- &lt;li&gt;Alex Burka&lt;/li&gt;
- &lt;li&gt;Alex Crichton&lt;/li&gt;
- &lt;li&gt;Alex Gaynor&lt;/li&gt;
- &lt;li&gt;Alexis Beingessner&lt;/li&gt;
- &lt;li&gt;Amanieu d'Antras&lt;/li&gt;
- &lt;li&gt;Amit Saha&lt;/li&gt;
- &lt;li&gt;Andrea Canciani&lt;/li&gt;
- &lt;li&gt;Andrew Paseltiner&lt;/li&gt;
- &lt;li&gt;androm3da&lt;/li&gt;
- &lt;li&gt;angelsl&lt;/li&gt;
- &lt;li&gt;Angus Lees&lt;/li&gt;
- &lt;li&gt;Antti Keränen&lt;/li&gt;
- &lt;li&gt;arcnmx&lt;/li&gt;
- &lt;li&gt;Ariel Ben-Yehuda&lt;/li&gt;
- &lt;li&gt;Ashkan Kiani&lt;/li&gt;
- &lt;li&gt;Barosl Lee&lt;/li&gt;
- &lt;li&gt;Benjamin Herr&lt;/li&gt;
- &lt;li&gt;Ben Striegel&lt;/li&gt;
- &lt;li&gt;Bhargav Patel&lt;/li&gt;
- &lt;li&gt;Björn Steinbrink&lt;/li&gt;
- &lt;li&gt;Boris Egorov&lt;/li&gt;
- &lt;li&gt;bors&lt;/li&gt;
- &lt;li&gt;Brian Anderson&lt;/li&gt;
- &lt;li&gt;Bruno Tavares&lt;/li&gt;
- &lt;li&gt;Bryce Van Dyk&lt;/li&gt;
- &lt;li&gt;Cameron Sun&lt;/li&gt;
- &lt;li&gt;Christopher Sumnicht&lt;/li&gt;
- &lt;li&gt;Cole Reynolds&lt;/li&gt;
- &lt;li&gt;corentih&lt;/li&gt;
- &lt;li&gt;Daniel Campbell&lt;/li&gt;
- &lt;li&gt;Daniel Keep&lt;/li&gt;
- &lt;li&gt;Daniel Rollins&lt;/li&gt;
- &lt;li&gt;Daniel Trebbien&lt;/li&gt;
- &lt;li&gt;Danilo Bargen&lt;/li&gt;
- &lt;li&gt;Devon Hollowood&lt;/li&gt;
- &lt;li&gt;Doug Goldstein&lt;/li&gt;
- &lt;li&gt;Dylan McKay&lt;/li&gt;
- &lt;li&gt;ebadf&lt;/li&gt;
- &lt;li&gt;Eli Friedman&lt;/li&gt;
- &lt;li&gt;Eric Findlay&lt;/li&gt;
- &lt;li&gt;Erik Davidson&lt;/li&gt;
- &lt;li&gt;Felix S. Klock II&lt;/li&gt;
- &lt;li&gt;Florian Hahn&lt;/li&gt;
- &lt;li&gt;Florian Hartwig&lt;/li&gt;
- &lt;li&gt;Gleb Kozyrev&lt;/li&gt;
- &lt;li&gt;Guillaume Gomez&lt;/li&gt;
- &lt;li&gt;Huon Wilson&lt;/li&gt;
- &lt;li&gt;Igor Shuvalov&lt;/li&gt;
- &lt;li&gt;Ivan Ivaschenko&lt;/li&gt;
- &lt;li&gt;Ivan Kozik&lt;/li&gt;
- &lt;li&gt;Ivan Stankovic&lt;/li&gt;
- &lt;li&gt;Jack Fransham&lt;/li&gt;
- &lt;li&gt;Jake Goulding&lt;/li&gt;
- &lt;li&gt;Jake Worth&lt;/li&gt;
- &lt;li&gt;James Miller&lt;/li&gt;
- &lt;li&gt;Jan Likar&lt;/li&gt;
- &lt;li&gt;Jean Maillard&lt;/li&gt;
- &lt;li&gt;Jeffrey Seyfried&lt;/li&gt;
- &lt;li&gt;Jethro Beekman&lt;/li&gt;
- &lt;li&gt;John KÃ¥re Alsaker&lt;/li&gt;
- &lt;li&gt;John Talling&lt;/li&gt;
- &lt;li&gt;Jonas Schievink&lt;/li&gt;
- &lt;li&gt;Jonathan S&lt;/li&gt;
- &lt;li&gt;Jose Narvaez&lt;/li&gt;
- &lt;li&gt;Josh Austin&lt;/li&gt;
- &lt;li&gt;Josh Stone&lt;/li&gt;
- &lt;li&gt;Joshua Holmer&lt;/li&gt;
- &lt;li&gt;JP Sugarbroad&lt;/li&gt;
- &lt;li&gt;jrburke&lt;/li&gt;
- &lt;li&gt;Kevin Butler&lt;/li&gt;
- &lt;li&gt;Kevin Yeh&lt;/li&gt;
- &lt;li&gt;Kohei Hasegawa&lt;/li&gt;
- &lt;li&gt;Kyle Mayes&lt;/li&gt;
- &lt;li&gt;Lee Jeffery&lt;/li&gt;
- &lt;li&gt;Manish Goregaokar&lt;/li&gt;
- &lt;li&gt;Marcell Pardavi&lt;/li&gt;
- &lt;li&gt;Markus Unterwaditzer&lt;/li&gt;
- &lt;li&gt;Martin Pool&lt;/li&gt;
- &lt;li&gt;Marvin Löbel&lt;/li&gt;
- &lt;li&gt;Matt Brubeck&lt;/li&gt;
- &lt;li&gt;Matthias Bussonnier&lt;/li&gt;
- &lt;li&gt;Matthias Kauer&lt;/li&gt;
- &lt;li&gt;mdinger&lt;/li&gt;
- &lt;li&gt;Michael Layzell&lt;/li&gt;
- &lt;li&gt;Michael Neumann&lt;/li&gt;
- &lt;li&gt;Michael Sproul&lt;/li&gt;
- &lt;li&gt;Michael Woerister&lt;/li&gt;
- &lt;li&gt;Mihaly Barasz&lt;/li&gt;
- &lt;li&gt;Mika Attila&lt;/li&gt;
- &lt;li&gt;mitaa&lt;/li&gt;
- &lt;li&gt;Ms2ger&lt;/li&gt;
- &lt;li&gt;Nicholas Mazzuca&lt;/li&gt;
- &lt;li&gt;Nick Cameron&lt;/li&gt;
- &lt;li&gt;Niko Matsakis&lt;/li&gt;
- &lt;li&gt;Ole Krüger&lt;/li&gt;
- &lt;li&gt;Oliver Middleton&lt;/li&gt;
- &lt;li&gt;Oliver Schneider&lt;/li&gt;
- &lt;li&gt;Ori Avtalion&lt;/li&gt;
- &lt;li&gt;Paul A. Jungwirth&lt;/li&gt;
- &lt;li&gt;Peter Atashian&lt;/li&gt;
- &lt;li&gt;Philipp Matthias Schäfer&lt;/li&gt;
- &lt;li&gt;pierzchalski&lt;/li&gt;
- &lt;li&gt;Ravi Shankar&lt;/li&gt;
- &lt;li&gt;Ricardo Martins&lt;/li&gt;
- &lt;li&gt;Ricardo Signes&lt;/li&gt;
- &lt;li&gt;Richard Diamond&lt;/li&gt;
- &lt;li&gt;Rizky Luthfianto&lt;/li&gt;
- &lt;li&gt;Ryan Scheel&lt;/li&gt;
- &lt;li&gt;Scott Olson&lt;/li&gt;
- &lt;li&gt;Sean Griffin&lt;/li&gt;
- &lt;li&gt;Sebastian Hahn&lt;/li&gt;
- &lt;li&gt;Sébastien Marie&lt;/li&gt;
- &lt;li&gt;Seo Sanghyeon&lt;/li&gt;
- &lt;li&gt;Simonas Kazlauskas&lt;/li&gt;
- &lt;li&gt;Simon Sapin&lt;/li&gt;
- &lt;li&gt;Stepan Koltsov&lt;/li&gt;
- &lt;li&gt;Steve Klabnik&lt;/li&gt;
- &lt;li&gt;Steven Fackler&lt;/li&gt;
- &lt;li&gt;Tamir Duberstein&lt;/li&gt;
- &lt;li&gt;Tobias Bucher&lt;/li&gt;
- &lt;li&gt;Toby Scrace&lt;/li&gt;
- &lt;li&gt;Tshepang Lekhonkhobe&lt;/li&gt;
- &lt;li&gt;Ulrik Sverdrup&lt;/li&gt;
- &lt;li&gt;Vadim Chugunov&lt;/li&gt;
- &lt;li&gt;Vadim Petrochenkov&lt;/li&gt;
- &lt;li&gt;William Throwe&lt;/li&gt;
- &lt;li&gt;xd1le&lt;/li&gt;
- &lt;li&gt;Xmasreturns&lt;/li&gt;
- &lt;/ul&gt;</description>
- <pubDate>Thu, 21 Jan 2016 00:00:00 +0000</pubDate>
- </item>
- <item>
- <title>Mozilla Addons Blog: Archiving AMO Stats</title>
- <guid isPermaLink="false">http://blog.mozilla.org/addons/?p=7644</guid>
- <link>https://blog.mozilla.org/addons/2016/01/20/archiving-amo-stats/</link>
- <description>&lt;p&gt;One of the advantages of listing an add-on or theme on &lt;a href=&quot;https://addons.mozilla.org&quot; target=&quot;_blank&quot;&gt;addons.mozilla.org&lt;/a&gt; (AMO) is that you’ll get statistics on your add-on’s usage. These stats, which are covered by the &lt;a href=&quot;https://www.mozilla.org/privacy/&quot; target=&quot;_blank&quot;&gt;Mozilla privacy policy&lt;/a&gt;, provide add-on developers with information such as the number of downloads and daily users, among other insights.&lt;/p&gt;
- &lt;p&gt;Currently, the data that generates these statistics can go back as far as 2007, as we haven’t had an archiving policy. As a result, statistics take up the vast majority of disk space in our database and require a significant amount of processing and operations time. Statistics over a year old are very rarely accessed, and the value of their generation is very low, while the costs are increasing.&lt;/p&gt;
- &lt;p&gt;To reduce our operating and development costs, and increase the site’s reliability for developers, we are introducing an archiving policy.&lt;/p&gt;
- &lt;p&gt;In the coming weeks, statistics data &lt;strong&gt;over one year old&lt;/strong&gt; will no longer be stored in the AMO database, and reports generated from them will no longer be accessible through AMO’s add-on statistics pages. Instead, the data will be archived and maintained as plain text files, which developers can download. We will write a follow-up post when these archives become available.&lt;/p&gt;
- &lt;p&gt;If you’ve chosen to keep your add-on’s statistics private, they will remain private when stats are archived. You can check your privacy settings by going to your add-on in the &lt;a href=&quot;https://addons.mozilla.org/developers/addons&quot; target=&quot;_blank&quot;&gt;Developer Hub&lt;/a&gt;, clicking on &lt;strong&gt;Edit Listing&lt;/strong&gt;, and then &lt;strong&gt;Technical Details&lt;/strong&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://blog.mozilla.org/addons/files/2016/01/Screenshot-2016-01-20-14.52.33.png&quot;&gt;&lt;img alt=&quot;editlisting&quot; class=&quot;alignnone size-large wp-image-7645&quot; height=&quot;389&quot; src=&quot;https://blog.mozilla.org/addons/files/2016/01/Screenshot-2016-01-20-14.52.33-600x389.png&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;The total number of users and other cumulative counts on add-ons and themes will not be affected and these will continue to function.&lt;/p&gt;
- &lt;p&gt;If you have feedback or concerns, please head to our &lt;a href=&quot;https://discourse.mozilla-community.org/t/archiving-of-add-on-statistics/6573&quot; target=&quot;_blank&quot;&gt;forum post&lt;/a&gt; on this topic.&lt;/p&gt;</description>
- <pubDate>Wed, 20 Jan 2016 23:54:09 +0000</pubDate>
- <dc:creator>Andy McKay</dc:creator>
- </item>
- <item>
- <title>Air Mozilla: The Joy of Coding - Episode 41</title>
- <guid isPermaLink="true">https://air.mozilla.org/the-joy-of-coding-episode-41/</guid>
- <link>https://air.mozilla.org/the-joy-of-coding-episode-41/</link>
- <description>&lt;p&gt;
- &lt;img alt=&quot;The Joy of Coding - Episode 41&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/cb/68/cb68b6ac48452be7e7f25ddc7b63c959.png&quot; width=&quot;160&quot; /&gt;
- mconley livehacks on real Firefox bugs while thinking aloud.
- &lt;/p&gt;</description>
- <pubDate>Wed, 20 Jan 2016 18:00:00 +0000</pubDate>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item>
- <title>Nathan Froyd: gecko and c++ onboarding presentation</title>
- <guid isPermaLink="false">http://blog.mozilla.org/nfroyd/?p=452</guid>
- <link>https://blog.mozilla.org/nfroyd/2016/01/20/gecko-and-c-onboarding-presentation/</link>
- <description>&lt;p&gt;One of the things the Firefox team has been doing recently is having onboarding sessions for new hires. This onboarding currently covers:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;1st day setup&lt;/li&gt;
- &lt;li&gt;Bugzilla&lt;/li&gt;
- &lt;li&gt;Building Firefox&lt;/li&gt;
- &lt;li&gt;Desktop Firefox Architecture / Product&lt;/li&gt;
- &lt;li&gt;Communication and Community&lt;/li&gt;
- &lt;li&gt;Javascript and the DOM&lt;/li&gt;
- &lt;li&gt;C++ and Gecko&lt;/li&gt;
- &lt;li&gt;Shipping Software&lt;/li&gt;
- &lt;li&gt;Telemetry&lt;/li&gt;
- &lt;li&gt;Org structure and career development&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;My first day consisted of some useful HR presentations and then I was given my laptop and a pointer to a wiki page on building Firefox. Needless to say, it took me a while to get started! It would have been super convenient to have an introduction to all the stuff above.&lt;/p&gt;
- &lt;p&gt;I’ve been asked to do the C++ and Gecko session three times. All of the sessions are open to whoever wants to come, not just the new hires, and I think yesterday’s session was easily the most well-attended yet: somewhere between 10 and 20 people showed up. Yesterday’s session was the first session where I made the slides available to attendees (should have been doing that from the start…) and it seemed equally useful to make the slides available to a broader audience as well. The &lt;a href=&quot;https://docs.google.com/presentation/d/1ZHUkNzZK2TrF5_4MWd_lqEq7Ph5B6CDbNsizIkBxbnQ/edit?usp=sharing&quot;&gt;Gecko and C++ Onboarding slides&lt;/a&gt; are up now!&lt;/p&gt;
- &lt;p&gt;This presentation is a “living†presentation; it will get updated for future sessions with feedback and as I think of things that should have been in the presentation or better ways to set things up (some diagrams would be nice…). If you have feedback (good, bad, or ugly) on particular things in the slides or you have suggestions on what other things should be covered, please contact me! Next time I do this I’ll try to record the presentation so folks can watch that if they prefer.&lt;/p&gt;</description>
- <pubDate>Wed, 20 Jan 2016 16:48:29 +0000</pubDate>
- <dc:creator>Nathan Froyd</dc:creator>
- </item>
- <item>
- <title>Andreas Gal: Brendan is back to save the Web</title>
- <guid isPermaLink="false">http://andreasgal.com/?p=573</guid>
- <link>http://andreasgal.com/2016/01/20/brendan-is-back-to-save-the-web/</link>
- <description>&lt;p class=&quot;p1&quot;&gt;Brendan is &lt;a href=&quot;https://github.com/brave&quot;&gt;back&lt;/a&gt;, and he has a &lt;a href=&quot;http://brave.com/&quot;&gt;plan&lt;/a&gt; to save the Web. Its a big and bold plan, and it may just work. I am pretty excited about this. If you have 5 minutes to read along I’ll explain why I think you should be as well.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;The Web is broken&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;Lets face it, the Web today is a mess. Everywhere we go online we are constantly inundated with annoying ads. Often pages are more ads than content, and the more ads the industry throws at us, the more we ignore them, the more obnoxious ads get, trying to catch our attention. As Brendan explains in his blog post, the browser used to be on the user’s side—we call browsers the user agent for a reason. Part of the early success of Firefox was that it blocked popup ads. But somewhere over the last 10 years of modern Web browsers, browsers lost their way and stopped being the user’s agent alone. Why?&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;Browsers aren’t free&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;Making a modern Web browser is not free. It takes hundreds of engineers to make a competitive modern browser engine. Someone has to pay for that, and that someone needs to have a reason to pay for it. Google doesn’t make Chrome for the good of mankind. Google makes Chrome so you can consume more Web and along with it, more Google ads. Each time you click on one, Google makes more money. Chrome is a billion dollar business for Google. And the same is true for pretty much every other browser. Every major browser out there is funded through advertisement. No browser maker can escape this dilemma. Maybe now you understand why no major browser ships with a builtin enabled by default ad-blocker, even though ad-blockers are by far the most popular add-ons.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;Our privacy is at stake&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;It’s not just the unregulated flood of advertisement that needs a solution. Every ad you see is often selected based on sensitive private information advertisement networks have extracted from your browsing behavior through tracking. Remember how the FBI used to track what books Americans read at the library, and it was a big scandal? Today the Googles and Facebooks of the world know almost every site you visit, everything you buy online, and they use this data to target you with advertisement. I am often puzzled why people are so afraid of the NSA spying on us but show so little concern about all the deeply personal data Google and Facebook are amassing about everyone.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;Blocking alone doesn’t scale&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;I wish the solution was as easy as just blocking all ads. There is a lot of great Web content out there: news, entertainment, educational content. It’s not free to make all this content, but we have gotten used to consuming it “for freeâ€. Banning all ads without an alternative mechanism would break the economic backbone of the Web. This dilemma has existed for many years, and the big browser vendors seem to have given up on it. It’s hard to blame them. How do you disrupt the status quo without sawing off the (ad revenue) branch you are sitting on?&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;It takes an newcomer to fix this mess&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;I think its unlikely that the incumbent browser vendors will make any bold moves to solve this mess. There is too much money at stake. I am excited to see a startup take a swipe at this problem, because they have little to lose (seed money aside). Brave is getting the user agent back into the game. Browsers have intentionally remained silent onlookers to the ad industry invading users’ privacy. With Brave, Brendan makes the user agent step up and fight for the user as it was always intended to do.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;Brave basically consists of two parts: part one blocks third party ad content and tracking signals. Instead of these Brave inserts alternative ad content. Sites can sign up to get a fair share of any ads that Brave displays for them. The big change in comparison to the status quo is that the Brave user agent is in control and can regulate what you see. It’s like a speed limit for advertisement on the Web, with the goal to restore balance and give sites a fair way to monetize while giving the user control through the user agent.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;Making money with a better Web&lt;/strong&gt;&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;The ironic part of Brave is that its for-profit. Brave can make money by reducing obnoxious ads and protecting your privacy at the same time. If Brave succeeds, it’s going to drain money away from the crappy privacy-invasive obnoxious advertisement world we have today, and publishers and sites will start transacting in the new Brave world that is regulated by the user agent. Brave will take a cut of these transactions. And I think this is key. It aligns the incentives right. The current funding structure of major browsers encourages them to keep things as they are. Brave’s incentive is to bring down the whole diseased temple and usher in a better Web. Exciting.&lt;/p&gt;
- &lt;p class=&quot;p1&quot;&gt;&lt;strong&gt;Quick update:&lt;/strong&gt; I had a chance to look over the Brave GitHub repo. It looks like the Brave Desktop browser is based on Chromium, not Gecko. Yes, you read that right. &lt;span style=&quot;text-decoration: underline;&quot;&gt;Brave is using Google’s rendering engine, not Mozilla’s.&lt;/span&gt; Much to write about this one, but it will definitely help Brave “hide†better in the large volume of Chrome users, making it harder for sites to identify and block Brave users. Brave for iOS seems to be a &lt;span style=&quot;text-decoration: underline;&quot;&gt;fork of Firefox for iOS, but it manages to block ads&lt;/span&gt; (Mozilla says they can’t).&lt;/p&gt;&lt;br /&gt;Filed under: &lt;a href=&quot;http://andreasgal.com/category/mozilla/&quot;&gt;Mozilla&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gocomments/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/godelicious/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/delicious/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gofacebook/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/facebook/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gotwitter/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/twitter/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gostumble/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/stumble/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/godigg/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/digg/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/goreddit/andreasgal.wordpress.com/573/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/reddit/andreasgal.wordpress.com/573/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;http://pixel.wp.com/b.gif?host=andreasgal.com&amp;amp;blog=891661&amp;amp;post=573&amp;amp;subd=andreasgal&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</description>
- <pubDate>Wed, 20 Jan 2016 16:00:00 +0000</pubDate>
- <dc:creator>Andreas</dc:creator>
- </item>
- <item>
- <title>Mike Taylor: 🙅 @media (-webkit-transform-3d)</title>
- <guid isPermaLink="true">https://miketaylr.com/posts/2016/01/at-media-webkit-transform-three-dee.html</guid>
- <link>https://miketaylr.com/posts/2016/01/at-media-webkit-transform-three-dee.html</link>
- <description>&lt;p&gt;&lt;code&gt;@media (-webkit-transform-3d)&lt;/code&gt; is a funny thing that exists on the web.&lt;/p&gt;
-
- &lt;p&gt;It's like, a &lt;a href=&quot;https://drafts.csswg.org/mediaqueries-4/#mq-features&quot;&gt;media query feature&lt;/a&gt; in the form of a prefixed CSS property, which should tell you if your (once upon a time probably Safari-only) browser supports 3D transforms, invented back in the day before we had &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@supports&quot;&gt;&lt;code&gt;@supports&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
-
- &lt;p&gt;(According to &lt;a href=&quot;https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariCSSRef/Articles/OtherStandardCSS3Features.html#//apple_ref/doc/uid/TP40007601-SW3&quot;&gt;Apple docs&lt;/a&gt; it first appeared in Safari 4, along side the other &lt;code&gt;-webkit-transition&lt;/code&gt; and &lt;code&gt;-webkit-transform-2d&lt;/code&gt; hybrid-media-query-feature-prefixed-css-properties-things that you should immediately forget exist.)&lt;/p&gt;
-
- &lt;p&gt;Older versions of Modernizr &lt;a href=&quot;https://github.com/Modernizr/Modernizr/blob/66c694d136241d356e0d24fcbaa5c068b0b0cdae/feature-detects/css/transforms3d.js#L26-L27&quot;&gt;used this (and only this)&lt;/a&gt; to detect support for 3D transforms, and that seemed pretty OK. (They also did the polite thing and tested &lt;code&gt;@media (transform-3d)&lt;/code&gt;, but no browser has ever actually supported that, as it turns out). And because they're so consistently polite, they've since &lt;a href=&quot;https://github.com/patrickkettner/Modernizr/commit/a54308e47e269a058472854b1ef417bd54f4e616&quot;&gt;updated the test&lt;/a&gt; to prefer &lt;code&gt;@supports&lt;/code&gt; too (via a pull request from Edge developer Jacob Rossi).&lt;/p&gt;
-
- &lt;p&gt;As it turns out other browsers have been &lt;a href=&quot;http://caniuse.com/#feat=transforms3d&quot;&gt;updated to support 3D CSS transforms&lt;/a&gt;, but sites didn't go back and update their version of Modernizr. So unless you support &lt;code&gt;@media (-webkit-transform-3d)&lt;/code&gt; these sites break. Niche websites like &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1239136&quot;&gt;yahoo.com&lt;/a&gt; and &lt;a href=&quot;https://github.com/webcompat/web-bugs/issues/2151&quot;&gt;about.com&lt;/a&gt;.&lt;/p&gt;
-
- &lt;p&gt;So, anyways. I added &lt;a href=&quot;https://compat.spec.whatwg.org/#css-media-queries-webkit-transform-3d&quot;&gt;&lt;code&gt;@media (-webkit-transform-3d)&lt;/code&gt; to the Compat Standard&lt;/a&gt; and we &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1239799&quot;&gt;added support for it Firefox&lt;/a&gt; so websites stop breaking.&lt;/p&gt;
-
- &lt;p&gt;But you shouldn't ever use it—use &lt;code&gt;@supports&lt;/code&gt;. In fact, don't even share this blog post. Maybe delete it from your browser history just in case.&lt;/p&gt;</description>
- <pubDate>Wed, 20 Jan 2016 08:00:00 +0000</pubDate>
- <dc:creator>Mike Taylor</dc:creator>
- </item>
- <item>
- <title>Byron Jones: happy bmo push day!</title>
- <guid isPermaLink="false">http://globau.wordpress.com/?p=881</guid>
- <link>https://globau.wordpress.com/2016/01/20/happy-bmo-push-day-166/</link>
- <description>&lt;p&gt;the following changes have been pushed to bugzilla.mozilla.org:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1236161&quot; target=&quot;_blank&quot;&gt;1236161&lt;/a&gt;] when converting a BMP attachment to PNG fails a zero byte attachment is created&lt;/li&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1231918&quot; target=&quot;_blank&quot;&gt;1231918&lt;/a&gt;] error handler doesn’t close multi-part responses&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;discuss these changes on &lt;a href=&quot;https://lists.mozilla.org/listinfo/tools-bmo&quot; target=&quot;_blank&quot;&gt;mozilla.tools.bmo&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;Filed under: &lt;a href=&quot;https://globau.wordpress.com/category/mozilla/bmo/&quot;&gt;bmo&lt;/a&gt;, &lt;a href=&quot;https://globau.wordpress.com/category/mozilla/&quot;&gt;mozilla&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;https://pixel.wp.com/b.gif?host=globau.wordpress.com&amp;amp;blog=25718030&amp;amp;post=881&amp;amp;subd=globau&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</description>
- <pubDate>Wed, 20 Jan 2016 07:33:46 +0000</pubDate>
- <dc:creator>glob</dc:creator>
- </item>
- <item>
- <title>Alex Johnson: Removing Honeycomb Code</title>
- <guid isPermaLink="false">https://www.alex-johnson.net/tag/mozilla/rss/85d84c54-ed0c-4ee5-beb3-8823edb3c074</guid>
- <link>https://www.alex-johnson.net/removing-honeycomb-code/</link>
- <description>&lt;p&gt;As an effort to reduce the APK size of Firefox for Android and to remove unnecessary code, I will be helping remove the Honeycomb code throughout the Fennec project. Honeycomb will not be supported since Firefox 46, so this code is not necessary. &lt;br /&gt;
- &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1217675&quot;&gt;Bug 1217675&lt;/a&gt; will keep track of the progress. &lt;br /&gt;
- Hopefully this will help reduce the APK size some and clean up the road for &lt;a href=&quot;https://www.youtube.com/watch?v=NJ6kzW5t02Y&quot;&gt;killing Gingerbread&lt;/a&gt; hopefully sometime in the near future.&lt;/p&gt;</description>
- <pubDate>Wed, 20 Jan 2016 04:59:34 +0000</pubDate>
- <dc:creator>Alex Johnson</dc:creator>
- </item>
- <item>
- <title>Brian R. Bondy: Brave Software</title>
- <guid isPermaLink="false">http://www.brianbondy.com/blog/id/172</guid>
- <link>http://www.brianbondy.com/blog/172/brave-software</link>
- <description>&lt;p&gt;&lt;/p&gt;&lt;p&gt;Since June of last year, I’ve been co-founding a new startup called &lt;a href=&quot;https://brave.com/&quot;&gt;Brave Software&lt;/a&gt; with &lt;a href=&quot;https://en.wikipedia.org/wiki/Brendan_Eich&quot;&gt;Brendan Eich&lt;/a&gt;.
- With our amazing team, we're developing something pretty epic.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
- &lt;p&gt;&lt;/p&gt;&lt;p&gt;We're building the next-generation of browsers for smartphones and laptops as part of our new ad-tech platform.
- Our terms of use give our users control over their personal data by blocking ad trackers and third party cookies.
- We re-integrate fewer and better ads directly into programmatic ad positions, paying revenue shares to users and publishers to support both of these essential parties in the web ecosystem.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
- &lt;p&gt;&lt;/p&gt;&lt;p&gt;Coming built in, we have new faster engines for tracking protection, ad block, HTTPS Everywhere, safe ads with rev-share, and more.
- We're seeing massive web page load time speedups.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
-
-
- &lt;p&gt;&lt;/p&gt;&lt;p&gt;We're starting to bring people in for early developer build access on all platforms.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
- &lt;p&gt;&lt;/p&gt;&lt;p&gt;I’m happy to share that the browsers we’re developing were made fully open sourced.
- We welcome contributors, and would love your help.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
- &lt;p&gt;&lt;/p&gt;&lt;p&gt;Some of the repositories include:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/brave/browser-laptop&quot;&gt;Brave OSX and Windows x64 browsers&lt;/a&gt;: Prototyped as a Gecko based browser, but now replaced with a powerful new browser built on top of the electron framework. The electron framework is the same one in use by Slack and the Atom editor. It uses the latest libchromiumcontent and Node.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/brave/link-bubble&quot;&gt;Brave for Android&lt;/a&gt;: Formerly Link Bubble, working as a background service so you can use other apps as your pages load.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/brave/browser-ios&quot;&gt;Brave for iOS&lt;/a&gt;: Originally forked from Firefox for iOS but with all of the built-in greatness described above.&lt;/li&gt;
- &lt;li&gt;And many others: Website, updater code, vault, electron fork, and others.&lt;/li&gt;
- &lt;/ul&gt;</description>
- <pubDate>Wed, 20 Jan 2016 00:00:00 +0000</pubDate>
- <dc:creator>Brian R. Bondy</dc:creator>
- </item>
- <item>
- <title>James Socol: PIEfection Slides Up</title>
- <guid isPermaLink="false">http://coffeeonthekeyboard.com/rss/0388d8a6-fc86-477e-a161-1b356e01fe77</guid>
- <link>http://coffeeonthekeyboard.com/piefection-slides-up/</link>
- <description>&lt;p&gt;I put &lt;a href=&quot;https://github.com/jsocol/talks/tree/master/2016-01-13-manhattanjs-pie&quot;&gt;the slides for my ManhattanJS talk, &quot;PIEfection&quot;&lt;/a&gt; up on GitHub the other day (sans images, but there are links in the source for all of those).&lt;/p&gt;
-
- &lt;p&gt;I completely neglected to talk about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Maillard_reaction&quot;&gt;Maillard reaction&lt;/a&gt;, which is responsible for food tasting good, and specifically for browning pie crusts. tl;dr: Amino acid (protein) + sugar + ~300°F (~150°C) = delicious. There are innumerable and poorly understood combinations of amino acids and sugars, but this class of reaction is responsible for everything from searing stakes to browning crusts to toasting marshmallows.&lt;/p&gt;
-
- &lt;p&gt;Above ~330°F, you get caramelization, which is also a delicious part of the pie and crust, but you don't want to overdo it. Starting around ~400°F, you get pyrolysis (burning, charring, carbonization) and below 285°F the reaction won't occur (at least not quickly) so you won't get the delicious compounds.&lt;/p&gt;
-
- &lt;p&gt;(All of these are, of course, temperatures measured in the material, not in the air of the oven.)&lt;/p&gt;
-
- &lt;p&gt;So, instead of an egg wash on your top crust, try whole milk, which has more sugar to react with the gluten in the crust.&lt;/p&gt;
-
- &lt;p&gt;I also didn't get a chance to mention a rolling technique I use, that I learned from a &lt;a href=&quot;https://www.facebook.com/ellenspirerstaffing&quot;&gt;cousin of mine&lt;/a&gt;, in whose baking shadow I happily live.&lt;/p&gt;
-
- &lt;p&gt;When rolling out a crust after it's been in the fridge, first roll it out in a long stretch, then fold it in thirds; do it again; then start rolling it out into a round. Not only do you add more layer structure (mmm, flaky, delicious layers) but it'll fill in the cracks that often form if you try to roll it out directly, resulting in a stronger crust.&lt;/p&gt;
-
- &lt;p&gt;Those &lt;a href=&quot;http://www.amazon.com/Cheese-Shaker-Pepper-Perforated-Stainless/dp/B007T40P28/ref=sr_1_1?ie=UTF8&amp;amp;qid=1453236391&amp;amp;sr=8-1&amp;amp;keywords=pizza+shaker&quot;&gt;pepper flake shakers&lt;/a&gt;, filled with flour, are a great way to keep adding flour to the workspace without worrying about your buttery hands.&lt;/p&gt;
-
- &lt;p&gt;For transferring the crust to the pie plate, try rolling it up onto your rolling pin and unrolling it on the plate. &lt;a href=&quot;http://www.amazon.com/Ateco-20-Inch-Length-French-Rolling/dp/B000KESQ1G&quot;&gt;Tapered (or &quot;French&quot;) rolling pins&lt;/a&gt; (or wine bottle) are particularly good at this since they don't have moving parts.&lt;/p&gt;
-
- &lt;p&gt;Finally, thanks again to &lt;a href=&quot;https://twitter.com/renrutnnej&quot;&gt;Jenn&lt;/a&gt; for helping me get pies from one island to another. It would not have been possible without her!&lt;/p&gt;</description>
- <pubDate>Tue, 19 Jan 2016 20:45:34 +0000</pubDate>
- <dc:creator>James Socol</dc:creator>
- </item>
- <item>
- <title>Air Mozilla: Reprendre le contrôle de sa vie privée sur Internet</title>
- <guid isPermaLink="true">https://air.mozilla.org/reprendre-le-controle-de-sa-vie-privee-sur-internet/</guid>
- <link>https://air.mozilla.org/reprendre-le-controle-de-sa-vie-privee-sur-internet/</link>
- <description>&lt;p&gt;
- &lt;img alt=&quot;Reprendre le contrôle de sa vie privée sur Internet&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/be/f6/bef62897fb87e08dc8392fe61d10bcfa.png&quot; width=&quot;160&quot; /&gt;
- L'omniprésence des réseaux sociaux, des moteurs de recherches et de la publicité est-elle compatible avec notre droit à la vie privée ?
- &lt;/p&gt;</description>
- <pubDate>Tue, 19 Jan 2016 18:00:00 +0000</pubDate>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item>
- <title>Myk Melez: New Year, New Blogware</title>
- <guid isPermaLink="false">https://mykzilla.org/?p=245</guid>
- <link>https://mykzilla.org/2016/01/19/new-year-new-blogware/</link>
- <description>&lt;p&gt;Four score and many moons ago, I decided to move this blog from Blogger to WordPress. The transition took longer than expected, but it’s finally done.&lt;/p&gt;
- &lt;p&gt;If you’ve been following along at the old address, &lt;a href=&quot;https://mykzilla.blogspot.com/&quot;&gt;https://mykzilla.blogspot.com/&lt;/a&gt;, now’s the time to update your address book! If you’ve been going to &lt;a href=&quot;https://mykzilla.org/&quot;&gt;https://mykzilla.org/&lt;/a&gt;, however, or you read the blog on &lt;a href=&quot;http://planet.mozilla.org/&quot;&gt;Planet Mozilla&lt;/a&gt;, then there’s nothing to do, as that’s the new address, and Planet Mozilla has been updated to syndicate posts from it.&lt;/p&gt;</description>
- <pubDate>Tue, 19 Jan 2016 16:56:05 +0000</pubDate>
- <dc:creator>Myk Melez</dc:creator>
- </item>
- <item>
- <title>Michael Kohler: Mozillas strategische Leitlinien für 2016 und danach</title>
- <guid isPermaLink="false">http://michaelkohler.info/?p=348</guid>
- <link>https://michaelkohler.info/2016/mozillas-strategische-leitlinien-fur-2016-und-danach</link>
- <description>&lt;p&gt;Dieser Beitrag wurde zuerst im Blog auf&lt;a href=&quot;https://blog.mozilla.org/community&quot;&gt; https://blog.mozilla.org/community&lt;/a&gt; veröffentlicht. Herzlichen Dank an Aryx und Coce für die Übersetzung!&lt;/p&gt;
- &lt;p&gt;Auf der ganzen Welt arbeiten leidenschaftliche Mozillianer am Fortschritt für Mozillas Mission. Aber fragt man fünf verschiedene Mozillianer, was die Mission ist, erhält man womöglich sieben verschiedene Antworten.&lt;/p&gt;
- &lt;p&gt;Am Ende des letzten Jahres legte Mozillas CEO Chris Beard klare Vorstellungen über Mozillas Mission, Vision und Rolle dar und zeigte auf, wie unsere Produkte uns diesem Ziel in den nächsten fünf Jahren näher bringen. Das Ziel dieser strategischen Leitlinien besteht darin, für Mozilla insgesamt ein prägnantes, gemeinsames Verständnis unserer Ziele zu entwickeln, die uns als Individuen das Treffen von Entscheidungen und Erkennen von Möglichkeiten erleichtert, mit denen wir Mozilla voranbringen.&lt;/p&gt;
- &lt;p&gt;Mozillas Mission können wir nicht alleine erreichen. Die Tausenden von Mozillianern auf der ganzen Welt müssen dahinter stehen, damit wir zügig und mit lauterer Stimme als je zuvor Unglaubliches erreichen können.&lt;/p&gt;
- &lt;p&gt;Deswegen ist eine der sechs&lt;a href=&quot;https://docs.google.com/presentation/d/1A3Ma9gNawAYYGbYC2bUW0wUwcpHuvyMiZvHNiMLriw0/edit#slide=id.gdaa7a0bd0_1_0&quot;&gt; strategischen Initiativen&lt;/a&gt; des Participation Teams für die erste Jahreshälfte, möglichst viele Mozillianer über diese Leitlinien aufzuklären, damit wir 2016 den bisher wesentlichsten Einfluss erzielen können. Wir werden einen weiteren Beitrag veröffentlichen, der sich näher mit der Strategie des Participation Teams für das Jahr 2016 befassen wird.&lt;/p&gt;
- &lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;alignnone&quot; height=&quot;335&quot; src=&quot;https://ffp4g1ylyit3jdyti1hqcvtb-wpengine.netdna-ssl.com/community/files/2016/01/Screen-Shot-2015-12-18-at-2.02.07-PM-600x335.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;Das Verstehen dieser Strategie wird unabdingbar sein für jeden, der bei Mozilla in diesem Jahr etwas bewirken möchte, denn sie wird bestimmen, wofür wir eintreten, wo wir unsere Ressourcen einsetzen und auf welche Projekte wir uns 2016 konzentrieren werden.&lt;/p&gt;
- &lt;p&gt;Zu Jahresbeginn werden wir näher auf diese Strategie eingehen und weitere Details dazu bekanntgeben, wie die diversen Teams und Projekte bei Mozilla auf diese Ziele hinarbeiten.&lt;/p&gt;
- &lt;p&gt;Der aktuelle Aufruf zum Handeln besteht darin, im Kontext Ihrer Arbeit über diese Ziele nachzudenken und darüber, wie Sie im kommenden Jahr bei Mozilla mitwirken möchten. Dies hilft, Ihre Innovationen, Ambitionen und Ihren Einfluss im Jahr 2016 zu gestalten.&lt;/p&gt;
- &lt;p&gt;Wir hoffen, dass Sie mitdiskutieren und Ihre Fragen, Kommentare und Pläne für das Vorantreiben der strategischen Leitlinien im Jahr 2016&lt;a href=&quot;https://discourse.mozilla-community.org/t/mozillas-strategic-narrative-2016/6397&quot;&gt; hier&lt;/a&gt; auf Discourse teilen und Ihre Gedanken auf Twitter mit dem Hashtag &lt;a href=&quot;https://twitter.com/search?q=%23mozilla2016strategy&amp;amp;src=typd&quot;&gt;#Mozilla2016Strategy&lt;/a&gt; mitteilen.&lt;/p&gt;
- &lt;p&gt; &lt;/p&gt;
- &lt;h3&gt;Mission, Vision &amp;amp; Strategie&lt;/h3&gt;
- &lt;p&gt;&lt;b&gt;Unsere Mission&lt;/b&gt;&lt;/p&gt;
- &lt;p&gt;Dafür zu sorgen, dass das Internet eine weltweite öffentliche Ressource ist, die allen zugänglich ist.&lt;/p&gt;
- &lt;p&gt;&lt;b&gt;Unsere Vision&lt;/b&gt;&lt;/p&gt;
- &lt;p&gt;Ein Internet, für das Menschen tatsächlich an erster Stelle stehen. Ein Internet, in dem Menschen ihr eigenes Erlebnis gestalten können. Ein Internet, in dem die Menschen selbst entscheiden können sowie sicher und unabhängig sind.&lt;/p&gt;
- &lt;p&gt;&lt;b&gt;Unsere Rolle&lt;/b&gt;&lt;/p&gt;
- &lt;p&gt;Mozilla setzt sich im wahrsten Sinne des Wortes in Ihrem Online-Leben für Sie ein. Wir setzen uns für Sie ein, sowohl in Ihrem Online-Erlebnis als auch für Ihre Interessen beim Zustand des Internets.&lt;/p&gt;
- &lt;p&gt;&lt;b&gt;Unsere Arbeit&lt;/b&gt;&lt;/p&gt;
- &lt;p&gt;Unsere Säulen&lt;/p&gt;
- &lt;ol&gt;
- &lt;li&gt;&lt;b&gt;Produkte:&lt;/b&gt; Wir entwickeln Produkte mit Menschen im Mittelpunkt sowie Bildungsprogramme, mit deren Hilfe Menschen online ihr gesamtes Potential ausschöpfen können.&lt;/li&gt;
- &lt;li&gt;&lt;b&gt;Technologie:&lt;/b&gt; Wir entwickeln robuste technische Lösungen, die das Internet über verschiedene Plattformen hinweg zum Leben erwecken.&lt;/li&gt;
- &lt;li&gt;&lt;b&gt;Menschen:&lt;/b&gt; Wir entwickeln Führungspersonen und Mitwirkende in der Gemeinschaft, die das Internet erfinden, gestalten und verteidigen.&lt;/li&gt;
- &lt;/ol&gt;
- &lt;p&gt;Wir wir positive Veränderungen in Zukunft anpacken wollen&lt;/p&gt;
- &lt;p&gt;Die Arbeitsweise ist ebensowichtig wie das Ziel. Unsere Gesundheit und bleibender Einfluss hängen davon ab, wie sehr unsere Produkte und Aktivitäten:&lt;/p&gt;
- &lt;ol&gt;
- &lt;li&gt;Interoperabilität, Open Source und offene Standards fördern,&lt;/li&gt;
- &lt;li&gt;Gemeinschaften aufbauen und fördern,&lt;/li&gt;
- &lt;li&gt;Für politische Veränderungen und rechtlichen Schutz eintreten sowie&lt;/li&gt;
- &lt;li&gt;Netzbürger bilden und einbeziehen.&lt;/li&gt;
- &lt;/ol&gt;
- &lt;p&gt; &lt;/p&gt;
- &lt;img alt=&quot;&quot; height=&quot;0&quot; src=&quot;http://piwik.michaelkohler.info/piwik.php?idsite=1&amp;amp;rec=1&amp;amp;url=https%3A%2F%2Fmichaelkohler.info%2F2016%2Fmozillas-strategische-leitlinien-fur-2016-und-danach&amp;amp;action_name=Mozillas+strategische+Leitlinien+f%C3%BCr+2016+und+danach&amp;amp;urlref=https%3A%2F%2Fmichaelkohler.info%2Ffeed&quot; style=&quot;border: 0; width: 0; height: 0;&quot; width=&quot;0&quot; /&gt;</description>
- <pubDate>Tue, 19 Jan 2016 15:27:24 +0000</pubDate>
- <dc:creator>Michael Kohler</dc:creator>
- </item>
- <item>
- <title>David Lawrence: happy bmo push day!</title>
- <guid isPermaLink="false">http://dlawrence.wordpress.com/?p=27</guid>
- <link>https://dlawrence.wordpress.com/2016/01/19/happy-bmo-push-day-3/</link>
- <description>&lt;p&gt;the following changes have been pushed to bugzilla.mozilla.org:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1238573&quot; target=&quot;_blank&quot;&gt;1238573&lt;/a&gt;] Change label of “New Bug†menu to “New/Clone Bugâ€&lt;/li&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1239065&quot; target=&quot;_blank&quot;&gt;1239065&lt;/a&gt;] Project Kickoff Form: Adjustments needed to Mozilla Infosec review portion&lt;/li&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1240157&quot; target=&quot;_blank&quot;&gt;1240157&lt;/a&gt;] Fix a typo in bug.rst&lt;/li&gt;
- &lt;li&gt;[&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1236461&quot; target=&quot;_blank&quot;&gt;1236461&lt;/a&gt;] Mass update mozilla-reps group&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;discuss these changes on &lt;a href=&quot;https://lists.mozilla.org/listinfo/tools-bmo&quot; target=&quot;_blank&quot;&gt;mozilla.tools.bmo&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gocomments/dlawrence.wordpress.com/27/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/dlawrence.wordpress.com/27/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;https://pixel.wp.com/b.gif?host=dlawrence.wordpress.com&amp;amp;blog=58816&amp;amp;post=27&amp;amp;subd=dlawrence&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</description>
- <pubDate>Tue, 19 Jan 2016 14:49:59 +0000</pubDate>
- <dc:creator>dlawrence</dc:creator>
- </item>
- <item>
- <title>Soledad Penades: Hardware Hack Day @ MozLDN, 1</title>
- <guid isPermaLink="false">http://soledadpenades.com/?p=6335</guid>
- <link>http://soledadpenades.com/2016/01/19/hardware-hack-day-mozldn-1/</link>
- <description>&lt;p&gt;Last week we ran an internal “hack day†here at the Mozilla space in London. It was just a bunch of &lt;em&gt;software&lt;/em&gt; engineers looking at various &lt;em&gt;hardware&lt;/em&gt; boards and things and learning about them &lt;img alt=&quot;:-)&quot; class=&quot;wp-smiley&quot; src=&quot;http://soledadpenades.com/wp-includes/images/smilies/simple-smile.png&quot; style=&quot;height: 1em;&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;Here’s what we did!&lt;/p&gt;
- &lt;h3&gt;&lt;a href=&quot;http://soledadpenades.com/&quot;&gt;Sole&lt;/a&gt;&lt;/h3&gt;
- &lt;p&gt;I essentially &lt;a href=&quot;http://soledadpenades.com/2016/01/19/kind-of-bricking-an-arduino-duemilanove-by-exhausting-its-memory/&quot;&gt;kind of bricked my Arduino Duemilanove&lt;/a&gt; trying to get it working with Johnny Five, but it was fine–apparently there’s a way to recover it using another Arduino, and someone offered to help with that in the next &lt;a href=&quot;http://www.meetup.com/NodeBots-of-London/events/227890374/&quot;&gt;NodeBots&lt;/a&gt; London, which I’m going to attend.&lt;/p&gt;
- &lt;h3&gt;&lt;a href=&quot;http://ardeenelinfierno.com/&quot;&gt;Francisco&lt;/a&gt;&lt;/h3&gt;
- &lt;p&gt;Thinks he’s having issues with cables. It seems like the boards are not reset automatically by the Arduino IDE nowadays? He found the button in the board actually resets the board when pressed i.e. it’s the RESET button.&lt;/p&gt;
- &lt;p&gt;On the Raspberry Pi side of things, he was very happy to put all his old-school Linux skills in action configuring network interfaces without GUIs!&lt;/p&gt;
- &lt;h3&gt;&lt;a href=&quot;http://gu.illau.me/&quot;&gt;Guillaume&lt;/a&gt;&lt;/h3&gt;
- &lt;p&gt;Played with mDNS advertising and listening to services on Raspberry Pi.&lt;/p&gt;
- &lt;p&gt;(He was very quiet)&lt;/p&gt;
- &lt;p&gt;(He also built a very nice LEGO case for the Raspberry Pi, but I do not have a picture, so just imagine it).&lt;/p&gt;
- &lt;h3&gt;&lt;a href=&quot;http://wilsonpage.co.uk/&quot;&gt;Wilson&lt;/a&gt;&lt;/h3&gt;
- &lt;blockquote&gt;&lt;p&gt;
- Wilson: “I got my Raspberry Pi on the Wi-Fiâ€&lt;/p&gt;
- &lt;p&gt;Francisco: “Sorry?â€&lt;/p&gt;
- &lt;p&gt;Wilson: “I mean, you got my Raspberry Pi on the network. And now I’m trying to build a web app on the Pi…â€&lt;/p&gt;&lt;/blockquote&gt;
- &lt;h3&gt;&lt;a href=&quot;http://chrislord.net/&quot;&gt;Chris&lt;/a&gt;&lt;/h3&gt;
- &lt;p&gt;Exploring the Pebble with Linux. There’s a libpebble, and he managed to connect…&lt;/p&gt;
- &lt;p&gt;&lt;del datetime=&quot;2016-01-20T11:22:33+00:00&quot;&gt;&lt;em&gt;&lt;small&gt;(sorry, I had to leave early so I do not know what else did Chris do!)&lt;/small&gt;&lt;/em&gt;&lt;/del&gt;&lt;/p&gt;
- &lt;p&gt;Updated, 20 January: Chris told me he just managed to successfully connect to the Pebble watch using the bluetooth WebAPI. It requires two Gecko patches (one regression patch and one obvious logic error that he hasn’t filed yet). PROGRESS!&lt;/p&gt;
- &lt;p&gt;~~~&lt;/p&gt;
- &lt;p&gt;So as you can see we didn’t really get super far in just a day, and I even ended up with unusable hardware. BUT! we all learned something, and next time we know what NOT to do (or at least I DO KNOW what NOT to do!).&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://soledadpenades.com/?flattrss_redirect&amp;amp;id=6335&amp;amp;md5=40427d69faa3b9c2d1530732fd78e66d&quot; target=&quot;_blank&quot; title=&quot;Flattr&quot;&gt;&lt;img alt=&quot;flattr this!&quot; src=&quot;http://soledadpenades.com/wp-content/plugins/flattr/img/flattr-badge-large.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
- <pubDate>Tue, 19 Jan 2016 13:31:55 +0000</pubDate>
- <dc:creator>sole</dc:creator>
- </item>
- <item>
- <title>Daniel Stenberg: “Subject: Urgent Warningâ€</title>
- <guid isPermaLink="false">http://daniel.haxx.se/blog/?p=8544</guid>
- <link>http://daniel.haxx.se/blog/2016/01/19/subject-urgent-warning/</link>
- <description>&lt;p&gt;Back in December I got a desperate email from this person. A woman who said her Instagram had been hacked and since she found my contact info in the app she mailed me and asked for help. I of course replied and said that I have nothing to do with her being hacked but I also have nothing to do with Instagram other than that they use software I’ve written.&lt;/p&gt;
- &lt;p&gt;Today she writes back. Clearly not convinced I told the truth before, and now she strikes back with more “evidence†of my wrongdoings.&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;Dear Daniel,&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;I had emailed you a couple months ago about my “screen dumps†aka screenshots and asked for your help with restoring my Instagram account since it had been hacked, my photos changed, and your name was included in the coding. You claimed to have no involvement whatsoever in developing a third party app for Instagram and could not help me salvage my original Instagram photos, pre-hacked, despite Instagram serving as my Photography portfolio and my career is a Photographer.&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;Since you weren’t aware that your name was attached to Instagram related hacking code, I thought you might want to know, in case you weren’t already aware, that your name is also included in Spotify terms and conditions. I came across this information using my Spotify which has also been hacked into and would love your help hacking out of Spotify. Also, I have yet to figure out how to unhack the hackers from my Instagram so if you change your mind and want to restore my Instagram to its original form as well as help me secure my account from future privacy breaches, I’d be extremely grateful. As you know, changing my passwords did nothing to resolve the problem. Please keep in mind that Facebook owns Instagram and these are big companies that you likely don’t want to have a trail of evidence that you are a part of an Instagram and Spotify hacking ring. Also, Spotify is a major partner of Spotify so you are likely familiar with the coding for all of these illegally developed third party apps. I’d be grateful for your help fixing this error immediately.&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;Thank you,&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;[name redacted]&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;P.S. Please see attached screen dump for a screen shot of your contact info included in Spotify (or what more likely seems to be a hacked Spotify developed illegally by a third party).&lt;/em&gt;&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_7393.png&quot; rel=&quot;attachment wp-att-8545&quot;&gt;&lt;img alt=&quot;Spotify credits screenshot&quot; class=&quot;aligncenter size-medium wp-image-8545&quot; height=&quot;450&quot; src=&quot;http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_7393-253x450.png&quot; width=&quot;253&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;Here’s the Instagram screenshot she sent me in a previous email:&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_2156.jpg&quot; rel=&quot;attachment wp-att-8546&quot;&gt;&lt;img alt=&quot;Instagram credits screenshot&quot; class=&quot;aligncenter size-medium wp-image-8546&quot; height=&quot;450&quot; src=&quot;http://daniel.haxx.se/blog/wp-content/uploads/2016/01/IMG_2156-253x450.jpg&quot; width=&quot;253&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;I’ve tried to respond with calm and clear reasonable logic and technical details on why she’s seeing my name there. That clearly failed. What do I try next?&lt;/p&gt;</description>
- <pubDate>Tue, 19 Jan 2016 08:37:32 +0000</pubDate>
- <dc:creator>Daniel Stenberg</dc:creator>
- </item>
- <item>
- <title>Emily Dunham: How much knowledge do you need to give a conference talk?</title>
- <guid isPermaLink="true">http://edunham.net/2016/01/19/how_much_knowledge_do_you_need_to_give_a_conference_talk.html</guid>
- <link>http://edunham.net/2016/01/19/how_much_knowledge_do_you_need_to_give_a_conference_talk.html</link>
- <description>&lt;h3&gt;How much knowledge do you need to give a conference talk?&lt;/h3&gt;
- &lt;p&gt;I was recently asked an excellent question when I promoted the &lt;a class=&quot;reference external&quot; href=&quot;http://www.linuxfestnorthwest.org/2016/present&quot;&gt;LFNW CFP&lt;/a&gt; on
- IRC:&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;div&gt;As someone who has never done a talk, but wants to, what kind of knowledge
- do you need about a subject to give a talk on it?&lt;/div&gt;&lt;/blockquote&gt;
- &lt;p&gt;If you answer “yes†to any of the following questions, you know enough to
- propose a talk:&lt;/p&gt;
- &lt;ul class=&quot;simple&quot;&gt;
- &lt;li&gt;Do you have a &lt;strong&gt;hobby&lt;/strong&gt; that most tech people aren’t experts on? Talk
- about applying a lesson or skill from that hobby to tech! For instance, I
- turned a habit of reading about psychology into my &lt;a class=&quot;reference external&quot; href=&quot;http://talks.edunham.net/scale13x/#1&quot;&gt;Human Hacking&lt;/a&gt; talk.&lt;/li&gt;
- &lt;li&gt;Have you ever spent a bunch of hours forcing two tools to work with each
- other, because the documentation wasn’t very helpful and Googling didn’t get
- you very far, and built something useful? “How to build ___ with ___†makes
- a catchy talk title, if the &lt;strong&gt;thing you built&lt;/strong&gt; solves a common problem.&lt;/li&gt;
- &lt;li&gt;Have you ever had a mentor sit down with you and explain a tool or
- technique, and the new understanding improved the quality of your work or
- code? Passing along useful &lt;strong&gt;lessons from your mentors&lt;/strong&gt; is a valuable talk,
- because it allows others to benefit from the knowledge without taking as
- much of your mentor’s time.&lt;/li&gt;
- &lt;li&gt;Have you seen a dozen newbies ask the same question over the course of a few
- months? When your &lt;strong&gt;answer to a common question&lt;/strong&gt; starts to feel like a
- broken record, it’s time to compose it into a talk then link the newbies to
- your slides or recording!&lt;/li&gt;
- &lt;li&gt;Have you taken a really &lt;strong&gt;interesting class&lt;/strong&gt; lately? Can you distill part of it
- into a 1-hour lesson that would appeal to nerds who don’t have the time or
- resources to take the class themselves? (thanks &lt;a class=&quot;reference external&quot; href=&quot;http://lucywyman.me/&quot;&gt;lucyw&lt;/a&gt; for adding this to
- the list!)&lt;/li&gt;
- &lt;li&gt;Have you built a cool thing that over a dozen other people use? A &lt;strong&gt;tutorial
- talk&lt;/strong&gt; can not only expand your community, but its recording can augment your
- documentation and make the project more accessible for those who prefer to
- learn directly from humans!&lt;/li&gt;
- &lt;li&gt;Did you benefit from a really great introductory talk when you were learning
- a tool? Consider doing your own tutorial! Any conference with beginners in
- their target audience needs at least one Git lesson, an IRC talk, and some
- discussions of how to use basic Unix utilities. These &lt;strong&gt;introductory talks&lt;/strong&gt;
- are actually better when given by someone who learned the technology
- relatively recently, because newer users remember what it’s like not to know
- how to use it. Just remember to have a more expert user look over your slides
- before you present, in case you made an incorrect assumption about the tool’s
- more advanced functionality.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;I personally try to propose talks I want to hear, because the dealine of a
- CFP or conference is great motivation to prioritize a cool project over
- ordinary chores.&lt;/p&gt;</description>
- <pubDate>Tue, 19 Jan 2016 08:00:00 +0000</pubDate>
- </item>
- <item>
- <title>QMO: Aurora 45.0 Testday Results</title>
- <guid isPermaLink="false">https://quality.mozilla.org/?p=49441</guid>
- <link>https://quality.mozilla.org/2016/01/aurora-45-0-testday-results/</link>
- <description>&lt;p&gt;Howdy mozillians!&lt;/p&gt;
- &lt;p&gt;Last week – on &lt;em&gt;Friday, January 15th&lt;/em&gt; – we held &lt;a href=&quot;https://quality.mozilla.org/2016/01/firefox-45-0-aurora-testday-january-15th/&quot;&gt;Aurora 45.0 Testday&lt;/a&gt;; and, of course, it was another outstanding event!&lt;/p&gt;
- &lt;p&gt;&lt;strong&gt;Thank you&lt;/strong&gt; all – &lt;span class=&quot;author-a-oz90z4z89zz89za7qfz70zda5z87zxz85z i&quot;&gt;&lt;i&gt;Mahmoudi Dris, Iryna Thompson, Chandrakant Dhutadmal, Preethi Dhinesh, Moin Shaikh, Ilse Macías, Hossain Al Ikram, Rezaul Huque Nayeem, Tahsan Chowdhury Akash, Kazi Nuzhat Tasnem, Fahmida Noor, Tazin Ahmed, Md. Ehsanul Hassan, Mohammad Maruf Islam, Kazi Sakib Ahmad, Khalid Syfullah Zaman, Asiful Kabir, Tabassum Mehnaz, Hasibul Hasan, Saddam Hossain, Mohammad Kamran Hossain, Amlan Biswas, Fazle Rabbi, Mohammed Jawad Ibne Ishaque, Asif Mahmud Shuvo, Nazir Ahmed Sabbir, Md. Raihan Ali, Md. Almas Hossain, Sadik Khan, Md. Faysal Alam Riyad, Faisal Mahmud, Md. Oliullah Sizan, Asif Mahmud Rony, Forhad Hossain &lt;/i&gt;and&lt;i&gt; Tanvir Rahman &lt;/i&gt;&lt;/span&gt;– for the participation!&lt;/p&gt;
- &lt;p&gt;A big &lt;strong&gt;thank you&lt;/strong&gt; to all our active moderators too!&lt;/p&gt;
- &lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;font-family: 'Open Sans', sans-serif;&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;u&gt;Results:&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;font-family: 'Open Sans', sans-serif;&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;strong&gt;15&lt;/strong&gt; issues were verified: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;font-family: 'Open Sans', sans-serif;&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt; &lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1235821&quot;&gt;1235821&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1228518&quot;&gt;1228518&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1165637&quot;&gt;1165637&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1232647&quot;&gt;1232647&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1235379&quot;&gt;1235379&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=842356&quot;&gt;842356&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1222971&quot;&gt;1222971&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=915962&quot;&gt;915962&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1180761&quot;&gt;1180761&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1218455&quot;&gt;1218455&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1222747&quot;&gt;1222747&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1210752&quot;&gt;1210752&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1198450&quot;&gt;1198450&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1222820&quot;&gt;1222820&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1225514&quot;&gt;1225514&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;1&lt;/strong&gt; bug was triaged: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1230789&quot;&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;1230789&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;some failures were mentioned for &lt;i&gt;Search Refactoring &lt;/i&gt;feature in the etherpads (&lt;a href=&quot;https://public.etherpad-mozilla.org/p/testday-20160115&quot;&gt;link 1&lt;/a&gt; and &lt;a href=&quot;https://public.etherpad-mozilla.org/p/bangladesh.testday-15012016&quot;&gt;link 2&lt;/a&gt;); please feel free to add the requested details in the etherpads or, even better, join us on &lt;a href=&quot;http://widget01.mibbit.com/?server=irc.mozilla.org&amp;amp;channel=%23qa&quot; target=&quot;_blank&quot;&gt;#qa IRC channel&lt;/a&gt; and let’s figure them out&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;I &lt;strong&gt;strongly&lt;/strong&gt; advise everyone of you to reach out to us, the moderators, via &lt;a href=&quot;http://widget01.mibbit.com/?server=irc.mozilla.org&amp;amp;channel=%23qa&quot;&gt;#qa&lt;/a&gt; during the events when you encountered any kind of failures. Keep up the great work! \o/&lt;/p&gt;
- &lt;p&gt;And keep an eye on QMO for upcoming events! &lt;img alt=&quot;😉&quot; class=&quot;wp-smiley&quot; src=&quot;https://s.w.org/images/core/emoji/72x72/1f609.png&quot; style=&quot;height: 1em;&quot; /&gt;&lt;/p&gt;</description>
- <pubDate>Tue, 19 Jan 2016 07:51:57 +0000</pubDate>
- <dc:creator>Alexandra Lucinet</dc:creator>
- </item>
- <item>
- <title>Eitan Isaacson: It’s MLK Day and It’s Not Too Late to Do Something About It</title>
- <guid isPermaLink="false">http://blog.monotonous.org/?p=678</guid>
- <link>http://blog.monotonous.org/2016/01/18/its-mlk-day-and-its-not-too-late-to-do-something-about-it/</link>
- <description>&lt;p&gt;For the last three years I have had the opportunity to send out a reminder to Mozilla staff that Martin Luther King Jr. Day is coming up, and that U.S. employees get the day off. It has turned into my MLK Day eve ritual. I read his letters, listen to speeches, and then I compose a belabored paragraph about Dr. King with some choice quotes.&lt;/p&gt;
- &lt;p&gt;If you didn’t get a chance to celebrate Dr. King’s legacy and the movements he was a part of, you still have a chance:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;Watch &lt;a href=&quot;http://www.imdb.com/title/tt1020072/&quot; target=&quot;_blank&quot;&gt;Selma.&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;Watch &lt;a href=&quot;http://www.imdb.com/title/tt1592527/&quot; target=&quot;_blank&quot;&gt;The Black Power Mixtape&lt;/a&gt; (it’s on Netflix).&lt;/li&gt;
- &lt;li&gt;Read &lt;a href=&quot;http://www.africa.upenn.edu/Articles_Gen/Letter_Birmingham.html&quot; target=&quot;_blank&quot;&gt;A Letter from a Birmingham Jail&lt;/a&gt; (it’s really really good).&lt;/li&gt;
- &lt;li&gt;Listen to his speech &lt;a href=&quot;https://www.youtube.com/watch?v=3Qf6x9_MLD0&quot; target=&quot;_blank&quot;&gt;Beyond Vietnam&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Listen to his last speech &lt;a href=&quot;https://www.youtube.com/watch?v=IDl84vusXos&quot; target=&quot;_blank&quot;&gt;I Have Been To The Mountaintop&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;&lt;br /&gt; &lt;a href=&quot;http://feeds.wordpress.com/1.0/gocomments/blogdotmonotonousdotorg.wordpress.com/678/&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/blogdotmonotonousdotorg.wordpress.com/678/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;http://pixel.wp.com/b.gif?host=blog.monotonous.org&amp;amp;blog=34885741&amp;amp;post=678&amp;amp;subd=blogdotmonotonousdotorg&amp;amp;ref=&amp;amp;feed=1&quot; width=&quot;1&quot; /&gt;</description>
- <pubDate>Mon, 18 Jan 2016 23:35:19 +0000</pubDate>
- <dc:creator>Eitan</dc:creator>
- </item>
- <item>
- <title>Nick Cameron: Libmacro</title>
- <guid isPermaLink="false">http://www.ncameron.org/blog/rss/0e4d587c-380c-40ce-954a-7206f69bc1dd</guid>
- <link>http://www.ncameron.org/blog/libmacro/</link>
- <description>&lt;p&gt;As I outlined in an &lt;a href=&quot;http://ncameron.org/blog/procedural-macros-framework/&quot;&gt;earlier post&lt;/a&gt;, libmacro is a new crate designed to be used by procedural macro authors. It provides the basic API for procedural macros to interact with the compiler. I expect higher level functionality to be provided by library crates. In this post I'll go into a bit more detail about the API I think should be exposed here.&lt;/p&gt;
-
- &lt;p&gt;This is a lot of stuff. I've probably missed something. If you use syntax extensions today and do something with libsyntax that would not be possible with libmacro, please let me know!&lt;/p&gt;
-
- &lt;p&gt;I previously introduced &lt;code&gt;MacroContext&lt;/code&gt; as one of the gateways to libmacro. All procedural macros will have access to a &lt;code&gt;&amp;amp;mut MacroContext&lt;/code&gt;.&lt;/p&gt;
-
- &lt;h3&gt;Tokens&lt;/h3&gt;
-
- &lt;p&gt;I described the &lt;code&gt;tokens&lt;/code&gt; module in the last post, I won't repeat that here.&lt;/p&gt;
-
- &lt;p&gt;There are a few more things I thought of. I mentioned a &lt;code&gt;TokenStream&lt;/code&gt; which is a sequence of tokens. We should also have &lt;code&gt;TokenSlice&lt;/code&gt; which is a borrowed slice of tokens (the slice to &lt;code&gt;TokenStream&lt;/code&gt;'s &lt;code&gt;Vec&lt;/code&gt;). These should implement the standard methods for sequences, in particular they support iteration, so can be &lt;code&gt;map&lt;/code&gt;ed, etc.&lt;/p&gt;
-
- &lt;p&gt;In the earlier blog post, I talked about a token kind called &lt;code&gt;Delimited&lt;/code&gt; which contains a delimited sequence of tokens. I would like to rename that to &lt;code&gt;Sequence&lt;/code&gt; and add a &lt;code&gt;None&lt;/code&gt; variant to the &lt;code&gt;Delimiter&lt;/code&gt; enum. The &lt;code&gt;None&lt;/code&gt; option is so that we can have blocks of tokens without using delimiters. It will be used for noting unsafety and other properties of tokens. Furthermore, it is useful for macro expansion (replacing the interpolated AST tokens currently present). Although &lt;code&gt;None&lt;/code&gt; blocks do not affect scoping, they do affect precedence and parsing.&lt;/p&gt;
-
- &lt;p&gt;We should provide API for creating tokens. By default these have no hygiene information and come with a span which has no place in the source code, but shows the source of the token to be the procedural macro itself (see below for how this interacts with expansion of the current macro). I expect a &lt;code&gt;make_&lt;/code&gt; function for each kind of token. We should also have API for creating macros in a given scope (which do the same thing but with provided hygiene information). This could be considered an over-rich API, since the hygiene information could be set after construction. However, since hygiene is fiddly and annoying to get right, we should make it as easy as possible to work with.&lt;/p&gt;
-
- &lt;p&gt;There should also be a function for creating a token which is just a fresh name. This is useful for creating new identifiers. Although this can be done by interning a string and then creating a token around it, it is used frequently enough to deserve a helper function.&lt;/p&gt;
-
- &lt;h3&gt;Emitting errors and warnings&lt;/h3&gt;
-
- &lt;p&gt;Procedural macros should report errors, warnings, etc. via the &lt;code&gt;MacroContext&lt;/code&gt;. They should avoid panicking as much as possible since this will crash the compiler (once &lt;code&gt;catch_panic&lt;/code&gt; is available, we should use it to catch such panics and exit gracefully, however, they will certainly still meaning aborting compilation).&lt;/p&gt;
-
- &lt;p&gt;Libmacro will 're-export' &lt;code&gt;DiagnosticBuilder&lt;/code&gt; from &lt;a href=&quot;https://dxr.mozilla.org/rust/source/src/libsyntax/errors/mod.rs&quot;&gt;syntax::errors&lt;/a&gt;. I don't actually expect this to be a literal re-export. We will use libmacro's version of &lt;code&gt;Span&lt;/code&gt;, for example.&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;impl MacroContext {
- pub fn struct_error(&amp;amp;self, &amp;amp;str) -&amp;gt; DiagnosticBuilder;
- pub fn error(&amp;amp;self, Option&amp;lt;Span&amp;gt;, &amp;amp;str);
- }
-
- pub mod errors {
- pub struct DiagnosticBuilder { ... }
- impl DiagnosticBuilder { ... }
- pub enum ErrorLevel { ... }
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;There should be a macro &lt;code&gt;try_emit!&lt;/code&gt;, which reduces a &lt;code&gt;Result&amp;lt;T, ErrStruct&amp;gt;&lt;/code&gt; to a T or calls &lt;code&gt;emit()&lt;/code&gt; and then calls &lt;code&gt;unreachable!()&lt;/code&gt; (if the error is not fatal, then it should be upgraded to a fatal error).&lt;/p&gt;
-
- &lt;h3&gt;Tokenising and quasi-quoting&lt;/h3&gt;
-
- &lt;p&gt;The simplest function here is &lt;code&gt;tokenize&lt;/code&gt; which takes a string (&lt;code&gt;&amp;amp;str&lt;/code&gt;) and returns a &lt;code&gt;Result&amp;lt;TokenStream, ErrStruct&amp;gt;&lt;/code&gt;. The string is treated like source text. The success option is the tokenised version of the string. I expect this function must take a &lt;code&gt;MacroContext&lt;/code&gt; argument.&lt;/p&gt;
-
- &lt;p&gt;We will offer a quasi-quoting macro. This will return a &lt;code&gt;TokenStream&lt;/code&gt; (in contrast to today's quasi-quoting which returns AST nodes), to be precise a &lt;code&gt;Result&amp;lt;TokenStream, ErrStruct&amp;gt;&lt;/code&gt;. The string which is quoted may include metavariables (&lt;code&gt;$x&lt;/code&gt;), and these are filled in with variables from the environment. The type of the variables should be either a &lt;code&gt;TokenStream&lt;/code&gt;, a &lt;code&gt;TokenTree&lt;/code&gt;, or a &lt;code&gt;Result&amp;lt;TokenStream, ErrStruct&amp;gt;&lt;/code&gt; (in this last case, if the variable is an error, then it is just returned by the macro). For example,&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;fn foo(cx: &amp;amp;mut MacroContext, tokens: TokenStream) -&amp;gt; TokenStream {
- quote!(cx, fn foo() { $tokens }).unwrap()
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;The &lt;code&gt;quote!&lt;/code&gt; macro can also handle multiple tokens when the variable corresponding with the metavariable has type &lt;code&gt;[TokenStream]&lt;/code&gt; (or is dereferencable to it). In this case, the same syntax as used in macros-by-example can be used. For example, if &lt;code&gt;x: Vec&amp;lt;TokenStream&amp;gt;&lt;/code&gt; then &lt;code&gt;quote!(cx, ($x),*)&lt;/code&gt; will produce a &lt;code&gt;TokenStream&lt;/code&gt; of a comma-separated list of tokens from the elements of &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;Since the &lt;code&gt;tokenize&lt;/code&gt; function is a degenerate case of quasi-quoting, an alternative would be to always use &lt;code&gt;quote!&lt;/code&gt; and remove &lt;code&gt;tokenize&lt;/code&gt;. I believe there is utility in the simple function, and it must be used internally in any case.&lt;/p&gt;
-
- &lt;p&gt;These functions and macros should create tokens with spans and hygiene information set as described above for making new tokens. We might also offer versions which takes a scope and uses that as the context for tokenising.&lt;/p&gt;
-
- &lt;h3&gt;Parsing helper functions&lt;/h3&gt;
-
- &lt;p&gt;There are some common patterns for tokens to follow in macros. In particular those used as arguments for attribute-like macros. We will offer some functions which attempt to parse tokens into these patterns. I expect there will be more of these in time; to start with:&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod parsing {
- // Expects `(foo = &quot;bar&quot;),*`
- pub fn parse_keyed_values(&amp;amp;TokenSlice, &amp;amp;mut MacroContext) -&amp;gt; Result&amp;lt;Vec&amp;lt;(InternedString, String)&amp;gt;, ErrStruct&amp;gt;;
- // Expects `&quot;bar&quot;`
- pub fn parse_string(&amp;amp;TokenSlice, &amp;amp;mut MacroContext) -&amp;gt; Result&amp;lt;String, ErrStruct&amp;gt;;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;To be honest, given the token design in the last post, I think &lt;code&gt;parse_string&lt;/code&gt; is unnecessary, but I wanted to give more than one example of this kind of function. If &lt;code&gt;parse_keyed_values&lt;/code&gt; is the only one we end up with, then that is fine.&lt;/p&gt;
-
- &lt;h3&gt;Pattern matching&lt;/h3&gt;
-
- &lt;p&gt;The goal with the pattern matching API is to allow procedural macros to operate on tokens in the same way as macros-by-example. The pattern language is thus the same as that for macros-by-example.&lt;/p&gt;
-
- &lt;p&gt;There is a single macro, which I propose calling &lt;code&gt;matches&lt;/code&gt;. Its first argument is the name of a &lt;code&gt;MacroContext&lt;/code&gt;. Its second argument is the input, which must be a &lt;code&gt;TokenSlice&lt;/code&gt; (or dereferencable to one). The third argument is a pattern definition. The macro produces a &lt;code&gt;Result&amp;lt;T, ErrStruct&amp;gt;&lt;/code&gt; where &lt;code&gt;T&lt;/code&gt; is the type produced by the pattern arms. If the pattern has multiple arms, then each arm must have the same type. An error is produced if none of the arms in the pattern are matched.&lt;/p&gt;
-
- &lt;p&gt;The pattern language follows the language for defining macros-by-example (but is slightly stricter). There are two forms, a single pattern form and a multiple pattern form. If the first character is a &lt;code&gt;{&lt;/code&gt; then the pattern is treated as a multiple pattern form, if it starts with &lt;code&gt;(&lt;/code&gt; then as a single pattern form, otherwise an error (causes a panic with a &lt;code&gt;Bug&lt;/code&gt; error, as opposed to returning an &lt;code&gt;Err&lt;/code&gt;).&lt;/p&gt;
-
- &lt;p&gt;The single pattern form is &lt;code&gt;(pattern) =&amp;gt; { code }&lt;/code&gt;. The multiple pattern form is &lt;code&gt;{(pattern) =&amp;gt; { code } (pattern) =&amp;gt; { code } ... (pattern) =&amp;gt; { code }}&lt;/code&gt;. &lt;code&gt;code&lt;/code&gt; is any old Rust code which is executed when the corresponding pattern is matched. The pattern follows from macros-by-example - it is a series of characters treated as literals, meta-variables indicated with &lt;code&gt;$&lt;/code&gt;, and the syntax for matching multiple variables. Any meta-variables are available as variables in the righthand side, e.g., &lt;code&gt;$x&lt;/code&gt; becomes available as &lt;code&gt;x&lt;/code&gt;. These variables have type &lt;code&gt;TokenStream&lt;/code&gt; if they appear singly or &lt;code&gt;Vec&amp;lt;TokenStream&amp;gt;&lt;/code&gt; if they appear multiply (or &lt;code&gt;Vec&amp;lt;Vec&amp;lt;TokenStream&amp;gt;&amp;gt;&lt;/code&gt; and so forth).&lt;/p&gt;
-
- &lt;p&gt;Examples:&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;matches!(cx, input, (foo($x:expr) bar) =&amp;gt; {quote(cx, foo_bar($x).unwrap()}).unwrap()
-
- matches!(cx, input, {
- () =&amp;gt; {
- cx.err(&quot;No input?&quot;);
- }
- (foo($($x:ident),+ bar) =&amp;gt; {
- println!(&quot;found {} idents&quot;, x.len());
- quote!(($x);*).unwrap()
- }
- }
- })
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;Note that since we match AST items here, our backwards compatibility story is a bit complicated (though hopefully not much more so than with current macros).&lt;/p&gt;
-
- &lt;h3&gt;Hygiene&lt;/h3&gt;
-
- &lt;p&gt;The intention of the design is that the actual hygiene algorithm applied is irrelevant. Procedural macros should be able to use the same API if the hygiene algorithm changes (of course the result of applying the API might change). To this end, all hygiene objects are opaque and cannot be directly manipulated by macros.&lt;/p&gt;
-
- &lt;p&gt;I propose one module (&lt;code&gt;hygiene&lt;/code&gt;) and two types: &lt;code&gt;Context&lt;/code&gt; and &lt;code&gt;Scope&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;A &lt;code&gt;Context&lt;/code&gt; is attached to each token and contains all hygiene information about that token. If two tokens have the same &lt;code&gt;Context&lt;/code&gt;, then they may be compared syntactically. The reverse is not true - two tokens can have different &lt;code&gt;Context&lt;/code&gt;s and still be equal. &lt;code&gt;Context&lt;/code&gt;s can only be created by applying the hygiene algorithm and cannot be manipulated, only moved and stored.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;MacroContext&lt;/code&gt; has a method &lt;code&gt;fresh_hygiene_context&lt;/code&gt; for creating a new, fresh &lt;code&gt;Context&lt;/code&gt; (i.e., a &lt;code&gt;Context&lt;/code&gt; not shared with any other tokens).&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;MacroContext&lt;/code&gt; has a method &lt;code&gt;expansion_hygiene_context&lt;/code&gt; for getting the &lt;code&gt;Context&lt;/code&gt; where the macro is defined. This is equivalent to &lt;code&gt;.expansion_scope().direct_context()&lt;/code&gt;, but might be more efficient (and I expect it to be used a lot).&lt;/p&gt;
-
- &lt;p&gt;A &lt;code&gt;Scope&lt;/code&gt; provides information about a position within an AST at a certain point during macro expansion. For example,&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;fn foo() {
- a
- {
- b
- c
- }
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;&lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; will have different &lt;code&gt;Scope&lt;/code&gt;s. &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt; will have the same &lt;code&gt;Scope&lt;/code&gt;s, even if &lt;code&gt;b&lt;/code&gt; was written in this position and &lt;code&gt;c&lt;/code&gt; is due to macro expansion. However, a &lt;code&gt;Scope&lt;/code&gt; may contain more information than just the syntactic scopes, for example, it may contain information about pending scopes yet to be applied by the hygiene algorithm (i.e., information about &lt;code&gt;let&lt;/code&gt; expressions which are in scope).&lt;/p&gt;
-
- &lt;p&gt;Note that a &lt;code&gt;Scope&lt;/code&gt; means a scope in the macro hygiene sense, not the commonly used sense of a scope declared with &lt;code&gt;{}&lt;/code&gt;. In particular, each &lt;code&gt;let&lt;/code&gt; statement starts a new scope and the items and statements in a function body are in different scopes.&lt;/p&gt;
-
- &lt;p&gt;The functions &lt;code&gt;lookup_item_scope&lt;/code&gt; and &lt;code&gt;lookup_statement_scope&lt;/code&gt; take a &lt;code&gt;MacroContext&lt;/code&gt; and a path, represented as a &lt;code&gt;TokenSlice&lt;/code&gt;, and return the &lt;code&gt;Scope&lt;/code&gt; which that item defines or an error if the path does not refer to an item, or the item does not define a scope of the right kind.&lt;/p&gt;
-
- &lt;p&gt;The function &lt;code&gt;lookup_scope_for&lt;/code&gt; is similar, but returns the &lt;code&gt;Scope&lt;/code&gt; in which an item is declared.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;MacroContext&lt;/code&gt; has a method &lt;code&gt;expansion_scope&lt;/code&gt; for getting the scope in which the current macro is being expanded.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;Scope&lt;/code&gt; has a method &lt;code&gt;direct_context&lt;/code&gt; which returns a &lt;code&gt;Context&lt;/code&gt; for items declared directly (c.f., via macro expansion) in that &lt;code&gt;Scope&lt;/code&gt;.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;Scope&lt;/code&gt; has a method &lt;code&gt;nested&lt;/code&gt; which creates a fresh &lt;code&gt;Scope&lt;/code&gt; nested within the receiver scope.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;Scope&lt;/code&gt; has a static method &lt;code&gt;empty&lt;/code&gt; for creating an empty scope, that is one with no scope information at all (note that this is different from a top-level scope).&lt;/p&gt;
-
- &lt;p&gt;I expect the exact API around &lt;code&gt;Scope&lt;/code&gt;s and &lt;code&gt;Context&lt;/code&gt;s will need some work. &lt;code&gt;Scope&lt;/code&gt; seems halfway between an intuitive, algorithm-neutral abstraction, and the scopes from the sets of scopes hygiene algorithm. I would prefer a &lt;code&gt;Scope&lt;/code&gt; should be more abstract, on the other hand, macro authors may want fine-grained control over hygiene application.&lt;/p&gt;
-
- &lt;h4&gt;Manipulating hygiene information on tokens,&lt;/h4&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod hygiene {
- pub fn add(cx: &amp;amp;mut MacroContext, t: &amp;amp;Token, scope: &amp;amp;Scope) -&amp;gt; Token;
- // Maybe unnecessary if we have direct access to Tokens.
- pub fn set(t: &amp;amp;Token, cx: &amp;amp;Context) -&amp;gt; Token;
- // Maybe unnecessary - can use set with cx.expansion_hygiene_context().
- // Also, bad name.
- pub fn current(cx: &amp;amp;MacroContext, t: &amp;amp;Token) -&amp;gt; Token;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;&lt;code&gt;add&lt;/code&gt; adds &lt;code&gt;scope&lt;/code&gt; to any context already on &lt;code&gt;t&lt;/code&gt; (&lt;code&gt;Context&lt;/code&gt; should have a similar method). Note that the implementation is a bit complex - the nature of the &lt;code&gt;Scope&lt;/code&gt; might mean we replace the old context completely, or add to it.&lt;/p&gt;
-
- &lt;h4&gt;Applying hygiene when expanding the current macro&lt;/h4&gt;
-
- &lt;p&gt;By default, the current macro will be expanded in the standard way, having hygiene applied as expected. Mechanically, hygiene information is added to tokens when the macro is expanded. Assuming the sets of scopes algorithm, scopes (for example, for the macro's definition, and for the introduction) are added to any scopes already present on the token. A token with no hygiene information will thus behave like a token in a macro-by-example macro. Hygiene due to nested scopes created by the macro do not need to be taken into account by the macro author, this is handled at expansion time.&lt;/p&gt;
-
- &lt;p&gt;Procedural macro authors may want to customise hygiene application (it is common in Racket), for example, to introduce items that can be referred to by code in the call-site scope.&lt;/p&gt;
-
- &lt;p&gt;We must provide an option to expand the current macro without applying hygiene; the macro author must then handle hygiene. For this to work, the macro must be able to access information about the scope in which it is applied (see &lt;code&gt;MacroContext::expansion_scope&lt;/code&gt;, above) and to supply a &lt;code&gt;Scope&lt;/code&gt; indicating scopes that should be added to tokens following the macro expansion.&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod hygiene {
- pub enum ExpansionMode {
- Automatic,
- Manual(Scope),
- }
- }
-
- impl MacroContext {
- pub fn set_hygienic_expansion(hygiene::ExpansionMode);
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;We may wish to offer other modes for expansion which allow for tweaking hygiene application without requiring full manual application. One possible mode is where the author provides a &lt;code&gt;Scope&lt;/code&gt; for the macro definition (rather than using the scope where the macro is actually defined), but hygiene is otherwise applied automatically. We might wish to give the author the option of applying scopes due to the macro definition, but not the introduction scopes.&lt;/p&gt;
-
- &lt;p&gt;On a related note, might we want to affect how spans are applied when the current macro is expanded? I can't think of a use case right now, but it seems like something that might be wanted.&lt;/p&gt;
-
- &lt;p&gt;Blocks of tokens (that is a &lt;code&gt;Sequence&lt;/code&gt; token) may be marked (not sure how, exactly, perhaps using a distinguished context) such that it is expanded without any hygiene being applied or spans changed. There should be a function for creating such a &lt;code&gt;Sequence&lt;/code&gt; from a &lt;code&gt;TokenSlice&lt;/code&gt; in the &lt;code&gt;tokens&lt;/code&gt; module. The primary motivation for this is to handle the tokens representing the body on which an annotation-like macro is present. For a 'decorator' macro, these tokens will be untouched (passed through by the macro), and since they are not touched by the macro, they should appear untouched by it (in terms of hygiene and spans).&lt;/p&gt;
-
- &lt;h3&gt;Applying macros&lt;/h3&gt;
-
- &lt;p&gt;We provide functionality to expand a provided macro or to lookup and expand a macro.&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod apply {
- pub fn expand_macro(cx: &amp;amp;mut MacroContext,
- expansion_scope: Scope,
- macro: &amp;amp;TokenSlice,
- macro_scope: Scope,
- input: &amp;amp;TokenSlice)
- -&amp;gt; Result&amp;lt;(TokenStream, Scope), ErrStruct&amp;gt;;
- pub fn lookup_and_expand_macro(cx: &amp;amp;mut MacroContext,
- expansion_scope: Scope,
- macro: &amp;amp;TokenSlice,
- input: &amp;amp;TokenSlice)
- -&amp;gt; Result&amp;lt;(TokenStream, Scope), ErrStruct&amp;gt;;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;These functions apply macro hygiene in the usual way, with &lt;code&gt;expansion_scope&lt;/code&gt; dictating the scope into which the macro is expanded. Other spans and hygiene information is taken from the tokens. &lt;code&gt;expand_macro&lt;/code&gt; takes pending scopes from &lt;code&gt;macro_scope&lt;/code&gt;, &lt;code&gt;lookup_and_expand_macro&lt;/code&gt; uses the proper pending scopes. In order to apply the hygiene algorithm, the result of the macro must be parsable. The returned scope will contain pending scopes that can be applied by the macro to subsequent tokens.&lt;/p&gt;
-
- &lt;p&gt;We could provide versions that don't take an &lt;code&gt;expansion_scope&lt;/code&gt; and use &lt;code&gt;cx.expansion_scope()&lt;/code&gt;. Probably unnecessary.&lt;/p&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod apply {
- pub fn expand_macro_unhygienic(cx: &amp;amp;mut MacroContext,
- macro: &amp;amp;TokenSlice,
- input: &amp;amp;TokenSlice)
- -&amp;gt; Result&amp;lt;TokenStream, ErrStruct&amp;gt;;
- pub fn lookup_and_expand_macro_unhygienic(cx: &amp;amp;mut MacroContext,
- macro: &amp;amp;TokenSlice,
- input: &amp;amp;TokenSlice)
- -&amp;gt; Result&amp;lt;TokenStream, ErrStruct&amp;gt;;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;The &lt;code&gt;_unhygienic&lt;/code&gt; variants expand a macro as in the first functions, but do not apply the hygiene algorithm or change any hygiene information. Any hygiene information on tokens is preserved. I'm not sure if &lt;code&gt;_unhygienic&lt;/code&gt; are the right names - using these is not necessarily unhygienic, just that we are automatically applying the hygiene algorithm.&lt;/p&gt;
-
- &lt;p&gt;Note that all these functions are doing an eager expansion of macros, or in Scheme terms they are &lt;code&gt;local-expand&lt;/code&gt; functions. &lt;/p&gt;
-
- &lt;h3&gt;Looking up items&lt;/h3&gt;
-
- &lt;p&gt;The function &lt;code&gt;lookup_item&lt;/code&gt; takes a &lt;code&gt;MacroContext&lt;/code&gt; and a path represented as a &lt;code&gt;TokenSlice&lt;/code&gt; and returns a &lt;code&gt;TokenStream&lt;/code&gt; for the item referred to by the path, or an error if name resolution failed. I'm not sure where this function should live.&lt;/p&gt;
-
- &lt;h3&gt;Interned strings&lt;/h3&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod strings {
- pub struct InternedString;
-
- impl InternedString {
- pub fn get(&amp;amp;self) -&amp;gt; String;
- }
-
- pub fn intern(cx: &amp;amp;mut MacroContext, s: &amp;amp;str) -&amp;gt; Result&amp;lt;InternedString, ErrStruct&amp;gt;;
- pub fn find(cx: &amp;amp;mut MacroContext, s: &amp;amp;str) -&amp;gt; Result&amp;lt;InternedString, ErrStruct&amp;gt;;
- pub fn find_or_intern(cx: &amp;amp;mut MacroContext, s: &amp;amp;str) -&amp;gt; Result&amp;lt;InternedString, ErrStruct&amp;gt;;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;&lt;code&gt;intern&lt;/code&gt; interns a string and returns a fresh &lt;code&gt;InternedString&lt;/code&gt;. &lt;code&gt;find&lt;/code&gt; tries to find &lt;em&gt;an&lt;/em&gt; existing &lt;code&gt;InternedString&lt;/code&gt;.&lt;/p&gt;
-
- &lt;h3&gt;Spans&lt;/h3&gt;
-
- &lt;p&gt;A span gives information about where in the source code a token is defined. It also gives information about where the token came from (how it was generated, if it was generated code).&lt;/p&gt;
-
- &lt;p&gt;There should be a &lt;code&gt;spans&lt;/code&gt; module in libmacro, which will include a &lt;code&gt;Span&lt;/code&gt; type which can be easily inter-converted with the &lt;code&gt;Span&lt;/code&gt; defined in libsyntax. Libsyntax spans currently include information about stability, this will not be present in libmacro spans.&lt;/p&gt;
-
- &lt;p&gt;If the programmer does nothing special with spans, then they will be 'correct' by default. There are two important cases: tokens passed to the macro and tokens made fresh by the macro. The former will have the source span indicating where they were written and will include their history. The latter will have no source span and indicate they were created by the current macro. All tokens will have the history relating to expansion of the current macro added when the macro is expanded. At macro expansion, tokens with no source span will be given the macro use-site as their source.&lt;/p&gt;
-
- &lt;p&gt;&lt;code&gt;Span&lt;/code&gt;s can be freely copied between tokens.&lt;/p&gt;
-
- &lt;p&gt;It will probably useful to make it easy to manipulate spans. For example, rather than point at the macro's defining function, point at a helper function where the token is made. Or to set the origin to the current macro when the token was produced by another which should an implementation detail. I'm not sure what such an interface should look like (and is probably not necessary in an initial library).&lt;/p&gt;
-
- &lt;h3&gt;Feature gates&lt;/h3&gt;
-
- &lt;pre&gt;&lt;code&gt;pub mod features {
- pub enum FeatureStatus {
- // The feature gate is allowed.
- Allowed,
- // The feature gate has not been enabled.
- Disallowed,
- // Use of the feature is forbidden by the compiler.
- Forbidden,
- }
-
- pub fn query_feature(cx: &amp;amp;MacroContext, feature: Token) -&amp;gt; Result&amp;lt;FeatureStatus, ErrStruct&amp;gt;;
- pub fn query_feature_by_str(cx: &amp;amp;MacroContext, feature: &amp;amp;str) -&amp;gt; Result&amp;lt;FeatureStatus, ErrStruct&amp;gt;;
- pub fn query_feature_unused(cx: &amp;amp;MacroContext, feature: Token) -&amp;gt; Result&amp;lt;FeatureStatus, ErrStruct&amp;gt;;
- pub fn query_feature_by_str_unused(cx: &amp;amp;MacroContext, feature: &amp;amp;str) -&amp;gt; Result&amp;lt;FeatureStatus, ErrStruct&amp;gt;;
-
- pub fn used_feature_gate(cx: &amp;amp;MacroContext, feature: Token) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
- pub fn used_feature_by_str(cx: &amp;amp;MacroContext, feature: &amp;amp;str) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
-
- pub fn allow_feature_gate(cx: &amp;amp;MacroContext, feature: Token) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
- pub fn allow_feature_by_str(cx: &amp;amp;MacroContext, feature: &amp;amp;str) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
- pub fn disallow_feature_gate(cx: &amp;amp;MacroContext, feature: Token) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
- pub fn disallow_feature_by_str(cx: &amp;amp;MacroContext, feature: &amp;amp;str) -&amp;gt; Result&amp;lt;(), ErrStruct&amp;gt;;
- }
- &lt;/code&gt;&lt;/pre&gt;
-
- &lt;p&gt;The &lt;code&gt;query_*&lt;/code&gt; functions query if a feature gate has been set. They return an error if the feature gate does not exist. The &lt;code&gt;_unused&lt;/code&gt; variants do not mark the feature gate as used. The &lt;code&gt;used_&lt;/code&gt; functions mark a feature gate as used, or return an error if it does not exist.&lt;/p&gt;
-
- &lt;p&gt;The &lt;code&gt;allow_&lt;/code&gt; and &lt;code&gt;disallow_&lt;/code&gt; functions set a feature gate as allowed or disallowed for the current crate. These functions will only affect feature gates which take affect after parsing and expansion are complete. They do not affect feature gates which are checked during parsing or expansion.&lt;/p&gt;
-
- &lt;p&gt;Question: do we need the &lt;code&gt;used_&lt;/code&gt; functions? Could just call &lt;code&gt;query_&lt;/code&gt; and ignore the result.&lt;/p&gt;
-
- &lt;h3&gt;Attributes&lt;/h3&gt;
-
- &lt;p&gt;We need some mechanism for setting attributes as used. I don't actually know how the unused attribute checking in the compiler works, so I can't spec this area. But, I expect &lt;code&gt;MacroContext&lt;/code&gt; to make available some interface for reading attributes on a macro use and marking them as used.&lt;/p&gt;</description>
- <pubDate>Mon, 18 Jan 2016 21:40:42 +0000</pubDate>
- <dc:creator>Nick Cameron</dc:creator>
- </item>
- <item>
- <title>Seif Lotfy: Skizze progress and REPL</title>
- <guid isPermaLink="false">http://geekyogre.com/rss/63eb682d-66b4-447d-8fb6-f4ed448019df</guid>
- <link>http://geekyogre.com/skizze-progress-and-repl/</link>
- <description>&lt;p&gt;&lt;img align=&quot;center&quot; height=&quot;190&quot; src=&quot;http://i.imgur.com/9z47NdA.png&quot; width=&quot;600&quot; /&gt; &lt;br /&gt;
- &lt;br /&gt; &lt;br /&gt;
- Over the last 3 weeks, based on feedback we proceeded fledging out the concepts and the code behind &lt;a href=&quot;https://github.com/skizzehq/skizze&quot;&gt;Skizze&lt;/a&gt;. &lt;br /&gt;
- &lt;a href=&quot;https://medium.com/@njpatel/&quot;&gt;Neil Patel&lt;/a&gt; suggested the following:&lt;/p&gt;
-
- &lt;hr /&gt;
-
- &lt;p&gt;&lt;em&gt;So I've been thinking about the server API. I think we want to choose one thing and do it as well as possible, instead of having six ways to talk to the server. I think that helps to keep things sane and simple overall.&lt;/em&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;em&gt;Thinking about usage, I can only really imagine Skizze in an environment like &lt;a href=&quot;https://xamarin.com/insights&quot;&gt;ours&lt;/a&gt;, which is high-throughput. I think that is it's 'home' and we should be optimising for that all day long.&lt;/em&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;em&gt;Taking that into account, I believe we have two options:&lt;/em&gt;&lt;/p&gt;
-
- &lt;ol&gt;
- &lt;li&gt;&lt;p&gt;&lt;em&gt;We go the gRPC route, provide .proto files and let people use the existing gRPC tooling to build support for their favourite language. That means we can happily give Ruby/Node/C#/etc devs a real way to get started up with Skizze almost immediately, piggy-backing on the gRPC docs etc.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
- &lt;li&gt;&lt;p&gt;&lt;em&gt;We absorb the Redis Protocol. It does everything we need, is very lean, and we can (mostly) easily adapt it for what we need to do. The downside is that to get support from other libs, there will have to be actual libraries for every language. This could slow adoption, or it might be easy enough if people can reuse existing REDIS code. It's hard to tell how that would end up.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
- &lt;/ol&gt;
-
- &lt;p&gt;&lt;em&gt;gRPC is interesting because it's built already for distributed systems, across bad networks, and obviously is bi-directional etc. Without us having to spend time on the protocol, gRPC let's us easily add features that require streaming. Like, imagine a client being able to listen for changes in count/size and be notified instantly. That's something that gRPC is built for right now.&lt;/em&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;em&gt;I think gRPC is a bit verbose, but I think it'll pay off for ease of third-party lib support and as things grow.&lt;/em&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;em&gt;The CLI could easily be built to work with gRPC, including adding support for streaming stuff etc. Which could be pretty exciting.&lt;/em&gt;&lt;/p&gt;
-
- &lt;hr /&gt;
-
- &lt;p&gt;That being said, we gave Skizze &lt;a href=&quot;https://github.com/skizzehq/&quot;&gt;a new home&lt;/a&gt;, where based on feedback we developed .proto files and started rewriting big chunks of the code.&lt;/p&gt;
-
- &lt;p&gt;We added a new wrapper called &quot;domain&quot; which represents a stream. It wraps around Count-Min-Log, Bloom Filter, Top-K and HyperLogLog++, so when feeding it values it feeds all the sketches. Later we intend to allow attaching and detaching sketches from &quot;domains&quot; (We need a better name).&lt;/p&gt;
-
- &lt;p&gt;We also implemented a gRPC API which should allow easy wrapper creation in other languages.&lt;/p&gt;
-
- &lt;p&gt;Special thanks go to &lt;a href=&quot;https://twitter.com/martinpintob&quot;&gt;Martin Pinto&lt;/a&gt; for helping out with unit tests and &lt;a href=&quot;http://dopeness.org&quot;&gt;Soren Macbeth&lt;/a&gt; for thorough feedback and ideas about the &quot;domain&quot; concept. &lt;br /&gt;
- Take a look at our initial REPL work there:&lt;/p&gt;
-
- &lt;p&gt;&lt;a href=&quot;http://geekyogre.com/content/images/2016/01/MBCY64aaKL.gif&quot;&gt;&lt;img alt=&quot;Link to this page&quot; border=&quot;0&quot; src=&quot;http://geekyogre.com/content/images/2016/01/skizze-1.png&quot; /&gt;&lt;/a&gt; &lt;br /&gt;
- &lt;a href=&quot;http://geekyogre.com/content/images/2016/01/MBCY64aaKL.gif&quot;&gt;click for GIF&lt;/a&gt;&lt;/p&gt;</description>
- <pubDate>Mon, 18 Jan 2016 17:41:43 +0000</pubDate>
- <dc:creator>Seif Lotfy</dc:creator>
- </item>
- <item>
- <title>Doug Belshaw: What a post-Persona landscape means for Open Badges</title>
- <guid isPermaLink="false">http://dougbelshaw.com/blog/?p=39986</guid>
- <link>http://dougbelshaw.com/blog/2016/01/18/open-badges-persona/</link>
- <description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; I don’t work for Mozilla any more, so (like &lt;a href=&quot;https://www.youtube.com/watch?v=YQHsXMglC9A&quot;&gt;Adele&lt;/a&gt;) these are my thoughts ‘from the outside’…&lt;/em&gt;&lt;/p&gt;
- &lt;hr /&gt;
- &lt;h3&gt;Introduction&lt;/h3&gt;
- &lt;p&gt;&lt;a href=&quot;http://openbadges.org&quot;&gt;Open Badges&lt;/a&gt; is no longer a &lt;a href=&quot;http://mozilla.org&quot;&gt;Mozilla&lt;/a&gt; project. In fact, it hasn’t been for a while — the &lt;a href=&quot;http://badgealliance.org&quot;&gt;Badge Alliance&lt;/a&gt; was set up a couple of years ago to promote the specification on a both a technical and community basis. As I stated in a recent post, this is a &lt;strong&gt;good&lt;/strong&gt; thing and means that &lt;a href=&quot;http://dougbelshaw.com/blog/2015/11/08/bright-future-badges/&quot;&gt;the future is bright for Open Badges&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;However, Mozilla &lt;em&gt;is&lt;/em&gt; still involved with the Open Badges project: Mark Surman, Executive Director of the Mozilla Foundation, sits on the board of the Badge Alliance. Mozilla also pays for contractors to work on the &lt;a href=&quot;http://backpack.openbadges.org&quot;&gt;Open Badges backpack&lt;/a&gt; and there were badges earned at the &lt;a href=&quot;http://mozillafestival.org&quot;&gt;Mozilla Festival&lt;/a&gt; a few months ago.&lt;/p&gt;
- &lt;p&gt;Although it may seem strange for those used to corporates interested purely in profit, Mozilla creates what the open web needs at any given time. Like any organisation, sometimes it gets these wrong, either because the concept was flawed, or because the execution was poor. Other times, I’d argue, Mozilla doesn’t give ideas and concepts enough time to gain traction.&lt;/p&gt;
- &lt;h3&gt;The end of Persona at Mozilla&lt;/h3&gt;
- &lt;p&gt;Open Badges, at its very essence, is a technical specification. It allows credentials with metadata hard-coded into them to be issued, exchanged, and displayed. This is done in a secure, standardised manner.&lt;/p&gt;
- &lt;p&gt;&lt;img alt=&quot;OBI diagram&quot; class=&quot;alignnone wp-image-39987 size-full&quot; src=&quot;http://i1.wp.com/dougbelshaw.com/blog/wp-content/uploads/2016/01/obi-diagram.png?w=100%25&quot; /&gt;&lt;/p&gt;
- &lt;p&gt;For users to be able to access their ‘backpack’ (i.e. the place they store badges) they needed a secure login system.Back in 2011 at the start of the Open Badges project it made sense to make use of Mozilla’s nascent &lt;a href=&quot;https://www.mozilla.org/en-US/persona/&quot;&gt;Persona&lt;/a&gt; project. This aimed to provide a way for users to easily sign into sites around the web without using their Facebook/Google logins. These ‘social’ sign-in methods mean that users are tracked around the web — something that Mozilla was obviously against.&lt;/p&gt;
- &lt;p&gt;By 2014, Persona wasn’t seen to be having the kind of ‘growth trajectory’ that Mozilla wanted. The project was transferred to &lt;a href=&quot;http://identity.mozilla.com/post/78873831485/transitioning-persona-to-community-ownership&quot;&gt;community ownership&lt;/a&gt; and most of the team left Mozilla in 2015. It was &lt;a href=&quot;https://groups.google.com/forum/#!msg/mozilla.dev.identity/mibOQrD6K0c/kt0NdMWbEQAJ&quot;&gt;announced&lt;/a&gt; that Persona would be shutting down as a Mozilla service in November 2016. While Persona will exist as an open source project, it won’t be hosted by Mozilla.&lt;/p&gt;
- &lt;h3&gt;What this means for Open Badges&lt;/h3&gt;
- &lt;p&gt;Although I’m not aware of an official announcement from the Badge Alliance, I think it’s worth making three points here.&lt;/p&gt;
- &lt;h5&gt;1. You can still use Persona&lt;/h5&gt;
- &lt;p&gt;If you’re a developer, you can still use Persona. It’s open source. It works.&lt;/p&gt;
- &lt;h5&gt;2. Persona is not central to the Open Badges Infrastructure&lt;/h5&gt;
- &lt;p&gt;The Open Badges backpack is &lt;em&gt;one&lt;/em&gt; place where users can store their badges. There are others, including the &lt;a href=&quot;https://openbadgepassport.com/&quot;&gt;Open Badge Passport&lt;/a&gt; and &lt;a href=&quot;https://www.openbadgeacademy.com/&quot;&gt;Open Badge Academy&lt;/a&gt;. MacArthur, who seed-funded the Open Badges ecosystem, have a new platform launching through &lt;a href=&quot;https://www.lrng.org/&quot;&gt;LRNG&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;It is up to the organisations behind these various solutions as to how they allow users to authenticate. They may choose to allow social logins. They may force users to create logins based on their email address. They may decide to use an open source version of Persona. It’s entirely up to them.&lt;/p&gt;
- &lt;h5&gt;3. A post-Persona badges system has its advantages&lt;/h5&gt;
- &lt;p&gt;The Persona authentication system runs off email addresses. This means that transitioning &lt;em&gt;from&lt;/em&gt; Persona to another system is relatively straightforward. It has, however, meant that for the past few years we’ve had a recurrent problem: what do you do with people being issued badges to multiple email addresses?&lt;/p&gt;
- &lt;p&gt;Tying badges to emails seemed like the easiest and fastest way to get to a critical mass in terms of Open Badge adoption. Now that’s worked, we need to think in a more nuanced way about allowing users to tie multiple identities to a single badge.&lt;/p&gt;
- &lt;h4&gt;Conclusion&lt;/h4&gt;
- &lt;p&gt;Persona was always a slightly awkward fit for Open Badges. Although, for a time, it made sense to use Persona for authentication to the Open Badges backpack, we’re now in a post-Persona landscape. This brings with it certain advantages.&lt;/p&gt;
- &lt;p&gt;As Nate Otto wrote in his post &lt;a href=&quot;https://medium.com/badge-alliance/open-badges-in-2016-a-look-ahead-3cfe5c3c9878#.l5mhiztwx&quot;&gt;Open Badges in 2016: A Look Ahead&lt;/a&gt;, the project is growing up. It’s time to move beyond what was expedient at the dawn of Open Badges and look to the future. I’m sad to see the decline of Persona, but I’m excited what the future holds!&lt;/p&gt;
- &lt;p style=&quot;text-align: right;&quot;&gt;&lt;em&gt;Header image CC BY-NC-SA &lt;a href=&quot;https://www.flickr.com/photos/blmiers2/6904758951/&quot;&gt;Barbara&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description>
- <pubDate>Mon, 18 Jan 2016 11:34:19 +0000</pubDate>
- <dc:creator>Doug Belshaw</dc:creator>
- </item>
- <item>
- <title>This Week In Rust: This Week in Rust 114</title>
- <guid isPermaLink="false">tag:this-week-in-rust.org,2016-01-18:blog/2016/01/18/this-week-in-rust-114/</guid>
- <link>http://this-week-in-rust.org/blog/2016/01/18/this-week-in-rust-114/</link>
- <description>&lt;p&gt;Hello and welcome to another issue of &lt;em&gt;This Week in Rust&lt;/em&gt;!
- &lt;a href=&quot;http://rust-lang.org&quot;&gt;Rust&lt;/a&gt; is a systems language pursuing the trifecta:
- safety, concurrency, and speed. This is a weekly summary of its progress and
- community. Want something mentioned? Tweet us at &lt;a href=&quot;https://twitter.com/ThisWeekInRust&quot;&gt;@ThisWeekInRust&lt;/a&gt; or &lt;a href=&quot;mailto:corey@octayn.net?subject=This%20Week%20in%20Rust%20Suggestion&quot;&gt;send us an
- email&lt;/a&gt;!
- Want to get involved? &lt;a href=&quot;https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md&quot;&gt;We love
- contributions&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;em&gt;This Week in Rust&lt;/em&gt; is openly developed &lt;a href=&quot;https://github.com/cmr/this-week-in-rust&quot;&gt;on GitHub&lt;/a&gt;.
- If you find any errors in this week's issue, &lt;a href=&quot;https://github.com/cmr/this-week-in-rust/pulls&quot;&gt;please submit a PR&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;This week's edition was edited by: &lt;a href=&quot;https://github.com/nasa42&quot;&gt;nasa42&lt;/a&gt;, &lt;a href=&quot;https://github.com/brson&quot;&gt;brson&lt;/a&gt;, and &lt;a href=&quot;https://github.com/llogiq&quot;&gt;llogiq&lt;/a&gt;.&lt;/p&gt;
- &lt;h3&gt;Updates from Rust Community&lt;/h3&gt;
- &lt;h4&gt;News &amp;amp; Blog Posts&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://gregchapple.com/contributing-to-the-rust-compiler/&quot;&gt;Guide: Contributing to the Rust compiler&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.ncameron.org/blog/a-type-safe-and-zero-allocation-library-for-reading-and-navigating-elf-files/&quot;&gt;A type-safe and zero-allocation library for reading and navigating ELF files&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;[podcast] &lt;a href=&quot;http://www.newrustacean.com/show_notes/e009/&quot;&gt;New Rustacean podcast episode 09&lt;/a&gt;. Getting into the nitty-gritty with Rust's traits.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://jadpole.github.io/arcaders/arcaders-1-12/&quot;&gt;ArcadeRS 1.12: Brawl, at last&lt;/a&gt;! Part of the series &lt;a href=&quot;https://jadpole.github.io/arcaders/arcaders-1-0/&quot;&gt;ArcadeRS 1.0: The project&lt;/a&gt; - a series whose objective is to explore the Rust programming language and ecosystem through the development of a simple, old-school shooter.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://blog.thiago.me/raspberry-pi-bare-metal-programming-with-rust/&quot;&gt;Raspberry Pi bare metal programming with Rust&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://blog.servo.org/2016/01/11/twis-47/&quot;&gt;This week in Servo 47&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.redox-os.org/news/this-week-in-redox-10/&quot;&gt;This week in Redox OS 10&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Notable New Crates &amp;amp; Project Updates&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/ebkalderon/amethyst&quot;&gt;Amethyst&lt;/a&gt;. Data-oriented game engine written in Rust.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust website&lt;/a&gt; has received some &lt;a href=&quot;https://www.reddit.com/r/rust/comments/40zxey/major_website_updates/&quot;&gt;major updates&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://packages.debian.org/stretch/rustc&quot;&gt;Rust&lt;/a&gt; and &lt;a href=&quot;https://packages.debian.org/stretch/cargo&quot;&gt;Cargo&lt;/a&gt; are now available in Debian stretch.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://community.particle.io/t/rust-on-particle-call-for-contributors/19090&quot;&gt;Rust on Particle: Call for contributors&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://dwrensha.github.io/capnproto-rust/2016/01/11/async-rpc.html&quot;&gt;capnp-rpc-rust rewritten to use async I/O&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/Ogeon/palette&quot;&gt;Palette&lt;/a&gt;. A Rust library for linear color calculations and conversion.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;Updates from Rust Core&lt;/h3&gt;
- &lt;p&gt;164 pull requests were &lt;a href=&quot;https://github.com/issues?q=is%3Apr+org%3Arust-lang+is%3Amerged+merged%3A2016-01-11..2016-01-18&quot;&gt;merged in the last week&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;See the &lt;a href=&quot;https://internals.rust-lang.org/t/triage-digest-tue-jan-05-2016/3052&quot;&gt;triage digest&lt;/a&gt; and &lt;a href=&quot;https://internals.rust-lang.org/t/subteam-reports-2016-01-08/3067&quot;&gt;subteam reports&lt;/a&gt; for more details.&lt;/p&gt;
- &lt;h4&gt;Notable changes&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30943&quot;&gt;std: Stabilize APIs for the 1.7 release&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/27807&quot;&gt;Refactor and improve: Arena, TypedArena&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/29498&quot;&gt;Let &lt;code&gt;str::replace&lt;/code&gt; take a pattern&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30295&quot;&gt;rustc_resolve: Fix bug in duplicate checking for extern crates&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30426&quot;&gt;Rewrite BTreeMap to use parent pointers&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30446&quot;&gt;Support generic associated consts&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30509&quot;&gt;Add an &lt;code&gt;impl&lt;/code&gt; for &lt;code&gt;Box&amp;lt;Error&amp;gt;&lt;/code&gt; from String&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30533&quot;&gt;Introduce &quot;obligation forest&quot; data structure into fulfillment to track backtraces&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30538&quot;&gt;Remove negate_unsigned feature gate&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30567&quot;&gt;llvm: Add support for vectorcall (X86_VectorCall) convention&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30676&quot;&gt;Make coherence more tolerant of error types&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30740&quot;&gt;Add fast path for ASCII in UTF-8 validation&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30753&quot;&gt;Downgrade unit struct match via S(..) warnings to errors&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pull/30930&quot;&gt;Move const block checks before lowering step&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;New Contributors&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;Anton Blanchard&lt;/li&gt;
- &lt;li&gt;Jonas Tepe&lt;/li&gt;
- &lt;li&gt;Jörg Krause&lt;/li&gt;
- &lt;li&gt;Joshua Olson&lt;/li&gt;
- &lt;li&gt;kalita.alexey&lt;/li&gt;
- &lt;li&gt;Pierre Krieger&lt;/li&gt;
- &lt;li&gt;Sergey Veselkov&lt;/li&gt;
- &lt;li&gt;Simon Martin&lt;/li&gt;
- &lt;li&gt;Steffen&lt;/li&gt;
- &lt;li&gt;tomaka&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Approved RFCs&lt;/h4&gt;
- &lt;p&gt;Changes to Rust follow the Rust &lt;a href=&quot;https://github.com/rust-lang/rfcs#rust-rfcs&quot;&gt;RFC (request for comments)
- process&lt;/a&gt;. These
- are the RFCs that were approved for implementation this week:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1331&quot;&gt;RFC 1331: &lt;code&gt;src/grammar&lt;/code&gt; for the canonical grammar of the Rust language&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;Final Comment Period&lt;/h4&gt;
- &lt;p&gt;Every week &lt;a href=&quot;https://rust-lang.org/team.html&quot;&gt;the team&lt;/a&gt; announces the
- 'final comment period' for RFCs and key PRs which are reaching a
- decision. Express your opinions now. &lt;a href=&quot;https://github.com/rust-lang/rfcs/labels/final-comment-period&quot;&gt;This week's FCPs&lt;/a&gt; are:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1462&quot;&gt;Add &lt;code&gt;[&lt;/code&gt; to the FOLLOW(ty) in macro future-proofing rules&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1457&quot;&gt;Rewrite &lt;code&gt;for&lt;/code&gt; loop desugaring to use language items&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1320&quot;&gt;Amend 1192 (RangeInclusive) to use an enum&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/243&quot;&gt;Trait-based exception handling&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1361&quot;&gt;Improve Cargo target-specific dependencies&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1129&quot;&gt;Add a &lt;code&gt;IndexAssign&lt;/code&gt; trait that allows overloading &quot;indexed assignment&quot; expressions like &lt;code&gt;a[b] = c&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1196&quot;&gt;Allow eliding more type parameters&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1296&quot;&gt;Add an &lt;code&gt;alias&lt;/code&gt; attribute to &lt;code&gt;#[link]&lt;/code&gt; and &lt;code&gt;-l&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h4&gt;New RFCs&lt;/h4&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1459&quot;&gt;Add a used attribute to prevent symbols from being discarded&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1461&quot;&gt;Move some net2 functionality into libstd&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1465&quot;&gt;Add &lt;code&gt;some!&lt;/code&gt; macro for unwrapping Option more safely&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1467&quot;&gt;Stabilize the &lt;code&gt;volatile_load&lt;/code&gt; and &lt;code&gt;volatile_store&lt;/code&gt; intrinsics as &lt;code&gt;ptr::volatile_read&lt;/code&gt; and &lt;code&gt;ptr::volatile_write&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;Upcoming Events&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/Rust-Meetup-Hamburg/events/227838367/&quot;&gt;1/19. Rust Hack and Learn Hamburg @ Ponton&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/Rust-Bay-Area/events/227841778/&quot;&gt;1/21. SF Bay Area: Rust Concurrency and Parallelism&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://www.meetup.com/opentechschool-berlin/&quot;&gt;1/27. OpenTechSchool Berlin: Rust Hack and Learn&lt;/a&gt;.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;If you are running a Rust event please add it to the &lt;a href=&quot;https://www.google.com/calendar/embed?src=apd9vmbc22egenmtu5l6c5jbfc%40group.calendar.google.com&quot;&gt;calendar&lt;/a&gt; to get
- it mentioned here. Email &lt;a href=&quot;mailto:erick.tryzelaar@gmail.com&quot;&gt;Erick Tryzelaar&lt;/a&gt; or &lt;a href=&quot;mailto:banderson@mozilla.com&quot;&gt;Brian
- Anderson&lt;/a&gt; for access.&lt;/p&gt;
- &lt;h3&gt;fn work(on: RustProject) -&amp;gt; Money&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://maidsafe.net/rust_engineer.html&quot;&gt;Rust Engineer&lt;/a&gt; at MaidSafe.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://careers.mozilla.org/en-US/position/ozy21fwU&quot;&gt;Research Engineer - Servo&lt;/a&gt; at Mozilla.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://careers.mozilla.org/en-US/position/o0H41fww&quot;&gt;Senior Research Engineer - Rust&lt;/a&gt; at Mozilla.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://plv.mpi-sws.org/rustbelt/&quot;&gt;PhD and postdoc positions&lt;/a&gt; at MPI-SWS.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;&lt;em&gt;Tweet us at &lt;a href=&quot;https://twitter.com/ThisWeekInRust&quot;&gt;@ThisWeekInRust&lt;/a&gt; to get your job offers listed here!&lt;/em&gt;&lt;/p&gt;
- &lt;h3&gt;Crate of the Week&lt;/h3&gt;
- &lt;p&gt;This week's Crate of the Week is &lt;a href=&quot;https://github.com/alexcrichton/toml-rs&quot;&gt;toml&lt;/a&gt;, a crate for all our configuration needs, simple yet effective.&lt;/p&gt;
- &lt;p&gt;Thanks to &lt;a href=&quot;https://users.rust-lang.org/users/stebalien&quot;&gt;Steven Allen&lt;/a&gt; for the suggestion.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://users.rust-lang.org/t/crate-of-the-week/2704&quot;&gt;Submit your suggestions for next week&lt;/a&gt;!&lt;/p&gt;
- &lt;h3&gt;Quote of the Week&lt;/h3&gt;
- &lt;blockquote&gt;
- &lt;p&gt;Borrow/lifetime errors are usually Rust compiler bugs.
- Typically, I will spend 20 minutes detailing the precise conditions of
- the bug, using language that understates my immense knowledge, while
- demonstrating sympathetic understanding of the pressures placed on a
- Rust compiler developer, who is also probably studying for several exams
- at the moment. The developer reading my bug report may not understand
- this stuff as well as I do, so I will carefully trace the lifetimes of
- each variable, where memory is allocated on the stack vs the heap, which
- struct or function owns a value at any point in time, where borrows
- begin and where they... oh yeah, actually that variable really doesn't
- live long enough.&lt;/p&gt;
- &lt;/blockquote&gt;
- &lt;p&gt;— &lt;a href=&quot;https://www.reddit.com/r/rust/comments/4084yx/my_trick_when_i_get_stuck_as_a_beginner/cysqz3s&quot;&gt;peterjoel on /r/rust&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Thanks to &lt;a href=&quot;https://users.rust-lang.org/users/WaDelma&quot;&gt;Wa Delma&lt;/a&gt; for the suggestion.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://users.rust-lang.org/t/twir-quote-of-the-week/328&quot;&gt;Submit your quotes for next week&lt;/a&gt;!&lt;/p&gt;</description>
- <pubDate>Mon, 18 Jan 2016 05:00:00 +0000</pubDate>
- <dc:creator>Corey Richardson</dc:creator>
- </item>
- <item>
- <title>Nikki Bee: Okay, But What Does Your Work Actually Mean, Nikki? Part 2: The Fetch Standard and Servo</title>
- <guid isPermaLink="true">http://nikkisquared.github.io/2016/01/17/what-does-your-work-mean-part-2.html</guid>
- <link>http://nikkisquared.github.io/2016/01/17/what-does-your-work-mean-part-2.html</link>
- <description>&lt;p&gt;In my previous post, I started discussing in more detail what my internship entails, by talking about my first contribution to Servo. As a refresher, my first contribution was as part of my application to Outreachy, which I later revisited during my internship after a change I introduced to the HTML Standard it relied on. I’m going to expand on that last point today- specifically, how easy it is to introduce changes in &lt;a href=&quot;https://wiki.whatwg.org/wiki/FAQ#What_is_the_WHATWG.3F&quot;&gt;WHATWG&lt;/a&gt;’s various standards. I’m also going to talk about how this accessibility to changing web standards affects how I can understand it, how I can help improve it, and my work on Servo.&lt;/p&gt;
-
- &lt;h3&gt;Two Ways To Change&lt;/h3&gt;
-
- &lt;p&gt;There are many ways to &lt;a href=&quot;https://wiki.whatwg.org/wiki/What_you_can_do&quot;&gt;get involved with WHATWG&lt;/a&gt;, but there are two that I’ve become the most familiar with: firstly, by opening a discussion about a perceived issue and asking how it should be resolved; secondly, by taking on an issue approved as needing change and making the desired change. I’ve almost entirely only done the former, and the latter only for some minor typos. Any changes that relate directly to my work, however minor, are significant for me though! Like I discussed in my previous post, I brought attention to &lt;a href=&quot;https://github.com/whatwg/html/issues/296&quot;&gt;an inconsistency&lt;/a&gt; that was resolved, giving me a new task of updating my first contribution to Servo to reflect the change in the HTML Standard. I’ve done that several times since, for the Fetch Standard.&lt;/p&gt;
-
- &lt;h3&gt;Understanding Fetch&lt;/h3&gt;
-
- &lt;p&gt;My first two weeks of my internship were spent on reading through the majority of the &lt;a href=&quot;https://fetch.spec.whatwg.org/&quot;&gt;Fetch Standard&lt;/a&gt;, primarily the various Fetch functions. I took many notes describing the steps to myself, annotated with questions I had and the answers I got from either other people on the Servo team who had worked with Fetch (including my internship mentor, of course!) or people from WHATWG who were involved in the Fetch Standard. Getting so familiar with Fetch meant a few things: I would notice minor errors (such as an out of date link) that I could submit a &lt;a href=&quot;https://github.com/whatwg/fetch/pull/173&quot;&gt;simple fix for&lt;/a&gt;, or a bigger issue that I couldn’t resolve myself.&lt;/p&gt;
-
- &lt;h3&gt;Discussions &amp;amp; Resolutions&lt;/h3&gt;
-
- &lt;p&gt;I’m going to go into more detail about some of those bigger issues. From my perspective, when I start a discussion about a piece of documentation (such as the Fetch Standard, or reading about a programming library Servo uses), I go into it thinking “Either this documentation is incorrect, or my understanding is incorrectâ€. Whichever the answer is, it doesn’t mean that the documentation is bad, or that I’m bad at reading comprehension. I understand best by building up a model of something in my head, putting that to practice, and asking a lot of questions along the way. I learn by getting things wrong and figuring out why I was wrong, and sometimes in the process I uncover a point that could be made more clear, or an inconsistency! I have good examples of both of the different outcomes I listed, which I’ll cover over the next two sections.&lt;/p&gt;
-
- &lt;h5&gt;Looking For The Big Picture&lt;/h5&gt;
-
- &lt;p&gt;Early on in my initial review of the Fetch Standard’s several protocols, I found a major step that seemed to have no use. I understood that since I was learning Fetch on a step-by-step basis, I did not have a view of the bigger picture, so I asked around what I was missing that would help me understand this. One of the people I work with on implementing Fetch agreed with me that the step seemed to have no purpose, and so we decided to &lt;a href=&quot;https://github.com/whatwg/fetch/issues/174&quot;&gt;open an issue&lt;/a&gt; asking about removing it from the standard. It turned out that I had actually missed the meaning of it, as we learned. However, instead of leaving it there, I shifted the issue into asking for some explanatory notes on why this step is needed, which was fulfilled. This meant that I would have a reference to go back to should I forget the significance of the step, and that people reading the Fetch Standard in the future would be much less likely to come to the same incorrect conclusion I had.&lt;/p&gt;
-
- &lt;h5&gt;A Confusing Order&lt;/h5&gt;
-
- &lt;p&gt;Shortly after I had first discovered that apparent issue, I found myself struggling to comprehend a sequence of actions in another Fetch protocol. The specification seemed to say that part of an early step was meant to only be done after the final step. I unfortunately don’t remember details of the discussion I had about this- if there was a reason for why it was organized like this, I forget what it was. Regardless, it was agreed that &lt;a href=&quot;https://github.com/whatwg/fetch/issues/176&quot;&gt;moving those sub-steps&lt;/a&gt; to be actually listed after the step they’re supposed to run after would be a good change. This meant that I would need to re-organize my notes to reflect the re-arranged sequence of actions, as well as have an easier time being able to follow this part of the Fetch Standard.&lt;/p&gt;
-
- &lt;h3&gt;A Living Standard&lt;/h3&gt;
-
- &lt;p&gt;Like I said at the start of this post, I’m going to talk about how changes in the Fetch Standard affects my work on Servo itself. What I’ve covered so far has mostly been how changes affect my understanding of the standard itself. A key aspect in understanding the Fetch protocols is reviewing them for updates that impact me. WHATWG labels every standard they author as a “&lt;a href=&quot;https://wiki.whatwg.org/wiki/FAQ#What_does_.22Living_Standard.22_mean.3F&quot;&gt;Living Standard&lt;/a&gt;†for good reason. It was one thing for me to learn how easy it is to introduce changes, while knowing exactly what’s going on, but it’s another for me to understand that anybody else can, and often does, make changes to the Fetch Standard!&lt;/p&gt;
-
- &lt;h5&gt;Changes Over Time&lt;/h5&gt;
-
- &lt;p&gt;When an update is made to the Fetch Standard, it’s not so difficult to deal with as one might imagine. The Fetch Standard always notes the last day it was updated at the top of the document, I follow a Twitter account that &lt;a href=&quot;https://twitter.com/fetchstandard&quot;&gt;posts about updates&lt;/a&gt;, and all the history can be &lt;a href=&quot;https://github.com/whatwg/fetch/commits&quot;&gt;seen on GitHub&lt;/a&gt; which will show me exactly what has been changed as well as some discussion on what the change does. All of these together alert me to the fact that the Fetch Standard has been modified, and I can quickly see what was revised. If it’s relevant to what I’m going to be implementing, I update my notes to match it. Occasionally, I need to change existing code to reflect the new Standard, which is also easily done by comparing my new notes to the Fetch implementation in Servo!&lt;/p&gt;
-
- &lt;h5&gt;Snapshots&lt;/h5&gt;
-
- &lt;p&gt;From all of this, it might sound like the Fetch Standard is unfinished, or unreliable/inconsistent. I don’t mean to misrepresent it- the many small improvements help make the Fetch Standard, like all of WHATWG’s standards, better and more reliable. You can think of the status of the Fetch Standard at any point in time as a single, working snapshot. If somebody implemented all of Fetch as it is now, they’d have something that works by itself correctly. A different snapshot of Fetch is just that- different. It will have an improvement or two, but that doesn’t obsolete anybody who implemented it previously. It just means if they revisit the implementation, they’ll have things to update.&lt;/p&gt;
-
- &lt;p&gt;Third post over.&lt;/p&gt;</description>
- <pubDate>Sun, 17 Jan 2016 20:20:27 +0000</pubDate>
- </item>
- <item>
- <title>Kevin Ngo: How to Write an A-Frame VR Component</title>
- <guid isPermaLink="true">http://ngokevin.com/blog/aframe-component/</guid>
- <link>http://ngokevin.com/blog/aframe-component/</link>
- <description>&lt;img align=&quot;left&quot; hspace=&quot;5&quot; src=&quot;http://thevrjump.com/assets/img/articles/aframe-system/aframe-example.jpg&quot; width=&quot;320&quot; /&gt;Abstract representation of components by @rubenmueller of thevrjump.com.
-
- &lt;p&gt;&lt;a href=&quot;http://ngokevin.com/blog/aframe&quot;&gt;A-Frame&lt;/a&gt; is a WebVR framework that introduces the
- &lt;a href=&quot;http://ngokevin.com/blog/aframe-vs-3dml&quot;&gt;entity-component system&lt;/a&gt; (&lt;a href=&quot;http://ngokevin.com/rss/docs&quot;&gt;docs&lt;/a&gt;) to the DOM. The
- entity-component system treats every &lt;strong&gt;entity&lt;/strong&gt; in the scene as a placeholder
- object which we apply and mix &lt;strong&gt;components&lt;/strong&gt; to in order to add appearance,
- behavior, and functionality. A-Frame comes with some standard components out of
- the box like camera, geometry, material, light, or sound. However, people can
- write, publish, and register their own components to do &lt;strong&gt;whatever&lt;/strong&gt; they want
- like have entities &lt;a href=&quot;https://github.com/dmarcos/a-invaders/tree/master/js/components&quot;&gt;collide/explode/spawn&lt;/a&gt;, be controlled by
- &lt;a href=&quot;https://github.com/ngokevin/aframe-physics-components&quot;&gt;physics&lt;/a&gt;, or &lt;a href=&quot;https://jsbin.com/dasefeh/edit?html,output&quot;&gt;follow a path&lt;/a&gt;. Today, we'll be going through
- how we can write our own A-Frame components.&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;p&gt;Note that this tutorial will be covering the upcoming release of &lt;a href=&quot;https://github.com/aframevr/aframe/blob/dev/CHANGELOG.md#dev&quot;&gt;A-Frame
- 0.2.0&lt;/a&gt; which vastly improves the component API.&lt;/p&gt;
- &lt;/blockquote&gt;
- &lt;h3&gt;Table of Contents&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#what-a-component-looks-like&quot;&gt;What a Component Looks Like&lt;/a&gt;&lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#from-the-dom&quot;&gt;From the DOM&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#under-the-hood&quot;&gt;Under the Hood&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#defining-the-schema&quot;&gt;Defining the Schema&lt;/a&gt;&lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#property-types&quot;&gt;Property Types&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#single-property-schemas&quot;&gt;Single-Property Schemas&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#multiple-property-schemas&quot;&gt;Multiple-Property Schemas&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#defining-the-lifecycle-methods&quot;&gt;Defining the Lifecycle Methods&lt;/a&gt;&lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#component-init-set-up&quot;&gt;Component.init() - Set Up&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#component-update-olddata-do-the-magic&quot;&gt;Component.update(oldData) - Do the Magic&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#component-remove-tear-down&quot;&gt;Component.remove() - Tear Down&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#component-tick-time-background-behavior&quot;&gt;Component.tick() - Background Behavior&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#component-pause-and-component-play-stop-and-go&quot;&gt;Component.pause() and Component.play() - Stop and Go&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#boilerplate&quot;&gt;Boilerplate&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#examples&quot;&gt;Examples&lt;/a&gt;&lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#text-component&quot;&gt;Text Component&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#physics-components&quot;&gt;Physics Components&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://ngokevin.com/rss/index.xml#layout-component&quot;&gt;Layout Component&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;What a Component Looks Like&lt;/h3&gt;
- &lt;p&gt;A component contains a bucket of data in the form of component properties. This
- data is used to modify the entity. For example, we might have an &lt;em&gt;engine&lt;/em&gt;
- component. Possible properties might be &lt;em&gt;horsepower&lt;/em&gt; or &lt;em&gt;cylinders&lt;/em&gt;.&lt;/p&gt;
- &lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;http://thevrjump.com/assets/img/articles/aframe-system/aframe-system.jpg&quot; /&gt;
- &lt;/p&gt;&lt;div class=&quot;page-caption&quot;&gt;&lt;span&gt;
- Abstract representation of a component by @rubenmueller of thevrjump.com.
- &lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;
- &lt;h4&gt;From the DOM&lt;/h4&gt;
- &lt;p&gt;Let's first see what a component looks like from the DOM.&lt;/p&gt;
- &lt;p&gt;For example, the &lt;a href=&quot;https://aframe.io/docs/components/light.html&quot;&gt;light component&lt;/a&gt; has properties such as type, color,
- and intensity. In A-Frame, we register and configure a component to an entity
- using an HTML attribute and a style-like syntax:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;type: point; color: crimson; intensity: 2.5&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;This would give us a light in the scene. To demonstrate composability, we could
- give the light a spherical representation by mixing in the &lt;a href=&quot;https://aframe.io/docs/components/geometry.html&quot;&gt;geometry
- component&lt;/a&gt;.&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;primitive: sphere; radius: 5&quot;&lt;/span&gt;
- &lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;type: point; color: crimson; intensity: 2.5&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Or we can configure the position component to move the light sphere a bit to the right.&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;primitive: sphere; radius: 5&quot;&lt;/span&gt;
- &lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;type: point; color: crimson; intensity: 2.5&quot;&lt;/span&gt;
- &lt;span class=&quot;na&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;5 0 0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a-entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Given the style-like syntax and that it modifies the appearance and behavior of
- DOM nodes, component properties can be thought of as a rough analog to CSS. In
- the near future, I can imagine component property stylesheets.&lt;/p&gt;
- &lt;h4&gt;Under the Hood&lt;/h4&gt;
- &lt;p&gt;Now let's see what a component looks like &lt;strong&gt;under the hood&lt;/strong&gt;. A-Frame's most
- basic component is the &lt;a href=&quot;https://aframe.io/docs/components/position.html&quot;&gt;position component&lt;/a&gt;:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;AFRAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'position'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vec3'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
-
- &lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;object3D&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
- &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;object3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;The position component uses only a tiny subset of the component API, but what
- this does is register the component with the name &quot;position&quot;, define a &lt;code&gt;schema&lt;/code&gt;
- where the component's value with be parsed to an &lt;code&gt;{x, y, z}&lt;/code&gt; object, and when
- the component initializes or the component's data updates, set the position of
- the entity with the &lt;code&gt;update&lt;/code&gt; callback. &lt;code&gt;this.el&lt;/code&gt; is a reference from the
- component to the DOM element, or entity, and &lt;code&gt;object3D&lt;/code&gt; is the entity's
- &lt;a href=&quot;http://threejs.org/&quot;&gt;three.js&lt;/a&gt;. Note that A-Frame is built on top of three.js so many
- components will be using the three.js API.&lt;/p&gt;
- &lt;p&gt;So we see that components consist of a name and a definition, and then they can
- be registered to A-Frame. We saw the the position component definition defined
- a &lt;code&gt;schema&lt;/code&gt; and an &lt;code&gt;update&lt;/code&gt; handler. Components simply consist of the &lt;code&gt;schema&lt;/code&gt;,
- which defines the shape of the data, and several handlers for the component to
- modify the entity in reaction to different types of events.&lt;/p&gt;
- &lt;p&gt;Here is the current list of properties and methods of a component definition:&lt;/p&gt;
- &lt;table class=&quot;pure-table-striped&quot;&gt;
- &lt;tbody&gt;&lt;tr&gt;
- &lt;th&gt;Property&lt;/th&gt;
- &lt;th&gt;Description&lt;/th&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;data&lt;/td&gt;
- &lt;td&gt;Data of the component derived from the schema default values, mixins, and the entity's attributes.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;el&lt;/td&gt;
- &lt;td&gt;Reference to the &lt;a href=&quot;https://aframe.io/docs/core/entity.html&quot;&gt;entity&lt;/a&gt; element.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;schema&lt;/td&gt;
- &lt;td&gt;Names, types, and default values of the component property value(s)&lt;/td&gt;
- &lt;/tr&gt;
- &lt;/tbody&gt;&lt;/table&gt;
-
- &lt;table class=&quot;pure-table-striped&quot;&gt;
- &lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;init&lt;/td&gt;
- &lt;td&gt;Called once when the component is initialized.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;update&lt;/td&gt;
- &lt;td&gt;Called both when the component is initialized and whenever the component's data changes (e.g, via &lt;i&gt;setAttribute&lt;/i&gt;).&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;remove&lt;/td&gt;
- &lt;td&gt;Called when the component detaches from the element (e.g., via &lt;i&gt;removeAttribute&lt;/i&gt;).&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;tick&lt;/td&gt;
- &lt;td&gt;Called on each render loop or tick of the scene.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;play&lt;/td&gt;
- &lt;td&gt;Called whenever the scene or entity plays to add any background or dynamic behavior.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;tr&gt;
- &lt;td&gt;pause&lt;/td&gt;
- &lt;td&gt;Called whenever the scene or entity pauses to remove any background or dynamic behavior.&lt;/td&gt;
- &lt;/tr&gt;
- &lt;/tbody&gt;&lt;/table&gt;
-
- &lt;h3&gt;Defining the Schema&lt;/h3&gt;
- &lt;p&gt;The component's schema defines what type of data it takes. A component can
- either be single-property or consist of multiple properties. And properties
- have &lt;em&gt;property types&lt;/em&gt;. Note that single-property schemas and property types are
- being released in A-Frame &lt;code&gt;v0.2.0&lt;/code&gt;.&lt;/p&gt;
- &lt;p&gt;A property might look like:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'int'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;And a schema consisting of multiple properties might look like:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#FFF'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'selector'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;uv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1 1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Since components in the entity-component system are just buckets of data that
- are used to affect the appearance or behavior of the entity, the schema plays a
- crucial role in the definition of the component.&lt;/p&gt;
- &lt;h4&gt;Property Types&lt;/h4&gt;
- &lt;p&gt;A-Frame comes with several built-in property types such as &lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;,
- &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;selector&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, or &lt;code&gt;vec3&lt;/code&gt;. Every single property is assigned a
- type, whether explicitly through the &lt;code&gt;type&lt;/code&gt; key or implictly via inferring the
- value. And each type is used to assign &lt;code&gt;parse&lt;/code&gt; and &lt;code&gt;stringify&lt;/code&gt; functions. The
- parser deserializes the incoming string value from the DOM to be put into the
- component's data object. The stringifier is used when using &lt;code&gt;setAttribute&lt;/code&gt; to
- serialize back to the DOM.&lt;/p&gt;
- &lt;p&gt;We can actually define and register our own property types:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;AFRAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerPropertyType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'radians'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
-
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
-
- &lt;span class=&quot;c1&quot;&gt;// Default stringify is .toString().&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;h4&gt;Single-Property Schemas&lt;/h4&gt;
- &lt;p&gt;If a component has only one property, then it must either have a &lt;code&gt;type&lt;/code&gt; or a
- &lt;code&gt;default&lt;/code&gt; value. If the type is defined, then the type is used to parse and
- coerce the string retrieved from the DOM (e.g., &lt;code&gt;getAttribute&lt;/code&gt;). Or if the
- default value is defined, the default value is used to infer the type.&lt;/p&gt;
- &lt;p&gt;Take for instance the &lt;a href=&quot;https://aframe.io/docs/components/visible.html&quot;&gt;visible component&lt;/a&gt;. The schema property
- definition implicitly defines it as a boolean:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;AFRAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'visible'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;c1&quot;&gt;// Type will be inferred to be boolean.&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
-
- &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Or the &lt;a href=&quot;https://aframe.io/docs/components/rotation.html&quot;&gt;rotation component&lt;/a&gt; which explicitly defines the value as a &lt;code&gt;vec3&lt;/code&gt;:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;AFRAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rotation'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;c1&quot;&gt;// Default value will be 0, 0, 0 as defined by the vec3 property type.&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vec3'&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
-
- &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Using these defined property types, schemas are processed by
- &lt;code&gt;registerComponent&lt;/code&gt; to inject default values, parsers, and stringifiers for
- each property. So if a default value is not defined, the default value will be
- whatever the property type defines as the &quot;default default value&quot;.&lt;/p&gt;
- &lt;h4&gt;Multiple-Property Schemas&lt;/h4&gt;
- &lt;p&gt;If a component has multiple properties (or one named property), then it consists of
- one or more property definitions, in the form described above, in an object keyed by
- property name. For instance, a physics body component might define a schema:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;AFRAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'physics-body'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;boundingBox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vec3'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;mass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;velocity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vec3'&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;Having multiple properties is what makes the component take the syntax in the
- form of &lt;code&gt;physics=&quot;mass: 2; velocity: 1 1 1&quot;&lt;/code&gt;.&lt;/p&gt;
- &lt;p&gt;With the schema defined, all data coming into the component will be passed
- through the schema for parsing. Then in the lifecycle methods, the component
- has access to &lt;code&gt;this.data&lt;/code&gt; which in a single-property schema is a value and in a
- multiple-propery schema is an object.&lt;/p&gt;
- &lt;h3&gt;Defining the Lifecycle Methods&lt;/h3&gt;
- &lt;h4&gt;Component.init() - Set Up&lt;/h4&gt;
- &lt;p&gt;&lt;code&gt;init&lt;/code&gt; is called once in the component's lifecycle when it is mounted to the
- entity. &lt;code&gt;init&lt;/code&gt; is generally used to set up variables or members that may used
- throughout the component or to set up state. Though not every component will
- need to define an &lt;code&gt;init&lt;/code&gt; handler. Sort of like the component-equivalent method
- to &lt;code&gt;createdCallback&lt;/code&gt; or &lt;code&gt;React.ComponentDidMount&lt;/code&gt;.&lt;/p&gt;
- &lt;p&gt;For example, the &lt;code&gt;look-at&lt;/code&gt; component's &lt;code&gt;init&lt;/code&gt; handler sets up some variables:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target3D&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Vector3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
-
- &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;h4&gt;Component.update(oldData) - Do the Magic&lt;/h4&gt;
- &lt;p&gt;The &lt;code&gt;update&lt;/code&gt; handler is called both at the beginning of the component's
- lifecycle with the initial &lt;code&gt;this.data&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; every time the component's data
- changes (generally during the entity's &lt;code&gt;attributeChangedCallback&lt;/code&gt; like with a
- &lt;code&gt;setAttribute&lt;/code&gt;). The update handler gets access to the previous state of the
- component data passed in through &lt;code&gt;oldData&lt;/code&gt;. The previous state of the component
- can be used to tell exactly which properties changed to do more granular
- updates.&lt;/p&gt;
- &lt;p&gt;The update handler uses &lt;code&gt;this.data&lt;/code&gt; to modify the entity, usually interacting
- with three.js APIs. One of the simplest update handlers is the
- &lt;a href=&quot;https://aframe.io/docs/components/visible.html&quot;&gt;visible&lt;/a&gt; component's:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;A slightly more complex update handler might be the &lt;a href=&quot;https://aframe.io/docs/components/light.html&quot;&gt;light&lt;/a&gt; component's,
- which we'll show via abbreviated code:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;oldData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diffData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oldData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{});&lt;/span&gt;
-
- &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'type'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diffData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;c1&quot;&gt;// If there is an existing light and the type hasn't changed, update light.&lt;/span&gt;
- &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;diffData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;nx&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diffData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;c1&quot;&gt;// No light exists yet or the type of light has changed, create a new light.&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
-
- &lt;span class=&quot;c1&quot;&gt;// Register the object3D of type `light` to the entity.&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setObject3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'light'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;p&gt;The entity's &lt;code&gt;object3D&lt;/code&gt; is a plain THREE.Object3D. Other three.js object types
- such as meshes, lights, and cameras can be set with &lt;code&gt;setObject3D&lt;/code&gt; where they
- will be appeneded to the entity's &lt;code&gt;object3D&lt;/code&gt;.&lt;/p&gt;
- &lt;h4&gt;Component.remove() - Tear Down&lt;/h4&gt;
- &lt;p&gt;The &lt;code&gt;remove&lt;/code&gt; handler is called when the component detaches from the entity such
- as with &lt;code&gt;removeAttribute&lt;/code&gt;. This is generally used to remove all modifications,
- listeners, and behaviors to the entity that the component added.&lt;/p&gt;
- &lt;p&gt;For example, when the &lt;a href=&quot;https://aframe.io/docs/components/light.html&quot;&gt;light component&lt;/a&gt; detaches, it removes the light
- it previously attached from the entity and thus the scene:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeObject3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'light'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;h4&gt;Component.tick(time) - Background Behavior&lt;/h4&gt;
- &lt;p&gt;The &lt;code&gt;tick&lt;/code&gt; handler is called on every single tick or render loop of the scene.
- So expect it to run on the order of 60-120 times for second. The global uptime of
- the scene in seconds is passed into the tick handler.&lt;/p&gt;
- &lt;p&gt;For example, the &lt;a href=&quot;https://aframe.io/docs/components/look-at.html&quot;&gt;look-at&lt;/a&gt; component, which instructs an entity to
- look at another target entity, uses the tick handler to update the rotation in
- case the target entity changes its position:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;c1&quot;&gt;// target3D and vector are set from the update handler.&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lookAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setFromMatrixPosition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target3D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;matrixWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;h4&gt;Component.pause() and Component.play() - Stop and Go&lt;/h4&gt;
- &lt;p&gt;To support pause and play, just as with a video game or to toggle entities for
- performance, components can implement &lt;code&gt;play&lt;/code&gt; and &lt;code&gt;pause&lt;/code&gt; handlers. These are
- invoked when the component's entity runs its &lt;code&gt;play&lt;/code&gt; or &lt;code&gt;pause&lt;/code&gt; method. When an
- entity plays or pauses, all of its child entities are also played or paused.&lt;/p&gt;
- &lt;p&gt;Components should implement play or pause handlers if they register any
- dynamic, asynchronous, or background behavior such as animations, event
- listeners, or tick handlers.&lt;/p&gt;
- &lt;p&gt;For example, the &lt;code&gt;look-controls&lt;/code&gt; component simply removes its event listeners
- such that the camera does not move when the scene is paused, and it adds its
- event listeners when the scene starts playing or is resumed:&lt;/p&gt;
- &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;pause&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeEventListeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
-
- &lt;span class=&quot;nx&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
- &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addEventListeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
-
-
- &lt;h3&gt;Boilerplate&lt;/h3&gt;
- &lt;p&gt;I suggest that people start off with my &lt;a href=&quot;https://github.com/ngokevin/aframe-component-boilerplate&quot;&gt;component boilerplate&lt;/a&gt;,
- even hardcore tool junkies. This will get you straight into building a
- component and comes with everything you will need to publish your component
- into the wild. The boilerplate handles creating a stubbed component, build
- steps for both NPM and browser distribution files, and publishing to Github
- Pages.&lt;/p&gt;
- &lt;p&gt;Generally with boilerplates, it is better to start from scratch and build your
- own boilerplate, but the A-Frame component boilerplate contains a lot of tribal
- inside knowledge about A-Frame and is updated frequently to reflect new things
- landing on A-Frame. The only possibly opinionated pieces about the boilerplate
- is the development tools it internally uses that are hidden away by NPM
- scripts.&lt;/p&gt;
- &lt;h3&gt;Examples&lt;/h3&gt;
- &lt;p&gt;Under construction. Stay tuned!&lt;/p&gt;
- &lt;h4&gt;Text Component&lt;/h4&gt;
- &lt;p&gt;&lt;a href=&quot;https://github.com/ngokevin/aframe-text-component&quot;&gt;Text component&lt;/a&gt;&lt;/p&gt;
- &lt;h4&gt;Physics Components&lt;/h4&gt;
- &lt;p&gt;&lt;a href=&quot;https://github.com/ngokevin/aframe-physics-components&quot;&gt;Physics components&lt;/a&gt;&lt;/p&gt;
- &lt;h4&gt;Layout Component&lt;/h4&gt;
- &lt;p&gt;&lt;a href=&quot;https://github.com/ngokevin/aframe-layout-component&quot;&gt;Layout component&lt;/a&gt;&lt;/p&gt;</description>
- <pubDate>Sun, 17 Jan 2016 00:00:00 +0000</pubDate>
- </item>
- <item>
- <title>Gervase Markham: Convenient… and Creepy</title>
- <guid isPermaLink="false">http://blog.gerv.net/?p=3527</guid>
- <link>http://feedproxy.google.com/~r/HackingForChrist/~3/DN054t04_dE/</link>
- <description>&lt;p&gt;The last Mozilla All-Hands was at one of the hotels in the Walt Disney World Resort in Florida. Every attendee was issued with one of these (although their use was optional):&lt;br /&gt;
- &lt;a href=&quot;http://blog.gerv.net/files/2016/01/Disneys_MagicBand.jpg&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-3530&quot; src=&quot;http://blog.gerv.net/files/2016/01/Disneys_MagicBand-1024x832.jpg&quot; width=&quot;292&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;p&gt;It’s called a “Magic Bandâ€. You register it online and connect it to your Disney account, and then it can be used for park entry, entry to pre-booked rides so you don’t have to queue (called “FastPass+â€), payment, picking up photos, as your room key, and all sorts of other convenient features. Note that it has no UI whatsoever – no lights, no buttons. Not even a battery compartment. (It does contain a battery, but it’s not replaceable.) These are specific design decisions – the aim is for ultra-simple convenience.&lt;/p&gt;
- &lt;p&gt;One of the talks we had at the All Hands was from one of the Magic Band team. The audience reactions to some of the things he said was really interesting. He gave the example of Cinderella wishing you a Happy Birthday as you walk round the park. “Cinderella just knowsâ€, he said. Of course, in fact, her costume’s tech prompts her when it silently reads your Magic Band from a distance. This got some initial impressed applause, but it was noticeable that after a few moments, it wavered – people were thinking “Cool… er, but creepy?â€&lt;/p&gt;
- &lt;p&gt;The Magic Band also has range sufficient that Disney can track you around the park. This enables some features which are good for both customers and Disney – for example, they can use it for load balancing. If one area of the park seems to be getting overcrowded, have some characters pop up in a neighbouring area to try and draw people away. But it means that they always know where you are and where you’ve been.&lt;/p&gt;
- &lt;p&gt;My take-away from learning about the Magic Band is that it’s really hard to have a technical solution to this kind of requirement which allows all the Convenient features but not the Creepy features. Disney does offer an RFID-card-based solution for the privacy-conscious which does some of these things, but not all of them. And it’s easier to lose. It seems to me that the only way to distinguish the two types of feature, and get one and not the other, is policy – either the policy of the organization, or external restrictions on them (e.g. from a watchdog body’s code of conduct they sign up to, or from law). And it’s often not in the organization’s interest to limit themselves in this way.&lt;/p&gt;
- &lt;img alt=&quot;&quot; height=&quot;1&quot; src=&quot;http://feeds.feedburner.com/~r/HackingForChrist/~4/DN054t04_dE&quot; width=&quot;1&quot; /&gt;</description>
- <pubDate>Sat, 16 Jan 2016 12:18:38 +0000</pubDate>
- <dc:creator>gerv</dc:creator>
- </item>
- <item>
- <title>Christian Heilmann: Don’t tell me what my browser can’t do!</title>
- <guid isPermaLink="false">https://www.christianheilmann.com/?p=4957</guid>
- <link>https://www.christianheilmann.com/2016/01/16/dont-tell-me-what-my-browser-cant-do/</link>
- <description>&lt;p&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;Chances are, your guess is wrong!&lt;/em&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;you are obviously in the wrong place&quot; src=&quot;https://d262ilb51hltx0.cloudfront.net/max/800/1*l9jPbOyAl00kjPhyNYA-IQ.jpeg&quot; width=&quot;100%&quot; /&gt;Arrogance towards possible customers never pays out – as shown in “Pretty Womanâ€&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;There is nothing more frustrating than being capable of something and not getting a chance to do it. The same goes for being blocked out from something although you are capable of consuming it. Or you’re even willing to put some extra effort or even money in and you still don’t get to consume it.&lt;/p&gt;
-
- &lt;p&gt;For example, I’d happily pay $50 a month to get access to Netflix’s world-wide library from any country I’m in. But the companies Netflix get their content from won’t go for that. Movies and TV show are budgeted by predicted revenue in different geographical markets with month-long breaks in between the releases. A world-wide network capable of delivering content in real time? Preposterous — let’s shut that down.&lt;/p&gt;
-
- &lt;p&gt;On a less “let’s break a 100 year old monopoly†scale of annoyance, &lt;a href=&quot;https://twitter.com/codepo8/status/687616620529844224&quot;&gt;I tweeted yesterday something glib and apparently cruel&lt;/a&gt;:&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;“Sorry, but your browser does not support WebGL!†– sorry, you are a shit coder.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;strong&gt;And I stand by this&lt;/strong&gt;. I went to a web site that promised me some cute, pointless animation and technological demo. I was using Firefox Nightly — a WebGL capable browser. I also went there with Microsoft Edge — another WebGL capable browser. Finally, using Chrome, I was able to delight in seeing an animation.&lt;/p&gt;
-
- &lt;p&gt;&lt;strong&gt;I’m not saying the creators of that thing lack in development capabilities&lt;/strong&gt;. The demo was slick, beautiful and well coded. They still do lack in two things developers of &lt;em&gt;web products &lt;/em&gt;(and I count apps into that) should have: empathy for the end user and an understanding that they are not in control.&lt;/p&gt;
-
- &lt;p&gt;Now, I am a pretty capable technical person. When you tell me that I might be lacking WebGL, I know what you mean. I don’t lack WebGL. I was blocked out because the web site did browser sniffing instead of capability testing. But I know what could be the problem.&lt;/p&gt;
-
- &lt;p&gt;A normal user of the web has no idea what WebGL is and — if you’re lucky — will try to find it on an app store. If you’re not lucky all you did is confuse a person. A person who went through the effort to click a link, open a browser and wait for your thing to load. A person that feels stupid for using your product as they have no clue what WebGL is and won’t ask. Humans hate feeling stupid and we do anything not to appear it or show it.&lt;/p&gt;
-
- &lt;p&gt;This is what I mean by empathy for the end user. Our problems should never become theirs.&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;A cryptic error message telling the user that they lack some technology helps nobody and is sloppy development at best, sheer arrogance at worst.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;The web is, sadly enough, littered with unhelpful error messages and assumptions that it is the user’s fault when they can’t consume the thing we built.&lt;/p&gt;
-
- &lt;p&gt;Here’s a reality check — this is what our users should have to do to consume the things we build:&lt;/p&gt;
-
- &lt;p&gt;&lt;img alt=&quot;&quot; height=&quot;600&quot; src=&quot;https://d262ilb51hltx0.cloudfront.net/max/800/1*DXtRIWTu-UzRb0YB-h8SmA.png&quot; width=&quot;10&quot; /&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;strong&gt;That’s right. Nothing&lt;/strong&gt;. This is the web. Everybody is invited to consume, contribute and create. This is what made it the success it is. This is what will make it outlive whatever other platform threatens it with shiny impressive interactions. Interactions at that time impossible to achieve with web technologies.&lt;/p&gt;
-
- &lt;p&gt;Whenever I mention this, the knee-jerk reaction is the same:&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote class=&quot;graf--blockquote graf-after--p&quot; id=&quot;79d6&quot; name=&quot;79d6&quot;&gt;How can you expect us to build delightful experiences close to magic (and whatever other soundbites were in the last Apple keynote) if we keep having to support old browsers and users with terrible setups?&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;You don’t have to support old browsers and terrible setups. But you are not allowed to block them out. It is a simple matter of giving a usable interface to end users. A button that does nothing when you click it is not a good experience. Test if the functionality is available, then create or show the button. &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;This is as simple as it is.&lt;/strong&gt;&lt;/p&gt;
-
- &lt;p&gt;If you really have to rely on some technology then show people what they are missing out on and tell them how to upgrade. A screenshot or a video of a WebGL animation is still lovely to see. A message telling me I have no WebGL less so.&lt;/p&gt;
-
- &lt;p&gt;Even more on the black and white scale, what the discussion boils down to is in essence:&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote class=&quot;graf--blockquote graf-after--p&quot; id=&quot;a775&quot; name=&quot;a775&quot;&gt;But it is 2016 — surely we can expect people to have JavaScript enabled — it is after all “the assembly language of the webâ€&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;Despite the cringe-worthy &lt;a href=&quot;http://www.hanselman.com/blog/JavaScriptIsAssemblyLanguageForTheWebSematicMarkupIsDeadCleanVsMachinecodedHTML.aspx&quot;&gt;misquote of the assembly language&lt;/a&gt; thing, here is a harsh truth:&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;You can absolutely expect JavaScript to be available on your end users computers in 2016. At the same time it is painfully &lt;strong&gt;naive&lt;/strong&gt; to expect it to work under all circumstances.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;strong&gt;JavaScript is brittle&lt;/strong&gt;. &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; both are &lt;em&gt;fault tolerant&lt;/em&gt;. If something goes wrong in &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, browsers either display the content of the element or try to fix minor issues like unclosed elements for you. &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; skips lines of code it can’t understand and merrily goes on its way to show the rest of it. JavaScript breaks on errors and tells you that something went wrong. It will not execute the rest of the script, but throws in the towel and tells you to get your house in order first.&lt;/p&gt;
-
- &lt;p&gt;There &lt;a href=&quot;http://kryogenix.org/code/browser/everyonehasjs.html&quot;&gt;are many outside influences&lt;/a&gt; that will interfere with the execution of your JavaScript. That’s why a non-naive and non-arrogant — a dedicated and seasoned web developer — will never rely on it. Instead, you treat it as an enhancement and in an almost paranoid fashion test for the availability of everything before you access it.&lt;/p&gt;
-
- &lt;p&gt;&lt;strong&gt;Sorry (not sorry) — this will never go away&lt;/strong&gt;. This is the nature of JavaScript. And it is a good thing. It means we can access new features of the language as they come along instead of getting stuck in a certain state. It means we have to think about using it every time instead of relying on libraries to do the work for us. It means that we need to keep evolving with the web — a living and constantly changing medium, and not a software platform. That’s just part of it.&lt;/p&gt;
-
- &lt;p&gt;This is why the whole discussion about JavaScript enabled or disabled is a massive waste of time. It is not the availability of JavaScript we need to worry about. It is our products breaking in perfectly capable environments because we rely on perfect execution instead of writing defensive code. A tumblr like &lt;a class=&quot;markup--anchor markup--p-anchor&quot; href=&quot;http://sighjavascript.tumblr.com/&quot; rel=&quot;nofollow&quot;&gt;Sigh, JavaScript&lt;/a&gt; is fun, but is pithy finger-pointing.&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;There is nothing wrong with using JavaScript to build things. Just be aware that the error handling is your responsibility.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;Any message telling the user that they have to turn on JavaScript to use a certain product is a proof that you care more about your developer convenience than your users.&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;It is damn hard these days to turn off JavaScript – you are complaining about a almost non-existent issue and tell the confused user to do something they don’t know how to.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;The chance that something in the JavaScript execution of any of your dozens of dependencies went wrong is much higher – and this is your job to fix. This is why advice like &lt;a href=&quot;http://webdesign.tutsplus.com/tutorials/quick-tip-dont-forget-the-noscript-element--cms-25498&quot;&gt;using noscript to provide alternative content&lt;/a&gt; is terrible. It means you double your workload instead of enhancing what works. Who knows? If you start with something not JavaScript dependent (or running it server side) you might find that you don’t need the complex solution you started with in the first place. Faster, smaller, easier. Sounds good, right?&lt;/p&gt;
-
- &lt;p&gt;So, please, stop sniffing my browser, you will fail and tell me lies. Stop pretending that working with a brittle technology is the user’s fault when something goes wrong.&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;As web developers we work in the service industry. We deliver products to people. And keeping these people happy and non-worried is our job. Nothing more, nothing less.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;Without users, your product is nothing. Sure, we are better paid and well educated and we are not flipping burgers. But we have no right whatsoever to be arrogant and not understanding that our mistakes are not the fault of our end users.&lt;/p&gt;
-
- &lt;p&gt;Our demeanor when complaining about how stupid our end users and their terrible setups are reminds me of &lt;a href=&quot;https://www.youtube.com/watch?v=CSj5stmFkQ0&quot;&gt;this Mitchell and Webb sketch&lt;/a&gt;.&lt;/p&gt;
-
- &lt;p&gt;&lt;/p&gt;
-
- &lt;p&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Don’t be that person. &lt;/strong&gt;Our job is to enable people to consume, participate and create the web. This is magic. This is beautiful. This is incredibly rewarding. The next markets we should care about are ready to be as excited about the web as we were when we first encountered it. Browsers are good these days. Use what they offer after testing for it and enjoy what you can achieve. Don’t tell the user when things go wrong – they can not fix what you messed up.&lt;/p&gt;
-
-
- &lt;img alt=&quot;&quot; height=&quot;1&quot; src=&quot;http://feeds.feedburner.com/~r/chrisheilmann/~4/vqtqgcNQXy8&quot; width=&quot;1&quot; /&gt;</description>
- <pubDate>Sat, 16 Jan 2016 11:28:10 +0000</pubDate>
- <dc:creator>Chris Heilmann</dc:creator>
- </item>
- <item>
- <title>Mike Hommey: Announcing git-cinnabar 0.3.1</title>
- <guid isPermaLink="true">http://glandium.org/blog/?p=3510</guid>
- <link>http://glandium.org/blog/?p=3510</link>
- <description>&lt;p&gt;This is a brown paper bag release. It turns out I managed to break the upgrade&lt;br /&gt;
- path only 10 commits before the release.&lt;/p&gt;
- &lt;h3&gt;What’s new since 0.3.0?&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;code&gt;git cinnabar fsck&lt;/code&gt; doesn’t fail to upgrade metadata.&lt;/li&gt;
- &lt;li&gt;The &lt;code&gt;remote.$remote.cinnabar-draft&lt;/code&gt; config works again.&lt;/li&gt;
- &lt;li&gt;Don’t fail to clone an empty repository.&lt;/li&gt;
- &lt;li&gt;Allow to specify mercurial configuration items in a .git/hgrc file.&lt;/li&gt;
- &lt;/ul&gt;</description>
- <pubDate>Sat, 16 Jan 2016 11:26:45 +0000</pubDate>
- <dc:creator>glandium</dc:creator>
- </item>
- <item>
- <title>Emily Dunham: Buildbot and EOFError</title>
- <guid isPermaLink="true">http://edunham.net/2016/01/16/buildbot_and_eoferror.html</guid>
- <link>http://edunham.net/2016/01/16/buildbot_and_eoferror.html</link>
- <description>&lt;h3&gt;Buildbot and EOFError&lt;/h3&gt;
- &lt;p&gt;More SEO-bait, after tracking down an poorly documented problem:&lt;/p&gt;
- &lt;div class=&quot;highlight-python&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;# buildbot start master
- Following twistd.log until startup finished..
- 2016-01-17 04:35:49+0000 [-] Log opened.
- 2016-01-17 04:35:49+0000 [-] twistd 14.0.2 (/usr/bin/python 2.7.6) starting up.
- 2016-01-17 04:35:49+0000 [-] reactor class: twisted.internet.epollreactor.EPollReactor.
- 2016-01-17 04:35:49+0000 [-] Starting BuildMaster -- buildbot.version: 0.8.12
- 2016-01-17 04:35:49+0000 [-] Loading configuration from '/home/user/buildbot/master/master.cfg'
- 2016-01-17 04:35:53+0000 [-] error while parsing config file:
- Traceback (most recent call last):
- File &quot;/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py&quot;, line 577, in _runCallbacks
- current.result = callback(current.result, *args, **kw)
- File &quot;/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py&quot;, line 1155, in gotResult
- _inlineCallbacks(r, g, deferred)
- File &quot;/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py&quot;, line 1099, in _inlineCallbacks
- result = g.send(result)
- File &quot;/usr/local/lib/python2.7/dist-packages/buildbot/master.py&quot;, line 189, in startService
- self.configFileName)
- --- &amp;lt;exception caught here&amp;gt; ---
- File &quot;/usr/local/lib/python2.7/dist-packages/buildbot/config.py&quot;, line 156, in loadConfig
- exec f in localDict
- File &quot;/home/user/buildbot/master/master.cfg&quot;, line 415, in &amp;lt;module&amp;gt;
- extra_post_params={'secret': HOMU_BUILDBOT_SECRET},
- File &quot;/usr/local/lib/python2.7/dist-packages/buildbot/status/status_push.py&quot;, line 404, in __init__
- secondaryQueue=DiskQueue(path, maxItems=maxDiskItems))
- File &quot;/usr/local/lib/python2.7/dist-packages/buildbot/status/persistent_queue.py&quot;, line 286, in __init__
- self.secondaryQueue.popChunk(self.primaryQueue.maxItems()))
- File &quot;/usr/local/lib/python2.7/dist-packages/buildbot/status/persistent_queue.py&quot;, line 208, in popChunk
- ret.append(self.unpickleFn(ReadFile(path)))
- exceptions.EOFError:
-
- 2016-01-17 04:35:53+0000 [-] Configuration Errors:
- 2016-01-17 04:35:53+0000 [-] error while parsing config file: (traceback in logfile)
- 2016-01-17 04:35:53+0000 [-] Halting master.
- 2016-01-17 04:35:53+0000 [-] Main loop terminated.
- 2016-01-17 04:35:53+0000 [-] Server Shut Down.
- &lt;/pre&gt;&lt;/div&gt;
- &lt;/div&gt;
- &lt;p&gt;This happened after the buildmaster’s disk filled up and a bunch of stuff was
- manually deleted. There were no changes to master.cfg since it worked
- perfectly.&lt;/p&gt;
- &lt;p&gt;The fix was to examine &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;master.cfg&lt;/span&gt;&lt;/span&gt; to see &lt;a class=&quot;reference external&quot; href=&quot;https://github.com/servo/saltfs/blob/master/buildbot/master/master.cfg#L413&quot;&gt;where the HttpStatusPush was
- created&lt;/a&gt;,
- of the form:&lt;/p&gt;
- &lt;div class=&quot;highlight-python&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'status'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HttpStatusPush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;serverUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://build.servo.org:54856/buildbot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;extra_post_params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'secret'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HOMU_BUILDBOT_SECRET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
- &lt;/div&gt;
- &lt;p&gt;Digging in the Buildbot source reveals that &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;persistent_queue.py&lt;/span&gt;&lt;/span&gt; wants to
- unpickle a cache file from &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;/events_build.servo.org/-1&lt;/span&gt;&lt;/span&gt; if there was nothing
- in &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;/events_build.servo.org/&lt;/span&gt;&lt;/span&gt;. To fix this the right way, create that file
- and make sure Buildbot has &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;+rwx&lt;/span&gt;&lt;/span&gt; on it.&lt;/p&gt;
- &lt;p&gt;Alternately, you can give up on writing your status push cache to disk
- entirely by adding the line &lt;span class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;maxDiskItems=0&lt;/span&gt;&lt;/span&gt; to the creation of the
- HttpStatusPush, giving you:&lt;/p&gt;
- &lt;div class=&quot;highlight-python&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'status'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HttpStatusPush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;serverUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://build.servo.org:54856/buildbot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;maxDiskItems&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
- &lt;span class=&quot;n&quot;&gt;extra_post_params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'secret'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HOMU_BUILDBOT_SECRET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
- &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
- &lt;/pre&gt;&lt;/div&gt;
- &lt;/div&gt;
- &lt;p&gt;The real moral of the story is “remember to use &lt;a class=&quot;reference external&quot; href=&quot;http://www.linuxcommand.org/man_pages/logrotate8.html&quot;&gt;logrotate&lt;/a&gt;.&lt;/p&gt;</description>
- <pubDate>Sat, 16 Jan 2016 08:00:00 +0000</pubDate>
- </item>
- <item>
- <title>Daniel Glazman: Ebook pagination and CSS</title>
- <guid isPermaLink="false">urn:md5:41d039bb28fb15c761578cba0b1454fa</guid>
- <link>http://www.glazman.org/weblog/dotclear/index.php?post/2016/01/16/Ebook-pagination-and-CSS</link>
- <description>&lt;p&gt;Let's suppose you have a rather long document, for instance a book chapter, and you want to render it in your browser &lt;em&gt;à la&lt;/em&gt; iBooks/Kindle. That's rather easy with just a dash of CSS:&lt;/p&gt;
- &lt;pre&gt;body {
- height: calc(100vh - 24px);
- column-width: 45vw;
- overflow: hidden;
- margin-left: calc(-50vw * attr(currentpage integer));
- }&lt;/pre&gt;
- &lt;p&gt;Yes, yes, I know that no browser implements that &lt;code&gt;attr()&lt;/code&gt;extended syntax. So put an inline style on your body for &lt;code&gt;margin-left: calc(-50vw * &lt;em&gt;&amp;lt;n&amp;gt;&lt;/em&gt;)&lt;/code&gt; where &lt;em&gt;&lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt;&lt;/em&gt; is the page number you want minus 1.&lt;/p&gt;
- &lt;p&gt;Then add the fixed positioned controls you need to let user change page, plus gesture detection. Add a transition on margin-left to make it nicer. Done. Works perfectly in Firefox, Safari, Chrome and Opera. I don't have a Windows box handy so I can't test on Edge.&lt;/p&gt;</description>
- <pubDate>Sat, 16 Jan 2016 03:43:00 +0000</pubDate>
- <dc:creator>glazou</dc:creator>
- </item>
- <item>
- <title>Nicolas Mandil: Mozilla cultural revolution: from ‘radical participation’ to ‘radical user-centric’</title>
- <guid isPermaLink="false">https://repeer.org/?p=48</guid>
- <link>https://repeer.org/2016/01/16/mozilla-cultural-revolution-from-radical-participation-to-radical-user-centric/</link>
- <description>&lt;p&gt;This post has been written about the &lt;a href=&quot;http://marksurman.commons.ca/2015/12/21/mofo2020/&quot;&gt;Mozilla Foundation (MoFo) 2020 strategy&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;The ideas developed in this post are in different levels: some are global, some focus on particular points of the proposed draft. But in my point of view, they all carry a transversal meaning: articulation (as piece connected to a structure allowing movement) with others and consistency with our mission.&lt;/p&gt;
- &lt;h3&gt;Summary&lt;/h3&gt;
- &lt;p&gt;On the way to &lt;a href=&quot;http://marksurman.commons.ca/2015/01/09/what-is-radical-participation/&quot;&gt;radical participation&lt;/a&gt;, Mozilla should be radical &lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;https://repeer.org/tag/mozilla/feed/#fn-48-1&quot; id=&quot;fnref-48-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; user-centric. Mozilla should not go against the social understanding of the (tech and whole society) situation because it’s what is massively shared and what polarizes the prism of understanding of the society. &lt;strong&gt;We should built solutions for it and transform (develop and change) it on the way. Our responsibility is to build &lt;em&gt;inclusivity&lt;/em&gt; (inclusion strengths) everywhere, to gather for multiplying our impact.&lt;/strong&gt; We must build (progressive) victories instead of battles (of static positions and postures).&lt;br /&gt;
- If we don’t do it, we go against users self-perceived need: use. We value our differences more than our commonalities and &lt;strong&gt;consider ethic more as an absolute objective than a concrete process&lt;/strong&gt;: we divide, separate, compete. Our solutions get irrelevant, we get rejected and marginalized, we reject compromises that improve the current situation for the ideal, we loose influence and therefore impact on the definition of the present and future. We already done it for the good and the bad in the past (H.264+Daala, pocket integration, Hello login, no Firefox for iOS, Google fishing vs Disconnect, FxOS Notes app which sync is evernote only, …).&lt;br /&gt;
- To get a consistent and impactful ability to integrate and transform the social understanding, there are four domains where we can take and articulate (connected structure allowing movement) action:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;People&lt;/strong&gt;: identity is the key to grow consciousness, understanding, skills, voice, representation and to articulate global/local, personal/common. &lt;strong&gt;[Activate]&lt;/strong&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;Technology&lt;/strong&gt;: universality is key for a platform (for resilience) with interfaces (for modularity) where services, features and front-ends can plug-in and communicate to provide (inter)active support ; Decouple conditions of fulfillment with execution (content/appearance/policy ; material/immaterial) to support remix (policy continuity, consistency thought providers, …). &lt;strong&gt;[Unlock]&lt;/strong&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;Product&lt;/strong&gt;: persona and (current and emerging) use via user-agents are the keys. Be on all major platforms depending on use, ethical alignment and opportunities, emerging newness to provide continuity (task, device) to users and leading on new practices. Features should be about products parity and opening new possibilities carrying our values to the action at a massive scale. &lt;strong&gt;[Build]&lt;/strong&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;Organizations/institutions&lt;/strong&gt;: sociological innovation for participation is the key. Research on historical (evolution) and sociological (human organizations, social institutions and social behaviors) analysis based on social networks (link as social interactions), in the perspective of producing commons. &lt;strong&gt;[Drive]&lt;/strong&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;Our front has two sides: &lt;strong&gt;propose and protect&lt;/strong&gt;. But each of them are connected and can have different strategic expressions, if our actions generate improving (progressive) curves:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;For the &lt;strong&gt;action taking&lt;/strong&gt;: consciousness, understanding, symbolic actions, behavior change, behavior advocacy (evangelism)&lt;/li&gt;
- &lt;li&gt;For the &lt;strong&gt;action mode&lt;/strong&gt;: promotion (spreading the idea), incitement (giving a competitive advantage to people involved), collaboration (open interactions to make a win-win exchange; process-centric), contractualization (formalize domains where a win-win exchange is made; object-centric), coercion (giving a competitive disadvantage to people not involved).&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;Social history is a history of social values.&lt;strong&gt; The way we understand and tell the problem determine the solution we can create&lt;/strong&gt;: we need, all the way long, a shared understanding. Tools and technologies are not tied, bound forever to their social value, which depends on people’s social representations that evolve over time.&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;The social behavior&lt;/strong&gt; is a first key. It is the narrative, and therefore its &lt;strong&gt;inclusion in the social history that we make, which converges the product with the values that it stands for&lt;/strong&gt;. Here is the articulation of product with people and technology, of product with leadership network and advocacy engine (it could be less persistent and inclusive: marketing).&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;The social organization&lt;/strong&gt; is a second key. It is about how the process, the tools, the architecture, the governance and the opportunities/constraints have changed for Mozilla (org) and Mozillians (people). &lt;strong&gt;Here comes the question of being open&lt;/strong&gt;. It is not enough because it is about availability (passive) and not inclusivity (active). The high level of automation coming is a challenge. We should level-up the meaning to differentiate from others: &lt;strong&gt;Mozilla should activate and unlock societal progress to build fair technical progress&lt;/strong&gt;. Mozilla need to &lt;strong&gt;identify its resilient backbone&lt;/strong&gt; (not only a technology, the web, but something that articulate people, technology and products) and make it more universal (through people and products). But our goals can’t be absolutely achieved because they have to be considered in a dynamic context. However, the brand engagement is persistent, if it’s included in the product, visible, and centered on easing the user’s action.&lt;br /&gt;
- Linked to the ‘being open’ question, the advocacy engine could be a thing to unlock societal progress. People are satisfied of narrow hills of choice until they understand it’s not socially neutral. It’s the case with technology: they accept things about technology to be build top-down. &lt;strong&gt;A successful advocacy, even one about technology, is always built bottom-up&lt;/strong&gt;, as its function is to give back the voice to the people, to get them involved, not to make them fulfill our predefined aims. The top-down method is too organization centric and administrative content centric: it can’t massively drive people that are not already committed to the org. It’s usually named advertisement or propaganda. &lt;strong&gt;If we want to have an impact, we should listen to people needs, not tell them to listen to ours&lt;/strong&gt;. People want (first) to be empowered, not to empower an org. We need to have content and user centric (not org and it’s process) tools/platform for advocates and leaders: let’s build the technology advocacy plan together. Yes it’s slower, but much more massive, inclusive and persistent. The impact will be higher because it will carry a meaning for people and it wont be too org centric. So it will be qualitatively better: not just an amount, &lt;strong&gt;accumulation is not our goal, but impact, that comes from articulation&lt;/strong&gt;. Likewise we should be careful to not use best practice as absolute solutions, but as solutions in a context, if we want to transpose them massively: when we unify we should avoid to homogenize. On the narrative side, our preoccupation should be about building short, medium and long term narrative to get action.&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;The social institutions&lt;/strong&gt; are the third key. Here is the articulation of the leadership network with the advocacy engine. &lt;strong&gt;Leaders build new solutions (products) and Advocates new voices (rallying), they are both about personal development and empower commons.&lt;/strong&gt; Leadership=learn+create and advocacy=teach+spread commons. Leaders are projects/orgs leaders, the ones that traduce DNA (values) in products (concrete ability and availability). Advocates are values advocates, the ones that traduce DNA (values) in actions (behavior). As they are both targeting commons, they both produce the same social organization (collaboration instead of competition). They are both involved in creating (different) representations (institutions) and organizations (foundation/firms) but &lt;strong&gt;with a different DNA (values) processing&lt;/strong&gt;: from public good to personal benefit or from personal interest to public benefit. If Mozilla cares about public good resilience, &lt;strong&gt;the articulation of their domains of values is critical&lt;/strong&gt;. So, on the social organization side, their articulation’s expression and the revision process must be said and clear: from hierarchy or contract or different autonomy levels (internal incubation and external advocacy), or … to criteria to start a revision. About the narrative, and hence about the social behavior side, leaders carry a lot of legitimacy and avoid the stay-experimental or non-massive (unique) thoughts. And we need legitimacy to get impact. But this legitimacy is already present if we&lt;strong&gt; make clear that our actions are about commons&lt;/strong&gt;. We should name them creators (compositors or managers) to make it clear that the creative process is a collaboration, made by a team and that the public good do not have the same role in the process and outcome. Full circle.&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;The social networks&lt;/strong&gt; are the keystone. Let’s shortly take an example based on social networks (link as social interactions) with the perspective of producing people, technological and product commons. &lt;strong&gt;We need better tools for collaboration and participation&lt;/strong&gt;: tools that merge discussion channels, capitalize on the discussion and preview the results to build a plan. From evolving the wiki discussion page to feature document production into peer-to-peer discussion.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;An analysis of the creation process is another way to the articulation of product with people and technology.&lt;br /&gt;
- Platforms move closer to strict ‘walled garden’ ecosystems. We need bridges from lab to home that carry different mix of customization and reliability to support the emancipation curve. We need to build pathways thought audiences and thought IT layers (content, software, hardware, distant service). &lt;strong&gt;We should find a convergence between customization&lt;/strong&gt; (dev code patch to users add-ons) &lt;strong&gt;and reliability&lt;/strong&gt; (self made to mass product), &lt;strong&gt;between first time experience, support and add-ons thought all our users’ persona by building bridges, pathways&lt;/strong&gt;. Mozilla should find ways to &lt;strong&gt;integrate learning&lt;/strong&gt; in its products, in-content, as we have code comment on code: on-boarding levels, progression from simple to high level techniques, reproducible/universal next task/skill building.&lt;/p&gt;
- &lt;h3&gt;Detailed discussion content&lt;/h3&gt;
- &lt;p&gt;Here are the developed ideas, with more reference to our allies and detractors’ products.&lt;/p&gt;
- &lt;h4&gt;People, the sociological side&lt;/h4&gt;
- &lt;h5&gt;From focused to systemic action&lt;/h5&gt;
- &lt;p&gt;First of all, I think &lt;strong&gt;the strategy move Mozilla is doing is the right one&lt;/strong&gt; as it embraces more our real life. People are not defined by one characteristic, we are complex: ex. we can be pedestrian, car driver, biker, Public Transport user… we think and do simultaneously. So why Mozilla should restrict its strategy by targeting people on skills, through education, thought better material only (the Mozilla Academy program). Education, even popular education, can’t do everything for the people to build change. &lt;strong&gt;We need a plan that balance intellectual and practical (abstraction/action, think/do) integrating progressive paths to massively scale so we get an impact: build change.&lt;/strong&gt;&lt;/p&gt;
- &lt;h5&gt;Real life: Social history, individuals and institutions as an articulation founding the action.&lt;/h5&gt;
- &lt;p&gt;Let’s start by some definitions based on my understanding of some &lt;a href=&quot;https://fr.wikipedia.org/wiki/Sociologie&quot;&gt;Wikipedia articles&lt;/a&gt;. Sociology is the study of the evolution of societies: human organizations and social institutions. It is about &lt;strong&gt;the impact of the social dimension on humans representations (ways of thinking) and behaviors (ways of acting)&lt;/strong&gt;. It allows to study the conceptions of social relations according to fundamental criteria (structuralism, functionalism, conventionalism, etc.) and the hooks to reality (interactionism, institutionalism, regulationisme, actionism, etc.), to think and shape the modernity. Currently (and this is key for Mozilla’s positioning), the combination of models replace the models’ unity, which aims to assume the multidimensionality. There are three major sociological paradigms, including one emerging:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;The holistic paradigm&lt;/strong&gt;: Society is a whole that is greater than the sum of its parts, it exists before the individual and individuals are governed by it. In this context, the Society includes the individual and the individual consciousness is seen only as a fragment of the collective consciousness. The emphasis is on the social fact, whose cause must be sought in earlier social facts. The social fact is part of a system of interlocking institutions that govern individuals. It is external to the individual and constraint it. Sociology is then the science of institutional invariants in which are the observable phenomenas.&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;The atomistic paradigm&lt;/strong&gt;: each individual is a social atom. The atoms act according to self motives, interests, emotions and are linked to other atoms. A system of constant interaction between atoms produces and reproduces Society. The emphasis is on the cause of social actions and the meaning given by individuals to their actions. A horizon of meanings serve as reference instead of the arrangements of institutions. The institution is there but it serves the motives and interests of agents. Sociology is then the study of the social action.&lt;/li&gt;
- &lt;li&gt;The recent emergence of a sociological analysis based on &lt;strong&gt;social networks&lt;/strong&gt; (which are a collection of individuals or organizations connected by regular social interactions) suggest lines of research &lt;strong&gt;beyond the opposition between the holistic and the atomistic approaches&lt;/strong&gt;. The theory of social networks conceives social relationships in terms of nodes and links. The nodes are usually social actors in the network but can also represent institutions, and links are the relationships between these nodes. There may be several kinds of links between nodes and their analysis determines social capital of the social actors.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;Consequently, Mozilla should build its strategy on &lt;strong&gt;historical&lt;/strong&gt; (evolution) and &lt;strong&gt;sociological&lt;/strong&gt; (human organizations, social institutions and social behaviors) analysis based on &lt;strong&gt;social networks&lt;/strong&gt; (links as social interactions), in the perspective of producing &lt;strong&gt;commons&lt;/strong&gt;. That is to say as an &lt;strong&gt;engine of transition from a model of value&lt;/strong&gt; on its last leg (rarity capitalism) to the emerging one (new articulation of the individual and the collective: commons).&lt;br /&gt;
- It is important and strategic to propose a sociological articulation supporting our mission and its purpose (commons) since &lt;strong&gt;the sociological concept (the paradigm) reveals an ideological characteristic&lt;/strong&gt;: because it participates in societal movements made in the Society, it serves an ideal. The societal domain, what’s making society, a political object, should be a stake for Mozilla.&lt;/p&gt;
- &lt;h5&gt;Build on a basement: current tech challenge articulated with current social meaning/perception&lt;/h5&gt;
- &lt;p&gt;&lt;strong&gt;We should articulate ‘our real life’ with the nowadays tech challenge&lt;/strong&gt;: how to get back control over our data at the time of IoT, cloud, big data, convergence (multi-devices/form factor)? From a user point of view, we have devices and want them convenient, easy and nice. The big moves in the tech industry (IoT, cloud, big data, convergence) free us for somethings and lock us for others. The lock key is that our devices don’t compute anymore our data that are in silos. From a developer point of view, the innovation is going very fast and it’s hard to have a complete open source toolbox that we can share, mostly because we don’t lead: Open has turn to be more open-releasing.&lt;br /&gt;
- We should articulate our new strategy with the tech industry moves: for example, &lt;strong&gt;as a user, how can I get (email) encryption on all my devices?&lt;/strong&gt; Should I follow (fragmented) different kind of howtos/tools/apps to achieve that? How do I know these are consistent together? How can I be sure it won’t brake my continuous workflow? (app silo? social silo? level of trust and reliability?)&lt;br /&gt;
- Mozilla have the skills to answer this as we already faced and solved some of these issues on particular points: like how to ease the installation of Firefox for Android for Firefox desktop users, open and discoverable choice of search engines, synchronization across devices, …&lt;br /&gt;
- &lt;strong&gt;Mozilla’s challenge is to not be marginalized by the change of practices. Having an impact is embracing the new practice and give it an alternative.&lt;/strong&gt; Mozilla already made that move by saying « &lt;em&gt;Firefox will go where users are&lt;/em&gt;« , by trying to balance the advertisement practice between adds companies and users, by integrating H.264 and developing Daala. But &lt;strong&gt;Mozilla never stated that clearly as a strategy&lt;/strong&gt;.&lt;/p&gt;
- &lt;h5&gt;A backbone to make our mission resilient in it expressions&lt;/h5&gt;
- &lt;p&gt;If we think about the &lt;strong&gt;Facebook’s strategy, they first built a network of people whiling to share&lt;/strong&gt; (no matter what they share) and then use this &lt;strong&gt;transversal backbone to power vertical business segments&lt;/strong&gt; (search, donation, local market selling, …). Google with its search engine and its open source policy have a similar (in a way) strategy. The difference here is that the backbone is people’s data and control over digital formats. In both cases, the level of use (of the social network, search engine, mobile OS, …) is the key (with fast innovation) to have an impact. And that’s a major obstacle to build successful alternatives.&lt;br /&gt;
- The proposed Mozilla’s strategy is built in the opposite way, and that’s questioning. &lt;strong&gt;We try to build people network depending on some shared matters&lt;/strong&gt;. Then, is our strategy able to scale enough to compete against GAFAM, or are we trying to build a third way ?&lt;br /&gt;
- For the products, the Mozilla’s strategy is still (and has always been) inclusive: everybody can use the product and then benefit of its open web values. A good product that answer people needs, plus giving people back/new power (allow new use) build a big community. For the network, should we build our global force of people based on concentric circles (of shared matters) or based on a (Mozilla own) transversal backbone (matter agnostic)? It seems to me the actual presentation of the strategy do not answer clearly enough this big question: &lt;strong&gt;which &lt;em&gt;inclusivity&lt;/em&gt; (inclusion strengths) mechanism in the strategy?&lt;/strong&gt;&lt;br /&gt;
- And that &lt;strong&gt;call back to our product strategy&lt;/strong&gt;: build a community that shares values, that is used to spread outcomes (product) OR build a community that shares a product, that is used to spread values. This is not a question on what matters more (product VS values) but on the strategy to get to a point, an objective (many web citizens). Shouldn’t we use our product to built a people network backbone ? Back to GAFAM: what can we learn from the Google try with Google+?&lt;br /&gt;
- If our core is not enough transversal (the backbone), more new web/tech market there will be, more we will be marginalized, because focused on our circles center not taking in account that the war front (the context) have changed. &lt;strong&gt;Mozilla have to be resilient: mutability of the means, stability in the objectives.&lt;/strong&gt;&lt;br /&gt;
- The document is the MoFo strategy, and so it doesn’t say anything about ‘build Firefox’ (aka the product strategy) and so don’t articulate our main product (Firefox) with our main people network building effort and values sharing engine. We should do it: at a strategic scale and a particular scale (articulating the agenda-setting with main product features).&lt;/p&gt;
- &lt;h5&gt;Brand engagement, a psychological backbone on the user side ?&lt;/h5&gt;
- &lt;p&gt;It seems that our GAFAM challengers get big and have impact by not educating (that much) people, and that’s what makes them not involved in the web citizenship. Or only when they are pushed by their customers. At the opposite, making people aware about web citizenship at first, makes it hard to have that much people involved and so to have impact. However, there is &lt;strong&gt;an other prism that drive people: the brand perceived values&lt;/strong&gt;. Google is seen as a tech pioneer innovator and doing the good because of its open policy, free model, fast innovation… Facebook is seen as really cool firm trying to help people by connecting them…&lt;br /&gt;
- Is the increase of marketing of Mozilla doing good enough to gains back users ? Is this resilient compared to the next-tech-thing coming ?&lt;br /&gt;
- Most of the time when I meet Goggle Chrome users and ask then why they use it and don’t switch to Firefox, they answer about use allowed (sync thought devices, apps everywhere that run only on GC, …). Sometimes, they argue that they make effort on other areas, and that they want to keep they digital life simple. They &lt;strong&gt;experience is not centered in a product/brand, but more on the person&lt;/strong&gt;: on that Google Chrome with its Person (with one click ‘auto-login’ to all Google services) is far superior than Firefox.&lt;/p&gt;
- &lt;h5&gt;User-agent or products ?&lt;/h5&gt;
- &lt;p&gt;A user-agent is an intermediary acting on behalf of a supplier. As a representative, it is the contact point with customers; It’s role is to manage, to administer the affairs; it is entrusted with a mission by one or more persons; it both acts and produce an effect.&lt;br /&gt;
- So, the user-agent can be describe with three criteria. It is: an intermediate (user/technology) ; a tool (used to manage and administrate depending on the user’s skills) ; a representative (mission bearer, values vector, for a group of people). It exceeds partly the contradiction between being active and passive.&lt;br /&gt;
- A &lt;strong&gt;user-agent articulate personal-identity with technology-identity&lt;/strong&gt; and give informations about available skills over these domains. It’s much more universal than a product that is about featuring a user-agent. &lt;strong&gt;If we target resilience, user-agent should be the target&lt;/strong&gt;.&lt;/p&gt;
- &lt;h4&gt;Social history, marketing: how we understand things to make choices&lt;/h4&gt;
- &lt;h5&gt;History of the social value&lt;/h5&gt;
- &lt;p&gt;The way we look at the past and current facts shape our understanding and determine if we open new ways to solve the issues identified. That’s the way to understand the challenges that come on the way and to agree on an adaptation of the strategy instead of splitting things. The way we understand and tell the problem determine the solution we can create: we need, all the way long, &lt;strong&gt;a shared understanding.&lt;/strong&gt;&lt;br /&gt;
- &lt;strong&gt;Tools and technologies are not necessarily tied to their social value, which depends on social representations. The social value can be built upstream and evolve downstream.&lt;/strong&gt; It also depends on the perspective in which we look at it, on the understanding of the action and therefore on past or current history. Example: the social value of a weapon can be a potential danger or defense, creative (liberating) or destructive. The nuclear bomb is a weapon of mass destruction (negative), whose social value was (ingeniously built as) freedom (positive).&lt;/p&gt;
- &lt;h5&gt;Impact in our strategy: a missing root&lt;/h5&gt;
- &lt;p&gt;To engage the public, before to « &lt;em&gt;Focus on creative campaigns that use media + software to engage the public.&lt;/em&gt; » we need to step back, in our speeding world, for understanding together the big picture and the big movement.&lt;br /&gt;
- Mozilla want to fuel a movement and propose a strong and consistent strategy. However, I think &lt;strong&gt;this plan miss a key point, a root point: build a common (hi)story.&lt;/strong&gt; This should be an objective, not just an action.&lt;br /&gt;
- Also, that’s maybe a missing root for the State of the web report: how do we understand what we want to evaluate? But it’s not only a missing root for an (annual?) report (a ‘Reporters without borders’ Press-Freedom like?), it’s a missing root for a new grow of our products’ market share.&lt;br /&gt;
- For example, I do think that most users don’t know and understand that Mozilla is a foundation, Firefox build by a community as a product to keep the web healthy: &lt;strong&gt;they don’t imagine any meaning about technology&lt;/strong&gt;, because they see it as a neutral tool at its root, so as a tool that should just fit they producing needs.&lt;br /&gt;
- Firefox, its technologies and its features are not bound for ever. It is the narrative, and therefore their inclusion in the social history that we make, which converges Firefox with the values that it stand for. &lt;strong&gt;Stoping or changing the deep narrative means cutting the source of common understanding and making stronger other consistencies captured by other objects, turning as centrifugal forces for Firefox.&lt;/strong&gt;&lt;br /&gt;
- Marketing is a way to change what we socially say about things: that’s why Google Chrome marketing campaign (and consistent features maturity) has been the decreasing starting point of Firefox. &lt;strong&gt;Our message has been scrambled.&lt;/strong&gt;&lt;/p&gt;
- &lt;h4&gt;From participation to emancipation: values, people and org relationships&lt;/h4&gt;
- &lt;p&gt;How to emancipate people in the digital world ?&lt;/p&gt;
- &lt;h5&gt;Keeping the open open&lt;/h5&gt;
- &lt;p&gt;Being open is not a thing we can achieve, it’s a constant process. « &lt;em&gt;Mozilla needs to engage on both fronts, tackling the big problems but also fuelling the next wave of open.&lt;/em&gt; » Yes, but &lt;strong&gt;Mozilla should say too how the next wave of open can stay under people’s control and rally new people&lt;/strong&gt;. Not only open code, but open participation, open governance, open organization. Being open is not a releasing policy about objects, it’s a mutation to participation process: a metamorphosis. It’s not reached by expanding, but by shifting. It’s not only about an amount, but about values: it’s qualitative.&lt;br /&gt;
- Maybe &lt;strong&gt;open is not enough&lt;/strong&gt;, because it doesn’t say enough about who control and how, about the governance, and says too much about &lt;strong&gt;availability (passive)&lt;/strong&gt; and not enough &lt;strong&gt;about &lt;em&gt;inclusivity&lt;/em&gt; (active ; inclusion strengths)&lt;/strong&gt;. It doesn’t say how the power is organized and articulated to the people (ex. think about how closed is the open Android). We may need to change the wording: indie web, the web that fuel autonomy, is a try, but it doesn’t say enough about &lt;em&gt;inclusivity&lt;/em&gt; compared to openness &amp;amp; opportunity. Emancipation is the concept. It’s strategic because it says what is aligned to what, especially how to articulate values and uses. It’s important because it tells what are the sufficient conditions of realization to ‘open/indie’. That’s key to get ‘open/indie at small and large scales, from Internet people to Internet institutions, thought all ‘open/indie’ detractors in the always-current situation: a resilient ecosystem.&lt;br /&gt;
- My intuition is that &lt;strong&gt;the leadership network and advocacy engine promoting open will be efficient if we clarify ‘open’ while keeping it universal&lt;/strong&gt;. We can do it by looking back at the raw material that we have worked for years, our DNA in action. Because after all, we are experts about it and wish others to become experts too. It does not mean to essentialize it (opposing its nature and its culture), &lt;strong&gt;but to define its conditions of continuous achievement in our social context&lt;/strong&gt;.&lt;/p&gt;
- &lt;h5&gt;Starting point: exemplary projects that tell a lot about the evolution of our DNA in action&lt;/h5&gt;
- &lt;p&gt;Clarifying the idea of ‘open’ is strategic to our action because it outlines the constitution of ‘open’, its high ‘rules’, like with laws in political regimes. It clarifies for all, if you are part of it or not, and it tells you what to change to get in. It can reinforce the brand by differentiating from the big players that are the GAFAM: &lt;strong&gt;it’s a way to drive, not to be driven by others lowering the meaning to catch the social impact. We should say that ‘open’ at Mozilla means more than ‘open’ at GAFAM&lt;/strong&gt;. I wish Mozilla to speak about its openness, not as an ‘equal in opportunity’ but as an ‘equal in participation’, because it fits openness not only for a moment (on boarding) or for a person, but during the whole process of people’s interaction.&lt;br /&gt;
- &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; and &lt;a href=&quot;https://servo.org/&quot;&gt;Servo&lt;/a&gt; or &lt;a href=&quot;https://firefoxos.mozilla.community/&quot;&gt;Firefox OS&lt;/a&gt; (since the Mozilla’s shift to radical participation) seem to be very good examples of projects with participation &amp;amp; impact centric rules, tools, process (RFC, new team and owners, …). Think about how Rust and &lt;a href=&quot;http://arc.applause.com/2015/03/27/google-dart-virtual-machine-chrome/&quot;&gt;Dart emerged and are evolving&lt;/a&gt;. Think about how stronger has been the locked-open Android with partnership than the open-locked FxOS. We should tell those stories, not as recipes that can be reproduced, but as process based on a Constitution (inclusive rules) that make a political regime (open) and define a mode of government (participation). That’s key to social understanding and therefore to transpose and advocate for it.&lt;br /&gt;
- As projects&lt;strong&gt; compared to ‘original Mozilla’, Rust, Servo and FxOS could say a lot&lt;/strong&gt; about how different they implemented learning/interaction/participation at the roots of the project. How the process, the tools, the architecture, the governance and the opportunities/constraints have changed for Mozilla and participants. This could definitely help to setup our curriculum resources, database and workshop at a personal (e.g., “How to teach / facilitate / organize / lead in the open like Mozilla.â€) and orgs levels, with personal and orgs policies.&lt;/p&gt;
- &lt;h5&gt;Spreading the high meanings in our strategy to consolidate it consistency&lt;/h5&gt;
- &lt;p&gt;Clarifying the constitution of ‘open’ calls to clarify other related wordings.&lt;br /&gt;
- I’m satisfied to read back (social) ‘movement’ instead of ‘community’, because it means that our goal can’t be achieve forever (is static), but we should protect it by acting. And it seems more inclusive, less ‘folds on itself’ and less ‘build the alternative beside’ than ‘community’: the alternative can be everywhere the actual system is. It can make a system. It can get global, convergent, continuous, … all at the same time. Because it’s roots are decentralized _and_ consistent, collaborating, …&lt;/p&gt;
- &lt;p&gt;About participation, we should think too (again) about engagement VS contribute VS participate: how much am I engaged ? Free about defining and receiving cost/gains? What is the impact of my actions ? … &lt;strong&gt;These different words carry different ideas about how we connect the ‘open’&lt;/strong&gt;: spread is not enough because it diffuses, _be_ everywhere is more permanent. Applied to Mozilla’s own actions, &lt;strong&gt;funding open projects and leaders, is maybe not enough and there should be others areas where we can connect&lt;/strong&gt; inside products, technology, people and organizations that build emancipation. So that say something about getting control (who, how, …).&lt;/p&gt;
- &lt;h5&gt;IA: a challenge for ‘open’&lt;/h5&gt;
- &lt;p&gt;IA is first developed to help us by improving our interactions. However, this seems to start to shift into taking decisions instead of us. This is problematic because these are indirect and direct ways for us to loose control, to be locked. And that can be as far as computers smarter than humans. The problem is that technical progress is made without any consideration of the societal progress it should made.&lt;br /&gt;
- That’s an other point, why open is not enough: automation should be build-in with superior humanization. &lt;strong&gt;Mozilla should activate and unlock societal progress to build fair technical progress.&lt;/strong&gt;&lt;/p&gt;
- &lt;h5&gt;Digital integration &amp;amp; democracy&lt;/h5&gt;
- &lt;p&gt;The digital (&amp;amp; virtual) world is gaining control over the physical world in many domains of our society (economy to finance, mail to email, automatic car, voting machine, …). It’s getting more and more integrated to our lives without getting back our (imperfect) democracy integrated into them. Public benefit and public good are turning ‘self benefit’ and ‘own sake’ because citizens don’t have control over private companies. &lt;strong&gt;We should build a digital democracy if we don’t want to loose at all the democratic governing of society.&lt;/strong&gt; We must overcome the poses and postures battles about private and public. We need to build.&lt;/p&gt;
- &lt;h4&gt;‘Leader’ &amp;amp; ‘Leadership’ need a clarification&lt;/h4&gt;
- &lt;h5&gt;Why a clarification?&lt;/h5&gt;
- &lt;p&gt;At some level, I’m not the only one to ask this question:&lt;/p&gt;
- &lt;blockquote&gt;&lt;p&gt;How do CRM requirements for Leadership and Advocacy overlap / differ? What’s our email management / communications platform for Leadership?&lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;Connect leaders to lead what ? How ? To whose benefit ? Do we want to connect leaders or initiatives (people or orgs) ? Will the leaders be emerging ones (building new networks) or established ones (use they influence to rally more people)? Are Leaders leaders of something part of Mozilla (like can be Reps) or outside of Mozilla (leaders of project, companies, newspaper: tech leaders, news leaders, …) ? This is especially important depending on what is the desire for the leaders to become in the future. &lt;strong&gt;The MoFo’s document should be more precise&lt;/strong&gt; about this and go forward than « &lt;em&gt;Mozilla must attract, develop, and support a global network of diverse leaders who use their expertise to collaboratively advance points-of-view, policies and practices that maintain the overall health of the Internet.&lt;/em&gt; »&lt;br /&gt;
- We should do it because &lt;strong&gt;the confusion about the leadership impact the advocacy engine&lt;/strong&gt;: « &lt;em&gt;The shared themes also provide explicit opportunities for our Leadership and Advocacy efforts to work together.&lt;/em&gt; » Regarding Mozilla, is the leaders role to be advocacy leaders ? It seems as they share themes and key initiatives (even if not worded the same sometimes). Or in other words, who Drives the Advocacy engine?&lt;/p&gt;
- &lt;h5&gt;Iterations with the actual definition: creators&lt;/h5&gt;
- &lt;p&gt;Here are my iterations on the definition of ‘Leaders’:&lt;/p&gt;
- &lt;ul&gt;
- &lt;li&gt;The Leaders could be the people platform (the community) and the advocacy engine the tool/themes/actions platform (the product).&lt;/li&gt;
- &lt;li&gt;Leaders could build at the end new solutions (products) and Advocates new voices (rallying), that could be translated in a learning area divided like Leadership=learn+create and advocacy=teach+spread.&lt;/li&gt;
- &lt;li&gt;Leadership: personal development to produce (turn into) new commons or add new facets to commons. Advocacy: personal development to protect established/identified commons.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;p&gt;With these definitions, then Leaders are maybe more a Lab, R&amp;amp;D place, incubation tool (if we think about start-up incubators, then it shows a tool-set that we will need to inspire for the future). But if we want to keep the emphasis on people, &lt;strong&gt;we could name them ‘creators’&lt;/strong&gt; (compositors or managers ; not commoners, because leaders and advocates are commoners ; yes, traditionally creators are craftspersons and intellectual designers). This make sens with the examples given in the MoFo 2020 strategy 0.8 document, where all persona are involved in a building-something-new process.&lt;/p&gt;
- &lt;p&gt;However, it’s interesting to understand why we choose at first ‘Leaders’. &lt;strong&gt;Leaders build new solutions (products) and Advocates new voices (rallying), they are both about personal development and empower commons.&lt;/strong&gt; Leadership=learn+create and advocacy=teach+spread commons. Leaders are projects/orgs leaders, the ones that traduce DNA (values) in products (concrete ability and availability). Advocates are values advocates, the ones that traduce DNA (values) in actions (behavior). As they are both targeting commons, they both produce the same social organization (collaboration instead of competition). They are both involved to create (different) representation (institutions) and organization (foundation/firms) but &lt;strong&gt;with a different DNA (values) processing&lt;/strong&gt;: from public good to personal interest or the opposite. If Mozilla cares about public good resilience, &lt;strong&gt;the articulation of they domains of values is critical. So their articulation’s expression and the revision process must be said and clear&lt;/strong&gt;: from hierarchy vs contract vs different autonomy levels (internal incubation and external advocacy), vs … to criteria to start a revision.&lt;/p&gt;
- &lt;h5&gt;The network effect&lt;/h5&gt;
- &lt;p&gt;Another argument for the switch from Leader to Creator is that the Leader word it too much tight to a single-person-made innovation. &lt;strong&gt;Creator make more clear that the innovation is possible not because of one genius, but because of a team&lt;/strong&gt;, a group, a collective: personS (where there could also be genius). The value is made by the collaboration of people (especially in an open project, especially in a network).&lt;br /&gt;
- That’s important because that could impact how well we do the convening part: not self-promoting, not-advertising, but sharing skills and knowledge for people and catalysing projects.&lt;br /&gt;
- &lt;strong&gt;The same for the wording ‘talent’&lt;/strong&gt;: alone, a talent can do nothing that has an impact. At least, we need two talents, a team (plus some assistants at some point).&lt;/p&gt;
- &lt;h5&gt;The cultural prism&lt;/h5&gt;
- &lt;p&gt;Again, this seems to be an open question:&lt;/p&gt;
- &lt;blockquote&gt;&lt;p&gt;Define and articulate “leadership.†Hone our story, ethos and definition for what we mean by “leadership development†(including cultural / localization aspects).&lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;In my culture, Leader carry positive (take action) and negative (dominate) meanings. That’s another reason why I prefer another naming.&lt;br /&gt;
- I understand too that it carries a lot of legitimacy (ex. market leader) in our societies and it avoids the stay-experimental or non-massive (unique) thoughts. And we need legitimacy to get impact.&lt;br /&gt;
- But the way Mozilla has an impact thought all cultures, its &lt;strong&gt;legitimacy, is by creating or expanding a common&lt;/strong&gt;. To do this, depending on the maturity, Mozilla could follow the market proposing an alternative with superior usability OR opening a new market by adding a vertical segment.&lt;/p&gt;
- &lt;h5&gt;Existing tool-set opportunities&lt;/h5&gt;
- &lt;p&gt;If Leadership is « &lt;em&gt;a year-round MozFest + Lab&lt;/em&gt;« , so it’s a social network + an incubation place. Then, we already have a social network for people involved with Mozilla: Which kind of link should have the leadership network with &lt;strong&gt;mozillians.org&lt;/strong&gt; ? What can we learn from this project and other specialized social network projects (linkedin, viadeo, …) to build the leadership network ?&lt;/p&gt;
- &lt;h4&gt;Advocacy engine: make it clear&lt;/h4&gt;
- &lt;h5&gt;What it is &amp;amp; how it works&lt;/h5&gt;
- &lt;p&gt;Mozilla is doing a great effort to build its advocacy engine on collaboration (« &lt;em&gt;Develop new partnerships and build on current partnerships&lt;/em&gt;« , « &lt;em&gt;begin collaboration&lt;/em&gt;« , « &lt;em&gt;build alliances with similar orgs&lt;/em&gt;« ) but at the same time affirms that Mozilla should be « &lt;em&gt;Part of a broader movement, be the boldest, loudest and most effective advocates&lt;/em&gt; » that could be seen as too centralized, too exclusive.&lt;br /&gt;
- While this can be consistent (or contradictory), &lt;strong&gt;the consistency has to be explained&lt;/strong&gt; looking at orgs and people, global and local, abstract and real, with a complementarity/competitive grid.&lt;br /&gt;
- First, &lt;strong&gt;the articulation with other orgs has to be explained&lt;/strong&gt;. What about others orgs doing things global (&lt;a href=&quot;https://eff.org/&quot;&gt;EFF&lt;/a&gt;, &lt;a href=&quot;https://fsf.org/&quot;&gt;FSF&lt;/a&gt;, …) and local (&lt;a href=&quot;http://www.laquadrature.net/&quot;&gt;Quadrature du net&lt;/a&gt;, CCC, …) ? What about the value they give and that Mozilla doesn’t have (juridic expertise for example) ? What about other advocate engines (&lt;a href=&quot;https://change.org/&quot;&gt;change.org&lt;/a&gt;, &lt;a href=&quot;https://secure.avaaz.org/&quot;&gt;Avaaz&lt;/a&gt;…) ? That should not be at an administrative level only like « &lt;em&gt;Develop an affiliate policy. Defining what MoFo does / does not offer to effectively govern relationships w. affiliated partners and networks (e.g., for issues like branding, fundraising, incentives, participation guidelines, in-kind resources.)&lt;/em&gt; »&lt;br /&gt;
- Second, this is key for users to understand and &lt;strong&gt;articulate the global level of the brand engagement and their local preoccupations and engagement&lt;/strong&gt;. How the engine will be used for local (non-US) battles ? In the past Mozilla totally involved against PIPA, SOPA by taking action, and hesitate a lot to take position and just published a blog post (and too late to gain traction and get impact) against French spying law for example.&lt;br /&gt;
- Third, &lt;strong&gt;the articulation ‘action(own agenda)/reaction’ should be clarified&lt;/strong&gt; in the objectives and functioning of the advocacy engine. Especially because other orgs, allies or detractors, try to to setup the social agenda. It’s important because it can change the social perception of our narrative (alternative promotion/issue fighting) and therefore people’s contributions.&lt;br /&gt;
- People think the technology is socially neutral. People are satisfied of narrow hills of choice (not the meaning, the aim, but only the ability to show your favorite avatar). &lt;strong&gt;People don’t want to feel guilty or oppressed&lt;/strong&gt;, they don’t want new constraints, they are looking for solution only: they want to use, not to do more, they want they things to be done. Part of the problem is about understanding (literacy, education), part of it is about the personal/common duality, part of it is about being hopeless about having an impact, part of it is about expressing change as a positive goal and a new possible way (alternative), not a fight against an issue. About the advocacy engine, I think &lt;strong&gt;our preoccupation should be people-centric and the aim to give them a short, medium and long term narrative to get action without being individuals-centric&lt;/strong&gt;.&lt;/p&gt;
- &lt;h5&gt;How we build it ?&lt;/h5&gt;
- &lt;p&gt;How to build a social movement ? How it has been built in the past ? Is it the same today ? Can it be transposed to the digital domain from others social domains ? How strong are the cultural differences between nations? These are the main questions we should answer, and our pivot era gives us many examples in diverse domains (climate change advocates, Syriza &amp;amp; Podemos, NSA &amp;amp; surveillance services in Europe, empowered syndicates in Venezuela, &lt;a href=&quot;http://blogs.valvesoftware.com/economics/why-valve-or-what-do-we-need-corporations-for-and-how-does-valves-management-structure-fit-into-todays-corporate-world/#more-252&quot;&gt;Valve corp. internal organization&lt;/a&gt;…) to set a search terrain. However, I will go strait to my intuitive understanding below.&lt;br /&gt;
- I’m kind of worried that it’s imagined to build the advocacy engine themes by a top-down method. &lt;strong&gt;I think a successful advocacy is always built bottom-up&lt;/strong&gt;, as its function is to give back the voice to the people, to get them involved, not to make them fulfill our predefined aims. The top-down method is too organization centric: it can’t massively drive people that are not already committed to the org. It’s usually named advertisement or propaganda. If we want to have impact, &lt;strong&gt;we should listen to people needs, not tell them to listen to ours. People want (first) to be empowered, not to empower an org&lt;/strong&gt;. So let’s organize the infrastructure, set the agenda and draw the horizon (strategic understanding) participative: make people fill them with content of their experience. It seems to me it is the only way, the only successful method, if we want to build a movement, and not just a shifting moment (that could be built by the top, with a good press campaign locally relayed for example ; that’s what happen in old style politics: the aim is short term, to cleave).&lt;br /&gt;
- &lt;strong&gt;Isn’t the advocacy engine a new Drumbeat ?&lt;/strong&gt; We shifted from Drumbeat to Webmaker+web literacy to Mozilla Academy and now to Leadership plus advocacy: it could be good to tell that story now that we are shifting again and learn from it.&lt;br /&gt;
- &lt;strong&gt;Mozilla should support, behave as a platform&lt;/strong&gt;, not define, not focus. Letting the people set the agenda makes them more involved and is a good way to build a network of shared aims with other orgs, that is not invasive or alienating, but a support relationship in a win-win move. The strength comes from the all agendas sewed. So at an org level, let’s on-board allies organizations as soon as plan building-time (now), to build it together. Yes it’s slower, but much more massive, inclusive and persistent.&lt;/p&gt;
- &lt;h5&gt;How we evaluate it: cultural bias &amp;amp; qualitative analysis&lt;/h5&gt;
- &lt;p&gt;First, about the agenda-setting KPI for 2016, should these KPI be an evaluation of the inclusion and rank in others strategic agendas, governance systems and productions (outcome/products) ? Others org could be from different domains: political, social, economy orgs.&lt;br /&gt;
- Then, as a wide size audience KPI, Mozilla wants « &lt;em&gt;celebration of our campaigns with ‘headline KPIs’ including number of actions, and number of advocates.&lt;/em&gt;« . While doing this could be the right thing to do for some cultures, it could be the worst for others. I think that these KPI don’t carry a meaning for people and are too org centric. In a way, they are to generic: it’s just an amount. &lt;strong&gt;Accumulation is not our goal: we want impact that is the grow of articulated actions&lt;/strong&gt; made by diverse people toward the same aim. &lt;strong&gt;We need our massive KPI to be more qualitative&lt;/strong&gt;, or at least find a way to present them in a more qualitative way: interactive map ? a global to local prism that engages people for the next step ?&lt;/p&gt;
- &lt;h5&gt;Best practices &amp;amp; massive impact&lt;/h5&gt;
- &lt;p&gt;Selecting best practices are an appealing method when we want to have a fast and strong impact in a wide area. However, &lt;strong&gt;when we unify we should avoid to homogenize&lt;/strong&gt;. The gain in area by scaling-up is always at the cost of loosing local impact because it is not corresponding to local specificities, hence to local expectations. Federating instead of scaling-up is a way to solve this challenge. So we should be careful to not &lt;strong&gt;use best practice as absolute solutions, but as solutions in a context&lt;/strong&gt; if we want to transpose them massively.&lt;/p&gt;
- &lt;h5&gt;Tools &amp;amp; platform balanced between user-centric and org-centric outcomes&lt;/h5&gt;
- &lt;p&gt;It’s good to hear that we will build a advocacy platform. As we ‘had’ bugzilla+svn then mercurial (hg)+… and are going to the &lt;strong&gt;integrated&lt;/strong&gt;, &lt;strong&gt;pluggable&lt;/strong&gt; and &lt;strong&gt;content-centric&lt;/strong&gt; (but non-free; admin tools are closed source) github (targeting more coder than users, but with a lower entry price for users still), we need to be able to have the same kind of tool for advocates and leaders. Something inspired maybe at some levels by the remixing tools we built in Webmakers for web users.&lt;/p&gt;
- &lt;h4&gt;From experiment to production: support (self made to mass product) + modularity (dev code patch to users add-ons).&lt;/h4&gt;
- &lt;p&gt;&lt;strong&gt;We need pathways from lab to home that carry different mix of customization and reliability to support the emancipation curve.&lt;/strong&gt;&lt;br /&gt;
- Users want things to work, because they want to use it. Geeks want to be able to modify a lot and accept to put their hands in the engine to build growing reliability. Advanced users want to customize their experience and keep control and understanding on working status. They want to be able to fix the reliability at a medium/low technical cost. They are OK to gain more control at these prices. Users want to use things to do what they need and want to trust a reliability maintained for them. They are OK to gain control at a no technical cost. Depending on the matter we all have different skill levels, so we are all geeks, advanced users and users depending on our position or on the moment. And depending on our aspirations, we all want to be able to move from one category to an other. That’s what we need to build: we don’t just need to « &lt;em&gt;better articulate the value to our audiences&lt;/em&gt;« , &lt;strong&gt;we need to build pathways thought audiences and thought IT layers&lt;/strong&gt; (content, software, hardware, distant service). &lt;strong&gt;We should find a convergence between customization and reliability, between first time experience, support and add-ons thought all our users’ persona by building bridges, pathways&lt;/strong&gt;. So, « &lt;em&gt;better articulate the value to our audiences&lt;/em&gt; » should not be restrained in our minds to the Mozilla Leadership Network.&lt;br /&gt;
- &lt;strong&gt;Part of this is being done in other projects outside of Mozilla in the commons movement.&lt;/strong&gt; There are many, but let’s take just one example, the &lt;a href=&quot;https://www.fairphone.com/&quot;&gt;Fairphone&lt;/a&gt; project: modularity, howtos, … all this help to break the product-to-use walls and drive appropriation/emancipation. &lt;strong&gt;Products are less product and brand centric and more people/user centric&lt;/strong&gt;.&lt;br /&gt;
- Part of this has been done inside Mozilla, like integrating learning in our products, in-content, as we have code comment on code. I think &lt;strong&gt;the &lt;a href=&quot;https://wiki.mozilla.org/Firefox_OS/Spark&quot;&gt;Spark&lt;/a&gt; project on Firefox OS is on a promising path&lt;/strong&gt;, even if maybe immature: it maybe has not been released mainstream because it misses bridges/pathways (on-boarding levels, progression from simple to high level techniques, and no or not enough reproducible/universal next task/skill building).&lt;br /&gt;
- So some solutions start to emerge, the direction is here, but has never been conceived and implemented that globally, as there isn’t integrated pathways with choice and opportunity and a strategy embracing all products and technologies (platform, tools, …).&lt;/p&gt;
- &lt;h4&gt;Better tools for collaboration and participation: task-centric to process-centric (use) infrastructure&lt;/h4&gt;
- &lt;p&gt;&lt;strong&gt;The open community should definitely improve the collaboration tools and infrastructure to ease participation.&lt;/strong&gt;&lt;br /&gt;
- &lt;strong&gt;&lt;a href=&quot;http://www.discourse.org&quot;&gt;Discourse&lt;/a&gt; ‘merged’ discussion channels&lt;/strong&gt;: email+forum(+instant, messaging, … and others peer-to-peer discussion?). &lt;strong&gt;&lt;a href=&quot;http://stackexchange.com&quot;&gt;Stack exchange&lt;/a&gt; merged the questioning/solving process&lt;/strong&gt; and added a vote mechanism to rank answers: it eased the collaboration on editing the statement and the results while staying synchronous with the discussion and keeping the discussion history. We need such kind of possibilities with discourse: &lt;strong&gt;capitalize on the discussion and preview the results to build a plan.&lt;/strong&gt;&lt;br /&gt;
- This exist in document oriented software (that added collaboration editing tools), but not that much in collaboration software (that don’t produce documents). For example, while discussing the future plan for Fx/FxOS be supported to keep track on a doc about the proposals plans + criteria &amp;amp; dependencies. In action, it is from &lt;a href=&quot;https://mail.mozilla.org/pipermail/firefox-dev/2015-July/003063.html&quot;&gt;this&lt;/a&gt; plus all the discussion taking place to &lt;a href=&quot;https://mail.mozilla.org/pipermail/firefox-dev/2015-July/003119.html&quot;&gt;that&lt;/a&gt;.&lt;br /&gt;
- This is maybe something like integrating Discourse+Wiki, maybe with the need to have competing and ranked (both for content and underlaying meaning of content=strategy?) plan/page proposals. &lt;strong&gt;From evolving the wiki discussion page to featuring document production into peer-to-peer discussion.&lt;/strong&gt;&lt;/p&gt;
- &lt;h4&gt;A recovering strategy: from fail to win&lt;/h4&gt;
- &lt;p&gt;There is maybe one thing that is in the shadow in this plan: &lt;strong&gt;what do we do when/if we (partially) fail ?&lt;/strong&gt;&lt;br /&gt;
- I think at least we should say that &lt;strong&gt;we document&lt;/strong&gt; (keep research going on) to be able to outline and spread the outcomes of what we tried to fight against. So we still try to built consciousness to be ready for the next round.&lt;/p&gt;
- &lt;p&gt; &lt;/p&gt;
- &lt;p&gt;&lt;em&gt;If you see some contradiction in my thoughts, let’s say it’s my state of thinking right now: please voice them so we can go forward.&lt;/em&gt;&lt;br /&gt;
- &lt;em&gt; The same for thoughts that are voiced definitive (like users are): take it as a first attempt with my bias: let’s state these bias to go forward.&lt;/em&gt;&lt;/p&gt;
- &lt;div class=&quot;footnotes&quot; id=&quot;footnotes-48&quot;&gt;
- &lt;div class=&quot;footnotedivider&quot;&gt;&lt;/div&gt;
- &lt;ol&gt;
- &lt;li id=&quot;fn-48-1&quot;&gt; ‘&lt;em&gt;Radical&lt;/em&gt;‘ can be in some cultures an euphemism to ‘&lt;em&gt;violent&lt;/em&gt;‘. Let’s be clear that the change by increasing violence is done to make a popular uprising of some part against others. While it does not help the majority to magically understand that the minority is right, it stigmatize the radical-violent-changers and in the way it discredits the alternative proposed. &lt;span class=&quot;footnotereverse&quot;&gt;&lt;a href=&quot;https://repeer.org/tag/mozilla/feed/#fnref-48-1&quot;&gt;↩&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
- &lt;/ol&gt;
- &lt;/div&gt;</description>
- <pubDate>Sat, 16 Jan 2016 00:27:13 +0000</pubDate>
- <dc:creator>Nicolas</dc:creator>
- </item>
- <item>
- <title>Will Kahn-Greene: pyvideo status: January 15th, 2016</title>
- <guid isPermaLink="true">http://bluesock.org/%7Ewillkg/blog/pyvideo/status_20160115.html</guid>
- <link>http://bluesock.org/%7Ewillkg/blog/pyvideo/status_20160115.html</link>
- <description>&lt;div class=&quot;section&quot; id=&quot;what-is-pyvideo-org&quot;&gt;
- &lt;h3&gt;What is pyvideo.org&lt;/h3&gt;
- &lt;p&gt;&lt;a class=&quot;reference external&quot; href=&quot;http://pyvideo.org/&quot;&gt;pyvideo.org&lt;/a&gt; is an index of Python-related conference and user-group videos on
- the Internet. Saw a session you liked and want to share it? It's likely you can
- find it, watch it, and share it with pyvideo.org.&lt;/p&gt;
- &lt;p&gt;This is the latest status report for all things happening on the site.&lt;/p&gt;
- &lt;p&gt;It's also an announcement about the end.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;http://bluesock.org/~willkg/blog/pyvideo/status_20160115.html&quot;&gt;Read more…&lt;/a&gt; (5 mins to read)&lt;/p&gt;&lt;/div&gt;</description>
- <pubDate>Fri, 15 Jan 2016 23:30:00 +0000</pubDate>
- <dc:creator>Will Kahn-Greene</dc:creator>
- </item>
- <item>
- <title>Chris Cooper: RelEng &amp; RelOps Weekly Highlights - January 15, 2016</title>
- <guid isPermaLink="true">http://coopcoopbware.tumblr.com/post/137371863755</guid>
- <link>http://coopcoopbware.tumblr.com/post/137371863755</link>
- <description>&lt;p&gt;One of releng’s big goals for Q1 is to deliver a beta via &lt;a href=&quot;https://bugzil.la/release-promotion&quot; target=&quot;_blank&quot;&gt;build promotion&lt;/a&gt;. It was great to have some tangible progress there this week with bouncer submission.&lt;/p&gt;
-
- &lt;p&gt;Lots of other stuff in-flight, more details below!
- &lt;/p&gt;&lt;p&gt;&lt;b&gt;Modernize infrastructure&lt;/b&gt;:&lt;/p&gt;
-
- &lt;p&gt;Dustin worked with Armen and Joel Maher to run Firefox tests in TaskCluster on an older EC2 instance type where the tests seem to fail less often, perhaps because they are single-CPU or slower.&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Improve CI pipeline&lt;/b&gt;:&lt;/p&gt;
-
- &lt;p&gt;We turned off automation for b2g 2.2 builds this week, which allowed us to remove some code, reduce some complexity, and regain some small amount of capacity. Thanks to Vlad and Alin on buildduty for helping to land those patches. (&lt;a href=&quot;https://bugzil.la/1236835&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1236835&lt;/a&gt; and &lt;a href=&quot;https://bugzil.la/1237985&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1237985&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;In a similar vein, Callek landed code to disable all b2g desktop builds and tests on all trees. Another win for increased capacity and reduced complexity! (&lt;a href=&quot;https://bugzil.la/1236835&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1236835&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Release&lt;/b&gt;:&lt;/p&gt;
-
- &lt;p&gt;Kim finished integrating bouncer submission with our release promotion project. That’s one more blocker out of the way! (&lt;a href=&quot;https://bugzil.la/1215204&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1215204&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;Ben landed several enhancements to our update server: adding aliases to update rules (&lt;a href=&quot;https://bugzil.la/1067402&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1067402&lt;/a&gt;), and allowing fallbacks for rules with whitelists (&lt;a href=&quot;https://bugzil.la/1235073&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/1235073&lt;/a&gt;).&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Operational&lt;/b&gt;:&lt;/p&gt;
- &lt;p&gt;There was some excitement last Sunday when all the trees were closed due to timeouts connectivity issues between our SCL3 datacentre and AWS. (&lt;a href=&quot;https://bugzil.la/238369&quot; target=&quot;_blank&quot;&gt;https://bugzil.la/238369&lt;/a&gt;)&lt;/p&gt;
-
- &lt;p&gt;&lt;b&gt;Build config&lt;/b&gt;:&lt;/p&gt;
-
- &lt;p&gt;Mike released v0.7.4 of &lt;a href=&quot;http://gittup.org/tup/&quot; target=&quot;_blank&quot;&gt;tup&lt;/a&gt;, and is working on generating the tup backend from moz.build. We hope to offer tup as an alternative build backend sometime soon.&lt;/p&gt;
-
- &lt;p&gt;See you all next week!&lt;/p&gt;</description>
- <pubDate>Fri, 15 Jan 2016 22:44:13 +0000</pubDate>
- </item>
- <item>
- <title>Air Mozilla: Webdev Beer and Tell: January 2016</title>
- <guid isPermaLink="true">https://air.mozilla.org/webdev-beer-and-tell-january-2016/</guid>
- <link>https://air.mozilla.org/webdev-beer-and-tell-january-2016/</link>
- <description>&lt;p&gt;
- &lt;img alt=&quot;Webdev Beer and Tell: January 2016&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/35/0f/350f246037ead3bab95fdbd4c2b77484.png&quot; width=&quot;160&quot; /&gt;
- Once a month web developers across the Mozilla community get together (in person and virtually) to share what cool stuff we've been working on in...
- &lt;/p&gt;</description>
- <pubDate>Fri, 15 Jan 2016 22:00:00 +0000</pubDate>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item>
- <title>Support.Mozilla.Org: What’s up with SUMO – 15th January</title>
- <guid isPermaLink="false">http://blog.mozilla.org/sumo/?p=3665</guid>
- <link>https://blog.mozilla.org/sumo/2016/01/15/whats-up-with-sumo-15th-january/</link>
- <description>&lt;p&gt;&lt;strong&gt;Hello, SUMO Nation!&lt;/strong&gt;&lt;/p&gt;
- &lt;p&gt;The second post of the year is here. Have you had a good time in 2016 so far? Let us know in the comments!&lt;/p&gt;
- &lt;p&gt;Now, let’s get going with the updates and activity summaries. It will be brief today, I promise.&lt;/p&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-name&quot;&gt;Welcome, new contributors!&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li class=&quot;author&quot;&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;a class=&quot;username&quot; href=&quot;https://support.mozilla.org/en-US/user/Andy.Yang&quot;&gt;Andy.Yang&lt;/a&gt;&lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;author&quot;&gt;After the massive influx over the last few weeks, we only had Andy introducing himself recently – the warmer the welcome for him!&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;If you just joined us, don’t hesitate – come over and &lt;a href=&quot;https://support.mozilla.org/forums/buddies&quot; target=&quot;_blank&quot;&gt;say “hi†in the forums!&lt;/a&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;
- &lt;h3&gt;&lt;strong&gt;Contributors of the week&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://blog.mozilla.org/sumo/2016/01/08/whats-up-with-sumo-8th-january/&quot; target=&quot;_blank&quot;&gt;All the people who joined us in the winter season so far!&lt;/a&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid64&quot;&gt;
- &lt;p&gt;&lt;strong&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;We salute you!&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
- &lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;Don’t forget that if you are new to SUMO and someone helped you get started in a nice way you can &lt;a href=&quot;https://support.mozilla.org/forums/buddies/711364?last=65670&quot; target=&quot;_blank&quot;&gt;nominate them for the Buddy of the Month!&lt;/a&gt;&lt;/div&gt;
- &lt;div class=&quot;author&quot;&gt;&lt;/div&gt;
- &lt;/div&gt;
- &lt;h3&gt;&lt;strong&gt;Most recent SUMO Community meeting&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-2016-01-11&quot; target=&quot;_blank&quot;&gt;You can read the notes here&lt;/a&gt; and see the video on our &lt;a href=&quot;https://www.youtube.com/channel/UCaiposaIhA7HfMqH2NIciyA/videos&quot; target=&quot;_blank&quot;&gt;YouTube channel&lt;/a&gt; and &lt;a href=&quot;https://air.mozilla.org/search/?q=sumo&quot; target=&quot;_blank&quot;&gt;at AirMozilla&lt;/a&gt;.&lt;del&gt; &lt;/del&gt;&lt;del&gt;&lt;br /&gt;
- &lt;/del&gt;&lt;/li&gt;
- &lt;li&gt;&lt;strong&gt;IMPORTANT: We are considering changing the way the meetings work. Help us figure out what’s best for you – join the discussion on the forums in this thread: &lt;a href=&quot;https://support.mozilla.org/en-US/forums/contributors/711752?last=67873&quot;&gt;(Monday) Community Meetings in 2016&lt;/a&gt;.&lt;/strong&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong&gt;The next SUMO Community meeting… &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;is happening on &lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-2016-01-18&quot; target=&quot;_blank&quot;&gt;Monday the 18th – join us&lt;/a&gt;!&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Reminder: if you want to add a discussion topic to the upcoming meeting agenda:&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;Start a thread in the &lt;a href=&quot;https://support.mozilla.org/forums/contributors&quot; target=&quot;_blank&quot;&gt;Community Forums&lt;/a&gt;, so that everyone in the community can see what will be discussed and voice their opinion here before Monday (this will make it easier to have an efficient meeting).&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;Please do so as soon as you can before the meeting, so that people have time to read, think, and reply (and also add it to the agenda).&lt;/li&gt;
- &lt;li style=&quot;text-align: left;&quot;&gt;If you can, please attend the meeting in person (or via IRC), so we can follow up on your discussion topic during the meeting with your feedback.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-g-ivsra51ph44x461i&quot;&gt;Developers&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;The new version of the Ask A Question page is here!&lt;/li&gt;
- &lt;li&gt;The 2.0 version of the KPI dashboard is in the works.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;http://edwin.mozilla.io/t/sumo&quot; target=&quot;_blank&quot;&gt;You can see the current state of the backlog our developers are working on here&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://public.etherpad-mozilla.org/p/sumo-p-2016-01-14&quot; target=&quot;_blank&quot;&gt;The latest SUMO Platform meeting notes can be found here&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Interested in learning how Kitsune (the engine behind SUMO) works? &lt;a href=&quot;http://kitsune.readthedocs.org/&quot; target=&quot;_blank&quot;&gt;Read more about it here&lt;/a&gt; and &lt;a href=&quot;https://github.com/mozilla/kitsune/&quot; target=&quot;_blank&quot;&gt;fork it on GitHub&lt;/a&gt;!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong&gt;Community&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Our awesome Bangladesh SUMO Warriors are on the road again! Follow their adventures on Twitter under this tag: &lt;a href=&quot;https://twitter.com/search?q=%23sumotourctg&quot; target=&quot;_blank&quot;&gt;#sumotourctg&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711729?last=67763&quot;&gt;Reminder: take a look at our Work Week Summary for Mozlando. We need your feedback for a few things there.&lt;/a&gt;&lt;/div&gt;
- &lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;Ongoing reminder: if you think you can benefit from getting &lt;a href=&quot;https://wiki.mozilla.org/Community_Hardware&quot; target=&quot;_blank&quot;&gt;a second-hand device&lt;/a&gt; to help you with contributing to SUMO, you know where to find us.&lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;&lt;strong class=&quot;user-chip&quot; title=&quot;adriel0415&quot;&gt;Support Forum&lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Say hello to the new people on the forums!
- &lt;ul&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/Tomi55&quot; target=&quot;_blank&quot;&gt;Tomi55&lt;/a&gt; (Hungarian)&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/jdc20181&quot; target=&quot;_blank&quot;&gt;jdc20181&lt;/a&gt; (English)&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/andexi&quot; target=&quot;_blank&quot;&gt;andexi&lt;/a&gt; (Spanish)&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/Qantas94Heavy&quot; target=&quot;_blank&quot;&gt;Qantas94Heavy&lt;/a&gt; (English)&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/samuelms79&quot; target=&quot;_blank&quot;&gt;samuelms79&lt;/a&gt; (Brazilian-PT)&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zkz70z39yz83zw7ykz89z3gz82zt&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/user/jorgecomun&quot; target=&quot;_blank&quot;&gt;jorgecomun&lt;/a&gt; (Spanish)&lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;div class=&quot;&quot;&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-g-ivsra51ph44x461i&quot;&gt;Knowledge Base&lt;/strong&gt;&lt;/h3&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid90&quot;&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid82&quot;&gt;
- &lt;ul class=&quot;list-bullet1&quot;&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-z87zjz80zxwjz85z4z65zytdpz68zoz69z&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/forums/knowledge-base-articles/711304#post-65289&quot; target=&quot;_blank&quot;&gt;Thanks to everyone who took part in the most recent KB Day!&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
- &lt;li&gt;Version 44 updates should be live now.&lt;/li&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-w2dz70zaz70z7z89zqz78ziz69zz78zz85zz90zj&quot;&gt;&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1lkpRPJp9P1P5MRU-c9dwbDC0w5bMmrMdu-BNMp1xe8w/edit#gid=6&quot; target=&quot;_blank&quot;&gt;Ongoing reminder: learn more about upcoming English article updates by clicking here&lt;/a&gt;&lt;/span&gt;.&lt;/li&gt;
- &lt;li&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;Ongoing reminder #2:&lt;a href=&quot;https://support.mozilla.org/forums/knowledge-base-articles/&quot; target=&quot;_blank&quot;&gt; do you have ideas about improving the KB guidelines and training materials? Let us know in the forums&lt;/a&gt;!&lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid83&quot;&gt;
- &lt;h3&gt;&lt;strong class=&quot;author-g-ivsra51ph44x461i&quot;&gt;Localization&lt;/strong&gt;&lt;/h3&gt;
- &lt;/div&gt;
- &lt;/div&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid95&quot;&gt;
- &lt;ul&gt;
- &lt;li&gt;Thanks to everyone writing in with problems, ideas, reports of bugs – all your feedback matters!&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid75&quot;&gt;
- &lt;h3&gt;&lt;strong&gt;Firefox&lt;br /&gt;
- &lt;/strong&gt;&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for Android&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711712?last=67653&quot;&gt;Learn more about Firefox 43 for Android from the official thread with release notes / issues / discussions&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;
- &lt;div class=&quot;title&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/forums/contributors/711718?last=67822&quot;&gt;Reminder: Roland is sharing Firefox 44 for Android release notes / issues / discussions&lt;/a&gt; with everyone in the forum.&lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for Desktop&lt;/strong&gt;
- &lt;ul&gt;
- &lt;li&gt;The &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1238620&quot; target=&quot;_blank&quot;&gt;uploading issues reported by many users are being tracked here.&lt;/a&gt;&lt;/li&gt;
- &lt;li&gt;&lt;a href=&quot;https://support.mozilla.org/questions/firefox?tagged=bug1208145&amp;amp;show=all&quot; target=&quot;_blank&quot;&gt;The “show passwords†button has been removed from the password manager for the Beta of Version 44&lt;/a&gt;. The developers are looking into &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1208145&quot; target=&quot;_blank&quot;&gt;last minute fixes for that in this bug&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Also in Version 44, the &lt;span class=&quot;author-a-kz88zz80zhz89z6hlz81znytez70zz66zz68z&quot;&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=606655&quot; target=&quot;_blank&quot;&gt;“ask me everytime†option for cookies will be removed from the privacy panel.&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;ul&gt;
- &lt;li&gt;&lt;strong&gt;for iOS&lt;/strong&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid85&quot;&gt;
- &lt;ul class=&quot;list-bullet1&quot;&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-107uz69zz81zhz78z0z78zz84zz66zz76zz82zz77zj&quot;&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/ios/1.4/releasenotes/&quot; target=&quot;_blank&quot;&gt;Firefox for iOS 1.4 primarily with features for China is here&lt;/a&gt;.&lt;br /&gt;
- &lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;div class=&quot;&quot; id=&quot;magicdomid86&quot;&gt;
- &lt;ul class=&quot;list-bullet1&quot;&gt;
- &lt;li&gt;&lt;span class=&quot;author-a-107uz69zz81zhz78z0z78zz84zz66zz76zz82zz77zj&quot;&gt;Firefox for iOS 2.0 is after 1.4 and hopefully sometime this quarter!&lt;/span&gt;&lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;/li&gt;
- &lt;/ul&gt;
- &lt;/div&gt;
- &lt;p&gt;Not that many updates this week, since we’re coming out of our winter slumber (even though winter will be here for a while, still) and plotting an awesome 2016 with you and for you. Take it easy, have a great weekend and see you around SUMO.&lt;/p&gt;</description>
- <pubDate>Fri, 15 Jan 2016 19:38:51 +0000</pubDate>
- <dc:creator>Michał</dc:creator>
- </item>
- <item>
- <title>Air Mozilla: Paris Firefox OS Hackathon Presentations</title>
- <guid isPermaLink="true">https://air.mozilla.org/paris-firefox-os-hackathon-presentations/</guid>
- <link>https://air.mozilla.org/paris-firefox-os-hackathon-presentations/</link>
- <description>&lt;p&gt;
- &lt;img alt=&quot;Paris Firefox OS Hackathon Presentations&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/35/83/358305bfa246fff07d707061082134aa.png&quot; width=&quot;160&quot; /&gt;
- As an introduction to this weekend's Firefox OS Hackathon in Paris we'll have two presentations: - Guillaume Marty will talk about the current state of...
- &lt;/p&gt;</description>
- <pubDate>Fri, 15 Jan 2016 18:00:00 +0000</pubDate>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
- <item>
- <title>J.C. Jones: Renewing Let's Encrypt Certs (Nginx)</title>
- <guid isPermaLink="false">https://tacticalsecret.com/tag/mozilla/rss/db7fec0c-34d3-4633-9904-79b98aab34e7</guid>
- <link>https://tacticalsecret.com/renewing-lets-encrypt-certs-nginx/</link>
- <description>&lt;p&gt;All the first &lt;a href=&quot;https://crt.sh/?id=10172479&quot;&gt;Let's Encrypt certs for my websites&lt;/a&gt; from the LE private beta began expiring last week, so it was time to work through the renewal tooling. I wanted a script that:&lt;/p&gt;
-
- &lt;ol&gt;
- &lt;li&gt;Would be okay to run daily, so there'd be plenty of retries if something went wrong, &lt;/li&gt;
- &lt;li&gt;Wouldn't require extra config for me to forget about if I add a new site, &lt;/li&gt;
- &lt;li&gt;Would only renew certificates expiring in the next few weeks.&lt;/li&gt;
- &lt;/ol&gt;
-
- &lt;p&gt;The official Let's Encrypt client team is hard at work producing a great renew tool to handle all this, but it's not released yet. Of course I could use &lt;a href=&quot;https://caddyserver.com/&quot;&gt;Caddy Server&lt;/a&gt; that &lt;a href=&quot;https://www.youtube.com/watch?v=nk4EWHvvZtI&quot;&gt;just handles all this&lt;/a&gt;, but I have a lot invested in Nginx here.&lt;/p&gt;
-
- &lt;p&gt;So I wrote a short script and &lt;a href=&quot;https://gist.github.com/jcjones/432eeaa6a2bf25e2c746&quot;&gt;put it up in a Gist&lt;/a&gt;. &lt;/p&gt;
-
- &lt;p&gt;The script is designed to run daily, with a random start between 00:00 and 02:00 to protect against load spikes at Let's Encrypt's infrastructure. It doesn't do any real reporting, though, except to maintain &lt;code&gt;/var/log/letsencrypt/renew.log&lt;/code&gt; as the most-recent failure if one fails.&lt;/p&gt;
-
- &lt;p&gt;It's written to handle Nginx with Upstart's &lt;code&gt;service&lt;/code&gt; command. It's pretty modular though; you could make this operate any webserver, or use the webroot method quite easily. Feel free to use the OpenSSL SubjectAlternativeName processing code for whatever purposes you have.&lt;/p&gt;
-
- &lt;p&gt;Happy renewing!&lt;/p&gt;</description>
- <pubDate>Fri, 15 Jan 2016 16:01:19 +0000</pubDate>
- <dc:creator>James 'J.C.' Jones</dc:creator>
- </item>
- <item>
- <title>Yunier José Sosa Vázquez: Conoce los complementos destacados para enero</title>
- <guid isPermaLink="false">http://firefoxmania.uci.cu/?p=15521</guid>
- <link>http://firefoxmania.uci.cu/conoce-los-complementos-destacados-para-enero-2016/</link>
- <description>&lt;p style=&quot;text-align: left;&quot;&gt;Comenzó un nuevo año y con él, te traemos nuevos e interesantes complementos para tu navegador preferido que mejoran con creces tu experiencia de navegación. Durante los próximos 6 meses estará trabajando nuevos miembros en el Add-ons Board Team, en la próxima selección desde Firefoxmanía te avisaremos.&lt;/p&gt;
- &lt;h3 style=&quot;text-align: left;&quot;&gt;Elección del mes: uMatrix&lt;/h3&gt;
- &lt;p&gt;uMatrix es muy parecido a un &lt;em&gt;firewall&lt;/em&gt; y desde una ventana fácilmente podrás controlar todos los lugares a donde tu navegador tiene permitido conectarse, qué tipo de datos pueden descargarse y cual puede ejecutar.&lt;/p&gt;
- &lt;blockquote&gt;&lt;p&gt;Esta puede ser la extensión perfecta para el control avanzado de los usuarios.&lt;/p&gt;&lt;/blockquote&gt;
- &lt;p&gt;&lt;span id=&quot;more-15521&quot;&gt;&lt;/span&gt;&lt;/p&gt;
-
- &lt;a href=&quot;http://firefoxmania.uci.cu/conoce-los-complementos-destacados-para-enero-2016/umatrix/&quot;&gt;&lt;img alt=&quot;Interfaz principal de uMatrix&quot; class=&quot;attachment-thumbnail size-thumbnail&quot; height=&quot;160&quot; src=&quot;http://firefoxmania.uci.cu/wp-content/uploads/2016/01/uMatrix-160x160.png&quot; width=&quot;160&quot; /&gt;&lt;/a&gt;
- &lt;a href=&quot;http://firefoxmania.uci.cu/conoce-los-complementos-destacados-para-enero-2016/umatrix2/&quot;&gt;&lt;img alt=&quot;Opciones de configuración de uMatrix&quot; class=&quot;attachment-thumbnail size-thumbnail&quot; height=&quot;160&quot; src=&quot;http://firefoxmania.uci.cu/wp-content/uploads/2016/01/uMatrix2-160x160.png&quot; width=&quot;160&quot; /&gt;&lt;/a&gt;
-
- &lt;p&gt;&lt;em&gt;&lt;a href=&quot;http://addons.firefoxmania.uci.cu/umatrix/&quot; target=&quot;_blank&quot;&gt;Instalar uMatrix »&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
- &lt;h3&gt;También te recomendamos&lt;/h3&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;http://addons.firefoxmania.uci.cu/https-everywhere/&quot; target=&quot;_blank&quot;&gt;⇒ HTTPS Everywhere&lt;/a&gt; por &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/user/eff-technologists/&quot; title=&quot;EFF Technologists&quot;&gt;EFF Technologists&lt;/a&gt;&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;Protege tus comunicaciones habilitando la encriptación HTTPS automáticamente en los sitios conocidos que la soportan, incluso cuando navegas mediante sitios que no incluyen el prefijo “https†en la URL.&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;http://addons.firefoxmania.uci.cu/add-to-search-bar/&quot; target=&quot;_blank&quot;&gt;⇒ Add to Search Bar&lt;/a&gt; por &lt;a href=&quot;https://addons.mozilla.org/firefox/user/dr-evil/&quot; target=&quot;_blank&quot; title=&quot;AdblockLite&quot;&gt;Dr. Evil&lt;/a&gt;&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;Hace posible que cualquier página con un formulario de búsqueda disponible pueda ser añadido fácilmente a la barra de búsqueda de Firefox.&lt;/p&gt;
- &lt;div class=&quot;wp-caption aligncenter&quot; id=&quot;attachment_15528&quot; style=&quot;width: 262px;&quot;&gt;&lt;a href=&quot;http://firefoxmania.uci.cu/wp-content/uploads/2016/01/add_to_search_bar.png&quot; rel=&quot;attachment wp-att-15528&quot;&gt;&lt;img alt=&quot;add_to_search_bar&quot; class=&quot;wp-image-15528 size-medium&quot; height=&quot;226&quot; src=&quot;http://firefoxmania.uci.cu/wp-content/uploads/2016/01/add_to_search_bar-252x226.png&quot; width=&quot;252&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Añadiendo la búsqueda de un sitio web a la barra de búsqueda&lt;/p&gt;&lt;/div&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;http://addons.firefoxmania.uci.cu/duplicate-tabs-closer/&quot; target=&quot;_blank&quot;&gt;⇒ Duplicate Tabs Closer&lt;/a&gt; por &lt;a href=&quot;https://addons.mozilla.org/firefox/user/peuj/&quot; target=&quot;_blank&quot; title=&quot;The 1-Click YouTube Video Download Team&quot;&gt;Peuj&lt;/a&gt;&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;Detecta las pestañas duplicadas en tu navegador y automáticamente las cierra.&lt;/p&gt;
- &lt;h3 style=&quot;text-align: left;&quot;&gt;Nomina tus complementos favoritos&lt;/h3&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;A nosotros nos encantaría que &lt;strong&gt;fueras parte del proceso&lt;/strong&gt; de seleccionar los mejores complementos para Firefox y nos gustaría escucharte. &lt;em&gt;¿No sabes cómo?&lt;/em&gt; Sólo tienes que &lt;em&gt;enviar un correo electrónico&lt;/em&gt; a la dirección &lt;strong&gt;amo-featured@mozilla.org&lt;/strong&gt; con el nombre del complemento o el archivo de instalación y los miembros evaluarán tu recomendación.&lt;/p&gt;
- &lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Fuente:&lt;/strong&gt; &lt;a href=&quot;https://blog.mozilla.org/addons/2016/01/01/january-2016-featured-add-ons/&quot; target=&quot;_blank&quot;&gt;Mozilla Add-ons Blog&lt;/a&gt;&lt;/p&gt;</description>
- <pubDate>Fri, 15 Jan 2016 15:10:26 +0000</pubDate>
- <dc:creator>Yunier J</dc:creator>
- </item>
- <item>
- <title>Tim Taubert: Build Your Own Signal Desktop</title>
- <guid isPermaLink="false">https://timtaubert.de/blog/2016/01/build-your-own-signal-desktop</guid>
- <link>https://timtaubert.de/blog/2016/01/build-your-own-signal-desktop/</link>
- <description>&lt;p&gt;The Signal Private Messenger is great. &lt;strong&gt;Use it.&lt;/strong&gt; It’s probably the best secure
- messenger on the market. When recently a desktop app was announced people were
- eager to join the beta and even happier when an invite finally showed up in
- their inbox. So was I, it’s a great app and works surprisingly well for an early
- version.&lt;/p&gt;
-
- &lt;p&gt;The only problem is that it’s a Chrome App. Apart from excluding folks with
- other browsers it’s also a shitty user experience. If you too want your
- messaging app not tied to a browser then let’s just build our own standalone
- variant of Signal Desktop.&lt;/p&gt;
-
- &lt;h3&gt;NW.js beta with Chrome App support&lt;/h3&gt;
-
- &lt;p&gt;Signal Desktop is a Chrome App, so the easiest way to turn it into a standalone
- app is to use &lt;a href=&quot;http://nwjs.io/&quot;&gt;NW.js&lt;/a&gt;. Conveniently, their next release v0.13
- will ship with Chrome App support and is available for download as a beta
- version.&lt;/p&gt;
-
- &lt;p&gt;First, make sure you have &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt; installed. Then open a terminal and
- prepare a temporary build directory to which we can download a few things and
- where we can build the app:&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ mkdir signal-build
- $ cd signal-build
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;h3&gt;[OS X] Packaging Signal and NW.js&lt;/h3&gt;
-
- &lt;p&gt;Download the latest beta of NW.js and &lt;code&gt;unzip&lt;/code&gt; it. We’ll extract the application
- and use it as a template for our Signal clone. The NW.js project does
- unfortunately not seem to provide a secure source (or at least hashes)
- for their downloads.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ wget http://dl.nwjs.io/v0.13.0-beta3/nwjs-sdk-v0.13.0-beta3-osx-x64.zip
- $ unzip nwjs-sdk-v0.13.0-beta3-osx-x64.zip
- $ cp -r nwjs-sdk-v0.13.0-beta3-osx-x64/nwjs.app SignalPrivateMessenger.app
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Next, clone the Signal repository and use NPM to install the necessary modules.
- Run the &lt;code&gt;grunt&lt;/code&gt; automation tool to build the application.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ git clone https://github.com/WhisperSystems/Signal-Desktop.git
- $ cd Signal-Desktop/
- $ npm install
- $ node_modules/grunt-cli/bin/grunt
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Finally, simply to copy the &lt;code&gt;dist&lt;/code&gt; folder containing all the juicy Signal files
- into the application template we created a few moments ago.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ cp -r dist ../SignalPrivateMessenger.app/Contents/Resources/app.nw
- $ open ..
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;The last command opens a Finder window. Move &lt;code&gt;SignalPrivateMessenger.app&lt;/code&gt; to
- your Applications folder and launch it as usual. You should now see a welcome
- page!&lt;/p&gt;
-
- &lt;h3&gt;[Linux] Packaging Signal and NW.js&lt;/h3&gt;
-
- &lt;p&gt;The build instructions for Linux aren’t too different but I’ll write them down,
- if just for convenience. Start by cloning the Signal Desktop repository and
- build.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ git clone https://github.com/WhisperSystems/Signal-Desktop.git
- $ cd Signal-Desktop/
- $ npm install
- $ node_modules/grunt-cli/bin/grunt
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;The &lt;code&gt;dist&lt;/code&gt; folder contains the app, ready to be launched. &lt;code&gt;zip&lt;/code&gt; it and place
- the resulting package somewhere handy.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ cd dist
- $ zip -r ../../package.nw *
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Back to the top. Download the NW.js binary, extract it, and change into the
- newly created directory. Move the &lt;code&gt;package.nw&lt;/code&gt; file we created earlier next to
- the &lt;code&gt;nw&lt;/code&gt; binary and we’re done. The &lt;code&gt;nwjs-sdk-v0.13.0-beta3-linux-x64&lt;/code&gt; folder
- does now contain the standalone Signal app.&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ cd ../..
- $ wget http://dl.nwjs.io/v0.13.0-beta3/nwjs-sdk-v0.13.0-beta3-linux-x64.tar.gz
- $ tar xfz nwjs-sdk-v0.13.0-beta3-linux-x64.tar.gz
- $ cd nwjs-sdk-v0.13.0-beta3-linux-x64
- $ mv ../package.nw .
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;p&gt;Finally, launch NW.js. You should see a welcome page!&lt;/p&gt;
-
- &lt;figure class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;$ ./nw
- &lt;/pre&gt;&lt;/div&gt;&lt;/figure&gt;
-
-
- &lt;h3&gt;If you see something, file something&lt;/h3&gt;
-
- &lt;p&gt;Our standalone Signal clone mostly works, but it’s far from perfect. We’re
- pulling from master and that might bring breaking changes that weren’t
- sufficiently tested.&lt;/p&gt;
-
- &lt;p&gt;We don’t have the right icons. The app crashes when you click a media message.
- It opens a blank popup when you click a link. It’s quite big because also NW.js
- has bugs and so we have to use the SDK build for now. In the future it would be
- great to have automatic updates, and maybe even signed builds.&lt;/p&gt;
-
- &lt;p&gt;Remember, Signal Desktop is beta, and completely untested with NW.js. If you
- want to help file bugs, but only after checking that those affect the Chrome
- App too. If you want to fix a bug only occurring in the standalone version
- it’s probably best to file a pull request and cross fingers.&lt;/p&gt;
-
- &lt;h3&gt;Is this secure?&lt;/h3&gt;
-
- &lt;p&gt;Great question! I don’t know. I would love to get some more insights from people
- that know more about the NW.js security model and whether it comes with all the
- protections Chromium can offer. Another interesting question is whether bundling
- Signal Desktop with NW.js is in any way worse (from a security perspective) than
- installing it as a Chrome extension. If you happen to have an opinion about
- that, I would love to hear it.&lt;/p&gt;
-
- &lt;p&gt;Another important thing to keep in mind is that when building Signal on your
- own you will possibly miss automatic and signed security updates from the
- Chrome Web Store. Keep an eye on the repository and rebuild your app from
- time to time to not fall behind too much.&lt;/p&gt;</description>
- <pubDate>Fri, 15 Jan 2016 14:00:00 +0000</pubDate>
- </item>
- <item>
- <title>Mike Hommey: Announcing git-cinnabar 0.3.0</title>
- <guid isPermaLink="true">http://glandium.org/blog/?p=3579</guid>
- <link>http://glandium.org/blog/?p=3579</link>
- <description>&lt;p&gt;Git-cinnabar is a git remote helper to interact with mercurial repositories. It allows to clone, pull and push from/to mercurial remote repositories, using git.&lt;/p&gt;
- &lt;p&gt;&lt;a href=&quot;https://github.com/glandium/git-cinnabar&quot;&gt;Get it on github&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;These release notes are also &lt;a href=&quot;https://github.com/glandium/git-cinnabar/wiki/Release-Notes:-0.3.0&quot;&gt;available on the git-cinnabar wiki&lt;/a&gt;.&lt;/p&gt;
- &lt;p&gt;Development had been stalled for a few months, with many improvements in the&lt;br /&gt;
- &lt;code&gt;next&lt;/code&gt; branch without any new release. I used some time during the new year&lt;br /&gt;
- break and after in order to straighten things up in order to create a new&lt;br /&gt;
- release, delaying many of the originally planned changes to a future 0.4.0&lt;br /&gt;
- release.&lt;/p&gt;
- &lt;h3&gt;What’s new since 0.2.2?&lt;/h3&gt;
- &lt;ul&gt;
- &lt;li&gt;Speed and memory usage were improved when doing &lt;code&gt;git push&lt;/code&gt;.&lt;/li&gt;
- &lt;li&gt;Now works on Windows, at least to some extent. See &lt;a href=&quot;http://glandium.org/blog/Windows-Support&quot;&gt;details&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Support for pre-0.1.0 git-cinnabar repositories was removed. You must first&lt;br /&gt;
- use a git-cinnabar version between 0.1.0 and 0.2.2 to upgrade its metadata.&lt;/li&gt;
- &lt;li&gt;It is now possible to attach/graft git-cinnabar metadata to existing commits&lt;br /&gt;
- matching mercurial changesets. This allows to migrate from some other&lt;br /&gt;
- hg-to-git tool to git-cinnabar while preserving the existing git commits.&lt;br /&gt;
- See &lt;a href=&quot;http://glandium.org/blog/Mozilla%3A-Using-a-git-clone-of-gecko%E2%80%90dev-to-push-to-mercurial&quot;&gt;an example of how this works with the git clone of the Gecko mercurial&lt;br /&gt;
- repository&lt;/a&gt;
- &lt;/li&gt;
- &lt;li&gt;Avoid mercurial printing its progress bar, messing up with git-cinnabar’s&lt;br /&gt;
- output.&lt;/li&gt;
- &lt;li&gt;It is now possible to fetch from an incremental mercurial bundle (without&lt;br /&gt;
- a root changeset).&lt;/li&gt;
- &lt;li&gt;It is now possible to push to a new mercurial repository without &lt;code&gt;-f&lt;/code&gt;.&lt;/li&gt;
- &lt;li&gt;By default, reject pushing a new root to a mercurial repository.&lt;/li&gt;
- &lt;li&gt;Make the connection to a mercurial repository through ssh respect the&lt;br /&gt;
- &lt;code&gt;GIT_SSH&lt;/code&gt; and &lt;code&gt;GIT_SSH_COMMAND&lt;/code&gt; environment variables.&lt;/li&gt;
- &lt;li&gt;
- &lt;code&gt;git cinnabar&lt;/code&gt; now has a proper argument parser for all its subcommands.&lt;/li&gt;
- &lt;li&gt;
- &lt;/li&gt;
- &lt;li&gt;A new &lt;code&gt;git cinnabar python&lt;/code&gt; command allows to run python scripts or open a&lt;br /&gt;
- python shell with the right sys.path to import the cinnabar module.&lt;/li&gt;
- &lt;li&gt;All git-cinnabar metadata is now kept under a single ref (although for&lt;br /&gt;
- convenience, other refs are created, but they can be derived if necessary).&lt;/li&gt;
- &lt;li&gt;Consequently, a new &lt;code&gt;git cinnabar rollback&lt;/code&gt; command allows to roll back to&lt;br /&gt;
- previous metadata states.&lt;/li&gt;
- &lt;li&gt;git-cinnabar metadata now tracks the manifests DAG.&lt;/li&gt;
- &lt;li&gt;A new &lt;code&gt;git cinnabar bundle&lt;/code&gt; command allows to create mercurial bundles,&lt;br /&gt;
- mostly for debugging purposes, without requiring to hit a mercurial server.&lt;/li&gt;
- &lt;li&gt;Updated git to 2.7.0 for the native helper.&lt;/li&gt;
- &lt;/ul&gt;
- &lt;h3&gt;Development process changes&lt;/h3&gt;
- &lt;p&gt;Up to before this release closing in, the &lt;code&gt;master&lt;/code&gt; branch was dedicated to&lt;br /&gt;
- releases, and development was happening on the &lt;code&gt;next&lt;/code&gt; branch, until a new&lt;br /&gt;
- release happens.&lt;/p&gt;
- &lt;p&gt;From now on, the &lt;code&gt;release&lt;/code&gt; branch will take dot-release fixes and new&lt;br /&gt;
- releases, while the &lt;code&gt;master&lt;/code&gt; branch will receive all changes that are&lt;br /&gt;
- validated through testing (currently semi-automatically tested with&lt;br /&gt;
- out-of-tree tests based on four real-life mercurial repositories, with&lt;br /&gt;
- some automated CI based on in-tree tests used in the future).&lt;/p&gt;
- &lt;p&gt;The &lt;code&gt;next&lt;/code&gt; branch will receive changes to be tested in CI when things&lt;br /&gt;
- will be hooked up, and may have rewritten history as a consequence of&lt;br /&gt;
- wanting passing tests on every commit on &lt;code&gt;master&lt;/code&gt;.&lt;/p&gt;</description>
- <pubDate>Fri, 15 Jan 2016 08:56:40 +0000</pubDate>
- <dc:creator>glandium</dc:creator>
- </item>
- <item>
- <title>Air Mozilla: Web QA Weekly Meeting, 14 Jan 2016</title>
- <guid isPermaLink="true">https://air.mozilla.org/web-qa-weekly-meeting-20160114/</guid>
- <link>https://air.mozilla.org/web-qa-weekly-meeting-20160114/</link>
- <description>&lt;p&gt;
- &lt;img alt=&quot;Web QA Weekly Meeting&quot; class=&quot;wp-post-image&quot; height=&quot;90&quot; src=&quot;https://air.cdn.mozilla.net/media/cache/f5/13/f5137857516694df0458e837c2d3a4be.png&quot; width=&quot;160&quot; /&gt;
- This is our weekly gathering of Mozilla'a Web QA team filled with discussion on our current and future projects, ideas, demos, and fun facts.
- &lt;/p&gt;</description>
- <pubDate>Thu, 14 Jan 2016 17:00:00 +0000</pubDate>
- <dc:creator>Air Mozilla</dc:creator>
- </item>
-
- </channel>
-</rss>
diff --git a/mobile/android/tests/background/junit4/resources/feed_rss_heise.xml b/mobile/android/tests/background/junit4/resources/feed_rss_heise.xml
deleted file mode 100644
index a23399bb8..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_rss_heise.xml
+++ /dev/null
@@ -1,1965 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet type='text/xsl' href='http://heise.de.feedsportal.com/xsl/de/rss.xsl'?>
-<rss xmlns:content="http://purl.org/rss/1.0/modules/content/"
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
- <channel>
- <title>heise online News</title>
- <link>http://www.heise.de/newsticker/</link>
- <description>Nachrichten nicht nur aus der Welt der Computer</description>
- <language>en</language>
- <copyright>Copyright (c) 2016 Heise Medien</copyright>
- <pubDate>Wed, 28 Jan 2016 17:36:00 GMT</pubDate>
- <lastBuildDate>Wed, 27 Jan 2016 17:32:00 GMT</lastBuildDate>
- <ttl>5</ttl>
- <item>
- <title>Google: “Dramatische Verbesserungen†für Chrome in iOS</title>
- <link>
- http://www.heise.de/newsticker/meldung/Google-Dramatische-Verbesserungen-fuer-Chrome-in-iOS-3085808.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Als Unterbau von iOS-Chrome kommt nun eine neuere, von Apple
- bereitgestellte Rendering-Engine zum Einsatz, die ohne Leistungseinschränkungen
- läuft. Manche Funktionen fallen dadurch allerdings weg.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2c8260/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 17:32:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085808</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Google-Dramatische-Verbesserungen-fuer-Chrome-in-iOS-3085808.html?wt_mc=rss.ho.beitrag.atom" title="Google: “Dramatische Verbesserungen†für Chrome in iOS"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/8/2/1/9/image-15fb016575d97662.jpeg" alt="Google Chrome für iOS" /> </a> <p>Als Unterbau von iOS-Chrome kommt nun eine neuere, von Apple bereitgestellte Rendering-Engine zum Einsatz, die ohne Leistungseinschränkungen läuft. Manche Funktionen fallen dadurch allerdings weg.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389546558/u/0/f/653902/c/35207/s/4d2c8260/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2c8260/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>IBM holt Ford-Chef in seinen Verwaltungsrat</title>
- <link>
- http://www.heise.de/newsticker/meldung/IBM-holt-Ford-Chef-in-seinen-Verwaltungsrat-3085806.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Mark Fields, der seit 2014 den zweitgrößten US-amerikanischen
- Autohersteller leitet, gehört nun dem IBM-Verwaltungsrat an.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2c54c4/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 17:19:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085806</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/IBM-holt-Ford-Chef-in-seinen-Verwaltungsrat-3085806.html?wt_mc=rss.ho.beitrag.atom" title="IBM holt Ford-Chef in seinen Verwaltungsrat"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/8/2/1/7/MARK-FIELDS_SV3_4814-8dc07e7cdcc86a8f.jpeg" alt="IBM holt Ford-Chef in seinen Verwaltungsrat" /> </a> <p>Mark Fields, der seit 2014 den zweitgrößten US-amerikanischen Autohersteller leitet, gehört nun dem IBM-Verwaltungsrat an.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389544988/u/0/f/653902/c/35207/s/4d2c54c4/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2c54c4/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>News Pro: Microsoft bringt Nachrichten-App fürs iPhone</title>
- <link>
- http://www.heise.de/newsticker/meldung/News-Pro-Microsoft-bringt-Nachrichten-App-fuers-iPhone-3085776.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Microsoft setzt besonders auf geschäftliche Nachrichten, die nach Branchen
- sortiert sind. News Pro soll außerdem interessenbasierte Vorschläge unterbreiten.
- Noch läuft die App als experimentelles Projekt.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2c039d/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 16:20:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085776</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/News-Pro-Microsoft-bringt-Nachrichten-App-fuers-iPhone-3085776.html?wt_mc=rss.ho.beitrag.atom" title="News Pro: Microsoft bringt Nachrichten-App fürs iPhone"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/8/1/9/1/Bildschirmfoto_2016-01-27_um_16-5f6322b07d567c2e.png" alt="News Pro" /> </a> <p>Microsoft setzt besonders auf geschäftliche Nachrichten, die nach Branchen sortiert sind. News Pro soll außerdem interessenbasierte Vorschläge unterbreiten. Noch läuft die App als experimentelles Projekt.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389583008/u/0/f/653902/c/35207/s/4d2c039d/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2c039d/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Supercomputer mit Xeon Phi Knights Landing wird im Frühsommer ausgeliefert
- </title>
- <link>
- http://www.heise.de/newsticker/meldung/Supercomputer-mit-Xeon-Phi-Knights-Landing-wird-im-Fruehsommer-ausgeliefert-3085672.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Im Juni soll Cray XC40-Systeme mit Xeon-E5 und Xeon Phi Knight Landing an
- den britischen Wetterdienst liefern.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2bfd33/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 15:58:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085672</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Supercomputer-mit-Xeon-Phi-Knights-Landing-wird-im-Fruehsommer-ausgeliefert-3085672.html?wt_mc=rss.ho.beitrag.atom" title="Supercomputer mit Xeon Phi Knights Landing wird im Frühsommer ausgeliefert"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/8/0/9/7/Cray_xc_40-d877918c20ec9586.jpeg" alt="Supercomputer mit Xeon Phi Knights Landing im Frühsommer" /> </a> <p>Im Juni soll Cray XC40-Systeme mit Xeon-E5 und Xeon Phi Knight Landing an den britischen Wetterdienst liefern.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389581460/u/0/f/653902/c/35207/s/4d2bfd33/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2bfd33/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>FDP reicht Verfassungsklage gegen Vorratsdatenspeicherung ein</title>
- <link>
- http://www.heise.de/newsticker/meldung/FDP-reicht-Verfassungsklage-gegen-Vorratsdatenspeicherung-ein-3085660.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>&amp;quot;Dieser Angriff auf die Bürgerrechte darf nicht akzeptiert werden&amp;quot;,
- kommentierte der FDP-Bundesvize Wolfgang Kubicki seinen Gang nach Karlsruhe.&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2bee54/sc/7/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 15:51:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085660</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/FDP-reicht-Verfassungsklage-gegen-Vorratsdatenspeicherung-ein-3085660.html?wt_mc=rss.ho.beitrag.atom" title="FDP reicht Verfassungsklage gegen Vorratsdatenspeicherung ein"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/8/0/8/5/bawue652x368-0b25c1bfcd112865.jpeg" alt="FDP reicht Verfassungsklage gegen Vorratsdatenspeicherung ein" /> </a> <p>"Dieser Angriff auf die Bürgerrechte darf nicht akzeptiert werden", kommentierte der FDP-Bundesvize Wolfgang Kubicki seinen Gang nach Karlsruhe.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/a2.htm"><img src="http://da.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389571260/u/0/f/653902/c/35207/s/4d2bee54/sc/7/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2bee54/sc/7/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Adblocker werden immer populärer</title>
- <link>
- http://www.heise.de/newsticker/meldung/Adblocker-werden-immer-populaerer-3085744.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Zwei aktuelle Studien zeigen: Werbeblocker werden immer populärer. Gerade
- mobil wollen Nutzer weniger Werbung sehen. Ausgerechnet ein Anbieter von
- Videowerbung sieht sich als Musterbeispiel.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2bee52/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 15:49:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085744</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Adblocker-werden-immer-populaerer-3085744.html?wt_mc=rss.ho.beitrag.atom" title="Adblocker werden immer populärer"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/8/1/6/1/image-144229995483704-6d7835c4aaf4c6f4-53beb923785f5926-27ea36c432306085-4339c9834103f557.jpeg" alt="Adblocker immer populärer" /> </a> <p>Zwei aktuelle Studien zeigen: Werbeblocker werden immer populärer. Gerade mobil wollen Nutzer weniger Werbung sehen. Ausgerechnet ein Anbieter von Videowerbung sieht sich als Musterbeispiel. </p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389571259/u/0/f/653902/c/35207/s/4d2bee52/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2bee52/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Steuererklärung: Bundesfinanzhof bleibt beim häuslichen Arbeitszimmer hart
- </title>
- <link>
- http://www.heise.de/newsticker/meldung/Steuererklaerung-Bundesfinanzhof-bleibt-beim-haeuslichen-Arbeitszimmer-hart-3085652.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Der Bundesfinanzhof hält in einem Grundsatzurteil an den strengen Vorgaben
- für die Absetzbarkeit des häuslichen Arbeitszimmers fest. Ein nur zeitweise für die
- Arbeit genutzter Raum wird nicht anerkannt.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2bb5a4/sc/17/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 15:37:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085652</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Steuererklaerung-Bundesfinanzhof-bleibt-beim-haeuslichen-Arbeitszimmer-hart-3085652.html?wt_mc=rss.ho.beitrag.atom" title="Steuererklärung: Bundesfinanzhof bleibt beim häuslichen Arbeitszimmer hart"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/8/0/7/7/home-office-picjumbo-e584e512dfc90c71.jpeg" alt="Steuererklärung: Bundesfinanzhof bleibt beim Arbeitszimmer hart" /> </a> <p>Der Bundesfinanzhof hält in einem Grundsatzurteil an den strengen Vorgaben für die Absetzbarkeit des häuslichen Arbeitszimmers fest. Ein nur zeitweise für die Arbeit genutzter Raum wird nicht anerkannt.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/a2.htm"><img src="http://da.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389578312/u/0/f/653902/c/35207/s/4d2bb5a4/sc/17/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2bb5a4/sc/17/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Olympus Pen F: Erster Eindruck von der spiegellosen Edel-Systemkamera</title>
- <link>
- http://www.heise.de/newsticker/meldung/Olympus-Pen-F-Erster-Eindruck-von-der-spiegellosen-Edel-Systemkamera-3085217.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Olympus möchte seine neue Pen F über das Lebensgefühl der 60er Jahre
- verkaufen. Die spiegellose Systemkamera wirkt extrem durchgestylt und will
- gleichzeitig ein mächtiges Werkzeug sein.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b625e/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 14:18:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085217</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Olympus-Pen-F-Erster-Eindruck-von-der-spiegellosen-Edel-Systemkamera-3085217.html?wt_mc=rss.ho.beitrag.atom" title="Olympus Pen F: Erster Eindruck von der spiegellosen Edel-Systemkamera"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/7/6/9/PENF0071-aa9642e8826de713.jpeg" alt="Olympus Pen F" /> </a> <p>Olympus möchte seine neue Pen F über das Lebensgefühl der 60er Jahre verkaufen. Die spiegellose Systemkamera wirkt extrem durchgestylt und will gleichzeitig ein mächtiges Werkzeug sein. </p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389561062/u/0/f/653902/c/35207/s/4d2b625e/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b625e/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>VW-Skandal: EU-Kommission verschärft Kfz-Aufsicht und Abgaskontrolle</title>
- <link>
- http://www.heise.de/newsticker/meldung/VW-Skandal-EU-Kommission-verschaerft-Kfz-Aufsicht-und-Abgaskontrolle-3085529.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Per Verordnung will die EU-Kommission erreichen, dass sich
- Automobilhersteller streng an die geltenden Sicherheits-, Umwelt- und
- Fertigungsanforderungen halten. Softwareprotokolle für Kfz sollen zugänglich werden.&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b625d/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 14:13:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085529</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/VW-Skandal-EU-Kommission-verschaerft-Kfz-Aufsicht-und-Abgaskontrolle-3085529.html?wt_mc=rss.ho.beitrag.atom" title="VW-Skandal: EU-Kommission verschärft Kfz-Aufsicht und Abgaskontrolle"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/9/9/9/41fec8622800cd459fa6eef48c5e80e2v1_max_755x425_b3535db83dc50e27c1bb1392364c95a2-ac47a5e9f14564b3.jpeg" alt="VW-Skandal: EU-Kommission verschärft Kfz-Aufsicht und Abgaskontrolle" /> </a> <p>Per Verordnung will die EU-Kommission erreichen, dass sich Automobilhersteller streng an die geltenden Sicherheits-, Umwelt- und Fertigungsanforderungen halten. Softwareprotokolle für Kfz sollen zugänglich werden.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389561061/u/0/f/653902/c/35207/s/4d2b625d/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b625d/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>PC-Version von Rise of the Tomb Raider: Die schärfste Lara Croft</title>
- <link>
- http://www.heise.de/newsticker/meldung/PC-Version-von-Rise-of-the-Tomb-Raider-Die-schaerfste-Lara-Croft-3084870.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Am 28. Januar erscheint die PC-Version von Rise of the Tomb Raider. Sie
- besticht durch tolle Grafik und flüssige Bildraten. Allerdings gibt es auch ein paar
- Probleme. heise online hat die PC-Version angetestet.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b625c/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 14:09:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084870</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/PC-Version-von-Rise-of-the-Tomb-Raider-Die-schaerfste-Lara-Croft-3084870.html?wt_mc=rss.ho.beitrag.atom" title="PC-Version von Rise of the Tomb Raider: Die schärfste Lara Croft"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/5/2/2/2016-01-25_00088-6b74693f3821a422.jpeg" alt="Lara Croft" /> </a> <p>Am 28. Januar erscheint die PC-Version von Rise of the Tomb Raider. Sie besticht durch tolle Grafik und flüssige Bildraten. Allerdings gibt es auch ein paar Probleme. heise online hat die PC-Version angetestet.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389561060/u/0/f/653902/c/35207/s/4d2b625c/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b625c/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>TP-Link-Router mit vorhersehbarem Standard-WLAN-Passwort</title>
- <link>
- http://www.heise.de/newsticker/meldung/TP-Link-Router-mit-vorhersehbarem-Standard-WLAN-Passwort-3085482.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Angreifer können das werkseitige WLAN-Passwort von einer
- TP-Link-Router-Serie vergleichsweise einfach herausfinden und sich so Zugang zum
- Netzwerk verschaffen. Weitere Serien könnten ebenfalls betroffen sein.&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b5c3d/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 14:06:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085482</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/TP-Link-Router-mit-vorhersehbarem-Standard-WLAN-Passwort-3085482.html?wt_mc=rss.ho.beitrag.atom" title="TP-Link-Router mit vorhersehbarem Standard-WLAN-Passwort"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/9/6/8/urn-newsml-dpa-com-20090101-150813-99-05231_large_4_3-fb565ab96dbaaf32.jpeg" alt="Hacker" /> </a> <p>Angreifer können das werkseitige WLAN-Passwort von einer TP-Link-Router-Serie vergleichsweise einfach herausfinden und sich so Zugang zum Netzwerk verschaffen. Weitere Serien könnten ebenfalls betroffen sein.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389559600/u/0/f/653902/c/35207/s/4d2b5c3d/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b5c3d/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Tails 2.0: Das Anonymisierungs-OS im neuen Look</title>
- <link>
- http://www.heise.de/newsticker/meldung/Tails-2-0-Das-Anonymisierungs-OS-im-neuen-Look-3085312.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Die neueste Version der spezialisierten Linux-Distribution basiert auf
- Debian Jessie und bringt Gnome Shell als neuen Desktop mit.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b0a56/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 13:47:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085312</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Tails-2-0-Das-Anonymisierungs-OS-im-neuen-Look-3085312.html?wt_mc=rss.ho.beitrag.atom" title="Tails 2.0: Das Anonymisierungs-OS im neuen Look"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/8/5/1/tails-2-3034d3a9e6bf582e.jpeg" alt="Tails 2.0" /> </a> <p>Die neueste Version der spezialisierten Linux-Distribution basiert auf Debian Jessie und bringt Gnome Shell als neuen Desktop mit.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389521976/u/0/f/653902/c/35207/s/4d2b0a56/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b0a56/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>US-Fotograf Steve McCurry: "Die Selfie-Generation ist cool"</title>
- <link>
- http://www.heise.de/newsticker/meldung/US-Fotograf-Steve-McCurry-Die-Selfie-Generation-ist-cool-3085412.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Der amerikanische Fotograf Steve McCurry ist für seine Aufnahme des &amp;quot;afghanischen
- Mädchens&amp;quot;, welches auf dem Cover der National Geographic um die Welt ging,
- bekannt. Nun sprach der 65-Jährige mit der Zeitung &amp;quot;Times of India&amp;quot;
- unter anderem über Selfies.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b0a54/sc/17/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 13:38:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085412</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/US-Fotograf-Steve-McCurry-Die-Selfie-Generation-ist-cool-3085412.html?wt_mc=rss.ho.beitrag.atom" title="US-Fotograf Steve McCurry: &quot;Die Selfie-Generation ist cool&quot;"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/9/2/0/selfie_Bild-3258a76bab7f85ec.png" alt="Selfie" /> </a> <p>Der amerikanische Fotograf Steve McCurry ist für seine Aufnahme des "afghanischen Mädchens", welches auf dem Cover der National Geographic um die Welt ging, bekannt. Nun sprach der 65-Jährige mit der Zeitung "Times of India" unter anderem über Selfies.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/a2.htm"><img src="http://da.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389521975/u/0/f/653902/c/35207/s/4d2b0a54/sc/17/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b0a54/sc/17/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>AMDs GPUOpen: Zahlreiche SDKs und Tools auf GitHub im Source verfügbar</title>
- <link>
- http://www.heise.de/newsticker/meldung/AMDs-GPUOpen-Zahlreiche-SDKs-und-Tools-auf-GitHub-im-Source-verfuegbar-3085309.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>AMDs Open-Source-Initiative spricht zum einen Spieleentwickler und zum
- anderen Entwickler von HPC-Anwendungen an. Der Chiphersteller veröffentlicht nun
- zahlreiche SDKs und Werkzeuge auf GitHub.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b26a0/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 13:36:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085309</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/AMDs-GPUOpen-Zahlreiche-SDKs-und-Tools-auf-GitHub-im-Source-verfuegbar-3085309.html?wt_mc=rss.ho.beitrag.atom" title="AMDs GPUOpen: Zahlreiche SDKs und Tools auf GitHub im Source verfügbar"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/8/4/8/aufmacher_ajax_7-7ba40e6cf8bbc8b9.jpeg" alt="AMDs GPUOpen: Zahlreiche SDKs und Tools auf GitHub im Source verfügbar" /> </a> <p>AMDs Open-Source-Initiative spricht zum einen Spieleentwickler und zum anderen Entwickler von HPC-Anwendungen an. Der Chiphersteller veröffentlicht nun zahlreiche SDKs und Werkzeuge auf GitHub.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389556077/u/0/f/653902/c/35207/s/4d2b26a0/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b26a0/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>ZTE Axon Mini: Erstes Android-Smartphone mit Force Touch kommt nach Deutschland
- </title>
- <link>
- http://www.heise.de/newsticker/meldung/ZTE-Axon-Mini-Erstes-Android-Smartphone-mit-Force-Touch-kommt-nach-Deutschland-3085296.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>ZTE bringt ein Smartphone auf den deutschen Markt, das je nach Fingerdruck
- anders reagiert. Davon abgesehen ist das Axon Mini ein 5,2-Zöller mit guter
- Ausstattung in gewöhnungsbedürftiger Farbe.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b269f/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 13:34:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085296</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/ZTE-Axon-Mini-Erstes-Android-Smartphone-mit-Force-Touch-kommt-nach-Deutschland-3085296.html?wt_mc=rss.ho.beitrag.atom" title="ZTE Axon Mini: Erstes Android-Smartphone mit Force Touch kommt nach Deutschland"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/8/3/5/Axon_mini_gross-3904a6075b401bc4.png" alt="ZTE Axon Mini: Erstes Android-Smartphone mit Force Touch kommt nach Deutschland" /> </a> <p>ZTE bringt ein Smartphone auf den deutschen Markt, das je nach Fingerdruck anders reagiert. Davon abgesehen ist das Axon Mini ein 5,2-Zöller mit guter Ausstattung in gewöhnungsbedürftiger Farbe.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389556076/u/0/f/653902/c/35207/s/4d2b269f/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2b269f/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>#heiseshow: Die wöchentliche Dosis Technik-News und Netzpolitik</title>
- <link>
- http://www.heise.de/newsticker/meldung/heiseshow-Die-woechentliche-Dosis-Technik-News-und-Netzpolitik-3085429.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Am Donnerstag um 16 Uhr starten wir ein neues Live-Videoformat: Mit Gästen
- diskutiert das Team von heise online über aktuelle Ereignisse in der Hightech-Welt
- und der Netzpolitik.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2ae4d2/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 13:21:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085429</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/heiseshow-Die-woechentliche-Dosis-Technik-News-und-Netzpolitik-3085429.html?wt_mc=rss.ho.beitrag.atom" title="#heiseshow: Die wöchentliche Dosis Technik-News und Netzpolitik "> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/9/3/1/heiseshow-3a3418ff4dee8a31.jpeg" alt="#heiseshow: Die wöchentliche Dosis Technik-News und Netzpolitik" /> </a> <p>Am Donnerstag um 16 Uhr starten wir ein neues Live-Videoformat: Mit Gästen diskutiert das Team von heise online über aktuelle Ereignisse in der Hightech-Welt und der Netzpolitik. </p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389554329/u/0/f/653902/c/35207/s/4d2ae4d2/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2ae4d2/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Wikipedianer lehnen sich gegen Wikimedia-Vorstand auf</title>
- <link>
- http://www.heise.de/newsticker/meldung/Wikipedianer-lehnen-sich-gegen-Wikimedia-Vorstand-auf-3085399.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Mit einem inoffiziellen Misstrauensvotum wollen Wikipedianer ein
- Vorstandsmitglied zum Rücktritt drängen. Der ehemalige Google-Manager will jedoch
- nicht gehen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2ad413/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 12:29:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085399</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Wikipedianer-lehnen-sich-gegen-Wikimedia-Vorstand-auf-3085399.html?wt_mc=rss.ho.beitrag.atom" title="Wikipedianer lehnen sich gegen Wikimedia-Vorstand auf"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/9/1/3/Arnnon_Geshuri_-_January_2016_by_Myleen_Hollero-5e314ca8f617253b.jpeg" alt="Arnnon Geshuri" /> </a> <p>Mit einem inoffiziellen Misstrauensvotum wollen Wikipedianer ein Vorstandsmitglied zum Rücktritt drängen. Der ehemalige Google-Manager will jedoch nicht gehen. </p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389550223/u/0/f/653902/c/35207/s/4d2ad413/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2ad413/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Google senkt Preise für Smartphones Nexus 5X und 6P</title>
- <link>
- http://www.heise.de/newsticker/meldung/Google-senkt-Preise-fuer-Smartphones-Nexus-5X-und-6P-3085276.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Bis Mitte Februar verkauft Google seine Nexus-Smartphones günstiger: Das
- Nexus 5X startet bei 349 Euro, das Nexus 6P bei 549 Euro.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a8d5f/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 12:15:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085276</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Google-senkt-Preise-fuer-Smartphones-Nexus-5X-und-6P-3085276.html?wt_mc=rss.ho.beitrag.atom" title="Google senkt Preise für Smartphones Nexus 5X und 6P"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/8/1/9/c2040d5fb8bfa013564ddfad41be1c81_edited_102383421_731166a169-760c6bc66e60d0b9.jpeg" alt="Google senkt Preise für Nexus 5X und 6P" /> </a> <p>Bis Mitte Februar verkauft Google seine Nexus-Smartphones günstiger: Das Nexus 5X startet bei 349 Euro, das Nexus 6P bei 549 Euro.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389510599/u/0/f/653902/c/35207/s/4d2a8d5f/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a8d5f/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Bundesregierung verlangt Glasfaserkabel entlang von Fernstraßen und anderer
- Infrastruktur
- </title>
- <link>
- http://www.heise.de/newsticker/meldung/Bundesregierung-verlangt-Glasfaserkabel-entlang-von-Fernstrassen-und-anderer-Infrastruktur-3085354.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Das Bundeskabinett will &amp;quot;Voraussetzungen für die
- Gigabit-Gesellschaft&amp;quot; schaffen und hat dafür ein Gesetz vorgelegt:
- Öffentliche Versorgungsnetzbetreiber sollen ihre Infrastruktur für Breitband öffnen.&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a7435/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 11:58:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085354</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Bundesregierung-verlangt-Glasfaserkabel-entlang-von-Fernstrassen-und-anderer-Infrastruktur-3085354.html?wt_mc=rss.ho.beitrag.atom" title="Bundesregierung verlangt Glasfaserkabel entlang von Fernstraßen und anderer Infrastruktur"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/8/8/5/Glasfaser4-7066ce2c9806ac68-51eff592570dcd6e.png" alt="Bundesregierung verlangt Glasfaserkabel entlang von Fernstraßen und anderer Infrastruktur" /> </a> <p>Das Bundeskabinett will "Voraussetzungen für die Gigabit-Gesellschaft" schaffen und hat dafür ein Gesetz vorgelegt: Öffentliche Versorgungsnetzbetreiber sollen ihre Infrastruktur für Breitband öffnen.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389552422/u/0/f/653902/c/35207/s/4d2a7435/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a7435/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>iOS und OS X: Safari-Vorschläge legen Apples Webbrowser lahm</title>
- <link>
- http://www.heise.de/newsticker/meldung/iOS-und-OS-X-Safari-Vorschlaege-legen-Apples-Webbrowser-lahm-3085337.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Eine Fehlkonfiguration bei Apples Suchhilfe scheint aktuell der Grund für
- einen sofortigen Absturz von Safari, wenn Nutzer auf iPhone oder iPad die
- Adresszeile auswählen oder eine Eingabe starten. Das Problem lässt sich umgehen.&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a66f7/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 11:38:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085337</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/iOS-und-OS-X-Safari-Vorschlaege-legen-Apples-Webbrowser-lahm-3085337.html?wt_mc=rss.ho.beitrag.atom" title="iOS und OS X: Safari-Vorschläge legen Apples Webbrowser lahm"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/8/7/4/urn-newsml-dpa-com-20090101-160127-99-251554_large_4_3-d71a5d70124b506d.jpeg" alt="Apple" /> </a> <p>Eine Fehlkonfiguration bei Apples Suchhilfe scheint aktuell der Grund für einen sofortigen Absturz von Safari, wenn Nutzer auf iPhone oder iPad die Adresszeile auswählen oder eine Eingabe starten. Das Problem lässt sich umgehen.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389542680/u/0/f/653902/c/35207/s/4d2a66f7/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a66f7/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>VMware baut 800 Arbeitsplätze ab</title>
- <link>
- http://www.heise.de/newsticker/meldung/VMware-baut-800-Arbeitsplaetze-ab-3085308.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Der Hersteller von Virtualisierungssoftware will sich umstrukturieren.
- Dafür müssen zunächst 800 Mitarbeiter gehen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a66f6/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 11:34:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085308</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/VMware-baut-800-Arbeitsplaetze-ab-3085308.html?wt_mc=rss.ho.beitrag.atom" title="VMware baut 800 Arbeitsplätze ab"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/8/4/7/logo-guidelines-f0ba93178fa3ecae.jpeg" alt="VMware baut 800 Arbeitsplätze ab" /> </a> <p>Der Hersteller von Virtualisierungssoftware will sich umstrukturieren. Dafür müssen zunächst 800 Mitarbeiter gehen.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389542679/u/0/f/653902/c/35207/s/4d2a66f6/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a66f6/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Menschen-Rohrpost Hyperloop: Elon Musk lässt Aecom Teststrecke bauen</title>
- <link>
- http://www.heise.de/newsticker/meldung/Menschen-Rohrpost-Hyperloop-Elon-Musk-laesst-Aecom-Teststrecke-bauen-3085245.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Die Firma Aecom will noch im Frühling mit dem Bau einer
- Hyperloop-Teststecke starten. Elon Musks Firma SpaceX hat das
- Fortune-500-Unternehmen damit beauftragt. Studierende sollen helfen,
- Kapsel-Prototypen zu bauen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a0cbe/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 11:13:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085245</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Menschen-Rohrpost-Hyperloop-Elon-Musk-laesst-Aecom-Teststrecke-bauen-3085245.html?wt_mc=rss.ho.beitrag.atom" title="Menschen-Rohrpost Hyperloop: Elon Musk lässt Aecom Teststrecke bauen"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/7/9/1/Hyperloop-0f7f26eb632745e4-61f3c13ae470a965.jpeg" alt="Hyperloop" /> </a> <p>Die Firma Aecom will noch im Frühling mit dem Bau einer Hyperloop-Teststecke starten. Elon Musks Firma SpaceX hat das Fortune-500-Unternehmen damit beauftragt. Studierende sollen helfen, Kapsel-Prototypen zu bauen. </p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389503052/u/0/f/653902/c/35207/s/4d2a0cbe/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a0cbe/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Lenovos Datentausch-App Shareit: 12345678 als Standardpasswort</title>
- <link>
- http://www.heise.de/newsticker/meldung/Lenovos-Datentausch-App-Shareit-12345678-als-Standardpasswort-3085250.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>In der Shareit-Anwendung von Lenovo klaffen mehrere Schwachstellen, über
- die Angreifer Nutzern unter anderem Schadcode unterjubeln können. Gefixte Version
- sollen das unterbinden.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a0506/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 10:54:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085250</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Lenovos-Datentausch-App-Shareit-12345678-als-Standardpasswort-3085250.html?wt_mc=rss.ho.beitrag.atom" title="Lenovos Datentausch-App Shareit: 12345678 als Standardpasswort"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/7/9/5/shareit-7a502640b4aca443.png" alt="Lenovos Datentausch-App Shareit mit 12345678 als Standardpasswort" /> </a> <p>In der Shareit-Anwendung von Lenovo klaffen mehrere Schwachstellen, über die Angreifer Nutzern unter anderem Schadcode unterjubeln können. Gefixte Version sollen das unterbinden.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389501134/u/0/f/653902/c/35207/s/4d2a0506/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a0506/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Paketdrohne: Google lässt sich beweglichen Paketempfangsbehälter patentieren
- </title>
- <link>
- http://www.heise.de/newsticker/meldung/Paketdrohne-Google-laesst-sich-beweglichen-Paketempfangsbehaelter-patentieren-3085263.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Manche Orte können von unbemannten Fluggeräten nicht ohne Sicherheitsrisiko
- angeflogen werden. Dafür haben sich Google-Entwickler eine Lösung ausgedacht.&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a0504/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 10:53:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085263</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Paketdrohne-Google-laesst-sich-beweglichen-Paketempfangsbehaelter-patentieren-3085263.html?wt_mc=rss.ho.beitrag.atom" title="Paketdrohne: Google lässt sich beweglichen Paketempfangsbehälter patentieren"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/8/0/7/Bildschirmfoto_2016-01-27_um_11-8a774a671e812db7.jpeg" alt="Paketdrohne: Google lässt sich beweglichen Paketempfangsbehälter patentieren" /> </a> <p>Manche Orte können von unbemannten Fluggeräten nicht ohne Sicherheitsrisiko angeflogen werden. Dafür haben sich Google-Entwickler eine Lösung ausgedacht.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389501131/u/0/f/653902/c/35207/s/4d2a0504/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2a0504/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Webbrowser Firefox 44 mit verbesserten Push-Nachrichten</title>
- <link>
- http://www.heise.de/newsticker/meldung/Webbrowser-Firefox-44-mit-verbesserten-Push-Nachrichten-3085193.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Version 44 des Firefox-Browsers verschickt nun auch Push-Nachrichten von
- Websites, die nicht geöffnet sind. Zudem haben die Entwickler die Fehlerseiten
- verbessert und die RC4-Unterstützung entfernt.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d29ec71/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 10:42:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085193</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Webbrowser-Firefox-44-mit-verbesserten-Push-Nachrichten-3085193.html?wt_mc=rss.ho.beitrag.atom" title="Webbrowser Firefox 44 mit verbesserten Push-Nachrichten"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/7/4/8/mozz_39339342_original-4109b22bb9b70d97.jpeg" alt="Firefox" /> </a> <p>Version 44 des Firefox-Browsers verschickt nun auch Push-Nachrichten von Websites, die nicht geöffnet sind. Zudem haben die Entwickler die Fehlerseiten verbessert und die RC4-Unterstützung entfernt.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389543121/u/0/f/653902/c/35207/s/4d29ec71/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d29ec71/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>BMW steuert via IFTTT das Smart Home</title>
- <link>
- http://www.heise.de/newsticker/meldung/BMW-steuert-via-IFTTT-das-Smart-Home-3085257.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Wer einen BMW mit ConnectedDrive Services fährt, kann jetzt mit einem
- Widget für den Automatisierungsdienst IFTTT zum Beispiel das Garagentor hochfahren
- lassen, wenn er auf dem Weg nach Hause ist.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d29ec70/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 10:38:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085257</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/BMW-steuert-via-IFTTT-das-Smart-Home-3085257.html?wt_mc=rss.ho.beitrag.atom" title="BMW steuert via IFTTT das Smart Home"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/8/0/1/IFTTT-8bf9c9011ff12a0d.png" alt="BMW steuert via IFTTT das Smart Home" /> </a> <p>Wer einen BMW mit ConnectedDrive Services fährt, kann jetzt mit einem Widget für den Automatisierungsdienst IFTTT zum Beispiel das Garagentor hochfahren lassen, wenn er auf dem Weg nach Hause ist.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389543120/u/0/f/653902/c/35207/s/4d29ec70/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d29ec70/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Eine Million Petenten protestieren gegen Elfenbeinhandel auf Yahoo Japan</title>
- <link>
- http://www.heise.de/newsticker/meldung/Eine-Million-Petenten-protestieren-gegen-Elfenbeinhandel-auf-Yahoo-Japan-3085214.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Jeden Tag werden auf der Welt hundert Elefanten wegen ihrer Stoßzähne
- getötet. Die Nichtregierungsorganisation Avaaz will erreichen, dass Elfenbein nicht
- mehr über Yahoo Japan verkauft werden kann.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d29ec6e/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 10:21:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085214</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Eine-Million-Petenten-protestieren-gegen-Elfenbeinhandel-auf-Yahoo-Japan-3085214.html?wt_mc=rss.ho.beitrag.atom" title="Eine Million Petenten protestieren gegen Elfenbeinhandel auf Yahoo Japan"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/7/6/6/Bildschirmfoto_2016-01-27_um_11-2e865cc25538fb20.jpeg" alt="Eine Million Petitenten protestieren gegen Elfenbeinhandel auf Yahoo Japan" /> </a> <p>Jeden Tag werden auf der Welt hundert Elefanten wegen ihrer Stoßzähne getötet. Die Nichtregierungsorganisation Avaaz will erreichen, dass Elfenbein nicht mehr über Yahoo Japan verkauft werden kann.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389543119/u/0/f/653902/c/35207/s/4d29ec6e/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d29ec6e/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Eine Million Petitenten protestieren gegen Elfenbeinhandel auf Yahoo Japan
- </title>
- <link>
- http://www.heise.de/newsticker/meldung/Eine-Million-Petitenten-protestieren-gegen-Elfenbeinhandel-auf-Yahoo-Japan-3085214.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Jeden Tag werden auf der Welt hundert Elefanten wegen ihrer Stoßzähne
- getötet. Die Nichtregierungsorganisation Avaaz will erreichen, dass Elfenbein nicht
- mehr über Yahoo Japan verkauft werden kann.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d29bd45/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 10:21:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085214</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Eine-Million-Petitenten-protestieren-gegen-Elfenbeinhandel-auf-Yahoo-Japan-3085214.html?wt_mc=rss.ho.beitrag.atom" title="Eine Million Petitenten protestieren gegen Elfenbeinhandel auf Yahoo Japan"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/7/6/6/Bildschirmfoto_2016-01-27_um_11-2e865cc25538fb20.jpeg" alt="Eine Million Petitenten protestieren gegen Elfenbeinhandel auf Yahoo Japan" /> </a> <p>Jeden Tag werden auf der Welt hundert Elefanten wegen ihrer Stoßzähne getötet. Die Nichtregierungsorganisation Avaaz will erreichen, dass Elfenbein nicht mehr über Yahoo Japan verkauft werden kann.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389541116/u/0/f/653902/c/35207/s/4d29bd45/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d29bd45/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>China überholt die USA als größter Markt für Elektroautos</title>
- <link>
- http://www.heise.de/newsticker/meldung/China-ueberholt-die-USA-als-groesster-Markt-fuer-Elektroautos-3085152.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Die Zahl der Neuzulassungen von E-Autos steigt – auch in Deutschland. Von
- einem Leitmarkt ist die Bundesrepublik aber weit entfernt.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d29a77c/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 09:54:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085152</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/China-ueberholt-die-USA-als-groesster-Markt-fuer-Elektroautos-3085152.html?wt_mc=rss.ho.beitrag.atom" title="China überholt die USA als größter Markt für Elektroautos"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/7/1/0/Bildschirmfoto_2016-01-27_um_10-efc56d9f4ea5c1e1.jpeg" alt="Elektroauto" /> </a> <p>Die Zahl der Neuzulassungen von E-Autos steigt – auch in Deutschland. Von einem Leitmarkt ist die Bundesrepublik aber weit entfernt.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389529191/u/0/f/653902/c/35207/s/4d29a77c/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d29a77c/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Altermedia: Deutschlandweite Razzia gegen rechtsextreme Internetplattform – zwei
- Festnahmen
- </title>
- <link>
- http://www.heise.de/newsticker/meldung/Altermedia-Deutschlandweite-Razzia-gegen-rechtsextreme-Internetplattform-zwei-Festnahmen-3085140.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>In einer bundesweiten Aktion gehen Ermittler der Bundesanwaltschaft gegen
- führende Betreiber des rechtsextremen Internetportals &amp;quot;Altermedia&amp;quot;
- vor. Ihnen wird die Gründung einer kriminellen Vereinigung vorgeworfen. Inzwischen
- wurde die Vereinigung verboten.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d293258/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 09:10:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085140</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Altermedia-Deutschlandweite-Razzia-gegen-rechtsextreme-Internetplattform-zwei-Festnahmen-3085140.html?wt_mc=rss.ho.beitrag.atom" title="Altermedia: Deutschlandweite Razzia gegen rechtsextreme Internetplattform – zwei Festnahmen"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/6/9/8/urn-newsml-dpa-com-20090101-150414-99-04666_large_4_3-6f20e7a913e9ebef.jpeg" alt="Hacker" /> </a> <p>In einer bundesweiten Aktion gehen Ermittler der Bundesanwaltschaft gegen führende Betreiber des rechtsextremen Internetportals "Altermedia" vor. Ihnen wird die Gründung einer kriminellen Vereinigung vorgeworfen. Inzwischen wurde die Vereinigung verboten.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389487846/u/0/f/653902/c/35207/s/4d293258/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d293258/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Bundesdatenschutzbeauftragte warnt vor Dashcams</title>
- <link>
- http://www.heise.de/newsticker/meldung/Bundesdatenschutzbeauftragte-warnt-vor-Dashcams-3085120.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Im Ausland setzen Autofahrer vermehrt Videokameras ein, die hinter der
- Windschutzscheibe postiert werden und das Geschehen vor dem Auto kontinuierlich
- aufzeichnen. In Deutschland ist das aus Datenschutzgründen unzulässig, meint Andrea
- Voßhoff.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d293d2a/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 08:52:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085120</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Bundesdatenschutzbeauftragte-warnt-vor-Dashcams-3085120.html?wt_mc=rss.ho.beitrag.atom" title="Bundesdatenschutzbeauftragte warnt vor Dashcams"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/6/8/2/Unbenannt-1-ccb6087fae248ce5.jpeg" alt="Dashcam" /> </a> <p>Im Ausland setzen Autofahrer vermehrt Videokameras ein, die hinter der Windschutzscheibe postiert werden und das Geschehen vor dem Auto kontinuierlich aufzeichnen. In Deutschland ist das aus Datenschutzgründen unzulässig, meint Andrea Voßhoff.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389528982/u/0/f/653902/c/35207/s/4d293d2a/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d293d2a/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Unitymedia bietet Kabelanschlüsse mit 400 MBit/s an</title>
- <link>
- http://www.heise.de/newsticker/meldung/Unitymedia-bietet-Kabelanschluesse-mit-400-MBit-s-an-3084956.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Der Kabelriese dreht an der Speed-Schraube: Rund 40 Prozent der Haushalte
- im Verbreitungsgebiet in Nordrhein-Westfalen, Hessen und Baden-Württemberg können in
- Kürze Anschlüsse mit bis zu 400 MBit/s buchen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d291cc3/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 08:30:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084956</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Unitymedia-bietet-Kabelanschluesse-mit-400-MBit-s-an-3084956.html?wt_mc=rss.ho.beitrag.atom" title="Unitymedia bietet Kabelanschlüsse mit 400 MBit/s an"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/5/7/5/kdg_docsis_200-b8c485b1e19b9753-9d3ae9132349e0f6-d75e967a29e534a4.jpeg" alt="Unitymedia" /> </a> <p>Der Kabelriese dreht an der Speed-Schraube: Rund 40 Prozent der Haushalte im Verbreitungsgebiet in Nordrhein-Westfalen, Hessen und Baden-Württemberg können in Kürze Anschlüsse mit bis zu 400 MBit/s buchen.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389519640/u/0/f/653902/c/35207/s/4d291cc3/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d291cc3/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Tim Cook zu den Apple-Quartalszahlen: Weiterhin kein Billig-iPhone</title>
- <link>
- http://www.heise.de/newsticker/meldung/Tim-Cook-zu-den-Apple-Quartalszahlen-Weiterhin-kein-Billig-iPhone-3085095.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Der Apple-Chef hat sich im Gespräch mit Analysten zur künftigen
- Geschäftsstrategie geäußert, da das geringe Wachstum beim iPhone der Börse Sorge
- bereitet. Auch zum für Cupertino zunehmend bedeutenden Wachstumsmarkt China nannte
- er Details.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d291cc2/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 08:12:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085095</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Tim-Cook-zu-den-Apple-Quartalszahlen-Weiterhin-kein-Billig-iPhone-3085095.html?wt_mc=rss.ho.beitrag.atom" title="Tim Cook zu den Apple-Quartalszahlen: Weiterhin kein Billig-iPhone"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/6/6/6/urn-newsml-dpa-com-20090101-151020-99-02535_large_4_3-44c62c7b61723c1b.jpeg" alt="Tim Cook" /> </a> <p>Der Apple-Chef hat sich im Gespräch mit Analysten zur künftigen Geschäftsstrategie geäußert, da das geringe Wachstum beim iPhone der Börse Sorge bereitet. Auch zum für Cupertino zunehmend bedeutenden Wachstumsmarkt China nannte er Details.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389519639/u/0/f/653902/c/35207/s/4d291cc2/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d291cc2/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Lufthansa und Drohnenhersteller DJI werden Partner</title>
- <link>
- http://www.heise.de/newsticker/meldung/Lufthansa-und-Drohnenhersteller-DJI-werden-Partner-3085067.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Die Lufthansa möchte neue Geschäftsfelder erobern. Zusammen mit dem
- Drohnenhersteller DJI sollen Drohnen für Großkunden gefertigt werden. Diese könnten
- mit den fliegenden Helfern etwa einfacher Windkraftanlagen überwachen oder
- Baufortschritte verfolgen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d28e6a3/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 08:11:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085067</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Lufthansa-und-Drohnenhersteller-DJI-werden-Partner-3085067.html?wt_mc=rss.ho.beitrag.atom" title="Lufthansa und Drohnenhersteller DJI werden Partner "> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/6/4/5/d20ed2f1c559d64f6fd690e5c8b54932_edited_102368661_e1e4041693-ff2f5513b2065135.jpeg" alt="Drohne" /> </a> <p>Die Lufthansa möchte neue Geschäftsfelder erobern. Zusammen mit dem Drohnenhersteller DJI sollen Drohnen für Großkunden gefertigt werden. Diese könnten mit den fliegenden Helfern etwa einfacher Windkraftanlagen überwachen oder Baufortschritte verfolgen. </p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389516237/u/0/f/653902/c/35207/s/4d28e6a3/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d28e6a3/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Wasserknappheit bedroht Stromproduktion</title>
- <link>
- http://www.heise.de/newsticker/meldung/Wasserknappheit-bedroht-Stromproduktion-3084350.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Forscher fürchten, dass die globale Stromproduktion aufgrund des
- Klimawandels in den nächsten 35 Jahren deutlich zurückgehen könnte. Der Grund: Dürre
- macht Kühlung unmöglich.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2893ec/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 07:07:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084350</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Wasserknappheit-bedroht-Stromproduktion-3084350.html?wt_mc=rss.ho.beitrag.atom" title="Wasserknappheit bedroht Stromproduktion"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/1/6/4/Medupi_Power_Station_-_700-f13dbe6e74040f34.jpeg" alt="Kraftwerk" /> </a> <p>Forscher fürchten, dass die globale Stromproduktion aufgrund des Klimawandels in den nächsten 35 Jahren deutlich zurückgehen könnte. Der Grund: Dürre macht Kühlung unmöglich.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389516745/u/0/f/653902/c/35207/s/4d2893ec/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2893ec/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Studie: Soziale Netzwerke und schlechter Schlaf gehören zusammen</title>
- <link>
- http://www.heise.de/newsticker/meldung/Studie-Soziale-Netzwerke-und-schlechter-Schlaf-gehoeren-zusammen-3085003.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Verbringen junge Erwachsene Zeit in sozialen Netzwerken und greifen häufig
- auf ihre Konten zu, leiden sie auch öfter unter Schlafstörungen. So lautet das
- Ergebnis einer Studie von Forschern der University of Pittsburgh.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d288bd0/sc/17/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 06:48:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085003</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Studie-Soziale-Netzwerke-und-schlechter-Schlaf-gehoeren-zusammen-3085003.html?wt_mc=rss.ho.beitrag.atom" title="Studie: Soziale Netzwerke und schlechter Schlaf gehören zusammen"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/6/0/8/urn-newsml-dpa-com-20090101-150914-99-09432_large_4_3-6b57417c781dba0f.jpeg" alt="Kind mit Tablet" /> </a> <p>Verbringen junge Erwachsene Zeit in sozialen Netzwerken und greifen häufig auf ihre Konten zu, leiden sie auch öfter unter Schlafstörungen. So lautet das Ergebnis einer Studie von Forschern der University of Pittsburgh.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/a2.htm"><img src="http://da.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389514741/u/0/f/653902/c/35207/s/4d288bd0/sc/17/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d288bd0/sc/17/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>136 Jahre nach Edisons Patent: Forscher arbeiten an einer Renaissance der
- Glühbirne
- </title>
- <link>
- http://www.heise.de/newsticker/meldung/136-Jahre-nach-Edisons-Patent-Forscher-arbeiten-an-einer-Renaissance-der-Gluehbirne-3084807.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Am 27. Januar 1880 erhielt Thomas A. Edison das Patent Nr. 223.898 für die
- &amp;quot;Elektrische Lampe&amp;quot;. Heute wollen Forscher des MIT und der Purdue
- University der totgesagten Glühbirne mit Nano-Beschichtung wieder eine Renaissance
- bescheren.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d28388a/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 06:30:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084807</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/136-Jahre-nach-Edisons-Patent-Forscher-arbeiten-an-einer-Renaissance-der-Gluehbirne-3084807.html?wt_mc=rss.ho.beitrag.atom" title="136 Jahre nach Edisons Patent: Forscher arbeiten an einer Renaissance der Glühbirne"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/4/8/1/b17ec7a6d8c60af156976d8240fd9726_edited_102352246_992ac921cb-4aec3b4d681674f7.jpeg" alt="Glühbirne" /> </a> <p>Am 27. Januar 1880 erhielt Thomas A. Edison das Patent Nr. 223.898 für die "Elektrische Lampe". Heute wollen Forscher des MIT und der Purdue University der totgesagten Glühbirne mit Nano-Beschichtung wieder eine Renaissance bescheren. </p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389470313/u/0/f/653902/c/35207/s/4d28388a/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d28388a/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Verschlüsselung: IETF standardisiert zwei weitere elliptische Kurven</title>
- <link>
- http://www.heise.de/newsticker/meldung/Verschluesselung-IETF-standardisiert-zwei-weitere-elliptische-Kurven-3084830.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Die IETF hat die beiden elliptischen Kurven Curve25519 und Curve448 als RFC
- für Krypto-Funktionen offiziell abgesegnet. Eine Standardisierung der Kurven für den
- Schlüsselaustausch bei TLS wird ebenfalls erwartet.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d283e99/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 06:01:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084830</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Verschluesselung-IETF-standardisiert-zwei-weitere-elliptische-Kurven-3084830.html?wt_mc=rss.ho.beitrag.atom" title="Verschlüsselung: IETF standardisiert zwei weitere elliptische Kurven"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/5/0/0/curve25519-ecc1ddd469ad6cd4.png" alt="IETF verabschiedet zwei elliptische Kurven" /> </a> <p>Die IETF hat die beiden elliptischen Kurven Curve25519 und Curve448 als RFC für Krypto-Funktionen offiziell abgesegnet. Eine Standardisierung der Kurven für den Schlüsselaustausch bei TLS wird ebenfalls erwartet.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389510249/u/0/f/653902/c/35207/s/4d283e99/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d283e99/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Rekordgewinn: Apple trotzt dem starken Dollar</title>
- <link>
- http://www.heise.de/newsticker/meldung/Rekordgewinn-Apple-trotzt-dem-starken-Dollar-3085026.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Höchster Umsatz, höchster Reingewinn und eine Marge von 40 Prozent erzielte
- Apple im Weihnachtsquartal. Weil frühere Weihnachtsquartale aber mehr Zuwachs
- gebracht hatten, reagierte der Aktienmarkt leicht pikiert.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d280d10/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 05:34:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3085026</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Rekordgewinn-Apple-trotzt-dem-starken-Dollar-3085026.html?wt_mc=rss.ho.beitrag.atom" title="Rekordgewinn: Apple trotzt dem starken Dollar"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/6/1/8/5bc9e08b71b608e7c32186a87b76aa6a_edited_102365868_95dcadf632-9fbfdf75e421933d.jpeg" alt="Abfallende Kurve" /> </a> <p>Höchster Umsatz, höchster Reingewinn und eine Marge von 40 Prozent erzielte Apple im Weihnachtsquartal. Weil frühere Weihnachtsquartale aber mehr Zuwachs gebracht hatten, reagierte der Aktienmarkt leicht pikiert.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389507720/u/0/f/653902/c/35207/s/4d280d10/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d280d10/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Dank Eigenbau-Exoskelett: Der menschliche Wagenheber</title>
- <link>
- http://www.heise.de/newsticker/meldung/Dank-Eigenbau-Exoskelett-Der-menschliche-Wagenheber-3084868.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Wie viel Krafttraining braucht man, um die Hinterachse eines Mini Coopers
- vom Boden zu heben? Keines, jedenfalls wenn man das pneumatische Exoskelett benutzt,
- das James Hobson selbst gebaut hat.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d281348/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Wed, 27 Jan 2016 05:00:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084868</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Dank-Eigenbau-Exoskelett-Der-menschliche-Wagenheber-3084868.html?wt_mc=rss.ho.beitrag.atom" title="Dank Eigenbau-Exoskelett: Der menschliche Wagenheber"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/5/2/0/Homemade_Exoskeleton_Lifts_Mini_Cooper__-_YouTube_2016-01-26_17-52-24-f2bb9d9aa796b6cb.png" alt="DIY Exoskelett hebt Auto" /> </a> <p>Wie viel Krafttraining braucht man, um die Hinterachse eines Mini Coopers vom Boden zu heben? Keines, jedenfalls wenn man das pneumatische Exoskelett benutzt, das James Hobson selbst gebaut hat.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389498069/u/0/f/653902/c/35207/s/4d281348/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d281348/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>"Online-Kriminellen nicht hinterherlaufen" – Mehr EU-Kooperation gegen
- Cyberkriminalität
- </title>
- <link>
- http://www.heise.de/newsticker/meldung/Online-Kriminellen-nicht-hinterherlaufen-Mehr-EU-Kooperation-gegen-Cyberkriminalitaet-3084940.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Wer ein Verbrechen begeht, hinterlässt oft Spuren – das gilt auch im
- Internet. Doch in der virtuellen Welt ist die Strafverfolgung schwierig. Was wenn
- der Täter von einem weit entfernten Erdteil agiert oder Daten dort gespeichert sind?&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d25a88b/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 18:08:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084940</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Online-Kriminellen-nicht-hinterherlaufen-Mehr-EU-Kooperation-gegen-Cyberkriminalitaet-3084940.html?wt_mc=rss.ho.beitrag.atom" title="&quot;Online-Kriminellen nicht hinterherlaufen&quot; – Mehr EU-Kooperation gegen Cyberkriminalität"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/5/6/3/urn-newsml-dpa-com-20090101-150617-99-05723_large_4_3-6d024b06feefb739.jpeg" alt="&quot;Enter Password&quot;" /> </a> <p>Wer ein Verbrechen begeht, hinterlässt oft Spuren – das gilt auch im Internet. Doch in der virtuellen Welt ist die Strafverfolgung schwierig. Was wenn der Täter von einem weit entfernten Erdteil agiert oder Daten dort gespeichert sind?</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389422225/u/0/f/653902/c/35207/s/4d25a88b/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d25a88b/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Jolla: Update für Sailfish OS, Tablet-Abwicklung ungeklärt</title>
- <link>
- http://www.heise.de/newsticker/meldung/Jolla-Update-fuer-Sailfish-OS-Tablet-Abwicklung-ungeklaert-3084918.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Die Abwicklung des gescheiterten Tablet-Projekts verzögert sich bei Jolla
- weiter. Dafür stellt das Start-up ein Update für sein Betriebssystem Sailfish OS
- bereit und Partner Intex kündigt für den MWC ein Smartphone mit Sailfish OS an.&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d256c68/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 17:41:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084918</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Jolla-Update-fuer-Sailfish-OS-Tablet-Abwicklung-ungeklaert-3084918.html?wt_mc=rss.ho.beitrag.atom" title="Jolla: Update für Sailfish OS, Tablet-Abwicklung ungeklärt"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/5/4/7/jolla-97b85423540dfde4.png" alt="Jolla: Update für Sailfish OS, Tablet-Abwicklung ungeklärt" /> </a> <p>Die Abwicklung des gescheiterten Tablet-Projekts verzögert sich bei Jolla weiter. Dafür stellt das Start-up ein Update für sein Betriebssystem Sailfish OS bereit und Partner Intex kündigt für den MWC ein Smartphone mit Sailfish OS an.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389460756/u/0/f/653902/c/35207/s/4d256c68/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d256c68/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Periscope ermöglicht Livestreaming mit GoPro-Kamera</title>
- <link>
- http://www.heise.de/newsticker/meldung/Periscope-ermoeglicht-Livestreaming-mit-GoPro-Kamera-3084901.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Die iPhone-App von Twitters Livestreaming-Dienstes unterstützt nun GoPro:
- Die Aufnahme der Action-Cam lässt sich so unmittelbar ausstrahlen – im Wechsel mit
- der iPhone-Kamera&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d252b88/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 17:11:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084901</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Periscope-ermoeglicht-Livestreaming-mit-GoPro-Kamera-3084901.html?wt_mc=rss.ho.beitrag.atom" title="Periscope ermöglicht Livestreaming mit GoPro-Kamera"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/5/3/3/Bildschirmfoto_2016-01-26_um_17-5a21fc7e60faedc5.png" alt="Periscope GoPro" /> </a> <p>Die iPhone-App von Twitters Livestreaming-Dienstes unterstützt nun GoPro: Die Aufnahme der Action-Cam lässt sich so unmittelbar ausstrahlen – im Wechsel mit der iPhone-Kamera</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389416151/u/0/f/653902/c/35207/s/4d252b88/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d252b88/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Globales Satelliten-Internet: Airbus gründet Joint Venture mit OneWeb</title>
- <link>
- http://www.heise.de/newsticker/meldung/Globales-Satelliten-Internet-Airbus-gruendet-Joint-Venture-mit-OneWeb-3084840.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Der europäische Rüstungs- und Weltraumkonzern Airbus arbeitet jetzt noch
- enger mit OneWeb zusammen bei dem Vorhaben, Hunderte Satelliten ins All zu schießen,
- die die ganze Erde mit Internet versorgen sollen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d252c8b/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 16:38:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084840</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Globales-Satelliten-Internet-Airbus-gruendet-Joint-Venture-mit-OneWeb-3084840.html?wt_mc=rss.ho.beitrag.atom" title="Globales Satelliten-Internet: Airbus gründet Joint Venture mit OneWeb"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/5/1/0/slide-2-42ff2dea3b808ad3.jpeg" alt="Globales Satelliten-Internet: Airbus gründet Joint Venture mit OneWeb" /> </a> <p>Der europäische Rüstungs- und Weltraumkonzern Airbus arbeitet jetzt noch enger mit OneWeb zusammen bei dem Vorhaben, Hunderte Satelliten ins All zu schießen, die die ganze Erde mit Internet versorgen sollen.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389454758/u/0/f/653902/c/35207/s/4d252c8b/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d252c8b/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Verfassungsgericht stoppt Vorratsdatenspeicherung vorerst nicht</title>
- <link>
- http://www.heise.de/newsticker/meldung/Verfassungsgericht-stoppt-Vorratsdatenspeicherung-vorerst-nicht-3084879.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Das Bundesverfassungsgericht hat einen Antrag aus einer
- Verfassungsbeschwerde abgelehnt, wonach die neue Speicherpflicht für elektronische
- Nutzerspuren zunächst gar nicht greifen sollte. In der Sache ist damit aber noch
- nichts entschieden.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d252c8a/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 16:37:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084879</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Verfassungsgericht-stoppt-Vorratsdatenspeicherung-vorerst-nicht-3084879.html?wt_mc=rss.ho.beitrag.atom" title="Verfassungsgericht stoppt Vorratsdatenspeicherung vorerst nicht"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/5/2/7/Bildschirmfoto_2016-01-26_um_17-1ebffe496feca16d.jpeg" alt="Verfassungsgericht stoppt Vorratsdatenspeicherung vorerst nicht" /> </a> <p>Das Bundesverfassungsgericht hat einen Antrag aus einer Verfassungsbeschwerde abgelehnt, wonach die neue Speicherpflicht für elektronische Nutzerspuren zunächst gar nicht greifen sollte. In der Sache ist damit aber noch nichts entschieden.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389454757/u/0/f/653902/c/35207/s/4d252c8a/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d252c8a/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Intel enthüllt erste Skylake-Prozessoren mit Iris-Pro-Grafik</title>
- <link>
- http://www.heise.de/newsticker/meldung/Intel-enthuellt-erste-Skylake-Prozessoren-mit-Iris-Pro-Grafik-3084686.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>In Intels neustem Preislisten-Update finden sich etliche neue
- Skylake-Modelle für Notebooks, darunter das neue Flaggschiff: der rund 1200
- US-Dollar teure Xeon E3-1575M v5 mit Iris Pro P580.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d24fe5f/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 16:27:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084686</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Intel-enthuellt-erste-Skylake-Prozessoren-mit-Iris-Pro-Grafik-3084686.html?wt_mc=rss.ho.beitrag.atom" title="Intel enthüllt erste Skylake-Prozessoren mit Iris-Pro-Grafik"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/4/0/9/Intel-Waferspin1-82c1b072cc5449c0.png" alt="Intel" /> </a> <p>In Intels neustem Preislisten-Update finden sich etliche neue Skylake-Modelle für Notebooks, darunter das neue Flaggschiff: der rund 1200 US-Dollar teure Xeon E3-1575M v5 mit Iris Pro P580.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389453021/u/0/f/653902/c/35207/s/4d24fe5f/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d24fe5f/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Pornografie-Vorwurf: Pakistan sperrt mehr als 400.000 Webseiten</title>
- <link>
- http://www.heise.de/newsticker/meldung/Pornografie-Vorwurf-Pakistan-sperrt-mehr-als-400-000-Webseiten-3084805.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Eine Woche nach der Wiederzulassung von YouTube hat Pakistans
- Telekommunikationsbehörde angekündigt, eine halbe Million Webseiten wegen
- angeblicher Pornografie zu löschen. Welche Seiten es letztlich trifft, ist noch
- nicht abzusehen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d24d43d/sc/17/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 15:50:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084805</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Pornografie-Vorwurf-Pakistan-sperrt-mehr-als-400-000-Webseiten-3084805.html?wt_mc=rss.ho.beitrag.atom" title="Pornografie-Vorwurf: Pakistan sperrt mehr als 400.000 Webseiten"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/4/7/9/urn-newsml-dpa-com-20090101-150316-99-09245_large_4_3-bea5f029e8655dbf.jpeg" alt="Surfen im Internet" /> </a> <p>Eine Woche nach der Wiederzulassung von YouTube hat Pakistans Telekommunikationsbehörde angekündigt, eine halbe Million Webseiten wegen angeblicher Pornografie zu löschen. Welche Seiten es letztlich trifft, ist noch nicht abzusehen.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/a2.htm"><img src="http://da.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389441451/u/0/f/653902/c/35207/s/4d24d43d/sc/17/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d24d43d/sc/17/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Phishing-SMS: Identitätsdiebstahl bei Car2go-Kunden</title>
- <link>
- http://www.heise.de/newsticker/meldung/Phishing-SMS-Identitaetsdiebstahl-bei-Car2go-Kunden-3084730.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Über eine SMS wollen Betrüger Car2go-Nutzer auf eine Phishing-Webseite
- locken und persönliche Daten abziehen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d24cd38/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 15:39:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084730</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Phishing-SMS-Identitaetsdiebstahl-bei-Car2go-Kunden-3084730.html?wt_mc=rss.ho.beitrag.atom" title="Phishing-SMS: Identitätsdiebstahl bei Car2go-Kunden"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/4/3/4/urn-newsml-dpa-com-20090101-141016-99-05211_large_4_3-b82d617fe2ae9b7d.jpeg" alt="SMS" /> </a> <p>Über eine SMS wollen Betrüger Car2go-Nutzer auf eine Phishing-Webseite locken und persönliche Daten abziehen. </p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389439795/u/0/f/653902/c/35207/s/4d24cd38/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d24cd38/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Studie: Vernetzung von Autos schafft mehr Sicherheit – aber auch Skepsis</title>
- <link>
- http://www.heise.de/newsticker/meldung/Studie-Vernetzung-von-Autos-schafft-mehr-Sicherheit-aber-auch-Skepsis-3084679.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Analysten im Auftrag des Wirtschaftsministeriums kommen zu dem Ergebnis,
- dass die Vernetzung von Fahrzeugen und Straßen Sicherheit und Komfort verbessert.
- Die Angst vorm gläsernen Fahrer müsse aber bewältigt werden.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d24bc09/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 15:18:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084679</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Studie-Vernetzung-von-Autos-schafft-mehr-Sicherheit-aber-auch-Skepsis-3084679.html?wt_mc=rss.ho.beitrag.atom" title="Studie: Vernetzung von Autos schafft mehr Sicherheit – aber auch Skepsis"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/4/0/4/Bildschirmfoto_2016-01-26_um_15-4f813edda1a7e109.jpeg" alt="Vernetzte Autos" /> </a> <p>Analysten im Auftrag des Wirtschaftsministeriums kommen zu dem Ergebnis, dass die Vernetzung von Fahrzeugen und Straßen Sicherheit und Komfort verbessert. Die Angst vorm gläsernen Fahrer müsse aber bewältigt werden.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389446423/u/0/f/653902/c/35207/s/4d24bc09/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d24bc09/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Spezieller Einhandmodus für Microsofts iPhone-Tastatur</title>
- <link>
- http://www.heise.de/newsticker/meldung/Spezieller-Einhandmodus-fuer-Microsofts-iPhone-Tastatur-3084738.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Die geplante iOS-Version von Microsofts Word-Flow-Keyboard erhält einem
- Bericht zufolge einen besonderen Modus für die einhändige Bedienung. Der öffentliche
- Beta-Test der Tastatur soll bald beginnen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2495f5/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 15:10:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084738</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Spezieller-Einhandmodus-fuer-Microsofts-iPhone-Tastatur-3084738.html?wt_mc=rss.ho.beitrag.atom" title="Spezieller Einhandmodus für Microsofts iPhone-Tastatur"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/4/4/2/Bildschirmfoto_2016-01-26_um_15-086c14c35aded06e.png" alt="Word Flow Microsoft" /> </a> <p>Die geplante iOS-Version von Microsofts Word-Flow-Keyboard erhält einem Bericht zufolge einen besonderen Modus für die einhändige Bedienung. Der öffentliche Beta-Test der Tastatur soll bald beginnen.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389403553/u/0/f/653902/c/35207/s/4d2495f5/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2495f5/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Groupon schließt in der Schweiz und in Österreich</title>
- <link>
- http://www.heise.de/newsticker/meldung/Groupon-schliesst-in-der-Schweiz-und-in-Oesterreich-3084595.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Das Rabatt-Portal Groupon reduziert sein internationales Angebot: Zum 25.
- Januar hat das Unternehmen seine Geschäfte in Österreich und in der Schweiz
- eingestellt.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d245ae7/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 14:30:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084595</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Groupon-schliesst-in-der-Schweiz-und-in-Oesterreich-3084595.html?wt_mc=rss.ho.beitrag.atom" title="Groupon schließt in der Schweiz und in Österreich"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/3/5/9/urn-newsml-dpa-com-20090101-150506-99-02759_large_4_3-0f1df47004187636.jpeg" alt="Groupon" /> </a> <p>Das Rabatt-Portal Groupon reduziert sein internationales Angebot: Zum 25. Januar hat das Unternehmen seine Geschäfte in Österreich und in der Schweiz eingestellt.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389398598/u/0/f/653902/c/35207/s/4d245ae7/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d245ae7/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Bilderkennung: Algorithmen aus Jena sollen Tiere auch in Bewegung bestimmen
- können
- </title>
- <link>
- http://www.heise.de/newsticker/meldung/Bilderkennung-Algorithmen-aus-Jena-sollen-Tiere-auch-in-Bewegung-bestimmen-koennen-3084658.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>So manches Elternteil wird stutzen, wenn das Kind auf dem Waldspaziergang
- nach dem Namen einer Pflanze oder eines Tieres fragt. Forscher der Uni Jena könnten
- mit einem von ihnen entwickelten Verfahren vielleicht bald Apphilfe schaffen.&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d245ae6/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 14:20:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084658</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Bilderkennung-Algorithmen-aus-Jena-sollen-Tiere-auch-in-Bewegung-bestimmen-koennen-3084658.html?wt_mc=rss.ho.beitrag.atom" title="Bilderkennung: Algorithmen aus Jena sollen Tiere auch in Bewegung bestimmen können"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/3/9/0/Tabletamsel_ka-1-171b29b5d58fb7f5.jpeg" alt="Bilderkennung: Algorithmen aus Jena sollen Tiere auch in Bewegung bestimmen können" /> </a> <p>So manches Elternteil wird stutzen, wenn das Kind auf dem Waldspaziergang nach dem Namen einer Pflanze oder eines Tieres fragt. Forscher der Uni Jena könnten mit einem von ihnen entwickelten Verfahren vielleicht bald Apphilfe schaffen.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389398597/u/0/f/653902/c/35207/s/4d245ae6/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d245ae6/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Neue Folgen von Akte X: "Ich will es immer noch glauben"</title>
- <link>
- http://www.heise.de/newsticker/meldung/Neue-Folgen-von-Akte-X-Ich-will-es-immer-noch-glauben-3084426.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>13 Jahre nach ihrem Ende geht die US-Serie &amp;quot;Akte X&amp;quot;
- weiter, als Fortsetzung des Klassikers in modernem Gewand und unserer Zeit.
- Inhaltlich bleibt sie sich treu: An allem sind geheime Verschwörer schuld – eine
- Einschätzung, die seltsam bekannt klingt.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d240285/sc/17/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 13:35:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084426</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Neue-Folgen-von-Akte-X-Ich-will-es-immer-noch-glauben-3084426.html?wt_mc=rss.ho.beitrag.atom" title="Neue Folgen von Akte X: &quot;Ich will es immer noch glauben&quot;"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/2/2/4/vlcsnap-2016-01-26-12h57m41s255-7b7bc03717696405.jpeg" alt="Neue Folgen von Akte X: &quot;Ich will es nur glauben&quot;" /> </a> <p>13 Jahre nach ihrem Ende geht die US-Serie "Akte X" weiter, als Fortsetzung des Klassikers in modernem Gewand und unserer Zeit. Inhaltlich bleibt sie sich treu: An allem sind geheime Verschwörer schuld – eine Einschätzung, die seltsam bekannt klingt.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/a2.htm"><img src="http://da.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389434588/u/0/f/653902/c/35207/s/4d240285/sc/17/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d240285/sc/17/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Frag den Bundestag: Parlamentsgutachten sollen öffentlich werden</title>
- <link>
- http://www.heise.de/newsticker/meldung/Frag-den-Bundestag-Parlamentsgutachten-sollen-oeffentlich-werden-3084481.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Über das neue Portal &amp;quot;Frag den Bundestag&amp;quot; können Nutzer
- per Knopfdruck Studien des Wissenschaftlichen Dienstes des Bundestags beantragen. So
- soll es möglich werden, alle herausgegebenen Untersuchungen in einer
- Online-Bibliothek zu veröffentlichen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d240284/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 13:32:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084481</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Frag-den-Bundestag-Parlamentsgutachten-sollen-oeffentlich-werden-3084481.html?wt_mc=rss.ho.beitrag.atom" title="Frag den Bundestag: Parlamentsgutachten sollen öffentlich werden"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/2/7/0/Bildschirmfoto_2016-01-26_um_14-0c84fcc438275a89.jpeg" alt="Frag den Bundestag: Parlamentsgutachten sollen öffentlich werden" /> </a> <p>Über das neue Portal "Frag den Bundestag" können Nutzer per Knopfdruck Studien des Wissenschaftlichen Dienstes des Bundestags beantragen. So soll es möglich werden, alle herausgegebenen Untersuchungen in einer Online-Bibliothek zu veröffentlichen.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389434587/u/0/f/653902/c/35207/s/4d240284/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d240284/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>USA: 300.000 Hobbypiloten registrieren ihre Drohnen</title>
- <link>
- http://www.heise.de/newsticker/meldung/USA-300-000-Hobbypiloten-registrieren-ihre-Drohnen-3084403.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Seit dem 21. Dezember 2015 müssen Hobbypiloten in den USA ihre kleinen
- unbemannten Flugobjekte registrieren. Nun hat die Luftfahrtbehörde erste Zahlen
- veröffentlicht. Bei einer Registrierung bis zum 20. Januar konnten Piloten mit einer
- Belohnung rechnen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d23ebcb/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 13:06:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084403</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/USA-300-000-Hobbypiloten-registrieren-ihre-Drohnen-3084403.html?wt_mc=rss.ho.beitrag.atom" title="USA: 300.000 Hobbypiloten registrieren ihre Drohnen"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/2/0/5/phantom-dda03c5466cdeaba-a1ea68cfecc952e7.jpeg" alt="Drohne" /> </a> <p>Seit dem 21. Dezember 2015 müssen Hobbypiloten in den USA ihre kleinen unbemannten Flugobjekte registrieren. Nun hat die Luftfahrtbehörde erste Zahlen veröffentlicht. Bei einer Registrierung bis zum 20. Januar konnten Piloten mit einer Belohnung rechnen. </p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389390571/u/0/f/653902/c/35207/s/4d23ebcb/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d23ebcb/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Autoindustrie und Datenschützer: KfZ-Daten unterliegen dem Datenschutz</title>
- <link>
- http://www.heise.de/newsticker/meldung/Autoindustrie-und-Datenschuetzer-KfZ-Daten-unterliegen-dem-Datenschutz-3084253.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Alle Daten, die in einem Fahrzeug anfallen, gelten als personenbezogen,
- sobald sie mit der Fahrzeugidentifikationsnummer oder dem Kfz-Kennzeichen verknüpft
- sind. Darauf und auf mehr haben sich Industrie und Datenschutzbeauftragte geeinigt.&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2348fb/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 11:37:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084253</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Autoindustrie-und-Datenschuetzer-KfZ-Daten-unterliegen-dem-Datenschutz-3084253.html?wt_mc=rss.ho.beitrag.atom" title="Autoindustrie und Datenschützer: KfZ-Daten unterliegen dem Datenschutz"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/0/9/6/image-1408514071782004-db0fcdb2cb0a7832-20569746602bb050.jpeg" alt="Auto" /> </a> <p>Alle Daten, die in einem Fahrzeug anfallen, gelten als personenbezogen, sobald sie mit der Fahrzeugidentifikationsnummer oder dem Kfz-Kennzeichen verknüpft sind. Darauf und auf mehr haben sich Industrie und Datenschutzbeauftragte geeinigt.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389411781/u/0/f/653902/c/35207/s/4d2348fb/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2348fb/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Wirtschaftsministerium richtet Leseraum für TTIP-Dokumente ein</title>
- <link>
- http://www.heise.de/newsticker/meldung/Wirtschaftsministerium-richtet-Leseraum-fuer-TTIP-Dokumente-ein-3084344.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Die Bundesregierung kommt einer Forderung des Bundestags nach und gewährt
- Abgeordneten und Ländervertretern Zugang zu vertraulichen Verhandlungspapieren rund
- um das umstrittene Handelsabkommen TTIP.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2348fa/sc/3/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 11:27:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084344</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Wirtschaftsministerium-richtet-Leseraum-fuer-TTIP-Dokumente-ein-3084344.html?wt_mc=rss.ho.beitrag.atom" title="Wirtschaftsministerium richtet Leseraum für TTIP-Dokumente ein"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/1/5/8/Bildschirmfoto_2016-01-26_um_12-1315b4276da79760.jpeg" alt="Wirtschaftsministerium richtet Leseraum für TTIP-Dokumente ein" /> </a> <p>Die Bundesregierung kommt einer Forderung des Bundestags nach und gewährt Abgeordneten und Ländervertretern Zugang zu vertraulichen Verhandlungspapieren rund um das umstrittene Handelsabkommen TTIP.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/a2.htm"><img src="http://da.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389411780/u/0/f/653902/c/35207/s/4d2348fa/sc/3/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d2348fa/sc/3/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Sony verlegt seine Playstation-Zentrale von Japan in die USA</title>
- <link>
- http://www.heise.de/newsticker/meldung/Sony-verlegt-seine-Playstation-Zentrale-von-Japan-in-die-USA-3084235.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Unter dem Dach der Sony Interactive Entertainment (SIE) sollen die
- Geschäfte mit Hard- und Software sowie Inhalten und Netzwerkservices zusammengeführt
- werden – und zwar in Kalifornien.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d22c030/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 10:13:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084235</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Sony-verlegt-seine-Playstation-Zentrale-von-Japan-in-die-USA-3084235.html?wt_mc=rss.ho.beitrag.atom" title="Sony verlegt seine Playstation-Zentrale von Japan in die USA"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/0/7/8/ps4-afdf7ad4d65f4b20-52131920b12f35b6-f3a1e1c612c84968.jpeg" alt="Playstation" /> </a> <p>Unter dem Dach der Sony Interactive Entertainment (SIE) sollen die Geschäfte mit Hard- und Software sowie Inhalten und Netzwerkservices zusammengeführt werden – und zwar in Kalifornien.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389402157/u/0/f/653902/c/35207/s/4d22c030/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d22c030/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>Sicherheitsupdate für OpenSSL steht an</title>
- <link>
- http://www.heise.de/newsticker/meldung/Sicherheitsupdate-fuer-OpenSSL-steht-an-3084227.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Neue OpenSSL-Versionen sollen zwei Sicherheitslücken schließen. Den
- Schweregrad einer Schwachstelle stuft das OpenSSL-Team mit hoch ein.&lt;br
- clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d22c02f/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 10:10:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084227</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/Sicherheitsupdate-fuer-OpenSSL-steht-an-3084227.html?wt_mc=rss.ho.beitrag.atom" title="Sicherheitsupdate für OpenSSL steht an"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/0/7/0/key-id-ec35f72fab481a99-9b59ced0bbaed03d-c4be465cb3c66623.jpeg" alt="Schlüssel" /> </a> <p>Neue OpenSSL-Versionen sollen zwei Sicherheitslücken schließen. Den Schweregrad einer Schwachstelle stuft das OpenSSL-Team mit hoch ein. </p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389402156/u/0/f/653902/c/35207/s/4d22c02f/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d22c02f/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- <item>
- <title>PDF-Reader Foxit Reader für Schadcode anfällig</title>
- <link>
- http://www.heise.de/newsticker/meldung/PDF-Reader-Foxit-Reader-fuer-Schadcode-anfaellig-3084161.html?wt_mc=rss.ho.beitrag.atom
- </link>
- <description>Neue Versionen sichern Foxit PhantomPDF und Foxit Reader ab. Beide
- Anwendungen lassen sich aus der Ferne attackieren und Angreifer können eigenen Code
- auf Computer schleusen.&lt;br clear='all'/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/1/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/1/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/2/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/2/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/3/rc.htm"
- rel="nofollow"&gt;&lt;img
- src="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/3/rc.img"
- border="0"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;a
- href="http://da.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/a2.htm"&gt;&lt;img
- src="http://da.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/a2.img"
- border="0"/&gt;&lt;/a&gt;&lt;img width="1" height="1"
- src="http://pi.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/a2t.img"
- border="0"/&gt;&lt;img width='1' height='1'
- src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d227a5f/sc/21/mf.gif'
- border='0'/&gt;</description>
- <pubDate>Tue, 26 Jan 2016 09:53:00 GMT</pubDate>
- <guid isPermaLink="false">http://heise.de/-3084161</guid>
- <content:encoded>
- <![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> <a href="http://www.heise.de/newsticker/meldung/PDF-Reader-Foxit-Reader-fuer-Schadcode-anfaellig-3084161.html?wt_mc=rss.ho.beitrag.atom" title="PDF-Reader Foxit Reader für Schadcode anfällig"> <img src="http://www.heise.de/scale/geometry/264/q80/imgs/18/1/7/3/7/0/2/4/img3File_thumb800-4b0bd095dcbcce5d.png" alt="Foxit Reader für Schadcode anfällig" /> </a> <p>Neue Versionen sichern Foxit PhantomPDF und Foxit Reader ab. Beide Anwendungen lassen sich aus der Ferne attackieren und Angreifer können eigenen Code auf Computer schleusen.</p> </div><br clear='all'/><br/><br/><a href="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/1/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/1/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/2/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/2/rc.img" border="0"/></a><br/><br/><a href="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/3/rc.htm" rel="nofollow"><img src="http://rc.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/rc/3/rc.img" border="0"/></a><br/><br/><a href="http://da.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/a2.htm"><img src="http://da.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/a2.img" border="0"/></a><img width="1" height="1" src="http://pi.feedsportal.com/r/247389406045/u/0/f/653902/c/35207/s/4d227a5f/sc/21/a2t.img" border="0"/><img width='1' height='1' src='http://heise.de.feedsportal.com/c/35207/f/653902/s/4d227a5f/sc/21/mf.gif' border='0'/>]]></content:encoded>
- </item>
- </channel>
-</rss>
diff --git a/mobile/android/tests/background/junit4/resources/feed_rss_medium.xml b/mobile/android/tests/background/junit4/resources/feed_rss_medium.xml
deleted file mode 100644
index 0f5a20ab6..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_rss_medium.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Snapshot from https://medium.com/feed/@Antlam/
--->
-<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
- <channel>
- <title><![CDATA[Anthony Lam on Medium]]></title>
- <description><![CDATA[Latest posts by Anthony Lam on Medium]]></description>
- <link>https://medium.com/@antlam?source=rss-59f49b9e4b19------2</link>
- <image>
- <url>https://d262ilb51hltx0.cloudfront.net/fit/c/150/150/1*BNfAhhQ8TybWsu_gMMixWw.jpeg</url>
- <title>Anthony Lam on Medium</title>
- <link>https://medium.com/@antlam?source=rss-59f49b9e4b19------2</link>
- </image>
- <generator>RSS for Node</generator>
- <lastBuildDate>Tue, 26 Jan 2016 17:06:09 GMT</lastBuildDate>
- <atom:link href="https://medium.com/feed/@antlam" rel="self" type="application/rss+xml"/>
- <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
- <atom:link href="http://medium.superfeedr.com" rel="hub"/>
- <item>
- <title><![CDATA[UX thoughts for 2016]]></title>
- <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@antlam/ux-thoughts-for-2016-1fc1d6e515e8?source=rss-59f49b9e4b19------2"><img src="https://d262ilb51hltx0.cloudfront.net/fit/c/600/200/1*mOiPSWfvCBoLUrfQlIrdVQ.png" width="600" height="200"></a></p><p class="medium-feed-snippet">And just like that, another year.</p><p class="medium-feed-link"><a href="https://medium.com/@antlam/ux-thoughts-for-2016-1fc1d6e515e8?source=rss-59f49b9e4b19------2">Continue reading on Medium »</a></p></div>]]></description>
- <link>https://medium.com/@antlam/ux-thoughts-for-2016-1fc1d6e515e8?source=rss-59f49b9e4b19------2</link>
- <guid isPermaLink="false">https://medium.com/p/1fc1d6e515e8</guid>
- <dc:creator><![CDATA[Anthony Lam]]></dc:creator>
- <pubDate>Mon, 11 Jan 2016 18:43:58 GMT</pubDate>
- </item>
- <item>
- <title><![CDATA[A New Mobile Tabs tray]]></title>
- <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@antlam/a-new-mobile-tabs-tray-327ac262eacb?source=rss-59f49b9e4b19------2"><img src="https://d262ilb51hltx0.cloudfront.net/fit/c/600/200/1*scpLRAL_zy9CcW6BLGZHng.png" width="600" height="200"></a></p><p class="medium-feed-snippet">Why we&#8217;re giving it an update in Firefox for Android</p><p class="medium-feed-link"><a href="https://medium.com/@antlam/a-new-mobile-tabs-tray-327ac262eacb?source=rss-59f49b9e4b19------2">Continue reading on Medium »</a></p></div>]]></description>
- <link>https://medium.com/@antlam/a-new-mobile-tabs-tray-327ac262eacb?source=rss-59f49b9e4b19------2</link>
- <guid isPermaLink="false">https://medium.com/p/327ac262eacb</guid>
- <dc:creator><![CDATA[Anthony Lam]]></dc:creator>
- <pubDate>Fri, 06 Nov 2015 17:30:55 GMT</pubDate>
- </item>
- <item>
- <title><![CDATA[Quick search]]></title>
- <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@antlam/quick-search-bdd374257e75?source=rss-59f49b9e4b19------2"><img src="https://d262ilb51hltx0.cloudfront.net/fit/c/600/200/1*DyBNARNADZsexPnxkMaEgQ.png" width="600" height="200"></a></p><p class="medium-feed-snippet">Instantly search with any of your search providers</p><p class="medium-feed-link"><a href="https://medium.com/@antlam/quick-search-bdd374257e75?source=rss-59f49b9e4b19------2">Continue reading on Medium »</a></p></div>]]></description>
- <link>https://medium.com/@antlam/quick-search-bdd374257e75?source=rss-59f49b9e4b19------2</link>
- <guid isPermaLink="false">https://medium.com/p/bdd374257e75</guid>
- <dc:creator><![CDATA[Anthony Lam]]></dc:creator>
- <pubDate>Tue, 01 Sep 2015 17:36:32 GMT</pubDate>
- </item>
- <item>
- <title><![CDATA[Designing helpfulness]]></title>
- <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@antlam/designing-helpfulness-c1777727faf?source=rss-59f49b9e4b19------2"><img src="https://d262ilb51hltx0.cloudfront.net/fit/c/600/200/1*Cg8wkgjwCH7A1Aotec1Okw.png" width="600" height="200"></a></p><p class="medium-feed-snippet">Being there, without being annoying</p><p class="medium-feed-link"><a href="https://medium.com/@antlam/designing-helpfulness-c1777727faf?source=rss-59f49b9e4b19------2">Continue reading on Medium »</a></p></div>]]></description>
- <link>https://medium.com/@antlam/designing-helpfulness-c1777727faf?source=rss-59f49b9e4b19------2</link>
- <guid isPermaLink="false">https://medium.com/p/c1777727faf</guid>
- <dc:creator><![CDATA[Anthony Lam]]></dc:creator>
- <pubDate>Tue, 11 Aug 2015 20:59:13 GMT</pubDate>
- </item>
- <item>
- <title><![CDATA[Share to… Firefox?]]></title>
- <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@antlam/share-to-firefox-245984b2da33?source=rss-59f49b9e4b19------2"><img src="https://d262ilb51hltx0.cloudfront.net/fit/c/600/200/1*H5wztlFTvbE1EM_5MRkuzg.png" width="600" height="200"></a></p><p class="medium-feed-snippet">You may remember this from such share intents as &#8220;Add to Firefox&#8221;</p><p class="medium-feed-link"><a href="https://medium.com/@antlam/share-to-firefox-245984b2da33?source=rss-59f49b9e4b19------2">Continue reading on Medium »</a></p></div>]]></description>
- <link>https://medium.com/@antlam/share-to-firefox-245984b2da33?source=rss-59f49b9e4b19------2</link>
- <guid isPermaLink="false">https://medium.com/p/245984b2da33</guid>
- <dc:creator><![CDATA[Anthony Lam]]></dc:creator>
- <pubDate>Fri, 08 May 2015 20:18:18 GMT</pubDate>
- </item>
- <item>
- <title><![CDATA[Open multiple links]]></title>
- <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@antlam/open-multiple-links-1ce475c47de3?source=rss-59f49b9e4b19------2"><img src="https://d262ilb51hltx0.cloudfront.net/fit/c/600/200/1*yEQ5DjomHZIgVzUN-FKx2A.jpeg" width="600" height="200"></a></p><p class="medium-feed-snippet">Queue links in Firefox instead of switching applications each time.</p><p class="medium-feed-link"><a href="https://medium.com/@antlam/open-multiple-links-1ce475c47de3?source=rss-59f49b9e4b19------2">Continue reading on Medium »</a></p></div>]]></description>
- <link>https://medium.com/@antlam/open-multiple-links-1ce475c47de3?source=rss-59f49b9e4b19------2</link>
- <guid isPermaLink="false">https://medium.com/p/1ce475c47de3</guid>
- <dc:creator><![CDATA[Anthony Lam]]></dc:creator>
- <pubDate>Tue, 14 Apr 2015 18:44:59 GMT</pubDate>
- </item>
- <item>
- <title><![CDATA[Firefox for Android on Tablets]]></title>
- <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@antlam/firefox-for-android-on-tablets-f67edc83dd46?source=rss-59f49b9e4b19------2"><img src="https://d262ilb51hltx0.cloudfront.net/fit/c/600/200/1*H5p3YQ1NGpfGPDryd22Ujg.png" width="600" height="200"></a></p><p class="medium-feed-snippet">Redesigning the browser interface&#8202;&#8212;&#8202;Part two</p><p class="medium-feed-link"><a href="https://medium.com/@antlam/firefox-for-android-on-tablets-f67edc83dd46?source=rss-59f49b9e4b19------2">Continue reading on Medium »</a></p></div>]]></description>
- <link>https://medium.com/@antlam/firefox-for-android-on-tablets-f67edc83dd46?source=rss-59f49b9e4b19------2</link>
- <guid isPermaLink="false">https://medium.com/p/f67edc83dd46</guid>
- <dc:creator><![CDATA[Anthony Lam]]></dc:creator>
- <pubDate>Tue, 03 Feb 2015 20:29:18 GMT</pubDate>
- </item>
- <item>
- <title><![CDATA[Are big phones back?]]></title>
- <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@antlam/are-big-phones-back-59550ba0f24e?source=rss-59f49b9e4b19------2"><img src="https://d262ilb51hltx0.cloudfront.net/fit/c/600/200/1*XArwkY9ZcmtCkEhDwl0aKA.jpeg" width="600" height="200"></a></p><p class="medium-feed-snippet">Some thoughts and impressions</p><p class="medium-feed-link"><a href="https://medium.com/@antlam/are-big-phones-back-59550ba0f24e?source=rss-59f49b9e4b19------2">Continue reading on Medium »</a></p></div>]]></description>
- <link>https://medium.com/@antlam/are-big-phones-back-59550ba0f24e?source=rss-59f49b9e4b19------2</link>
- <guid isPermaLink="false">https://medium.com/p/59550ba0f24e</guid>
- <dc:creator><![CDATA[Anthony Lam]]></dc:creator>
- <pubDate>Tue, 23 Dec 2014 20:05:36 GMT</pubDate>
- </item>
- <item>
- <title><![CDATA[Firefox for Android looks a bit different]]></title>
- <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@antlam/firefox-for-android-looks-a-bit-different-8ae8eba41b1f?source=rss-59f49b9e4b19------2"><img src="https://d262ilb51hltx0.cloudfront.net/fit/c/600/200/1*Lk31G3Qt2fs5WcOtBQQVgw.png" width="600" height="200"></a></p><p class="medium-feed-snippet">Redesigning the browser interface</p><p class="medium-feed-link"><a href="https://medium.com/@antlam/firefox-for-android-looks-a-bit-different-8ae8eba41b1f?source=rss-59f49b9e4b19------2">Continue reading on Medium »</a></p></div>]]></description>
- <link>https://medium.com/@antlam/firefox-for-android-looks-a-bit-different-8ae8eba41b1f?source=rss-59f49b9e4b19------2</link>
- <guid isPermaLink="false">https://medium.com/p/8ae8eba41b1f</guid>
- <dc:creator><![CDATA[Anthony Lam]]></dc:creator>
- <pubDate>Fri, 29 Aug 2014 23:38:07 GMT</pubDate>
- </item>
- <item>
- <title><![CDATA[My fancy new watch]]></title>
- <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@antlam/my-fancy-new-watch-4856162890a3?source=rss-59f49b9e4b19------2"><img src="https://d262ilb51hltx0.cloudfront.net/fit/c/600/200/1*_gsBD-Vw7qevrwLxXZe8jA.jpeg" width="600" height="200"></a></p><p class="medium-feed-snippet">Early thoughts</p><p class="medium-feed-link"><a href="https://medium.com/@antlam/my-fancy-new-watch-4856162890a3?source=rss-59f49b9e4b19------2">Continue reading on Medium »</a></p></div>]]></description>
- <link>https://medium.com/@antlam/my-fancy-new-watch-4856162890a3?source=rss-59f49b9e4b19------2</link>
- <guid isPermaLink="false">https://medium.com/p/4856162890a3</guid>
- <dc:creator><![CDATA[Anthony Lam]]></dc:creator>
- <pubDate>Tue, 22 Jul 2014 01:36:52 GMT</pubDate>
- </item>
- </channel> \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/resources/feed_rss_spon.xml b/mobile/android/tests/background/junit4/resources/feed_rss_spon.xml
deleted file mode 100644
index e5a81d514..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_rss_spon.xml
+++ /dev/null
@@ -1,314 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
-<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
- <channel>
- <title>SPIEGEL ONLINE - Schlagzeilen</title>
- <link>http://www.spiegel.de</link>
- <description>Deutschlands führende Nachrichtenseite. Alles Wichtige aus Politik, Wirtschaft, Sport, Kultur, Wissenschaft, Technik und mehr.</description>
- <language>de</language>
- <pubDate>Wed, 27 Jan 2016 18:20:31 +0100</pubDate>
- <lastBuildDate>Wed, 27 Jan 2016 18:20:31 +0100</lastBuildDate>
- <image>
- <title>SPIEGEL ONLINE</title>
- <link>http://www.spiegel.de</link>
- <url>http://www.spiegel.de/static/sys/logo_120x61.gif</url>
- </image>
- <item>
- <title>Angebliche Vergewaltigung einer 13-Jährigen: Steinmeier kanzelt russischen Minister Lawrow ab</title>
- <link>http://www.spiegel.de/politik/ausland/steinmeier-kanzelt-lawrow-ab-aerger-um-angebliche-vergewaltigung-a-1074292.html#ref=rss</link>
- <description>Der Ton wird scharf zwischen Berlin und Moskau: Frank-Walter Steinmeier wirft dem russischen Außenminister Lawrow politische Propaganda vor - es geht um die angebliche Vergewaltigung einer 13-Jährigen in Berlin.</description>
- <category>Politik</category>
- <pubDate>Wed, 27 Jan 2016 18:16:16 +0100</pubDate>
- <guid>http://www.spiegel.de/politik/ausland/steinmeier-kanzelt-lawrow-ab-aerger-um-angebliche-vergewaltigung-a-1074292.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949492-thumbsmall-wtgq.jpg" hspace="5" align="left" >Der Ton wird scharf zwischen Berlin und Moskau: Frank-Walter Steinmeier wirft dem russischen Außenminister Lawrow politische Propaganda vor - es geht um die angebliche Vergewaltigung einer 13-Jährigen in Berlin.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949492-thumbsmall-wtgq.jpg"/>
- </item>
- <item>
- <title>Grafischer Überblick: Hier gibt es die wenigsten Herzinfarkte in Deutschland</title>
- <link>http://www.spiegel.de/gesundheit/diagnose/ostdeutsche-sterben-deutlich-haeufiger-an-einem-herzinfarkt-a-1074231.html#ref=rss</link>
- <description>Nirgendwo arbeiten mehr Kardiologen als in Hamburg - auch deshalb gibt es dort weniger Herzinfarkte als in anderen Bundesländern. Wie sieht es in Ihrer Gegend aus, wo ist die Sterblichkeit am höchsten? Der Überblick.</description>
- <category>Gesundheit</category>
- <pubDate>Wed, 27 Jan 2016 18:08:00 +0100</pubDate>
- <guid>http://www.spiegel.de/gesundheit/diagnose/ostdeutsche-sterben-deutlich-haeufiger-an-einem-herzinfarkt-a-1074231.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-566602-thumbsmall-bxcg.jpg" hspace="5" align="left" >Nirgendwo arbeiten mehr Kardiologen als in Hamburg - auch deshalb gibt es dort weniger Herzinfarkte als in anderen Bundesländern. Wie sieht es in Ihrer Gegend aus, wo ist die Sterblichkeit am höchsten? Der Überblick.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-566602-thumbsmall-bxcg.jpg"/>
- </item>
- <item>
- <title>Nachhilfe für gute Schüler: Lasst Eure Kinder auch das Scheitern lernen</title>
- <link>http://www.spiegel.de/schulspiegel/nachhilfe-entspannte-schueler-brauchen-entspannte-eltern-a-1074197.html#ref=rss</link>
- <description>Selbst gute Schüler werden von ihren Eltern zur Nachhilfe geschickt. Das schadet mehr, als es nützt - denn die Kinder lernen dabei vor allem eines: Dass sie nicht scheitern dürfen.</description>
- <category>SchulSPIEGEL</category>
- <pubDate>Wed, 27 Jan 2016 18:02:00 +0100</pubDate>
- <guid>http://www.spiegel.de/schulspiegel/nachhilfe-entspannte-schueler-brauchen-entspannte-eltern-a-1074197.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-396678-thumbsmall-dhws.jpg" hspace="5" align="left" >Selbst gute Schüler werden von ihren Eltern zur Nachhilfe geschickt. Das schadet mehr, als es nützt - denn die Kinder lernen dabei vor allem eines: Dass sie nicht scheitern dürfen.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-396678-thumbsmall-dhws.jpg"/>
- </item>
- <item>
- <title>Germanwings-Katastrophe: Arbeitsgruppe regt Schleuse zwischen Kabine und Cockpit an</title>
- <link>http://www.spiegel.de/panorama/germanwings-katastrophe-arbeitsgruppe-legt-abschlussbericht-vor-a-1074294.html#ref=rss</link>
- <description>Wie sicher muss ein Flugzeugcockpit sein? Nach dem Germanwings-Absturz mit 150 Toten hat sich eine Arbeitsgruppe mit dieser Frage befasst - und nun ihren Abschlussbericht vorgelegt.</description>
- <category>Panorama</category>
- <pubDate>Wed, 27 Jan 2016 17:52:00 +0100</pubDate>
- <guid>http://www.spiegel.de/panorama/germanwings-katastrophe-arbeitsgruppe-legt-abschlussbericht-vor-a-1074294.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-828832-thumbsmall-gjvf.jpg" hspace="5" align="left" >Wie sicher muss ein Flugzeugcockpit sein? Nach dem Germanwings-Absturz mit 150 Toten hat sich eine Arbeitsgruppe mit dieser Frage befasst - und nun ihren Abschlussbericht vorgelegt.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-828832-thumbsmall-gjvf.jpg"/>
- </item>
- <item>
- <title>Polen: Händler wehren sich gegen Supermarktsteuer</title>
- <link>http://www.spiegel.de/wirtschaft/soziales/polen-will-internationale-einzelhaendler-hoeher-besteuern-a-1074101.html#ref=rss</link>
- <description>Polens Regierung plant, Einzelhändler höher zu besteuern - und will mit den Einnahmen soziale Wohltaten finanzieren. Besonders trifft es ausländische Unternehmen wie Kaufland und Metro.</description>
- <category>Wirtschaft</category>
- <pubDate>Wed, 27 Jan 2016 17:46:10 +0100</pubDate>
- <guid>http://www.spiegel.de/wirtschaft/soziales/polen-will-internationale-einzelhaendler-hoeher-besteuern-a-1074101.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949308-thumbsmall-wwsr.jpg" hspace="5" align="left" >Polens Regierung plant, Einzelhändler höher zu besteuern - und will mit den Einnahmen soziale Wohltaten finanzieren. Besonders trifft es ausländische Unternehmen wie Kaufland und Metro.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949308-thumbsmall-wwsr.jpg"/>
- </item>
- <item>
- <title>Übergriffe in Köln: Polizei erteilt Silvester-Verdächtigen Karnevalverbot</title>
- <link>http://www.spiegel.de/panorama/justiz/koeln-polizei-erteilt-silvester-verdaechtigen-verbote-fuer-karneval-a-1074274.html#ref=rss</link>
- <description>Kölns Polizei bereitet sich auf die Karnevalstage vor: Tatverdächtige aus der Silvesternacht sollen mit Zutrittsverboten von bestimmten Orten ferngehalten werden. Der Polizeipräsident forderte die Narren zudem auf, keine Spielzeugwaffen zu tragen.</description>
- <category>Panorama</category>
- <pubDate>Wed, 27 Jan 2016 17:23:00 +0100</pubDate>
- <guid>http://www.spiegel.de/panorama/justiz/koeln-polizei-erteilt-silvester-verdaechtigen-verbote-fuer-karneval-a-1074274.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-942482-thumbsmall-qyge.jpg" hspace="5" align="left" >Kölns Polizei bereitet sich auf die Karnevalstage vor: Tatverdächtige aus der Silvesternacht sollen mit Zutrittsverboten von bestimmten Orten ferngehalten werden. Der Polizeipräsident forderte die Narren zudem auf, keine Spielzeugwaffen zu tragen.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-942482-thumbsmall-qyge.jpg"/>
- </item>
- <item>
- <title>"The Hateful 8"-Stars im Interview: "Wahnsinn, was da alles passiert!"</title>
- <link>http://www.spiegel.de/kultur/kino/the-hateful-8-quentin-tarantino-und-jennifer-jason-leigh-im-interview-a-1074202.html#ref=rss</link>
- <description>Sieben Männer und eine Frau - in seinem Western "The Hateful 8" entwirft Quentin Tarantino ein brutales Abbild der US-Gesellschaft. Hier erklären der Regisseur und seine Hauptdarstellerin, warum es sich lohnt, den Film gleich mehrmals anzusehen.</description>
- <category>Kultur</category>
- <pubDate>Wed, 27 Jan 2016 17:08:00 +0100</pubDate>
- <guid>http://www.spiegel.de/kultur/kino/the-hateful-8-quentin-tarantino-und-jennifer-jason-leigh-im-interview-a-1074202.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949256-thumbsmall-hbrj.jpg" hspace="5" align="left" >Sieben Männer und eine Frau - in seinem Western "The Hateful 8" entwirft Quentin Tarantino ein brutales Abbild der US-Gesellschaft. Hier erklären der Regisseur und seine Hauptdarstellerin, warum es sich lohnt, den Film gleich mehrmals anzusehen.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949256-thumbsmall-hbrj.jpg"/>
- </item>
- <item>
- <title>Drama auf zugefrorenem Teich: Baby in akuter Lebensgefahr - Messer gefunden</title>
- <link>http://www.spiegel.de/panorama/justiz/hamburg-vater-mit-baby-in-zugefrorenem-teich-eingebrochen-messer-gefunden-a-1074258.html#ref=rss</link>
- <description>Der Fall gibt Rätsel auf: In Hamburg wird ein Vater mit seinem Baby aus einem zugefrorenen Teich gerettet - zwei Männer hätten ihn überfallen, sagt der 24-Jährige. Nun haben Ermittler in der Nähe des Gewässers ein Messer gefunden.</description>
- <category>Panorama</category>
- <pubDate>Wed, 27 Jan 2016 16:32:00 +0100</pubDate>
- <guid>http://www.spiegel.de/panorama/justiz/hamburg-vater-mit-baby-in-zugefrorenem-teich-eingebrochen-messer-gefunden-a-1074258.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949367-thumbsmall-vpsq.jpg" hspace="5" align="left" >Der Fall gibt Rätsel auf: In Hamburg wird ein Vater mit seinem Baby aus einem zugefrorenen Teich gerettet - zwei Männer hätten ihn überfallen, sagt der 24-Jährige. Nun haben Ermittler in der Nähe des Gewässers ein Messer gefunden.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949367-thumbsmall-vpsq.jpg"/>
- </item>
- <item>
- <title>Rheinland-Pfalz: Elefantenrunde soll mit sechs Parteien stattfinden</title>
- <link>http://www.spiegel.de/politik/deutschland/swr-fernsehdebatte-jetzt-mit-sechs-parteien-a-1074262.html#ref=rss</link>
- <description>Erst drei, dann eine, jetzt sechs Parteien: Die TV-Diskussion im Südwestrundfunk zur rheinland-pfälzischen Landtagswahl findet nun in ganz großer Runde statt.</description>
- <category>Politik</category>
- <pubDate>Wed, 27 Jan 2016 16:29:00 +0100</pubDate>
- <guid>http://www.spiegel.de/politik/deutschland/swr-fernsehdebatte-jetzt-mit-sechs-parteien-a-1074262.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-946925-thumbsmall-icoq.jpg" hspace="5" align="left" >Erst drei, dann eine, jetzt sechs Parteien: Die TV-Diskussion im Südwestrundfunk zur rheinland-pfälzischen Landtagswahl findet nun in ganz großer Runde statt.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-946925-thumbsmall-icoq.jpg"/>
- </item>
- <item>
- <title>Blauer Brief: Britische Schulleiterin mahnt Pyjama-Eltern ab</title>
- <link>http://www.spiegel.de/schulspiegel/direktorin-appelliert-an-eltern-bringt-eure-kinder-nicht-im-schlafanzug-zur-schule-a-1074167.html#ref=rss</link>
- <description>Rektorin Kate Chisholm hat genug: Ständig beobachtet sie Eltern, die noch im Schlafanzug stecken, wenn sie ihre Kinder an der Schule absetzen. Nun schrieb sie einen Brandbrief, die Elternschaft reagiert gespalten.</description>
- <category>SchulSPIEGEL</category>
- <pubDate>Wed, 27 Jan 2016 16:26:00 +0100</pubDate>
- <guid>http://www.spiegel.de/schulspiegel/direktorin-appelliert-an-eltern-bringt-eure-kinder-nicht-im-schlafanzug-zur-schule-a-1074167.html</guid>
- <content:encoded><![CDATA[Rektorin Kate Chisholm hat genug: Ständig beobachtet sie Eltern, die noch im Schlafanzug stecken, wenn sie ihre Kinder an der Schule absetzen. Nun schrieb sie einen Brandbrief, die Elternschaft reagiert gespalten.]]></content:encoded>
- </item>
- <item>
- <title>Zwischenruf bei Merkel-Besuch: Hochschule verwirft juristische Schritte gegen Stör-Professor</title>
- <link>http://www.spiegel.de/unispiegel/studium/zwischenruf-bei-merkel-besuch-hochschule-verwirft-juristische-schritte-gegen-professor-a-1074208.html#ref=rss</link>
- <description>Seine politische Stör-Aktion während einer Rede von Kanzlerin Merkel ist für einen Merseburger Professor glimpflich ausgegangen. Die Hochschule sieht von juristischen Schritten ab. </description>
- <category>UniSPIEGEL</category>
- <pubDate>Wed, 27 Jan 2016 16:08:00 +0100</pubDate>
- <guid>http://www.spiegel.de/unispiegel/studium/zwischenruf-bei-merkel-besuch-hochschule-verwirft-juristische-schritte-gegen-professor-a-1074208.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949364-thumbsmall-nnis.jpg" hspace="5" align="left" >Seine politische Stör-Aktion während einer Rede von Kanzlerin Merkel ist für einen Merseburger Professor glimpflich ausgegangen. Die Hochschule sieht von juristischen Schritten ab. ]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949364-thumbsmall-nnis.jpg"/>
- </item>
- <item>
- <title>Bundesautobahngesellschaft: Verkehrsminister wehren sich gegen "Mammutbehörde"</title>
- <link>http://www.spiegel.de/auto/aktuell/bundesautobahngesellschaft-widerstand-der-verkehrsminister-a-1074198.html#ref=rss</link>
- <description>Der Bund könnte die Gründung einer Bundesautobahngesellschaft vorantreiben. Mehrere Verkehrsminister der Länder stellen sich dagegen - auch aus Furcht vor privaten Investoren beim Fernstraßenbau. </description>
- <category>Auto</category>
- <pubDate>Wed, 27 Jan 2016 15:54:00 +0100</pubDate>
- <guid>http://www.spiegel.de/auto/aktuell/bundesautobahngesellschaft-widerstand-der-verkehrsminister-a-1074198.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949241-thumbsmall-cksv.jpg" hspace="5" align="left" >Der Bund könnte die Gründung einer Bundesautobahngesellschaft vorantreiben. Mehrere Verkehrsminister der Länder stellen sich dagegen - auch aus Furcht vor privaten Investoren beim Fernstraßenbau. ]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949241-thumbsmall-cksv.jpg"/>
- </item>
- <item>
- <title>Glasfaser-Ausbau: Dobrindt will schnelles Netz unter die Autobahnen legen</title>
- <link>http://www.spiegel.de/netzwelt/netzpolitik/alexander-dobrindt-will-schnelles-netz-unter-die-autobahnen-legen-a-1074151.html#ref=rss</link>
- <description>Jede Baustelle soll Bandbreite bringen: Die Bundesregierung beschließt, dass künftig beim Straßenbau automatisch Glasfaserkabel verlegt werden müssen. Kommt Deutschland so schneller ins Netz?</description>
- <category>Netzwelt</category>
- <pubDate>Wed, 27 Jan 2016 15:52:00 +0100</pubDate>
- <guid>http://www.spiegel.de/netzwelt/netzpolitik/alexander-dobrindt-will-schnelles-netz-unter-die-autobahnen-legen-a-1074151.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949166-thumbsmall-xrfd.jpg" hspace="5" align="left" >Jede Baustelle soll Bandbreite bringen: Die Bundesregierung beschließt, dass künftig beim Straßenbau automatisch Glasfaserkabel verlegt werden müssen. Kommt Deutschland so schneller ins Netz?]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949166-thumbsmall-xrfd.jpg"/>
- </item>
- <item>
- <title>Handball-Insolvenz: Flensburg will den HSV verklagen</title>
- <link>http://www.spiegel.de/sport/sonst/handball-bundesliga-sg-flensburg-handewitt-klagt-gegen-hsv-a-1074260.html#ref=rss</link>
- <description>Einem nackten Mann kann man nicht in die Tasche greifen? Die SG Flensburg-Handewitt will den insolventen HSV Handball verklagen. Der Traditionsverein will Schadenersatz aus Hamburg haben.</description>
- <category>Sport</category>
- <pubDate>Wed, 27 Jan 2016 15:49:00 +0100</pubDate>
- <guid>http://www.spiegel.de/sport/sonst/handball-bundesliga-sg-flensburg-handewitt-klagt-gegen-hsv-a-1074260.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-948459-thumbsmall-banl.jpg" hspace="5" align="left" >Einem nackten Mann kann man nicht in die Tasche greifen? Die SG Flensburg-Handewitt will den insolventen HSV Handball verklagen. Der Traditionsverein will Schadenersatz aus Hamburg haben.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-948459-thumbsmall-banl.jpg"/>
- </item>
- <item>
- <title>Lage am Lageso: Berliner Senatsverwaltung bestreitet Tod eines Flüchtlings</title>
- <link>http://www.spiegel.de/politik/deutschland/berlin-fluechtling-vom-lageso-tot-senat-widerspricht-a-1074255.html#ref=rss</link>
- <description>Ist in Berlin ein syrischer Flüchtling gestorben, nachdem er lange vor dem Lageso warten musste? Der Helfer, der darüber berichtete, ist abgetaucht - die Senatsverwaltung widerspricht der Darstellung über den Todesfall.</description>
- <category>Politik</category>
- <pubDate>Wed, 27 Jan 2016 15:45:00 +0100</pubDate>
- <guid>http://www.spiegel.de/politik/deutschland/berlin-fluechtling-vom-lageso-tot-senat-widerspricht-a-1074255.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949380-thumbsmall-umdf.jpg" hspace="5" align="left" >Ist in Berlin ein syrischer Flüchtling gestorben, nachdem er lange vor dem Lageso warten musste? Der Helfer, der darüber berichtete, ist abgetaucht - die Senatsverwaltung widerspricht der Darstellung über den Todesfall.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949380-thumbsmall-umdf.jpg"/>
- </item>
- <item>
- <title>Tierarzt-Ikone: Evan Antin, der "heißeste Veterinär der Welt" </title>
- <link>http://www.spiegel.de/panorama/leute/tierarzt-evan-antin-ist-der-sexiest-veterinaer-ever-laut-people-a-1074229.html#ref=rss</link>
- <description>Evan Antin ist Tierarzt, Model und Personal Trainer. So irritierend gutaussehend, dass er zum "Sexiest Tierbetörer" avancierte. Trotz seiner Vorliebe für blutiges Gedärm und anatomische Anomalien.</description>
- <category>Panorama</category>
- <pubDate>Wed, 27 Jan 2016 15:31:00 +0100</pubDate>
- <guid>http://www.spiegel.de/panorama/leute/tierarzt-evan-antin-ist-der-sexiest-veterinaer-ever-laut-people-a-1074229.html</guid>
- <content:encoded><![CDATA[Evan Antin ist Tierarzt, Model und Personal Trainer. So irritierend gutaussehend, dass er zum "Sexiest Tierbetörer" avancierte. Trotz seiner Vorliebe für blutiges Gedärm und anatomische Anomalien.]]></content:encoded>
- </item>
- <item>
- <title>Verteidigungshaushalt: Schäuble will mehr Geld für Bundeswehr ausgeben</title>
- <link>http://www.spiegel.de/politik/deutschland/wolfgang-schaeuble-einverstanden-mit-mehr-geld-fuer-ruestung-a-1074242.html#ref=rss</link>
- <description>Drei Milliarden Euro mehr pro Jahr für Waffen: Finanzminister Schäuble sieht die Aufrüstungspläne der Verteidigungsministerin von der Leyen positiv.</description>
- <category>Politik</category>
- <pubDate>Wed, 27 Jan 2016 15:29:00 +0100</pubDate>
- <guid>http://www.spiegel.de/politik/deutschland/wolfgang-schaeuble-einverstanden-mit-mehr-geld-fuer-ruestung-a-1074242.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-947025-thumbsmall-qecb.jpg" hspace="5" align="left" >Drei Milliarden Euro mehr pro Jahr für Waffen: Finanzminister Schäuble sieht die Aufrüstungspläne der Verteidigungsministerin von der Leyen positiv.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-947025-thumbsmall-qecb.jpg"/>
- </item>
- <item>
- <title>Doping-Vorwürfe: NFL leitet Untersuchung gegen Manning ein</title>
- <link>http://www.spiegel.de/sport/sonst/nfl-peyton-manning-unter-doping-verdacht-a-1074230.html#ref=rss</link>
- <description>Die NFL prüft Vorwürfe gegen einen Superstar: Die Football-Liga geht jetzt offiziell den Doping-Gerüchten um Peyton Manning nach. Der Quarterback soll über seine Frau Hormone geordert haben.</description>
- <category>Sport</category>
- <pubDate>Wed, 27 Jan 2016 15:23:00 +0100</pubDate>
- <guid>http://www.spiegel.de/sport/sonst/nfl-peyton-manning-unter-doping-verdacht-a-1074230.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949287-thumbsmall-cwxj.jpg" hspace="5" align="left" >Die NFL prüft Vorwürfe gegen einen Superstar: Die Football-Liga geht jetzt offiziell den Doping-Gerüchten um Peyton Manning nach. Der Quarterback soll über seine Frau Hormone geordert haben.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949287-thumbsmall-cwxj.jpg"/>
- </item>
- <item>
- <title>Posse um SWR-Elefantenrunde: Feigheit vor dem Feind</title>
- <link>http://www.spiegel.de/politik/deutschland/spd-und-swr-posse-um-tv-auftritt-in-rheinland-pfalz-kommentar-a-1074235.html#ref=rss</link>
- <description>Die Sozialdemokraten weigern sich, an einer TV-Debatte mit der AfD teilzunehmen, jetzt geht das Spektakel in eine neue Runde. Statt der Ministerpräsidentin soll der SPD-Landeschef ran. Wie absurd ist das denn? </description>
- <category>Politik</category>
- <pubDate>Wed, 27 Jan 2016 15:23:00 +0100</pubDate>
- <guid>http://www.spiegel.de/politik/deutschland/spd-und-swr-posse-um-tv-auftritt-in-rheinland-pfalz-kommentar-a-1074235.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949309-thumbsmall-zhac.jpg" hspace="5" align="left" >Die Sozialdemokraten weigern sich, an einer TV-Debatte mit der AfD teilzunehmen, jetzt geht das Spektakel in eine neue Runde. Statt der Ministerpräsidentin soll der SPD-Landeschef ran. Wie absurd ist das denn? ]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949309-thumbsmall-zhac.jpg"/>
- </item>
- <item>
- <title>Apple-Browser: Und plötzlich stürzt Safari ab</title>
- <link>http://www.spiegel.de/netzwelt/apps/apple-safari-browser-stuerzt-ploetzlich-ab-a-1074217.html#ref=rss</link>
- <description>Seit einigen Stunden haben Apple-Nutzer Probleme mit dem Safari-Browser. Wodurch die Abstürze ausgelöst werden, ist unklar. Doch mit einem kleinen Trick kann man sich helfen.</description>
- <category>Netzwelt</category>
- <pubDate>Wed, 27 Jan 2016 15:18:00 +0100</pubDate>
- <guid>http://www.spiegel.de/netzwelt/apps/apple-safari-browser-stuerzt-ploetzlich-ab-a-1074217.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949312-thumbsmall-jqlt.jpg" hspace="5" align="left" >Seit einigen Stunden haben Apple-Nutzer Probleme mit dem Safari-Browser. Wodurch die Abstürze ausgelöst werden, ist unklar. Doch mit einem kleinen Trick kann man sich helfen.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949312-thumbsmall-jqlt.jpg"/>
- </item>
- <item>
- <title>EU-Bericht zu Grenzsicherung: Griechenland droht Schengen-Rauswurf</title>
- <link>http://www.spiegel.de/politik/ausland/griechenland-eu-kommission-droht-mit-schengen-rauswurf-a-1074201.html#ref=rss</link>
- <description>Griechenland gerät in der Flüchtlingskrise unter massiven Druck der EU: Die Kommission will Athen Forderungen zum Grenzschutz schicken. Werden die nicht binnen drei Monaten erfüllt, droht der Ausschluss aus dem Schengen-Raum.</description>
- <category>Politik</category>
- <pubDate>Wed, 27 Jan 2016 15:04:00 +0100</pubDate>
- <guid>http://www.spiegel.de/politik/ausland/griechenland-eu-kommission-droht-mit-schengen-rauswurf-a-1074201.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949347-thumbsmall-vbmi.jpg" hspace="5" align="left" >Griechenland gerät in der Flüchtlingskrise unter massiven Druck der EU: Die Kommission will Athen Forderungen zum Grenzschutz schicken. Werden die nicht binnen drei Monaten erfüllt, droht der Ausschluss aus dem Schengen-Raum.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949347-thumbsmall-vbmi.jpg"/>
- </item>
- <item>
- <title>Protest gegen dänisches Asylrecht: Ai Weiwei schließt Ausstellung in Kopenhagen</title>
- <link>http://www.spiegel.de/kultur/gesellschaft/protest-gegen-daenisches-asylrecht-ai-weiwei-schliesst-ausstellung-a-1074241.html#ref=rss</link>
- <description>Ai Weiwei, Chinas wohl bekanntester Künstler, beendet seine Ausstellung in Kopenhagen vorzeitig. Grund ist eine Verschärfung der Asylregeln in Dänemark.</description>
- <category>Kultur</category>
- <pubDate>Wed, 27 Jan 2016 15:01:00 +0100</pubDate>
- <guid>http://www.spiegel.de/kultur/gesellschaft/protest-gegen-daenisches-asylrecht-ai-weiwei-schliesst-ausstellung-a-1074241.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949292-thumbsmall-uhox.jpg" hspace="5" align="left" >Ai Weiwei, Chinas wohl bekanntester Künstler, beendet seine Ausstellung in Kopenhagen vorzeitig. Grund ist eine Verschärfung der Asylregeln in Dänemark.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949292-thumbsmall-uhox.jpg"/>
- </item>
- <item>
- <title>Deutsche Handballer gegen Dänemark: Jetzt muss es schmutzig werden</title>
- <link>http://www.spiegel.de/sport/sonst/handball-em-2016-jetzt-muss-es-schmutzig-werden-a-1074123.html#ref=rss</link>
- <description>Noch ein Sieg bis zum Halbfinale: Die deutsche Handball-Nationalmannschaft hat bei der EM einen Lauf, sie ist gierig auf den Titel. Jetzt geht es gegen einen großen Favoriten - und Dänemark wirkt angeschlagen. </description>
- <category>Sport</category>
- <pubDate>Wed, 27 Jan 2016 14:59:00 +0100</pubDate>
- <guid>http://www.spiegel.de/sport/sonst/handball-em-2016-jetzt-muss-es-schmutzig-werden-a-1074123.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949116-thumbsmall-fpcj.jpg" hspace="5" align="left" >Noch ein Sieg bis zum Halbfinale: Die deutsche Handball-Nationalmannschaft hat bei der EM einen Lauf, sie ist gierig auf den Titel. Jetzt geht es gegen einen großen Favoriten - und Dänemark wirkt angeschlagen. ]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949116-thumbsmall-fpcj.jpg"/>
- </item>
- <item>
- <title>Sicherheitslage nach Anschlag: Russland spricht Reisewarnung für Türkei aus</title>
- <link>http://www.spiegel.de/reise/aktuell/russland-spricht-reisewarnung-fuer-tuerkei-aus-a-1074225.html#ref=rss</link>
- <description>Die russische Regierung warnt ihre Bürger vor Reisen in die Türkei. Damit schränkt sie den Tourismus in das Land weiter ein. Nach dem Anschlag in Istanbul sind auch die Buchungen von deutschen Urlaubern eingebrochen.</description>
- <category>Reise</category>
- <pubDate>Wed, 27 Jan 2016 14:58:00 +0100</pubDate>
- <guid>http://www.spiegel.de/reise/aktuell/russland-spricht-reisewarnung-fuer-tuerkei-aus-a-1074225.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-378624-thumbsmall-xtnj.jpg" hspace="5" align="left" >Die russische Regierung warnt ihre Bürger vor Reisen in die Türkei. Damit schränkt sie den Tourismus in das Land weiter ein. Nach dem Anschlag in Istanbul sind auch die Buchungen von deutschen Urlaubern eingebrochen.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-378624-thumbsmall-xtnj.jpg"/>
- </item>
- <item>
- <title>Bayern-Deal mit Katar: Scheich Di!</title>
- <link>http://www.spiegel.de/sport/fussball/fc-bayern-muenchen-und-der-katar-deal-in-der-pflicht-kommentar-a-1074187.html#ref=rss</link>
- <description>Der FC Bayern schließt einen Sponsoren-Deal mit Katar ab, die Kritik darüber ist ebenso berechtigt wie vorhersehbar. Dabei darf es nicht bleiben. Nehmen wir den Rekordmeister doch beim Wort.</description>
- <category>Sport</category>
- <pubDate>Wed, 27 Jan 2016 14:52:00 +0100</pubDate>
- <guid>http://www.spiegel.de/sport/fussball/fc-bayern-muenchen-und-der-katar-deal-in-der-pflicht-kommentar-a-1074187.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949236-thumbsmall-hyyw.jpg" hspace="5" align="left" >Der FC Bayern schließt einen Sponsoren-Deal mit Katar ab, die Kritik darüber ist ebenso berechtigt wie vorhersehbar. Dabei darf es nicht bleiben. Nehmen wir den Rekordmeister doch beim Wort.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949236-thumbsmall-hyyw.jpg"/>
- </item>
- <item>
- <title>Flüchtlingskrise: EU wirft Griechenland schwere Mängel bei Grenzkontrolle vor</title>
- <link>http://www.spiegel.de/politik/ausland/fluechtlinge-eu-wirft-griechenland-maengel-bei-grenzkontrolle-vor-a-1074219.html#ref=rss</link>
- <description>Die griechische Regierung verletzt ihre Pflichten bei der Grenzsicherung - zu diesem Schluss kommt ein Untersuchungsbericht der EU-Kommission. Brüssel spricht nun eine klare Drohung gegen Athen aus.</description>
- <category>Politik</category>
- <pubDate>Wed, 27 Jan 2016 14:47:00 +0100</pubDate>
- <guid>http://www.spiegel.de/politik/ausland/fluechtlinge-eu-wirft-griechenland-maengel-bei-grenzkontrolle-vor-a-1074219.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949273-thumbsmall-ifxg.jpg" hspace="5" align="left" >Die griechische Regierung verletzt ihre Pflichten bei der Grenzsicherung - zu diesem Schluss kommt ein Untersuchungsbericht der EU-Kommission. Brüssel spricht nun eine klare Drohung gegen Athen aus.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949273-thumbsmall-ifxg.jpg"/>
- </item>
- <item>
- <title>Abgasaffäre: Brüssel will Autokonzerne bestrafen können</title>
- <link>http://www.spiegel.de/wirtschaft/soziales/abgasaffaere-bruessel-will-autokonzerne-bestrafen-koennen-a-1074228.html#ref=rss</link>
- <description>Im Abgas-Skandal ist der VW-Konzern Schuldiger - aber auch die Aufseher in Brüssel sind blamiert. Denn US-Behörden enthüllten, was ihnen jahrelang durch die Lappen ging. Die EU-Kommission will jetzt dafür sorgen, dass sich das nicht wiederholt.</description>
- <category>Wirtschaft</category>
- <pubDate>Wed, 27 Jan 2016 14:46:00 +0100</pubDate>
- <guid>http://www.spiegel.de/wirtschaft/soziales/abgasaffaere-bruessel-will-autokonzerne-bestrafen-koennen-a-1074228.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-938136-thumbsmall-hxbc.jpg" hspace="5" align="left" >Im Abgas-Skandal ist der VW-Konzern Schuldiger - aber auch die Aufseher in Brüssel sind blamiert. Denn US-Behörden enthüllten, was ihnen jahrelang durch die Lappen ging. Die EU-Kommission will jetzt dafür sorgen, dass sich das nicht wiederholt.]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-938136-thumbsmall-hxbc.jpg"/>
- </item>
- <item>
- <title>Bundesverfassungsgericht: Wer alles gegen die Vorratsdatenspeicherung klagt</title>
- <link>http://www.spiegel.de/netzwelt/netzpolitik/vorratsdatenspeicherung-wer-klagt-vor-dem-bundesverfassungsgericht-a-1074152.html#ref=rss</link>
- <description>Widerstand gegen Vorratsdatenspeicherung: Die FDP hat Klage in Karlsruhe eingereicht, und auch weitere Gegner versuchen, das Gesetz vor Gericht noch zu kippen. Der Überblick. </description>
- <category>Netzwelt</category>
- <pubDate>Wed, 27 Jan 2016 14:42:00 +0100</pubDate>
- <guid>http://www.spiegel.de/netzwelt/netzpolitik/vorratsdatenspeicherung-wer-klagt-vor-dem-bundesverfassungsgericht-a-1074152.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-925932-thumbsmall-zbbn.jpg" hspace="5" align="left" >Widerstand gegen Vorratsdatenspeicherung: Die FDP hat Klage in Karlsruhe eingereicht, und auch weitere Gegner versuchen, das Gesetz vor Gericht noch zu kippen. Der Überblick. ]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-925932-thumbsmall-zbbn.jpg"/>
- </item>
- <item>
- <title>Berliner Flüchtlingsamt: Das Scheitern des Lageso - das Protokoll</title>
- <link>http://www.spiegel.de/politik/deutschland/berlin-das-scheitern-des-lageso-eine-chronik-a-1074186.html#ref=rss</link>
- <description>Tagelanges Warten, keine Auszahlung von Essensgeld, Gewalt - jetzt angeblich ein Toter: Seit Monaten steht das Berliner Flüchtlingsamt Lageso in den Schlagzeilen. Die Chronologie des Scheiterns. </description>
- <category>Politik</category>
- <pubDate>Wed, 27 Jan 2016 14:22:00 +0100</pubDate>
- <guid>http://www.spiegel.de/politik/deutschland/berlin-das-scheitern-des-lageso-eine-chronik-a-1074186.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949137-thumbsmall-pgoa.jpg" hspace="5" align="left" >Tagelanges Warten, keine Auszahlung von Essensgeld, Gewalt - jetzt angeblich ein Toter: Seit Monaten steht das Berliner Flüchtlingsamt Lageso in den Schlagzeilen. Die Chronologie des Scheiterns. ]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949137-thumbsmall-pgoa.jpg"/>
- </item>
- <item>
- <title>Apple-Gerüchte: So könnte das neue iPhone aussehen. Aber was wünschen Sie sich?</title>
- <link>http://www.spiegel.de/netzwelt/gadgets/apple-so-gut-muss-das-iphone-7-sein-a-1074158.html#ref=rss</link>
- <description>Ist der iPhone-Boom vorbei? Nicht unbedingt - das nächste Gerät könnte starke neue Features haben. Hier der Stand der Gerüchte. Und Sie können abstimmen: Was brauchen Sie wirklich?</description>
- <category>Netzwelt</category>
- <pubDate>Wed, 27 Jan 2016 14:17:00 +0100</pubDate>
- <guid>http://www.spiegel.de/netzwelt/gadgets/apple-so-gut-muss-das-iphone-7-sein-a-1074158.html</guid>
- <content:encoded><![CDATA[<img src="http://www.spiegel.de/images/image-949140-thumbsmall-bdof.jpg" hspace="5" align="left" >Ist der iPhone-Boom vorbei? Nicht unbedingt - das nächste Gerät könnte starke neue Features haben. Hier der Stand der Gerüchte. Und Sie können abstimmen: Was brauchen Sie wirklich?]]></content:encoded>
- <enclosure type="image/jpeg" url="http://www.spiegel.de/images/image-949140-thumbsmall-bdof.jpg"/>
- </item>
- </channel>
-</rss> \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/resources/feed_rss_tumblr.xml b/mobile/android/tests/background/junit4/resources/feed_rss_tumblr.xml
deleted file mode 100644
index 15b20b652..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_rss_tumblr.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><description>Your reliable source for up-to-the-minute commodities pricing.</description><title>Tumblr Staff</title><generator>Tumblr (3.0; @staff)</generator><link>http://staff.tumblr.com/</link><item><title>hardyboyscovers:
-
- Can Nancy Drew see things through and solve...</title><description>&lt;img src="http://41.media.tumblr.com/6dcceee090b2eef840cf694b205e1551/tumblr_o0r7mqDr5P1ug9yhzo1_400.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;&lt;a class="tumblr_blog" href="http://hardyboyscovers.tumblr.com/post/137036714181"&gt;hardyboyscovers&lt;/a&gt;:&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;p&gt;Can Nancy Drew see things through and solve the case?&lt;br/&gt;&lt;br/&gt;&lt;/p&gt;
- &lt;/blockquote&gt;
-
- &lt;p&gt;Please horse, no&lt;/p&gt;</description><link>http://staff.tumblr.com/post/138124026275</link><guid>http://staff.tumblr.com/post/138124026275</guid><pubDate>Tue, 26 Jan 2016 21:30:12 -0500</pubDate><category>good blog</category><category>bad horse</category><category>book covers</category><category>book cover week</category></item><item><title>Chasing Storms at 17,500mph</title><description>&lt;p&gt;&lt;a class="tumblr_blog" href="http://stationcdrkelly.tumblr.com/post/138047038357"&gt;stationcdrkelly&lt;/a&gt;:&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;p&gt;Flying 250 miles above the Earth aboard the International Space Station has given me the unique vantage point from which to view our planet. Spending a year in space has given me the unique opportunity to see a wide range of spectacular storm systems in space and on Earth. &lt;br/&gt;&lt;/p&gt;
- &lt;p&gt;The recent blizzard was remarkably visible from space. I took several photos of the first big storm system on Earth of year 2016 as it moved across the East Coast, Chicago and Washington D.C. Since my time here on the space station began in March 2015, I’ve been able to capture an array of storms on Earth and in space, ranging from hurricanes and dust storms to solar storms and most recently a rare thunder snowstorm. &lt;/p&gt;
- &lt;figure class="tmblr-full" data-orig-height="1065" data-orig-width="1600"&gt;&lt;img src="http://41.media.tumblr.com/ba62a8f18ceef5a20f60b700d14b39fe/tumblr_inline_o1hmtucs6o1tmec5e_540.jpg" data-orig-height="1065" data-orig-width="1600"/&gt;&lt;/figure&gt;&lt;p&gt;Blizzard 2016&lt;/p&gt;
- &lt;figure class="tmblr-full" data-orig-height="1065" data-orig-width="1600"&gt;&lt;img src="http://40.media.tumblr.com/371eedcc0adf48ed07c5d1bd3f326ef1/tumblr_inline_o1hmuyAVw01tmec5e_540.jpg" data-orig-height="1065" data-orig-width="1600"/&gt;&lt;/figure&gt;&lt;p&gt;Hurricane Patricia 2015&lt;/p&gt;
- &lt;figure class="tmblr-full" data-orig-height="1065" data-orig-width="1600"&gt;&lt;img src="http://40.media.tumblr.com/07cc92970eea9607b20264f589a94f59/tumblr_inline_o1hmwd9dIE1tmec5e_540.jpg" data-orig-height="1065" data-orig-width="1600"/&gt;&lt;/figure&gt;&lt;p&gt;Hurricane Joaquin 2015&lt;/p&gt;
- &lt;figure class="tmblr-full" data-orig-height="682" data-orig-width="1024"&gt;&lt;img src="http://41.media.tumblr.com/ee5232cbf15d24b23932e0af0384f922/tumblr_inline_o1hmyeCO2I1tmec5e_540.jpg" data-orig-height="682" data-orig-width="1024"/&gt;&lt;/figure&gt;&lt;p&gt;Dust Storm in the Red Sea 2015&lt;/p&gt;
- &lt;figure class="tmblr-full" data-orig-height="1065" data-orig-width="1600"&gt;&lt;img src="http://41.media.tumblr.com/e1c72c1a9be6394db409f0ffd0db31f8/tumblr_inline_o1hmzrMkBF1tmec5e_540.jpg" data-orig-height="1065" data-orig-width="1600"/&gt;&lt;/figure&gt;&lt;p&gt;Dust Storm of Gobi Desert 2015&lt;/p&gt;
- &lt;figure class="tmblr-full" data-orig-height="1065" data-orig-width="1600"&gt;&lt;img src="http://40.media.tumblr.com/aa3a6d80dc603a9cc2cd5ceeb528ca55/tumblr_inline_o1hn1cI5xt1tmec5e_540.jpg" data-orig-height="1065" data-orig-width="1600"/&gt;&lt;/figure&gt;&lt;p&gt;Aurora Solar Storm 2015&lt;/p&gt;
- &lt;figure class="tmblr-full" data-orig-height="1065" data-orig-width="1600"&gt;&lt;img src="http://40.media.tumblr.com/6d5c5715f629aa0a37908cc7ddc9e9a4/tumblr_inline_o1hn2ewElf1tmec5e_540.jpg" data-orig-height="1065" data-orig-width="1600"/&gt;&lt;/figure&gt;&lt;p&gt;Aurora Solar Storm 2016&lt;/p&gt;
- &lt;figure class="tmblr-full" data-orig-height="1065" data-orig-width="1600"&gt;&lt;img src="http://41.media.tumblr.com/ec251e592ad4132c3141d3289344f6b0/tumblr_inline_o1hn7eMqGD1tmec5e_540.jpg" data-orig-height="1065" data-orig-width="1600"/&gt;&lt;/figure&gt;&lt;p&gt;Thunderstorm over Italy 2015&lt;/p&gt;
- &lt;figure class="tmblr-full" data-orig-height="1067" data-orig-width="1600"&gt;&lt;img src="http://36.media.tumblr.com/d15b6033547c0e5c465a35614cdd753e/tumblr_inline_o1hnaxgi6r1tmec5e_540.jpg" data-orig-height="1067" data-orig-width="1600"/&gt;&lt;/figure&gt;&lt;p&gt;Lightning and Aurora 2016&lt;/p&gt;
- &lt;figure class="tmblr-full" data-orig-height="1065" data-orig-width="1600"&gt;&lt;img src="http://36.media.tumblr.com/96f14b994bba66b9f690a6e086657333/tumblr_inline_o1hnc4GTCi1tmec5e_540.jpg" data-orig-height="1065" data-orig-width="1600"/&gt;&lt;/figure&gt;&lt;p&gt;Rare Thunder Snowstorm 2016&lt;/p&gt;
- &lt;p&gt;Follow my Year In Space on Twitter, Facebook and Instagram. &lt;/p&gt;
- &lt;/blockquote&gt;
-
- &lt;p&gt;Astronaut Scott Kelly just signed up for Tumblr all the way from space. &lt;i&gt;Outer&lt;/i&gt; space. So far, this the coolest weather blog of all time. &lt;/p&gt;</description><link>http://staff.tumblr.com/post/138053124065</link><guid>http://staff.tumblr.com/post/138053124065</guid><pubDate>Mon, 25 Jan 2016 19:48:40 -0500</pubDate></item><item><title>digg:
-
- first it starts out like a little spinning hexagonthen it spins more and gets biggermore...</title><description>&lt;p&gt;&lt;a href="http://digg.tumblr.com/post/137842908963/first-it-starts-out-like-a-little-spinning-hexagon" class="tumblr_blog"&gt;digg&lt;/a&gt;:&lt;/p&gt;
-
- &lt;blockquote&gt;&lt;figure data-orig-width="473" data-orig-height="52" class="tmblr-full"&gt;&lt;img src="http://40.media.tumblr.com/0ec3a49eb7143dc50e7d3a7252bb707f/tumblr_inline_o1dnci9q4j1ro8h5m_540.png" data-orig-width="473" data-orig-height="52"/&gt;&lt;/figure&gt;&lt;p&gt;&lt;br/&gt;first it starts out like a little spinning hexagon&lt;/p&gt;&lt;figure data-orig-width="400" data-orig-height="396" class="tmblr-full"&gt;&lt;img src="http://38.media.tumblr.com/fb369bd707e311591f85de1d10b94bc6/tumblr_inline_o1dnbpkqXI1ro8h5m_500.gif" data-orig-width="400" data-orig-height="396"/&gt;&lt;/figure&gt;&lt;p&gt;then it spins more and gets bigger&lt;br/&gt;&lt;/p&gt;&lt;figure data-orig-width="400" data-orig-height="396" class="tmblr-full"&gt;&lt;img src="http://33.media.tumblr.com/5d5e6abd203bda735f5b798bd7d100cb/tumblr_inline_o1dnbnbv6r1ro8h5m_500.gif" data-orig-width="400" data-orig-height="396"/&gt;&lt;/figure&gt;&lt;p&gt;more spinning, the background gets red&lt;/p&gt;&lt;figure data-orig-width="400" data-orig-height="396" class="tmblr-full"&gt;&lt;img src="http://38.media.tumblr.com/7b11f8f9abec6211440880cee0c94a89/tumblr_inline_o1dnbnn1IM1ro8h5m_500.gif" data-orig-width="400" data-orig-height="396"/&gt;&lt;/figure&gt;&lt;p&gt;then it goes all over your driveway like this&lt;/p&gt;&lt;figure class="tmblr-full" data-orig-height="225" data-orig-width="400"&gt;&lt;img src="http://38.media.tumblr.com/6e3d06c9a97f3acc05c20d2e37f3f730/tumblr_inline_o1dney205v1ro8h5m_500.gif" data-orig-height="225" data-orig-width="400"/&gt;&lt;/figure&gt;&lt;/blockquote&gt;</description><link>http://staff.tumblr.com/post/137845368600</link><guid>http://staff.tumblr.com/post/137845368600</guid><pubDate>Fri, 22 Jan 2016 19:47:00 -0500</pubDate><category>have a good weekend tumblr</category><category>stay safe stay beautiful</category></item><item><title>This week in drama clubHigh School Musical: Bopped to the top 10...</title><description>&lt;img src="http://40.media.tumblr.com/9c69a850eece63c29d913b6e83dd49a7/tumblr_o1dcfztyzk1qz8q0ho1_500.png"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;h2&gt;This week in drama club&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;&lt;a href="http://tumblr.com/search/golden%20disk%20awards"&gt;&lt;/a&gt;&lt;/b&gt;&lt;a href="http://tumblr.com/search/hsm"&gt;&lt;i&gt;&lt;b&gt;High School Musical&lt;/b&gt;&lt;/i&gt;&lt;/a&gt;: Bopped to the top 10 years ago this week.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/golden%20disk%20awards"&gt;&lt;i&gt;&lt;b&gt;Golden Disk Awards&lt;/b&gt;&lt;/i&gt;&lt;/a&gt;: Baked to perfection. Thanks, Zeke!&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/miraculous%20ladybug"&gt;&lt;b&gt;&lt;i&gt;Miraculous Ladybug&lt;/i&gt;&lt;/b&gt;&lt;/a&gt;: The Gabriella to Cat Noir’s Troy.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/agent%20carter"&gt;&lt;b&gt;&lt;i&gt;Agent Carter&lt;/i&gt;&lt;/b&gt;&lt;/a&gt;: The start of something new (season two).&lt;br/&gt;&lt;/li&gt;&lt;/ul&gt;&lt;figure data-orig-width="160" data-orig-height="180" data-tumblr-attribution="hunting-the-grievers:cPVhQbqjjwjt3Hpa2i0A3Q:ZDFbbm1f4dbEu" class="tmblr-full"&gt;&lt;img src="http://38.media.tumblr.com/d6c281341a84fd1367682d598b008af9/tumblr_nkrg1eqpXu1tl1wyoo1_250.gif" alt="image" data-orig-width="160" data-orig-height="180"/&gt;&lt;/figure&gt;&lt;h2&gt;Student government elections&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/sarah%20palin"&gt;&lt;b&gt;Sarah Palin&lt;/b&gt;&lt;/a&gt;: Song singin’, bitter clingin’, proud clingers of West Side Knights.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/democratic%20debate"&gt;&lt;b&gt;Democratic debate&lt;/b&gt;&lt;/a&gt;: A political decathlon.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Wildcat co-captains&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/matt%20the%20radar%20technician"&gt;&lt;b&gt;Matt the Radar Technician&lt;/b&gt;&lt;/a&gt;: Secretly Coach Bolton.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/jada%20pinkett%20smith"&gt;&lt;b&gt;Jada Pinkett Smith&lt;/b&gt;&lt;/a&gt;: Owns more hats than Ryan Evans.&lt;br/&gt;&lt;/li&gt;&lt;/ul&gt;&lt;figure data-orig-width="480" data-orig-height="270" data-tumblr-attribution="nbcsnl:B-Wm_cenWtc03w62FRwf1A:ZpdRYu201JEGk" class="tmblr-full"&gt;&lt;img src="http://31.media.tumblr.com/acd5b9d1d6ef051d12fabbedeb1bc023/tumblr_o13140hUBg1rdzuduo1_500.gif" alt="image" data-orig-width="480" data-orig-height="270"/&gt;&lt;/figure&gt;&lt;h2&gt;Get’cha head in the game&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/wwe"&gt;&lt;b&gt;WWE&lt;/b&gt;&lt;/a&gt;: We’re all in this Royal Rumble together.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/australian%20open"&gt;&lt;b&gt;Australian Open&lt;/b&gt;&lt;/a&gt;: Go Wildcats!&lt;br/&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Sticking to the status quo: Check out these Tumblrs&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Creative Capital&lt;/b&gt; (&lt;a href="http://tmblr.co/mcSeD8C3uF_aHrmt0C6VpUw"&gt;@creative-cap&lt;/a&gt;): Patron of the arts.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Broadway Con&lt;/b&gt; (&lt;a href="http://tmblr.co/miT9FBjVCw7YfioPNppjryw"&gt;@bwaycon&lt;/a&gt;): What you’ve been looking for.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Mall Goth Phase&lt;/b&gt; (&lt;a href="http://tmblr.co/mUHclMBjOwpJBi4M1bucs5Q"&gt;@mallgothphase&lt;/a&gt;): Hot, topical blog.&lt;br/&gt;&lt;/li&gt;&lt;/ul&gt;&lt;figure data-orig-width="367" data-orig-height="245" data-tumblr-attribution="wrestling-giffer:V0IfEVup_dIDxzIYMr5R0A:Z1UX8r1yd0krY" class="tmblr-full"&gt;&lt;img src="http://38.media.tumblr.com/5685bb235ec944c5084939da16c24958/tumblr_ny9xzoSQ5K1sbzhteo1_400.gif" alt="image" data-orig-width="367" data-orig-height="245"/&gt;&lt;/figure&gt;</description><link>http://staff.tumblr.com/post/137833222680</link><guid>http://staff.tumblr.com/post/137833222680</guid><pubDate>Fri, 22 Jan 2016 16:07:26 -0500</pubDate><category>trends</category></item><item><title>nationwideexposure:
-
- I’M CRYING...</title><description>&lt;img src="http://40.media.tumblr.com/7ba6d036bd5939f087f8feee424dc337/tumblr_n1aawcsEOd1rr31p0o1_400.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://41.media.tumblr.com/8bfce3018cf868734dc73f11c9c84cce/tumblr_n1aawcsEOd1rr31p0o2_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://41.media.tumblr.com/68275fc41a5879e03f6b67401d21b9c6/tumblr_n1aawcsEOd1rr31p0o3_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://40.media.tumblr.com/4d987c36b13dc78ec66d9f7311f23ed8/tumblr_n1aawcsEOd1rr31p0o4_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://40.media.tumblr.com/052fb3ff421e40865f517b60e7a00af4/tumblr_n1aawcsEOd1rr31p0o5_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://40.media.tumblr.com/b4d65c50fed46518eef6091575171247/tumblr_n1aawcsEOd1rr31p0o6_250.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://41.media.tumblr.com/e989c0771b588d4b8e4068caa71c7764/tumblr_n1aawcsEOd1rr31p0o7_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://41.media.tumblr.com/3a9ca6beb713678743987b830ce2a5a6/tumblr_n1aawcsEOd1rr31p0o8_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://41.media.tumblr.com/72daba4a9a2598dcbc18f6d5b7c1ecaa/tumblr_n1aawcsEOd1rr31p0o9_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://40.media.tumblr.com/a9db431bf354b42fd035d44c9910bfe6/tumblr_n1aawcsEOd1rr31p0o10_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;p&gt;&lt;a class="tumblr_blog" href="http://nationwideexposure.tumblr.com/post/77260363328"&gt;nationwideexposure&lt;/a&gt;:&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;p&gt;I’M CRYING 😂😭😂😭😂&lt;/p&gt;
- &lt;/blockquote&gt;
- &lt;p&gt;——&lt;br/&gt;——&lt;br/&gt;——&lt;br/&gt;——&lt;/p&gt;&lt;p&gt; 👀&lt;br/&gt;——&lt;br/&gt;——&lt;br/&gt;——&lt;br/&gt;——&lt;/p&gt;</description><link>http://staff.tumblr.com/post/137788176890</link><guid>http://staff.tumblr.com/post/137788176890</guid><pubDate>Thu, 21 Jan 2016 22:00:16 -0500</pubDate><category>stock photo</category><category>stock photo week</category></item><item><title>risingfunk:
-
- hey creationists,
- if evolution isn’t real… explain...</title><description>&lt;img src="http://41.media.tumblr.com/9dd0ed0e50f1963930b55002f22d2569/tumblr_njt97mInHy1rz419eo3_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://41.media.tumblr.com/39362963e0d3bab55f84c7b9e7acc1b1/tumblr_njt97mInHy1rz419eo4_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://36.media.tumblr.com/f2e4d58b37bebdd48c0593b66c2fa910/tumblr_njt97mInHy1rz419eo2_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;img src="http://40.media.tumblr.com/0e0fb52c15c625d46ee1fa108c102e41/tumblr_njt97mInHy1rz419eo1_500.jpg"/&gt;&lt;br/&gt; &lt;br/&gt;&lt;p&gt;&lt;a class="tumblr_blog" href="http://risingfunk.tumblr.com/post/111068384527"&gt;risingfunk&lt;/a&gt;:&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;p&gt;hey creationists,&lt;/p&gt;
- &lt;p&gt;if evolution isn’t real… explain &lt;b&gt;THIS&lt;/b&gt;&lt;br/&gt;&lt;/p&gt;
- &lt;/blockquote&gt;
-
- &lt;p&gt;We’d like anyone to explain this.&lt;/p&gt;</description><link>http://staff.tumblr.com/post/137724564137</link><guid>http://staff.tumblr.com/post/137724564137</guid><pubDate>Wed, 20 Jan 2016 22:00:29 -0500</pubDate><category>stock photo</category><category>stock photo week</category></item><item><title>I’ll Be There For You (Theme from…)</title><description>&lt;p&gt;&lt;a class="tumblr_blog" href="http://thefandometrics.tumblr.com/post/137713318764"&gt;thefandometrics&lt;/a&gt;:&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;p&gt;&lt;figure class="tmblr-full" data-orig-height="100" data-orig-width="500"&gt;&lt;img src="http://36.media.tumblr.com/b528045dbfddacd8dcb1789ae1aabad8/tumblr_inline_o19xl51Nx51qz7tc0_540.png" data-orig-height="100" data-orig-width="500"/&gt;&lt;/figure&gt;&lt;/p&gt;&lt;h2&gt;
- &lt;a href="http://thefandometrics.tumblr.com/post/137583618255/tv-shows-week-ending-january-18th-2016-steven"&gt;Television&lt;/a&gt;: So no one told you life was gonna be this way.&lt;/h2&gt;
- &lt;blockquote&gt;&lt;p&gt;☆ &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Saturday+Night+Live"&gt;Saturday Night Live&lt;/a&gt;&lt;/i&gt;&lt;/b&gt; returns to No. 11 with a little help from Kyl–uh, Matt the Radar Technician.&lt;br/&gt; ⬆ &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Pretty%20Little%20Liars"&gt;Pretty Little Liars&lt;/a&gt;&lt;/i&gt;&lt;/b&gt; (No. 7) jumped five years in the future and eleven spots on our list.&lt;br/&gt;☆ &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Rick%20and%20Morty"&gt;Rick and Morty&lt;/a&gt;&lt;/i&gt;&lt;/b&gt; came back at a solid No. 18 while all of you played &lt;i&gt;Pocket Mortys&lt;/i&gt;. &lt;/p&gt;&lt;/blockquote&gt;
- &lt;figure class="tmblr-full" data-orig-height="271" data-orig-width="480" data-tumblr-attribution="ren-rey-lo:3VGJxt125Qzd9mCpO3SEBg:ZZ1ZMi202CMhl"&gt;&lt;img src="http://38.media.tumblr.com/fd91b6634cfd45862f50b955a4dcecd6/tumblr_o13kbrUuy51v4pr6ko4_500.gif" data-orig-height="271" data-orig-width="480"/&gt;&lt;/figure&gt;&lt;h2&gt;
- &lt;a href="http://thefandometrics.tumblr.com/post/137583047944/movies-week-ending-january-18th-2016-star-wars"&gt;Movies&lt;/a&gt;: ðŸ‘ðŸ‘ðŸ‘ðŸ‘.&lt;/h2&gt;
- &lt;blockquote&gt;&lt;p&gt;⬆ &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Deadpool"&gt;Deadpool&lt;/a&gt;&lt;/i&gt;&lt;/b&gt;’s (No. 2) &lt;a href="http://www.herochan.com/post/137155502690/deadpool-movie-promotion-done-right"&gt;marketing&lt;/a&gt; team deserves a raise. &lt;br/&gt;☆ &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Labyrinth"&gt;Labyrinth&lt;/a&gt;&lt;/i&gt;&lt;/b&gt; debuted at No. 6. All hail The Goblin King. &lt;/p&gt;&lt;/blockquote&gt;
- &lt;h2&gt;
- &lt;a href="http://thefandometrics.tumblr.com/post/137582487533/musical-acts-week-ending-january-18th-2016-david"&gt;Music&lt;/a&gt;: Your life’s a joke, you’re broke.&lt;/h2&gt;
- &lt;blockquote&gt;&lt;p&gt;☆ &lt;b&gt;&lt;a href="https://www.tumblr.com/search/David%20Bowie"&gt;David Bowie&lt;/a&gt;&lt;/b&gt; is No. 1, as he should be.&lt;br/&gt;⬆ &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Panic%20at%20the%20Disco"&gt;Panic! at the Disco&lt;/a&gt;&lt;/b&gt; did the hustle up to No. 4.&lt;/p&gt;&lt;/blockquote&gt;
- &lt;h2&gt;
- &lt;a href="http://thefandometrics.tumblr.com/post/137581921455/celebrities-week-ending-january-18th-2016-alan"&gt;Celebrities&lt;/a&gt;: Your love life’s D.O.A.&lt;/h2&gt;
- &lt;blockquote&gt;&lt;p&gt;☆ &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Alan%20Rickman"&gt;Alan Rickman&lt;/a&gt;&lt;/b&gt; is No. 1, as he should be.&lt;br/&gt; ⬆ &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Leonardo%20DiCaprio"&gt;Leonardo DiCaprio&lt;/a&gt;&lt;/b&gt; continues his climb, moves up to No. 5. A true revenant.&lt;br/&gt; ☆ &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Gillian%20Anderson"&gt;Gillian Anderson&lt;/a&gt;&lt;/b&gt; debuted at No. 14. We want to believe in the reboot. &lt;/p&gt;&lt;/blockquote&gt;
- &lt;figure class="tmblr-full" data-orig-height="211" data-orig-width="500" data-tumblr-attribution="szabcsiify:6F9QwBM8is-j-q9KKvjFOQ:Z5xAar1qg38kJ"&gt;&lt;img src="http://33.media.tumblr.com/ea080946a865dd802c098792fc303649/tumblr_ns7chfYxeU1sxov47o1_500.gif" data-orig-height="211" data-orig-width="500"/&gt;&lt;/figure&gt;&lt;h2&gt;
- &lt;a href="http://thefandometrics.tumblr.com/post/137581349025/video-games-week-ending-january-18th-2016"&gt;Games&lt;/a&gt;: It’s like you’re always stuck in second gear. &lt;/h2&gt;
- &lt;blockquote&gt;&lt;p&gt;⬆ &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Pok%C3%A9mon"&gt;Pokémon&lt;/a&gt;&lt;/i&gt;&lt;/b&gt; (No. 2) is twenty years old. Like, human earth years. Twenty of them.&lt;br/&gt; ⬆ &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Splatoon"&gt;Splatoon&lt;/a&gt;&lt;/i&gt;&lt;/b&gt;’s Splatfest was an inky success, propelling it to No. 10.&lt;/p&gt;&lt;/blockquote&gt;
- &lt;h2&gt;
- &lt;a href="http://thefandometrics.tumblr.com/post/137580830792/web-stuff-week-ending-january-18th-2016"&gt;Web stuff&lt;/a&gt;: When it hasn’t been your day, your week, your month, or even your year.&lt;/h2&gt;
- &lt;blockquote&gt;&lt;p&gt;⬆ Vlogging savant &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Troye%20Sivan"&gt;Troye Sivan&lt;/a&gt;&lt;/b&gt; moves up to No. 4.&lt;br/&gt; ⬇︎ Story time! &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Thomas%20Sanders"&gt;Thomas Sanders&lt;/a&gt;&lt;/b&gt; fell seven spots to No. 19.&lt;/p&gt;&lt;/blockquote&gt;
- &lt;/blockquote&gt;</description><link>http://staff.tumblr.com/post/137714050360</link><guid>http://staff.tumblr.com/post/137714050360</guid><pubDate>Wed, 20 Jan 2016 18:42:44 -0500</pubDate><category>week in review</category></item><item><title>Photo</title><description>&lt;img src="http://36.media.tumblr.com/9886e52dcd701c004da445cecd89e7a7/tumblr_ne2u5i2aWI1sq05vko1_400.png"/&gt;&lt;br/&gt;&lt;br/&gt;</description><link>http://staff.tumblr.com/post/137656822367</link><guid>http://staff.tumblr.com/post/137656822367</guid><pubDate>Tue, 19 Jan 2016 21:00:09 -0500</pubDate><category>stock</category><category>stock photo week</category><category>businessing</category><category>business</category></item><item><title>vedranmisic:
-
- Happy Birthday, Dr. Martin Luther King Jr.“I HAVE...</title><description>&lt;img src="http://40.media.tumblr.com/01e16942f7f596872c5e7d73d41f989b/tumblr_o0z9nswYMm1re26ajo1_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;&lt;a href="http://vedranmisic.tumblr.com/post/137328304708/happy-birthday-dr-martin-luther-king-jr-i-have" class="tumblr_blog"&gt;vedranmisic&lt;/a&gt;:&lt;/p&gt;
-
- &lt;blockquote&gt;&lt;p&gt;Happy Birthday, Dr. Martin Luther King Jr.&lt;br/&gt;“I HAVE A DREAM†(ink on paper, 11x14 inches)&lt;br/&gt;&lt;/p&gt;&lt;/blockquote&gt;</description><link>http://staff.tumblr.com/post/137556640935</link><guid>http://staff.tumblr.com/post/137556640935</guid><pubDate>Mon, 18 Jan 2016 11:20:27 -0500</pubDate><category>martin luther king jr</category></item><item><title>fruitsoftheweb:
-
- Elastic and non-linear plastic effects are...</title><description>&lt;img src="http://45.media.tumblr.com/525d91fe69a7815bc84438e4dab4e8e0/tumblr_n7lvudTrkx1skn1oxo1_400.gif"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;&lt;a class="tumblr_blog" href="http://fruitsoftheweb.tumblr.com/post/89724820207"&gt;fruitsoftheweb&lt;/a&gt;:&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;p class="p1"&gt;&lt;a href="https://www.youtube.com/watch?v=1Q_zb65SXt0"&gt;&lt;em&gt;Elastic and non-linear plastic effects are obtained by adding springs with varying rest length between particles.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
- &lt;/blockquote&gt;
-
- &lt;p&gt;You can dress this description up any way you want, but this here link is a video about straight-up slime.&lt;/p&gt;</description><link>http://staff.tumblr.com/post/137382144100</link><guid>http://staff.tumblr.com/post/137382144100</guid><pubDate>Fri, 15 Jan 2016 21:00:30 -0500</pubDate><category>slime</category><category>slime week</category></item><item><title>Video</title><description>
- &lt;video id='embed-56a8a4909ac31729864247' class='crt-video crt-skin-default' width='400' height='225' poster='http://media.tumblr.com/tumblr_o10q0s4lQw1qz8q0h_frame1.jpg' preload='none' data-crt-video data-crt-options='{"autoheight":null,"duration":299,"hdUrl":false,"filmstrip":{"url":"http:\/\/38.media.tumblr.com\/previews\/tumblr_o10q0s4lQw1qz8q0h_filmstrip.jpg","width":"200","height":"112"}}' &gt;
- &lt;source src="http://staff.tumblr.com/video_file/137376306290/tumblr_o10q0s4lQw1qz8q0h" type="video/mp4"&gt;
- &lt;/video&gt;
- &lt;br/&gt;&lt;br/&gt;</description><link>http://staff.tumblr.com/post/137376306290</link><guid>http://staff.tumblr.com/post/137376306290</guid><pubDate>Fri, 15 Jan 2016 19:06:25 -0500</pubDate><category>have a relaxing weekend tumblr</category></item><item><title>Losing one was hard enough… David Bowie said his goodbye, we’re...</title><description>&lt;img src="http://40.media.tumblr.com/9c69a850eece63c29d913b6e83dd49a7/tumblr_o10jfzocXP1qz8q0ho1_500.png"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;h2&gt;Losing one was hard enough… &lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/david%20bowie"&gt;&lt;b&gt;David Bowie&lt;/b&gt;&lt;/a&gt; said his goodbye, we’re all thinking of his love. &lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/alan%20rickman"&gt;&lt;b&gt;Alan Rickman&lt;/b&gt;&lt;/a&gt; is survived by his wife and his magic.&lt;br/&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Losing &lt;a href="http://tumblr.com/search/powerball"&gt;&lt;b&gt;POWERBALL&lt;/b&gt;&lt;/a&gt; didn’t help anything.&lt;/p&gt;&lt;figure data-orig-width="500" data-orig-height="278" data-tumblr-attribution="rustbeltjessie:Z20sTdCnR6V5dULG-Pk5FA:ZyRL1u1-svswa" class="tmblr-full"&gt;&lt;img src="http://33.media.tumblr.com/896e5f5e4ea77f08a930d01a39723805/tumblr_o0y90c1KPr1rift8jo1_500.gif" alt="image" data-orig-width="500" data-orig-height="278"/&gt;&lt;/figure&gt;&lt;h2&gt;It’s award season (again)&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/golden%20globes"&gt;&lt;b&gt;Golden Globes&lt;/b&gt;&lt;/a&gt; got a little loose with the juice.&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/leonardo%20dicaprio"&gt;&lt;b&gt;Leo DiCaprio&lt;/b&gt;&lt;/a&gt; got on Lady Gaga’s shit list.&lt;/li&gt;&lt;li&gt;And &lt;a href="http://tumblr.com/search/oscars%202016"&gt;&lt;b&gt;Oscars 2016&lt;/b&gt;&lt;/a&gt;: got heat for an all-white nomination slate.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Trends gonna trend&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/coming%20out"&gt;&lt;b&gt;Coming out&lt;/b&gt;&lt;/a&gt;: It’s all part of growing up.&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/the%20shannara%20chronicles"&gt;&lt;b&gt;&lt;i&gt;The Shannara Chronicles&lt;/i&gt;&lt;/b&gt;&lt;/a&gt;: A shoo be doo wop / bop bop doo wop.&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/shadowhunters"&gt;&lt;b&gt;&lt;i&gt;Shadowhunters&lt;/i&gt;&lt;/b&gt;&lt;/a&gt;: Best played on a sunny day.&lt;/li&gt;&lt;/ul&gt;&lt;figure data-orig-width="500" data-orig-height="281" data-tumblr-attribution="katiecouric:bvFuZWnCzpG75MylRNwCUA:ZPcBQw1-hna98" class="tmblr-full"&gt;&lt;img src="http://33.media.tumblr.com/1da9dfe557532a71323d45749dd6ea3c/tumblr_o0swib9HUI1r7kaf3o1_500.gif" alt="image" data-orig-width="500" data-orig-height="281"/&gt;&lt;/figure&gt;&lt;h2&gt;And these dynamite Tumblrs: &lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Plus Size Never Looked So Good&lt;/b&gt; (&lt;a href="http://tmblr.co/mpKfpxC4WXhPT0bbAU74L0w"&gt;@plussizeneverlookedsogood&lt;/a&gt;): Big girl swag.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Amandla&lt;/b&gt; (&lt;a href="http://tmblr.co/mfy9cYbpNQiEgZnaWyfwSRg"&gt;@amandla&lt;/a&gt;): You know her as Rue, but you should see her graphic novels.&lt;br/&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Black Shop, White Writing &lt;/b&gt;(&lt;a href="http://tmblr.co/myTgmVRoFyIoi0hhKlWr0vw"&gt;@blackshopswhitewriting&lt;/a&gt;): Shades of gentrification&lt;br/&gt;&lt;/li&gt;&lt;/ul&gt;&lt;figure data-orig-width="500" data-orig-height="190" data-tumblr-attribution="ziggyreturns:LA35rxFHUTbzeMrpzP2h-w:ZfoOZm1mAh7Bv" class="tmblr-full"&gt;&lt;img src="http://33.media.tumblr.com/6bb8b39e6a9cd2c981fee71de1a281a6/tumblr_noi61wxvz31tlqitmo1_500.gif" alt="image" data-orig-width="500" data-orig-height="190"/&gt;&lt;/figure&gt;</description><link>http://staff.tumblr.com/post/137369118080</link><guid>http://staff.tumblr.com/post/137369118080</guid><pubDate>Fri, 15 Jan 2016 16:55:09 -0500</pubDate><category>trends</category></item><item><title>Is this satisfying or enraging? We can’t decide. </title><description>&lt;img src="http://49.media.tumblr.com/d022b6caad3f1b5ae988b94d7113b434/tumblr_nyv2d24zYP1v0kd8mo1_500.gif"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;Is this satisfying or enraging? We can’t decide. &lt;/p&gt;</description><link>http://staff.tumblr.com/post/137318516024</link><guid>http://staff.tumblr.com/post/137318516024</guid><pubDate>Thu, 14 Jan 2016 21:00:04 -0500</pubDate><category>slime</category><category>slime week</category><category>you decide</category></item><item><title>⬆ This great GIF button is now on iOS This button turns your...</title><description>&lt;img src="http://49.media.tumblr.com/8342edc0521edf0edcfabeed522825c9/tumblr_o0st80ul691qz8q0ho1_500.gif"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;h2&gt;⬆ This great GIF button is now on iOS &lt;/h2&gt;&lt;p&gt;This button turns your feelings into GIFs, then inserts those GIFs into your posts. &lt;a href="http://staff.tumblr.com/post/120720833005/since-gifs-have-replaced-written-language-were"&gt;Web&lt;/a&gt; and &lt;a href="http://staff.tumblr.com/post/135263390205/a-treat-for-android-users-now-you-can-add-gifs-to"&gt;Android&lt;/a&gt; users have had it for a little while, and now the triumvirate is complete. &lt;/p&gt;&lt;p&gt;First, get the &lt;a href="https://itunes.apple.com/us/app/tumblr/id305343404?mt=8"&gt;latest version of the app&lt;/a&gt;. Next, open up a new post (or reblog!) and tap the GIF button. Search for something you want to express. Something like “potato.†Pick one, and into your post it goes:&lt;/p&gt;&lt;figure data-orig-width="500" data-orig-height="367" data-orig-src="http://38.media.tumblr.com/801919ec41dfc2f1c5ec1b5d62482ba4/tumblr_inline_o0yfc3XE0y1qzpzhj_500.gif" data-tumblr-attribution="addyisabutler:Hr9auQKKX-zyrYFX_K4zIQ:ZClLCj1wTXFo4" class="tmblr-full"&gt;&lt;img src="http://38.media.tumblr.com/801919ec41dfc2f1c5ec1b5d62482ba4/tumblr_inline_o0zac6myJV1qzpzhj_500.gif" alt="image" data-orig-width="500" data-orig-height="367" data-orig-src="http://38.media.tumblr.com/801919ec41dfc2f1c5ec1b5d62482ba4/tumblr_inline_o0yfc3XE0y1qzpzhj_500.gif"/&gt;&lt;/figure&gt;&lt;p&gt;What a marvelous potato! It communicates a passion that words cannot. Very nice. &lt;i&gt;Very nice indeed&lt;/i&gt;. &lt;/p&gt;</description><link>http://staff.tumblr.com/post/137292522640</link><guid>http://staff.tumblr.com/post/137292522640</guid><pubDate>Thu, 14 Jan 2016 13:00:03 -0500</pubDate><category>features</category></item><item><title>jellygummies:
- Iridescent goo! (and the guy doesn’t even...</title><description>&lt;img src="http://45.media.tumblr.com/5c93c21e43e0e672a5ae97d7e93d34e7/tumblr_n3je4jy7zk1syjt2wo1_400.gif"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;&lt;a class="tumblr_blog" href="http://jellygummies.tumblr.com/post/81738200024"&gt;jellygummies&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;
- &lt;p&gt;Iridescent goo! (and the guy doesn’t even flinch) &lt;/p&gt;
- &lt;/blockquote&gt;</description><link>http://staff.tumblr.com/post/137259011190</link><guid>http://staff.tumblr.com/post/137259011190</guid><pubDate>Wed, 13 Jan 2016 22:15:43 -0500</pubDate><category>slime week</category><category>sorry</category><category>we hate this too</category><category>in a real appreciative way</category></item><item><title>Heavens to Betsy, it’s…</title><description>&lt;p&gt;&lt;a href="http://thefandometrics.tumblr.com/post/137250140754/heavens-to-betsy-its" class="tumblr_blog"&gt;thefandometrics&lt;/a&gt;:&lt;/p&gt;
-
- &lt;blockquote&gt;&lt;figure data-orig-width="500" data-orig-height="100" class="tmblr-full"&gt;&lt;img src="http://41.media.tumblr.com/b528045dbfddacd8dcb1789ae1aabad8/tumblr_inline_o0wy2ln5Md1qz7tc0_540.png" alt="image" data-orig-width="500" data-orig-height="100"/&gt;&lt;/figure&gt;&lt;h2&gt;&lt;a href="http://thefandometrics.tumblr.com/post/137118390340/tv-shows-week-ending-january-11th-2016-steven"&gt;Television&lt;/a&gt;: This section adjusted to fit your screen.&lt;/h2&gt;&lt;blockquote&gt;&lt;p&gt;⬆ &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Teen+Wolf"&gt;Teen Wolf&lt;/a&gt;&lt;/i&gt;&lt;/b&gt; makes a hair-raising leap to No. 2.&lt;br/&gt;☆ &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/The%20Golden%20Globes"&gt;The Golden Globes&lt;/a&gt;&lt;/i&gt;&lt;/b&gt; debuted at No. 3. Shoulda been an award for &lt;a href="http://mtv.tumblr.com/post/137063593090/leo"&gt;best grimace&lt;/a&gt;.&lt;br/&gt;☆ Some elves cannot be shelved. &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/The%20Shannara%20Chronicles"&gt;The Shannara Chronicles&lt;/a&gt;&lt;/i&gt;&lt;/b&gt; debuted at No. 16.&lt;/p&gt;&lt;/blockquote&gt;&lt;figure data-orig-width="500" data-orig-height="281" data-tumblr-attribution="darkvoidpack:I6_HYH3Z998B28zTSV1YSQ:ZnIIfj1slKySo" class="tmblr-full"&gt;&lt;img src="http://38.media.tumblr.com/05b727c83aace22632b2d8474b2d112b/tumblr_ntlpl06Z3f1uesvvmo1_500.gif" alt="image" data-orig-width="500" data-orig-height="281"/&gt;&lt;/figure&gt;&lt;h2&gt;&lt;a href="http://thefandometrics.tumblr.com/post/137117810802/movies-week-ending-january-11th-2016-star-wars"&gt;Movies&lt;/a&gt;: Don’t forget to put on your 3D glasses for the next two sentences. &lt;/h2&gt;&lt;blockquote&gt;&lt;p&gt;⬆ Was &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Mad%20Max"&gt;Mad Max&lt;/a&gt;&lt;/i&gt;&lt;/b&gt; snubbed at the awards? Your passionate cries lifted it to No. 10.&lt;br/&gt;☆ &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Ghostbusters"&gt;Ghostbusters&lt;/a&gt;&lt;/i&gt;&lt;/b&gt;, a revamp of the breathtaking documentary &lt;i&gt;Ghostbusters&lt;/i&gt;, returns at No. 14.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;&lt;a href="http://thefandometrics.tumblr.com/post/137117244608/musical-acts-week-ending-january-11th-2016-5"&gt;Music&lt;/a&gt;: Musicians without music.&lt;/h2&gt;&lt;blockquote&gt;&lt;p&gt;⬆ &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Beyonce"&gt;Beyonce&lt;/a&gt;&lt;/b&gt; moved up to No. 8 without making a peep on &lt;i&gt;Lip Sync Battle&lt;/i&gt;.&lt;br/&gt;⬆ &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Lady%20Gaga"&gt;Lady Gaga&lt;/a&gt;&lt;/b&gt; won best actress and the equally impressive rank of No. 9.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;&lt;a href="http://thefandometrics.tumblr.com/post/137116652699/celebrities-week-ending-january-11th-2016-adam"&gt;Celebrities&lt;/a&gt;: Please don’t let a rich person win the Powerball.&lt;/h2&gt;&lt;blockquote&gt;&lt;p&gt;☆ &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Leonardo%20DiCaprio"&gt;Leonardo DiCaprio&lt;/a&gt;&lt;/b&gt; battled a bear, won a Golden Globe, landed at No. 17. What a night.&lt;br/&gt;☆ Teen Queen &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Amandla%20Stenberg"&gt;Amandla Stenberg&lt;/a&gt;&lt;/b&gt; debuted at No 18 after a &lt;a href="http://tmblr.co/mJ7SklFRPVSBBt8ifjeqy2w"&gt;@teenvogue&lt;/a&gt; Snapchat takeover.&lt;br/&gt;☆ OTP alert. &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Rami%20Malek"&gt;Rami Malek&lt;/a&gt;&lt;/b&gt; cabooses our list at No. 20 after Christian Slater sang his praises.&lt;/p&gt;&lt;/blockquote&gt;&lt;figure class="tmblr-full" data-orig-height="250" data-orig-width="500" data-tumblr-attribution="tvwatercooler:lbxG1rwZpwLHmhy8rIunCQ:Z7loFw1tgtiVe"&gt;&lt;img src="http://38.media.tumblr.com/5f5e8438f58442fb65cee706a1631608/tumblr_nu9i5x036O1r9x12go1_500.gif" data-orig-height="250" data-orig-width="500"/&gt;&lt;/figure&gt;&lt;h2&gt;&lt;a href="http://thefandometrics.tumblr.com/post/137116069969/video-games-week-ending-january-11th-2016"&gt;Games&lt;/a&gt;: Don’t Wake Daddy.&lt;/h2&gt;&lt;blockquote&gt;&lt;p&gt;⬆ LOL, &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/League%20of%20Legends"&gt;League of Legends&lt;/a&gt;&lt;/i&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt; moved up to No. 7.&lt;br/&gt;⬆ Neither Hell Nohr high water could keep &lt;b&gt;&lt;i&gt;&lt;a href="https://www.tumblr.com/search/Fire%20Emblem%20Fates"&gt;Fire Emblem Fates&lt;/a&gt; &lt;/i&gt;&lt;/b&gt;(No. 19) off our list.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;&lt;a href="http://thefandometrics.tumblr.com/post/137115545596/web-stuff-week-ending-january-11th-2016"&gt;Web stuff&lt;/a&gt;: The internet is cool, good bye. &lt;/h2&gt;&lt;blockquote&gt;&lt;p&gt;⬆ &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Jacksepticeye"&gt;Jacksepticeye&lt;/a&gt;&lt;/b&gt; (No. 4) reached 8 million subscribers. Is that even a real number?&lt;br/&gt;⬇︎ Animator, voice actor, rapper, human male &lt;b&gt;&lt;a href="https://www.tumblr.com/search/Arin%20Hanson"&gt;Arin Hanson&lt;/a&gt;&lt;/b&gt; falls to No. 16.&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;</description><link>http://staff.tumblr.com/post/137250668505</link><guid>http://staff.tumblr.com/post/137250668505</guid><pubDate>Wed, 13 Jan 2016 19:39:47 -0500</pubDate><category>week in review</category></item><item><title>Photo</title><description>&lt;img src="http://49.media.tumblr.com/2edae122171f1a99abd1ce4dc40fe2d1/tumblr_o0aokm7F9s1v1xodyo1_500.gif"/&gt;&lt;br/&gt;&lt;br/&gt;</description><link>http://staff.tumblr.com/post/137191044499</link><guid>http://staff.tumblr.com/post/137191044499</guid><pubDate>Tue, 12 Jan 2016 21:00:05 -0500</pubDate><category>welcome to the slime zone</category><category>slime week</category></item><item><title>dollychops:
-
- ‘Time may change me’
-
-
- Thank you, David Bowie, for...</title><description>&lt;img src="http://36.media.tumblr.com/6d3af2caaf3a1e444d8f22489e54fcf7/tumblr_nhuzifiESR1qaetdco1_500.png"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;&lt;a class="tumblr_blog" href="http://dollychops.tumblr.com/post/107623338570"&gt;dollychops&lt;/a&gt;:&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;p&gt;‘Time may change me’&lt;/p&gt;
- &lt;/blockquote&gt;
-
- &lt;p&gt;Thank you, David Bowie, for everything you left on this planet.&lt;/p&gt;</description><link>http://staff.tumblr.com/post/137108708620</link><guid>http://staff.tumblr.com/post/137108708620</guid><pubDate>Mon, 11 Jan 2016 16:08:34 -0500</pubDate><category>âš¡ï¸</category></item><item><title>Photo</title><description>&lt;img src="http://41.media.tumblr.com/967aba4d63cfa34fb00ed3edbc2ef27e/tumblr_nxky79R9Xz1sflxizo1_500.png"/&gt;&lt;br/&gt;&lt;br/&gt;</description><link>http://staff.tumblr.com/post/136905518945</link><guid>http://staff.tumblr.com/post/136905518945</guid><pubDate>Fri, 08 Jan 2016 17:44:31 -0500</pubDate><category>have a good weekend tumblr</category></item><item><title>New year, new trends, new youBlowing up now: Graphic novelist...</title><description>&lt;img src="http://41.media.tumblr.com/9c69a850eece63c29d913b6e83dd49a7/tumblr_o0ne9sk7yG1qz8q0ho1_500.png"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;h2&gt;New year, new trends, new you&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Blowing up now: Graphic novelist &lt;b&gt;&lt;a href="http://tumblr.com/search/amandla%20stenberg"&gt;Amandla Stenberg’s&lt;/a&gt;&lt;/b&gt; (alias: Rue) &lt;a href="http://amandla.tumblr.com/post/136866720678/so-i-took-over-the-teen-vogue-snapchat-today"&gt;inspiring message&lt;/a&gt;. &lt;/li&gt;&lt;li&gt;It took Sherlock Holmes to figure out the &lt;a href="http://tumblr.com/search/sherlock"&gt;&lt;b&gt;&lt;i&gt;Sherlock&lt;/i&gt;&lt;/b&gt;&lt;/a&gt; special.&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/teen%20wolf"&gt;&lt;b&gt;&lt;i&gt;Teen Wolf&lt;/i&gt;&lt;/b&gt;&lt;/a&gt; and friends chased Taylor Swift &lt;a href="http://tumblr.com/search/out%20of%20the%20woods"&gt;&lt;b&gt;&lt;i&gt;Out of the Woods&lt;/i&gt;&lt;/b&gt;&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/oregon"&gt;&lt;b&gt;Oregon&lt;/b&gt;&lt;/a&gt; is hosting everyone’s drunk uncles.&lt;/li&gt;&lt;li&gt;POTUS announced new &lt;a href="http://tumblr.com/search/gun%20control"&gt;&lt;b&gt;gun control&lt;/b&gt;&lt;/a&gt; policies.&lt;/li&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/ces%202016"&gt;&lt;b&gt;CES 2016&lt;/b&gt;&lt;/a&gt;: for people who don’t get invited to &lt;a href="http://tumblr.com/search/pca%202016"&gt;&lt;b&gt;PCA 2016&lt;/b&gt;&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;figure data-orig-width="500" data-orig-height="333" data-tumblr-attribution="qualcomm:w-2kl3XPK9VC_h4I30lZQQ:ZAN2in1-NvniN" class="tmblr-full"&gt;&lt;img src="http://33.media.tumblr.com/86405300020cd161baa702cf983c6189/tumblr_o0juioRm5j1ta1bw6o1_500.gif" alt="image" data-orig-width="500" data-orig-height="333"/&gt;&lt;/figure&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://tumblr.com/search/pvris"&gt;&lt;b&gt;PVRIS&lt;/b&gt;&lt;/a&gt;: untrilled as in “Morris.â€&lt;/li&gt;&lt;li&gt;And it’s definitely &lt;a href="http://tumblr.com/search/jailey"&gt;&lt;b&gt;Jailey&lt;/b&gt;&lt;/a&gt;. Bieldwin slays orcs in Enedwaith.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Once-around-the-sun Tumblrs&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Daily Overview &lt;/b&gt;(&lt;a href="http://tmblr.co/mfB7_qm9Di9WXyvW2jkKcDA"&gt;@dailyoverview&lt;/a&gt;): Cool stuff from above ground.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Earth Blingg &lt;/b&gt;(&lt;a href="http://tmblr.co/mMwXAkW_6d4ddLGw7VhfWaQ"&gt;@earthblingg&lt;/a&gt;): Cool stuff from underground&lt;/li&gt;&lt;/ul&gt;</description><link>http://staff.tumblr.com/post/136898076525</link><guid>http://staff.tumblr.com/post/136898076525</guid><pubDate>Fri, 08 Jan 2016 15:36:23 -0500</pubDate><category>trends</category></item></channel></rss>
diff --git a/mobile/android/tests/background/junit4/resources/feed_rss_wikipedia.xml b/mobile/android/tests/background/junit4/resources/feed_rss_wikipedia.xml
deleted file mode 100644
index a20082231..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_rss_wikipedia.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
- https://en.wikipedia.org/wiki/RSS#Example
--->
-<rss version="2.0">
- <channel>
- <title>RSS Title</title>
- <description>This is an example of an RSS feed</description>
- <link>http://www.example.com/main.html</link>
- <lastBuildDate>Mon, 06 Sep 2010 00:01:00 +0000 </lastBuildDate>
- <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
- <ttl>1800</ttl>
- <item>
- <title>Example entry</title>
- <description>Here is some text containing an interesting description.</description>
- <link>http://www.example.com/blog/post/1</link>
- <guid isPermaLink="true">7bd204c6-1655-4c27-aeee-53f933c5395f</guid>
- <pubDate>Sun, 06 Sep 2009 16:20:00 +0000</pubDate>
- </item>
- </channel>
-</rss>
diff --git a/mobile/android/tests/background/junit4/resources/feed_rss_wordpress.xml b/mobile/android/tests/background/junit4/resources/feed_rss_wordpress.xml
deleted file mode 100644
index 7981eb173..000000000
--- a/mobile/android/tests/background/junit4/resources/feed_rss_wordpress.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
- xmlns:content="http://purl.org/rss/1.0/modules/content/"
- xmlns:wfw="http://wellformedweb.org/CommentAPI/"
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:atom="http://www.w3.org/2005/Atom"
- xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
- xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
- xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
- >
-
- <channel>
- <title>justasimpletest2016</title>
- <atom:link href="https://justasimpletest2016.wordpress.com/feed/" rel="self" type="application/rss+xml" />
- <link>https://justasimpletest2016.wordpress.com</link>
- <description></description>
- <lastBuildDate>Fri, 26 Feb 2016 22:08:00 +0000</lastBuildDate>
- <language>en</language>
- <sy:updatePeriod>hourly</sy:updatePeriod>
- <sy:updateFrequency>1</sy:updateFrequency>
- <generator>http://wordpress.com/</generator>
- <cloud domain='justasimpletest2016.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
- <image>
- <url>https://s2.wp.com/i/buttonw-com.png</url>
- <title>justasimpletest2016</title>
- <link>https://justasimpletest2016.wordpress.com</link>
- </image>
- <atom:link rel="search" type="application/opensearchdescription+xml" href="https://justasimpletest2016.wordpress.com/osd.xml" title="justasimpletest2016" />
- <atom:link rel='hub' href='https://justasimpletest2016.wordpress.com/?pushpress=hub'/>
- <item>
- <title>Hello World!</title>
- <link>https://justasimpletest2016.wordpress.com/2016/02/26/hello-world/</link>
- <comments>https://justasimpletest2016.wordpress.com/2016/02/26/hello-world/#respond</comments>
- <pubDate>Fri, 26 Feb 2016 22:07:46 +0000</pubDate>
- <dc:creator><![CDATA[justasimpletest2016]]></dc:creator>
- <category><![CDATA[Uncategorized]]></category>
-
- <guid isPermaLink="false">http://justasimpletest2016.wordpress.com/?p=6</guid>
- <description><![CDATA[What&#8217;s up?<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=justasimpletest2016.wordpress.com&#038;blog=107552275&#038;post=6&#038;subd=justasimpletest2016&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
- <content:encoded><![CDATA[<p>What&#8217;s up?</p><br /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/justasimpletest2016.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/justasimpletest2016.wordpress.com/6/" /></a> <img alt="" border="0" src="https://pixel.wp.com/b.gif?host=justasimpletest2016.wordpress.com&#038;blog=107552275&#038;post=6&#038;subd=justasimpletest2016&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
- <wfw:commentRss>https://justasimpletest2016.wordpress.com/2016/02/26/hello-world/feed/</wfw:commentRss>
- <slash:comments>0</slash:comments>
-
- <media:content url="https://2.gravatar.com/avatar/ba82024e6f43884f4ae0e379273b0743?s=96&#38;d=identicon&#38;r=G" medium="image">
- <media:title type="html">justasimpletest2016</media:title>
- </media:content>
- </item>
- <item>
- <title>The second post</title>
- <link>https://justasimpletest2016.wordpress.com/2016/02/26/the-second-post/</link>
- <comments>https://justasimpletest2016.wordpress.com/2016/02/26/the-second-post/#respond</comments>
- <pubDate>Fri, 26 Feb 2016 00:23:04 +0000</pubDate>
- <dc:creator><![CDATA[justasimpletest2016]]></dc:creator>
- <category><![CDATA[Uncategorized]]></category>
-
- <guid isPermaLink="false">http://justasimpletest2016.wordpress.com/2016/02/26/the-second-post/</guid>
- <description><![CDATA[Hello.<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=justasimpletest2016.wordpress.com&#038;blog=107552275&#038;post=4&#038;subd=justasimpletest2016&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
- <content:encoded><![CDATA[<p>Hello.</p><br /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/justasimpletest2016.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/justasimpletest2016.wordpress.com/4/" /></a> <img alt="" border="0" src="https://pixel.wp.com/b.gif?host=justasimpletest2016.wordpress.com&#038;blog=107552275&#038;post=4&#038;subd=justasimpletest2016&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
- <wfw:commentRss>https://justasimpletest2016.wordpress.com/2016/02/26/the-second-post/feed/</wfw:commentRss>
- <slash:comments>0</slash:comments>
-
- <media:content url="https://2.gravatar.com/avatar/ba82024e6f43884f4ae0e379273b0743?s=96&#38;d=identicon&#38;r=G" medium="image">
- <media:title type="html">justasimpletest2016</media:title>
- </media:content>
- </item>
- <item>
- <title>This is just a test</title>
- <link>https://justasimpletest2016.wordpress.com/2016/02/26/this-is-just-a-test/</link>
- <comments>https://justasimpletest2016.wordpress.com/2016/02/26/this-is-just-a-test/#respond</comments>
- <pubDate>Fri, 26 Feb 2016 00:22:58 +0000</pubDate>
- <dc:creator><![CDATA[justasimpletest2016]]></dc:creator>
- <category><![CDATA[Uncategorized]]></category>
-
- <guid isPermaLink="false">http://justasimpletest2016.wordpress.com/?p=2</guid>
- <description><![CDATA[Hello World. First blog post from WordPress.<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=justasimpletest2016.wordpress.com&#038;blog=107552275&#038;post=2&#038;subd=justasimpletest2016&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
- <content:encoded><![CDATA[<p>Hello World. First blog post from WordPress.</p><br /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/justasimpletest2016.wordpress.com/2/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/justasimpletest2016.wordpress.com/2/" /></a> <img alt="" border="0" src="https://pixel.wp.com/b.gif?host=justasimpletest2016.wordpress.com&#038;blog=107552275&#038;post=2&#038;subd=justasimpletest2016&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
- <wfw:commentRss>https://justasimpletest2016.wordpress.com/2016/02/26/this-is-just-a-test/feed/</wfw:commentRss>
- <slash:comments>0</slash:comments>
-
- <media:content url="https://2.gravatar.com/avatar/ba82024e6f43884f4ae0e379273b0743?s=96&#38;d=identicon&#38;r=G" medium="image">
- <media:title type="html">justasimpletest2016</media:title>
- </media:content>
- </item>
- </channel>
-</rss>
diff --git a/mobile/android/tests/background/junit4/resources/robolectric.properties b/mobile/android/tests/background/junit4/resources/robolectric.properties
deleted file mode 100644
index a809da730..000000000
--- a/mobile/android/tests/background/junit4/resources/robolectric.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-sdk=21
-constants=org.mozilla.gecko.BuildConfig
-packageName=org.mozilla.gecko
diff --git a/mobile/android/tests/background/junit4/src/com/keepsafe/switchboard/TestSwitchboard.java b/mobile/android/tests/background/junit4/src/com/keepsafe/switchboard/TestSwitchboard.java
deleted file mode 100644
index 5726f12db..000000000
--- a/mobile/android/tests/background/junit4/src/com/keepsafe/switchboard/TestSwitchboard.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package com.keepsafe.switchboard;
-
-import android.content.Context;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.Experiments;
-import org.mozilla.gecko.util.IOUtils;
-import org.robolectric.RuntimeEnvironment;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.List;
-import java.util.UUID;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class TestSwitchboard {
-
- /**
- * Create a JSON response from a JSON file.
- */
- private String readFromFile(String fileName) throws IOException {
- URL url = getClass().getResource("/" + fileName);
- if (url == null) {
- throw new FileNotFoundException(fileName);
- }
-
- InputStream inputStream = null;
- ByteArrayOutputStream outputStream = null;
-
- try {
- inputStream = new BufferedInputStream(new FileInputStream(url.getPath()));
- InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
- BufferedReader bufferReader = new BufferedReader(inputStreamReader, 8192);
- String line;
- StringBuilder resultContent = new StringBuilder();
- while ((line = bufferReader.readLine()) != null) {
- resultContent.append(line);
- }
- bufferReader.close();
-
- return resultContent.toString();
-
- } finally {
- IOUtils.safeStreamClose(inputStream);
- }
- }
-
- @Before
- public void setUp() throws IOException {
- final Context c = RuntimeEnvironment.application;
- Preferences.setDynamicConfigJson(c, readFromFile("experiments.json"));
- }
-
- @Test
- public void testDeviceUuidFactory() {
- final Context c = RuntimeEnvironment.application;
- final DeviceUuidFactory df = new DeviceUuidFactory(c);
- final UUID uuid = df.getDeviceUuid();
- assertNotNull("UUID is not null", uuid);
- assertEquals("DeviceUuidFactory always returns the same UUID", df.getDeviceUuid(), uuid);
- }
-
- @Test
- public void testIsInExperiment() {
- final Context c = RuntimeEnvironment.application;
- assertTrue("active-experiment is active", SwitchBoard.isInExperiment(c, "active-experiment"));
- assertFalse("inactive-experiment is inactive", SwitchBoard.isInExperiment(c, "inactive-experiment"));
- }
-
- @Test
- public void testExperimentValues() throws JSONException {
- final Context c = RuntimeEnvironment.application;
- assertTrue("active-experiment has values", SwitchBoard.hasExperimentValues(c, "active-experiment"));
- assertFalse("inactive-experiment doesn't have values", SwitchBoard.hasExperimentValues(c, "inactive-experiment"));
-
- final JSONObject values = SwitchBoard.getExperimentValuesFromJson(c, "active-experiment");
- assertNotNull("active-experiment values are not null", values);
- assertTrue("\"foo\" extra value is true", values.getBoolean("foo"));
- }
-
- @Test
- public void testGetActiveExperiments() {
- final Context c = RuntimeEnvironment.application;
- final List<String> experiments = SwitchBoard.getActiveExperiments(c);
- assertNotNull("List of active experiments is not null", experiments);
-
- assertTrue("List of active experiments contains active-experiment", experiments.contains("active-experiment"));
- assertFalse("List of active experiments does not contain inactive-experiment", experiments.contains("inactive-experiment"));
- }
-
- @Test
- public void testOverride() {
- final Context c = RuntimeEnvironment.application;
-
- Experiments.setOverride(c, "active-experiment", false);
- assertFalse("active-experiment is not active because of override", SwitchBoard.isInExperiment(c, "active-experiment"));
- assertFalse("List of active experiments does not contain active-experiment", SwitchBoard.getActiveExperiments(c).contains("active-experiment"));
-
- Experiments.clearOverride(c, "active-experiment");
- assertTrue("active-experiment is active after override is cleared", SwitchBoard.isInExperiment(c, "active-experiment"));
- assertTrue("List of active experiments contains active-experiment again", SwitchBoard.getActiveExperiments(c).contains("active-experiment"));
-
- Experiments.setOverride(c, "inactive-experiment", true);
- assertTrue("inactive-experiment is active because of override", SwitchBoard.isInExperiment(c, "inactive-experiment"));
- assertTrue("List of active experiments contains inactive-experiment", SwitchBoard.getActiveExperiments(c).contains("inactive-experiment"));
-
- Experiments.clearOverride(c, "inactive-experiment");
- assertFalse("inactive-experiment is inactive after override is cleared", SwitchBoard.isInExperiment(c, "inactive-experiment"));
- assertFalse("List of active experiments does not contain inactive-experiment again", SwitchBoard.getActiveExperiments(c).contains("inactive-experiment"));
- }
-
- @Test
- public void testMatching() {
- final Context c = RuntimeEnvironment.application;
- assertTrue("is-experiment is matching", SwitchBoard.isInExperiment(c, "is-matching"));
- assertFalse("is-not-matching is not matching", SwitchBoard.isInExperiment(c, "is-not-matching"));
- }
-
- @Test
- public void testNotExisting() {
- final Context c = RuntimeEnvironment.application;
- assertFalse("F0O does not exists", SwitchBoard.isInExperiment(c, "F0O"));
- assertFalse("BaAaz does not exists", SwitchBoard.hasExperimentValues(c, "BaAaz"));
- }
-
-
-
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestBackoff.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestBackoff.java
deleted file mode 100644
index 8e8152e36..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestBackoff.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.ProtocolVersion;
-import ch.boye.httpclientandroidlib.message.BasicHttpResponse;
-import ch.boye.httpclientandroidlib.message.BasicStatusLine;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.MockGlobalSessionCallback;
-import org.mozilla.gecko.background.testhelpers.MockGlobalSession;
-import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestBackoff {
- private final String TEST_USERNAME = "johndoe";
- private final String TEST_PASSWORD = "password";
- private final String TEST_SYNC_KEY = "abcdeabcdeabcdeabcdeabcdea";
- private final long TEST_BACKOFF_IN_SECONDS = 1201;
-
- /**
- * Test that interpretHTTPFailure calls requestBackoff if
- * X-Weave-Backoff is present.
- */
- @Test
- public void testBackoffCalledIfBackoffHeaderPresent() {
- try {
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
- SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
- final GlobalSession session = new MockGlobalSession(config, callback);
-
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
- response.addHeader("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS)); // Backoff given in seconds.
-
- session.interpretHTTPFailure(response); // This is synchronous...
-
- assertEquals(false, callback.calledSuccess); // ... so we can test immediately.
- assertEquals(false, callback.calledError);
- assertEquals(false, callback.calledAborted);
- assertEquals(true, callback.calledRequestBackoff);
- assertEquals(TEST_BACKOFF_IN_SECONDS * 1000, callback.weaveBackoff); // Backoff returned in milliseconds.
- } catch (Exception e) {
- e.printStackTrace();
- fail("Got exception.");
- }
- }
-
- /**
- * Test that interpretHTTPFailure does not call requestBackoff if
- * X-Weave-Backoff is not present.
- */
- @Test
- public void testBackoffNotCalledIfBackoffHeaderNotPresent() {
- try {
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
- SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
- final GlobalSession session = new MockGlobalSession(config, callback);
-
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
-
- session.interpretHTTPFailure(response); // This is synchronous...
-
- assertEquals(false, callback.calledSuccess); // ... so we can test immediately.
- assertEquals(false, callback.calledError);
- assertEquals(false, callback.calledAborted);
- assertEquals(false, callback.calledRequestBackoff);
- } catch (Exception e) {
- e.printStackTrace();
- fail("Got exception.");
- }
- }
-
- /**
- * Test that interpretHTTPFailure calls requestBackoff with the
- * largest specified value if X-Weave-Backoff and Retry-After are
- * present.
- */
- @Test
- public void testBackoffCalledIfMultipleBackoffHeadersPresent() {
- try {
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
- SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
- final GlobalSession session = new MockGlobalSession(config, callback);
-
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
- response.addHeader("Retry-After", Long.toString(TEST_BACKOFF_IN_SECONDS)); // Backoff given in seconds.
- response.addHeader("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS + 1)); // If we now add a second header, the larger should be returned.
-
- session.interpretHTTPFailure(response); // This is synchronous...
-
- assertEquals(false, callback.calledSuccess); // ... so we can test immediately.
- assertEquals(false, callback.calledError);
- assertEquals(false, callback.calledAborted);
- assertEquals(true, callback.calledRequestBackoff);
- assertEquals((TEST_BACKOFF_IN_SECONDS + 1) * 1000, callback.weaveBackoff); // Backoff returned in milliseconds.
- } catch (Exception e) {
- e.printStackTrace();
- fail("Got exception.");
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestBrowserIDAuthHeaderProvider.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestBrowserIDAuthHeaderProvider.java
deleted file mode 100644
index 6a14c6d29..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestBrowserIDAuthHeaderProvider.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import ch.boye.httpclientandroidlib.Header;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.net.BrowserIDAuthHeaderProvider;
-
-import static org.junit.Assert.assertEquals;
-
-@RunWith(TestRunner.class)
-public class TestBrowserIDAuthHeaderProvider {
- @Test
- public void testHeader() {
- Header header = new BrowserIDAuthHeaderProvider("assertion").getAuthHeader(null, null, null);
-
- assertEquals("authorization", header.getName().toLowerCase());
- assertEquals("BrowserID assertion", header.getValue());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestClientsEngineStage.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestClientsEngineStage.java
deleted file mode 100644
index 920cafb35..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestClientsEngineStage.java
+++ /dev/null
@@ -1,806 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import ch.boye.httpclientandroidlib.HttpStatus;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.junit.After;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockGlobalSessionCallback;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.android.sync.test.helpers.MockSyncClientsEngineStage;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.testhelpers.CommandHelpers;
-import org.mozilla.gecko.background.testhelpers.MockClientsDataDelegate;
-import org.mozilla.gecko.background.testhelpers.MockClientsDatabaseAccessor;
-import org.mozilla.gecko.background.testhelpers.MockGlobalSession;
-import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.CollectionKeys;
-import org.mozilla.gecko.sync.CommandProcessor.Command;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.mozilla.gecko.sync.repositories.NullCursorException;
-import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.math.BigDecimal;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-/**
- * Some tests in this class run client/server multi-threaded code but JUnit assertions triggered
- * from background threads do not fail the test. If you see unexplained connection-related test failures,
- * an assertion on the server may have been thrown. Unfortunately, it is non-trivial to get the background
- * threads to transfer failures back to the test thread so we leave the tests in this state for now.
- *
- * One reason the server might throw an assertion is if you have not installed the crypto policies. See
- * https://wiki.mozilla.org/Mobile/Fennec/Android/Testing#JUnit4_tests for more information.
- */
-@RunWith(TestRunner.class)
-public class TestClientsEngineStage extends MockSyncClientsEngineStage {
- public final static String LOG_TAG = "TestClientsEngSta";
-
- public TestClientsEngineStage() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException, URISyntaxException {
- super();
- session = initializeSession();
- }
-
- // Static so we can set it during the constructor. This is so evil.
- private static MockGlobalSessionCallback callback;
- private static GlobalSession initializeSession() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException, URISyntaxException {
- callback = new MockGlobalSessionCallback();
- SyncConfiguration config = new SyncConfiguration(USERNAME, new BasicAuthHeaderProvider(USERNAME, PASSWORD), new MockSharedPreferences());
- config.syncKeyBundle = new KeyBundle(USERNAME, SYNC_KEY);
- GlobalSession session = new MockClientsGlobalSession(config, callback);
- session.config.setClusterURL(new URI(TEST_SERVER));
- session.config.setCollectionKeys(CollectionKeys.generateCollectionKeys());
- return session;
- }
-
- private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private static final String TEST_SERVER = "http://localhost:" + TEST_PORT;
-
- private static final String USERNAME = "john";
- private static final String PASSWORD = "password";
- private static final String SYNC_KEY = "abcdeabcdeabcdeabcdeabcdea";
-
- private HTTPServerTestHelper data = new HTTPServerTestHelper();
- private int numRecordsFromGetRequest = 0;
-
- private ArrayList<ClientRecord> expectedClients = new ArrayList<ClientRecord>();
- private ArrayList<ClientRecord> downloadedClients = new ArrayList<ClientRecord>();
-
- // For test purposes.
- private ClientRecord lastComputedLocalClientRecord;
- private ClientRecord uploadedRecord;
- private String uploadBodyTimestamp;
- private long uploadHeaderTimestamp;
- private MockServer currentUploadMockServer;
- private MockServer currentDownloadMockServer;
-
- private boolean stubUpload = false;
-
- protected static WaitHelper testWaiter() {
- return WaitHelper.getTestWaiter();
- }
-
- @Override
- protected ClientRecord newLocalClientRecord(ClientsDataDelegate delegate) {
- lastComputedLocalClientRecord = super.newLocalClientRecord(delegate);
- return lastComputedLocalClientRecord;
- }
-
- @After
- public void teardown() {
- stubUpload = false;
- getMockDataAccessor().resetVars();
- }
-
- @Override
- public synchronized ClientsDatabaseAccessor getClientsDatabaseAccessor() {
- if (db == null) {
- db = new MockClientsDatabaseAccessor();
- }
- return db;
- }
-
- // For test use.
- private MockClientsDatabaseAccessor getMockDataAccessor() {
- return (MockClientsDatabaseAccessor) getClientsDatabaseAccessor();
- }
-
- private synchronized boolean mockDataAccessorIsClosed() {
- if (db == null) {
- return true;
- }
- return ((MockClientsDatabaseAccessor) db).closed;
- }
-
- @Override
- protected ClientDownloadDelegate makeClientDownloadDelegate() {
- return clientDownloadDelegate;
- }
-
- @Override
- protected void downloadClientRecords() {
- BaseResource.rewriteLocalhost = false;
- data.startHTTPServer(currentDownloadMockServer);
- super.downloadClientRecords();
- }
-
- @Override
- protected void uploadClientRecord(CryptoRecord record) {
- BaseResource.rewriteLocalhost = false;
- if (stubUpload) {
- session.advance();
- return;
- }
- data.startHTTPServer(currentUploadMockServer);
- super.uploadClientRecord(record);
- }
-
- @Override
- protected void uploadClientRecords(JSONArray records) {
- BaseResource.rewriteLocalhost = false;
- if (stubUpload) {
- return;
- }
- data.startHTTPServer(currentUploadMockServer);
- super.uploadClientRecords(records);
- }
-
- public static class MockClientsGlobalSession extends MockGlobalSession {
- private ClientsDataDelegate clientsDataDelegate = new MockClientsDataDelegate();
-
- public MockClientsGlobalSession(SyncConfiguration config,
- GlobalSessionCallback callback)
- throws SyncConfigurationException,
- IllegalArgumentException,
- IOException,
- NonObjectJSONException {
- super(config, callback);
- }
-
- @Override
- public ClientsDataDelegate getClientsDelegate() {
- return clientsDataDelegate;
- }
- }
-
- public class TestSuccessClientDownloadDelegate extends TestClientDownloadDelegate {
- public TestSuccessClientDownloadDelegate(HTTPServerTestHelper data) {
- super(data);
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- super.handleRequestFailure(response);
- assertTrue(getMockDataAccessor().closed);
- fail("Should not error.");
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- super.handleRequestError(ex);
- assertTrue(getMockDataAccessor().closed);
- fail("Should not fail.");
- }
-
- @Override
- public void handleWBO(CryptoRecord record) {
- ClientRecord r;
- try {
- r = (ClientRecord) factory.createRecord(record.decrypt());
- downloadedClients.add(r);
- numRecordsFromGetRequest++;
- } catch (Exception e) {
- fail("handleWBO failed.");
- }
- }
- }
-
- public class TestHandleWBODownloadDelegate extends TestClientDownloadDelegate {
- public TestHandleWBODownloadDelegate(HTTPServerTestHelper data) {
- super(data);
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- super.handleRequestFailure(response);
- assertTrue(getMockDataAccessor().closed);
- fail("Should not error.");
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- super.handleRequestError(ex);
- assertTrue(getMockDataAccessor().closed);
- ex.printStackTrace();
- fail("Should not fail.");
- }
- }
-
- public class MockSuccessClientUploadDelegate extends MockClientUploadDelegate {
- public MockSuccessClientUploadDelegate(HTTPServerTestHelper data) {
- super(data);
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse response) {
- uploadHeaderTimestamp = response.normalizedWeaveTimestamp();
- super.handleRequestSuccess(response);
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- super.handleRequestFailure(response);
- fail("Should not fail.");
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- super.handleRequestError(ex);
- ex.printStackTrace();
- fail("Should not error.");
- }
- }
-
- public class MockFailureClientUploadDelegate extends MockClientUploadDelegate {
- public MockFailureClientUploadDelegate(HTTPServerTestHelper data) {
- super(data);
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse response) {
- super.handleRequestSuccess(response);
- fail("Should not succeed.");
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- super.handleRequestError(ex);
- fail("Should not fail.");
- }
- }
-
- public class UploadMockServer extends MockServer {
- @SuppressWarnings("unchecked")
- private String postBodyForRecord(ClientRecord cr) {
- final long now = cr.lastModified;
- final BigDecimal modified = Utils.millisecondsToDecimalSeconds(now);
-
- Logger.debug(LOG_TAG, "Now is " + now + " (" + modified + ")");
- final JSONArray idArray = new JSONArray();
- idArray.add(cr.guid);
-
- final JSONObject result = new JSONObject();
- result.put("modified", modified);
- result.put("success", idArray);
- result.put("failed", new JSONObject());
-
- uploadBodyTimestamp = modified.toString();
- return result.toJSONString();
- }
-
- private String putBodyForRecord(ClientRecord cr) {
- final String modified = Utils.millisecondsToDecimalSecondsString(cr.lastModified);
- uploadBodyTimestamp = modified;
- return modified;
- }
-
- protected void handleUploadPUT(Request request, Response response) throws Exception {
- Logger.debug(LOG_TAG, "Handling PUT: " + request.getPath());
-
- // Save uploadedRecord to test against.
- CryptoRecord cryptoRecord = CryptoRecord.fromJSONRecord(request.getContent());
- cryptoRecord.keyBundle = session.keyBundleForCollection(COLLECTION_NAME);
- uploadedRecord = (ClientRecord) factory.createRecord(cryptoRecord.decrypt());
-
- // Note: collection is not saved in CryptoRecord.toJSONObject() upon upload.
- // So its value is null and is set here so ClientRecord.equals() may be used.
- uploadedRecord.collection = lastComputedLocalClientRecord.collection;
-
- // Create response body containing current timestamp.
- long now = System.currentTimeMillis();
- PrintStream bodyStream = this.handleBasicHeaders(request, response, 200, "application/json", now);
- uploadedRecord.lastModified = now;
-
- bodyStream.println(putBodyForRecord(uploadedRecord));
- bodyStream.close();
- }
-
- protected void handleUploadPOST(Request request, Response response) throws Exception {
- Logger.debug(LOG_TAG, "Handling POST: " + request.getPath());
- String content = request.getContent();
- Logger.debug(LOG_TAG, "Content is " + content);
- JSONArray array = ExtendedJSONObject.parseJSONArray(content);
-
- Logger.debug(LOG_TAG, "Content is " + array);
-
- KeyBundle keyBundle = session.keyBundleForCollection(COLLECTION_NAME);
- if (array.size() != 1) {
- Logger.debug(LOG_TAG, "Expecting only one record! Fail!");
- PrintStream bodyStream = this.handleBasicHeaders(request, response, 400, "text/plain");
- bodyStream.println("Expecting only one record! Fail!");
- bodyStream.close();
- return;
- }
-
- CryptoRecord r = CryptoRecord.fromJSONRecord(new ExtendedJSONObject((JSONObject) array.get(0)));
- r.keyBundle = keyBundle;
- ClientRecord cr = (ClientRecord) factory.createRecord(r.decrypt());
- cr.collection = lastComputedLocalClientRecord.collection;
- uploadedRecord = cr;
-
- Logger.debug(LOG_TAG, "Record is " + cr);
- long now = System.currentTimeMillis();
- PrintStream bodyStream = this.handleBasicHeaders(request, response, 200, "application/json", now);
- cr.lastModified = now;
- final String responseBody = postBodyForRecord(cr);
- Logger.debug(LOG_TAG, "Response is " + responseBody);
- bodyStream.println(responseBody);
- bodyStream.close();
- }
-
- @Override
- public void handle(Request request, Response response) {
- try {
- String method = request.getMethod();
- Logger.debug(LOG_TAG, "Handling " + method);
- if (method.equalsIgnoreCase("post")) {
- handleUploadPOST(request, response);
- } else if (method.equalsIgnoreCase("put")) {
- handleUploadPUT(request, response);
- } else {
- PrintStream bodyStream = this.handleBasicHeaders(request, response, 404, "text/plain");
- bodyStream.close();
- }
- } catch (Exception e) {
- fail("Error handling uploaded client record in UploadMockServer.");
- }
- }
- }
-
- public class DownloadMockServer extends MockServer {
- @Override
- public void handle(Request request, Response response) {
- try {
- PrintStream bodyStream = this.handleBasicHeaders(request, response, 200, "application/newlines");
- for (int i = 0; i < 5; i++) {
- ClientRecord record = new ClientRecord();
- if (i != 2) { // So we test null version.
- record.version = Integer.toString(28 + i);
- }
- expectedClients.add(record);
- CryptoRecord cryptoRecord = cryptoFromClient(record);
- bodyStream.print(cryptoRecord.toJSONString() + "\n");
- }
- bodyStream.close();
- } catch (IOException e) {
- fail("Error handling downloaded client records in DownloadMockServer.");
- }
- }
- }
-
- public class DownloadLocalRecordMockServer extends MockServer {
- @SuppressWarnings("unchecked")
- @Override
- public void handle(Request request, Response response) {
- try {
- PrintStream bodyStream = this.handleBasicHeaders(request, response, 200, "application/newlines");
- ClientRecord record = new ClientRecord(session.getClientsDelegate().getAccountGUID());
-
- // Timestamp on server is 10 seconds after local timestamp
- // (would trigger 412 if upload was attempted).
- CryptoRecord cryptoRecord = cryptoFromClient(record);
- JSONObject object = cryptoRecord.toJSONObject();
- final long modified = (setRecentClientRecordTimestamp() + 10000) / 1000;
- Logger.debug(LOG_TAG, "Setting modified to " + modified);
- object.put("modified", modified);
- bodyStream.print(object.toJSONString() + "\n");
- bodyStream.close();
- } catch (IOException e) {
- fail("Error handling downloaded client records in DownloadLocalRecordMockServer.");
- }
- }
- }
-
- private CryptoRecord cryptoFromClient(ClientRecord record) {
- CryptoRecord cryptoRecord = record.getEnvelope();
- cryptoRecord.keyBundle = clientDownloadDelegate.keyBundle();
- try {
- cryptoRecord.encrypt();
- } catch (Exception e) {
- fail("Cannot encrypt client record.");
- }
- return cryptoRecord;
- }
-
- private long setRecentClientRecordTimestamp() {
- long timestamp = System.currentTimeMillis() - (CLIENTS_TTL_REFRESH - 1000);
- session.config.persistServerClientRecordTimestamp(timestamp);
- return timestamp;
- }
-
- private void performFailingUpload() {
- // performNotify() occurs in MockGlobalSessionCallback.
- testWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- clientUploadDelegate = new MockFailureClientUploadDelegate(data);
- checkAndUpload();
- }
- });
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void testShouldUploadNoCommandsToProcess() throws NullCursorException {
- // shouldUpload() returns true.
- assertEquals(0, session.config.getPersistedServerClientRecordTimestamp());
- assertFalse(shouldUploadLocalRecord);
- assertTrue(shouldUpload());
-
- // Set the timestamp to be a little earlier than refresh time,
- // so shouldUpload() returns false.
- setRecentClientRecordTimestamp();
- assertFalse(0 == session.config.getPersistedServerClientRecordTimestamp());
- assertFalse(shouldUploadLocalRecord);
- assertFalse(shouldUpload());
-
- // Now simulate observing a client record with the incorrect version.
-
- ClientRecord outdatedRecord = new ClientRecord("dontmatter12", "clients", System.currentTimeMillis(), false);
-
- outdatedRecord.version = getLocalClientVersion();
- outdatedRecord.protocols = getLocalClientProtocols();
- handleDownloadedLocalRecord(outdatedRecord);
-
- assertEquals(outdatedRecord.lastModified, session.config.getPersistedServerClientRecordTimestamp());
- assertFalse(shouldUploadLocalRecord);
- assertFalse(shouldUpload());
-
- outdatedRecord.version = outdatedRecord.version + "a1";
- handleDownloadedLocalRecord(outdatedRecord);
-
- // Now we think we need to upload because the version is outdated.
- assertTrue(shouldUploadLocalRecord);
- assertTrue(shouldUpload());
-
- shouldUploadLocalRecord = false;
- assertFalse(shouldUpload());
-
- // If the protocol list is missing or wrong, we should reupload.
- outdatedRecord.protocols = new JSONArray();
- handleDownloadedLocalRecord(outdatedRecord);
- assertTrue(shouldUpload());
-
- shouldUploadLocalRecord = false;
- assertFalse(shouldUpload());
-
- outdatedRecord.protocols.add("1.0");
- handleDownloadedLocalRecord(outdatedRecord);
- assertTrue(shouldUpload());
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void testShouldUploadProcessCommands() throws NullCursorException {
- // shouldUpload() returns false since array is size 0 and
- // it has not been long enough yet to require an upload.
- processCommands(new JSONArray());
- setRecentClientRecordTimestamp();
- assertFalse(shouldUploadLocalRecord);
- assertFalse(shouldUpload());
-
- // shouldUpload() returns true since array is size 1 even though
- // it has not been long enough yet to require an upload.
- JSONArray commands = new JSONArray();
- commands.add(new JSONObject());
- processCommands(commands);
- setRecentClientRecordTimestamp();
- assertEquals(1, commands.size());
- assertTrue(shouldUploadLocalRecord);
- assertTrue(shouldUpload());
- }
-
- @Test
- public void testWipeAndStoreShouldNotWipe() {
- assertFalse(shouldWipe);
- wipeAndStore(new ClientRecord());
- assertFalse(shouldWipe);
- assertFalse(getMockDataAccessor().clientsTableWiped);
- assertTrue(getMockDataAccessor().storedRecord);
- }
-
- @Test
- public void testWipeAndStoreShouldWipe() {
- assertFalse(shouldWipe);
- shouldWipe = true;
- wipeAndStore(new ClientRecord());
- assertFalse(shouldWipe);
- assertTrue(getMockDataAccessor().clientsTableWiped);
- assertTrue(getMockDataAccessor().storedRecord);
- }
-
- @Test
- public void testDownloadClientRecord() {
- // Make sure no upload occurs after a download so we can
- // test download in isolation.
- stubUpload = true;
-
- currentDownloadMockServer = new DownloadMockServer();
- // performNotify() occurs in MockGlobalSessionCallback.
- testWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- clientDownloadDelegate = new TestSuccessClientDownloadDelegate(data);
- downloadClientRecords();
- }
- });
-
- assertEquals(expectedClients.size(), numRecordsFromGetRequest);
- for (int i = 0; i < downloadedClients.size(); i++) {
- final ClientRecord downloaded = downloadedClients.get(i);
- final ClientRecord expected = expectedClients.get(i);
- assertTrue(expected.guid.equals(downloaded.guid));
- assertEquals(expected.version, downloaded.version);
- }
- assertTrue(mockDataAccessorIsClosed());
- }
-
- @Test
- public void testCheckAndUploadClientRecord() {
- uploadAttemptsCount.set(MAX_UPLOAD_FAILURE_COUNT);
- assertFalse(shouldUploadLocalRecord);
- assertEquals(0, session.config.getPersistedServerClientRecordTimestamp());
- currentUploadMockServer = new UploadMockServer();
- // performNotify() occurs in MockGlobalSessionCallback.
- testWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- clientUploadDelegate = new MockSuccessClientUploadDelegate(data);
- checkAndUpload();
- }
- });
-
- // Test ClientUploadDelegate.handleRequestSuccess().
- Logger.debug(LOG_TAG, "Last computed local client record: " + lastComputedLocalClientRecord.guid);
- Logger.debug(LOG_TAG, "Uploaded client record: " + uploadedRecord.guid);
- assertTrue(lastComputedLocalClientRecord.equalPayloads(uploadedRecord));
- assertEquals(0, uploadAttemptsCount.get());
- assertTrue(callback.calledSuccess);
-
- assertFalse(0 == session.config.getPersistedServerClientRecordTimestamp());
-
- // Body and header are the same.
- assertEquals(Utils.decimalSecondsToMilliseconds(uploadBodyTimestamp),
- session.config.getPersistedServerClientsTimestamp());
- assertEquals(uploadedRecord.lastModified,
- session.config.getPersistedServerClientRecordTimestamp());
- assertEquals(uploadHeaderTimestamp, session.config.getPersistedServerClientsTimestamp());
- }
-
- @Test // client/server multi-threaded
- public void testDownloadHasOurRecord() {
- // Make sure no upload occurs after a download so we can
- // test download in isolation.
- stubUpload = true;
-
- // We've uploaded our local record recently.
- long initialTimestamp = setRecentClientRecordTimestamp();
-
- currentDownloadMockServer = new DownloadLocalRecordMockServer();
- // performNotify() occurs in MockGlobalSessionCallback.
- testWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- clientDownloadDelegate = new TestHandleWBODownloadDelegate(data);
- downloadClientRecords();
- }
- });
-
- // Timestamp got updated (but not reset) since we downloaded our record
- assertFalse(0 == session.config.getPersistedServerClientRecordTimestamp());
- assertTrue(initialTimestamp < session.config.getPersistedServerClientRecordTimestamp());
- assertTrue(mockDataAccessorIsClosed());
- }
-
- @Test
- public void testResetTimestampOnDownload() {
- // Make sure no upload occurs after a download so we can
- // test download in isolation.
- stubUpload = true;
-
- currentDownloadMockServer = new DownloadMockServer();
- // performNotify() occurs in MockGlobalSessionCallback.
- testWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- clientDownloadDelegate = new TestHandleWBODownloadDelegate(data);
- downloadClientRecords();
- }
- });
-
- // Timestamp got reset since our record wasn't downloaded.
- assertEquals(0, session.config.getPersistedServerClientRecordTimestamp());
- assertTrue(mockDataAccessorIsClosed());
- }
-
- /**
- * The following 8 tests are for ClientUploadDelegate.handleRequestFailure().
- * for the varying values of uploadAttemptsCount, shouldUploadLocalRecord,
- * and the type of server error.
- *
- * The first 4 are for 412 Precondition Failures.
- * The second 4 represent the functionality given any other type of variable.
- */
- @Test
- public void testHandle412UploadFailureLowCount() {
- assertFalse(shouldUploadLocalRecord);
- currentUploadMockServer = new MockServer(HttpStatus.SC_PRECONDITION_FAILED, null);
- assertEquals(0, uploadAttemptsCount.get());
- performFailingUpload();
- assertEquals(0, uploadAttemptsCount.get());
- assertTrue(callback.calledError);
- }
-
- @Test
- public void testHandle412UploadFailureHighCount() {
- assertFalse(shouldUploadLocalRecord);
- currentUploadMockServer = new MockServer(HttpStatus.SC_PRECONDITION_FAILED, null);
- uploadAttemptsCount.set(MAX_UPLOAD_FAILURE_COUNT);
- performFailingUpload();
- assertEquals(MAX_UPLOAD_FAILURE_COUNT, uploadAttemptsCount.get());
- assertTrue(callback.calledError);
- }
-
- @Test
- public void testHandle412UploadFailureLowCountWithCommand() {
- shouldUploadLocalRecord = true;
- currentUploadMockServer = new MockServer(HttpStatus.SC_PRECONDITION_FAILED, null);
- assertEquals(0, uploadAttemptsCount.get());
- performFailingUpload();
- assertEquals(0, uploadAttemptsCount.get());
- assertTrue(callback.calledError);
- }
-
- @Test
- public void testHandle412UploadFailureHighCountWithCommand() {
- shouldUploadLocalRecord = true;
- currentUploadMockServer = new MockServer(HttpStatus.SC_PRECONDITION_FAILED, null);
- uploadAttemptsCount.set(MAX_UPLOAD_FAILURE_COUNT);
- performFailingUpload();
- assertEquals(MAX_UPLOAD_FAILURE_COUNT, uploadAttemptsCount.get());
- assertTrue(callback.calledError);
- }
-
- @Test
- public void testHandleMiscUploadFailureLowCount() {
- currentUploadMockServer = new MockServer(HttpStatus.SC_BAD_REQUEST, null);
- assertFalse(shouldUploadLocalRecord);
- assertEquals(0, uploadAttemptsCount.get());
- performFailingUpload();
- assertEquals(0, uploadAttemptsCount.get());
- assertTrue(callback.calledError);
- }
-
- @Test
- public void testHandleMiscUploadFailureHighCount() {
- currentUploadMockServer = new MockServer(HttpStatus.SC_BAD_REQUEST, null);
- assertFalse(shouldUploadLocalRecord);
- uploadAttemptsCount.set(MAX_UPLOAD_FAILURE_COUNT);
- performFailingUpload();
- assertEquals(MAX_UPLOAD_FAILURE_COUNT, uploadAttemptsCount.get());
- assertTrue(callback.calledError);
- }
-
- @Test
- public void testHandleMiscUploadFailureHighCountWithCommands() {
- currentUploadMockServer = new MockServer(HttpStatus.SC_BAD_REQUEST, null);
- shouldUploadLocalRecord = true;
- uploadAttemptsCount.set(MAX_UPLOAD_FAILURE_COUNT);
- performFailingUpload();
- assertEquals(MAX_UPLOAD_FAILURE_COUNT + 1, uploadAttemptsCount.get());
- assertTrue(callback.calledError);
- }
-
- @Test
- public void testHandleMiscUploadFailureMaxAttempts() {
- currentUploadMockServer = new MockServer(HttpStatus.SC_BAD_REQUEST, null);
- shouldUploadLocalRecord = true;
- assertEquals(0, uploadAttemptsCount.get());
- performFailingUpload();
- assertEquals(MAX_UPLOAD_FAILURE_COUNT + 1, uploadAttemptsCount.get());
- assertTrue(callback.calledError);
- }
-
- class TestAddCommandsMockClientsDatabaseAccessor extends MockClientsDatabaseAccessor {
- @Override
- public List<Command> fetchCommandsForClient(String accountGUID) throws NullCursorException {
- List<Command> commands = new ArrayList<Command>();
- commands.add(CommandHelpers.getCommand1());
- commands.add(CommandHelpers.getCommand2());
- commands.add(CommandHelpers.getCommand3());
- commands.add(CommandHelpers.getCommand4());
- return commands;
- }
- }
-
- @Test
- public void testAddCommandsToUnversionedClient() throws NullCursorException {
- db = new TestAddCommandsMockClientsDatabaseAccessor();
-
- final ClientRecord remoteRecord = new ClientRecord();
- remoteRecord.version = null;
- final String expectedGUID = remoteRecord.guid;
-
- this.addCommands(remoteRecord);
- assertEquals(1, modifiedClientsToUpload.size());
-
- final ClientRecord recordToUpload = modifiedClientsToUpload.get(0);
- assertEquals(4, recordToUpload.commands.size());
- assertEquals(expectedGUID, recordToUpload.guid);
- assertEquals(null, recordToUpload.version);
- }
-
- @Test
- public void testAddCommandsToVersionedClient() throws NullCursorException {
- db = new TestAddCommandsMockClientsDatabaseAccessor();
-
- final ClientRecord remoteRecord = new ClientRecord();
- remoteRecord.version = "12a1";
- final String expectedGUID = remoteRecord.guid;
-
- this.addCommands(remoteRecord);
- assertEquals(1, modifiedClientsToUpload.size());
-
- final ClientRecord recordToUpload = modifiedClientsToUpload.get(0);
- assertEquals(4, recordToUpload.commands.size());
- assertEquals(expectedGUID, recordToUpload.guid);
- assertEquals("12a1", recordToUpload.version);
- }
-
- @Test
- public void testLastModifiedTimestamp() throws NullCursorException {
- // If we uploaded a record a moment ago, we shouldn't upload another.
- final long now = System.currentTimeMillis() - 1;
- session.config.persistServerClientRecordTimestamp(now);
- assertEquals(now, session.config.getPersistedServerClientRecordTimestamp());
- assertFalse(shouldUploadLocalRecord);
- assertFalse(shouldUpload());
-
- // But if we change our client data, we should upload.
- session.getClientsDelegate().setClientName("new name", System.currentTimeMillis());
- assertTrue(shouldUpload());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java
deleted file mode 100644
index 0f568a81e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-
-import ch.boye.httpclientandroidlib.Header;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Test the transfer of a UTF-8 string from desktop, and ensure that it results in the
- * correct hashed Basic Auth header.
- */
-@RunWith(TestRunner.class)
-public class TestCredentialsEndToEnd {
-
- public static final String REAL_PASSWORD = "pïgéons1";
- public static final String USERNAME = "utvm3mk6hnngiir2sp4jsxf2uvoycrv6";
- public static final String DESKTOP_PASSWORD_JSON = "{\"password\":\"pïgéons1\"}";
- public static final String BTOA_PASSWORD = "cMOvZ8Opb25zMQ==";
- public static final int DESKTOP_ASSERTED_SIZE = 10;
- public static final String DESKTOP_BASIC_AUTH = "Basic dXR2bTNtazZobm5naWlyMnNwNGpzeGYydXZveWNydjY6cMOvZ8Opb25zMQ==";
-
- private String getCreds(String password) {
- Header authenticate = new BasicAuthHeaderProvider(USERNAME, password).getAuthHeader(null, null, null);
- return authenticate.getValue();
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testUTF8() throws UnsupportedEncodingException {
- final String in = "pïgéons1";
- final String out = "pïgéons1";
- assertEquals(out, Utils.decodeUTF8(in));
- }
-
- @Test
- public void testAuthHeaderFromPassword() throws NonObjectJSONException, IOException {
- final ExtendedJSONObject parsed = new ExtendedJSONObject(DESKTOP_PASSWORD_JSON);
-
- final String password = parsed.getString("password");
- final String decoded = Utils.decodeUTF8(password);
-
- final byte[] expectedBytes = Utils.decodeBase64(BTOA_PASSWORD);
- final String expected = new String(expectedBytes, "UTF-8");
-
- assertEquals(DESKTOP_ASSERTED_SIZE, password.length());
- assertEquals(expected, decoded);
-
- System.out.println("Retrieved password: " + password);
- System.out.println("Expected password: " + expected);
- System.out.println("Rescued password: " + decoded);
-
- assertEquals(getCreds(expected), getCreds(decoded));
- assertEquals(getCreds(decoded), DESKTOP_BASIC_AUTH);
- }
-
- // Note that we do *not* have a test for the J-PAKE setup process
- // (SetupSyncActivity) that actually stores credentials and requires
- // decodeUTF8. This will have to suffice.
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java
deleted file mode 100644
index c00da9b26..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.ProtocolVersion;
-import ch.boye.httpclientandroidlib.message.BasicHttpResponse;
-import ch.boye.httpclientandroidlib.message.BasicStatusLine;
-import junit.framework.AssertionFailedError;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockGlobalSessionCallback;
-import org.mozilla.android.sync.test.helpers.MockResourceDelegate;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.testhelpers.MockAbstractNonRepositorySyncStage;
-import org.mozilla.gecko.background.testhelpers.MockGlobalSession;
-import org.mozilla.gecko.background.testhelpers.MockPrefsGlobalSession;
-import org.mozilla.gecko.background.testhelpers.MockServerSyncStage;
-import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.EngineSettings;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.MetaGlobal;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.mozilla.gecko.sync.repositories.domain.VersionConstants;
-import org.mozilla.gecko.sync.stage.AndroidBrowserBookmarksServerSyncStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-import org.mozilla.gecko.sync.stage.NoSuchStageException;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestGlobalSession {
- private int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private final String TEST_CLUSTER_URL = "http://localhost:" + TEST_PORT;
- private final String TEST_USERNAME = "johndoe";
- private final String TEST_PASSWORD = "password";
- private final String TEST_SYNC_KEY = "abcdeabcdeabcdeabcdeabcdea";
- private final long TEST_BACKOFF_IN_SECONDS = 2401;
-
- public static WaitHelper getTestWaiter() {
- return WaitHelper.getTestWaiter();
- }
-
- @Test
- public void testGetSyncStagesBy() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException, NoSuchStageException {
-
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
- GlobalSession s = MockPrefsGlobalSession.getSession(TEST_USERNAME, TEST_PASSWORD,
- new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY),
- callback, /* context */ null, null);
-
- assertTrue(s.getSyncStageByName(Stage.syncBookmarks) instanceof AndroidBrowserBookmarksServerSyncStage);
-
- final Set<String> empty = new HashSet<String>();
-
- final Set<String> bookmarksAndTabsNames = new HashSet<String>();
- bookmarksAndTabsNames.add("bookmarks");
- bookmarksAndTabsNames.add("tabs");
-
- final Set<GlobalSyncStage> bookmarksAndTabsSyncStages = new HashSet<GlobalSyncStage>();
- GlobalSyncStage bookmarksStage = s.getSyncStageByName("bookmarks");
- GlobalSyncStage tabsStage = s.getSyncStageByName(Stage.syncTabs);
- bookmarksAndTabsSyncStages.add(bookmarksStage);
- bookmarksAndTabsSyncStages.add(tabsStage);
-
- final Set<Stage> bookmarksAndTabsEnums = new HashSet<Stage>();
- bookmarksAndTabsEnums.add(Stage.syncBookmarks);
- bookmarksAndTabsEnums.add(Stage.syncTabs);
-
- assertTrue(s.getSyncStagesByName(empty).isEmpty());
- assertEquals(bookmarksAndTabsSyncStages, new HashSet<GlobalSyncStage>(s.getSyncStagesByName(bookmarksAndTabsNames)));
- assertEquals(bookmarksAndTabsSyncStages, new HashSet<GlobalSyncStage>(s.getSyncStagesByEnum(bookmarksAndTabsEnums)));
- }
-
- /**
- * Test that handleHTTPError does in fact backoff.
- */
- @Test
- public void testBackoffCalledByHandleHTTPError() {
- try {
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
- SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
- final GlobalSession session = new MockGlobalSession(config, callback);
-
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
- response.setHeader("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS)); // Backoff given in seconds.
-
- getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- session.handleHTTPError(new SyncStorageResponse(response), "Illegal method/protocol");
- }
- }));
-
- assertEquals(false, callback.calledSuccess);
- assertEquals(true, callback.calledError);
- assertEquals(false, callback.calledAborted);
- assertEquals(true, callback.calledRequestBackoff);
- assertEquals(TEST_BACKOFF_IN_SECONDS * 1000, callback.weaveBackoff); // Backoff returned in milliseconds.
- } catch (Exception e) {
- e.printStackTrace();
- fail("Got exception.");
- }
- }
-
- /**
- * Test that a trivially successful GlobalSession does not fail or backoff.
- */
- @Test
- public void testSuccessCalledAfterStages() {
- try {
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
- SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
- final GlobalSession session = new MockGlobalSession(config, callback);
-
- getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- try {
- session.start();
- } catch (Exception e) {
- final AssertionFailedError error = new AssertionFailedError();
- error.initCause(e);
- getTestWaiter().performNotify(error);
- }
- }
- }));
-
- assertEquals(true, callback.calledSuccess);
- assertEquals(false, callback.calledError);
- assertEquals(false, callback.calledAborted);
- assertEquals(false, callback.calledRequestBackoff);
- } catch (Exception e) {
- e.printStackTrace();
- fail("Got exception.");
- }
- }
-
- /**
- * Test that a failing GlobalSession does in fact fail and back off.
- */
- @Test
- public void testBackoffCalledInStages() {
- try {
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
-
- // Stage fakes a 503 and sets X-Weave-Backoff header to the given seconds.
- final GlobalSyncStage stage = new MockAbstractNonRepositorySyncStage() {
- @Override
- public void execute() {
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
-
- response.addHeader("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS)); // Backoff given in seconds.
- session.handleHTTPError(new SyncStorageResponse(response), "Failure fetching info/collections.");
- }
- };
-
- // Session installs fake stage to fetch info/collections.
- SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
- final GlobalSession session = new MockGlobalSession(config, callback)
- .withStage(Stage.fetchInfoCollections, stage);
-
- getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- try {
- session.start();
- } catch (Exception e) {
- final AssertionFailedError error = new AssertionFailedError();
- error.initCause(e);
- getTestWaiter().performNotify(error);
- }
- }
- }));
-
- assertEquals(false, callback.calledSuccess);
- assertEquals(true, callback.calledError);
- assertEquals(false, callback.calledAborted);
- assertEquals(true, callback.calledRequestBackoff);
- assertEquals(TEST_BACKOFF_IN_SECONDS * 1000, callback.weaveBackoff); // Backoff returned in milliseconds.
- } catch (Exception e) {
- e.printStackTrace();
- fail("Got exception.");
- }
- }
-
- private HTTPServerTestHelper data = new HTTPServerTestHelper();
-
- @SuppressWarnings("static-method")
- @Before
- public void setUp() {
- BaseResource.rewriteLocalhost = false;
- }
-
- public void doRequest() {
- final WaitHelper innerWaitHelper = new WaitHelper();
- innerWaitHelper.performWait(new Runnable() {
- @Override
- public void run() {
- try {
- final BaseResource r = new BaseResource(TEST_CLUSTER_URL);
- r.delegate = new MockResourceDelegate(innerWaitHelper);
- r.get();
- } catch (URISyntaxException e) {
- innerWaitHelper.performNotify(e);
- }
- }
- });
- }
-
- public MockGlobalSessionCallback doTestSuccess(final boolean stageShouldBackoff, final boolean stageShouldAdvance) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException {
- MockServer server = new MockServer() {
- @Override
- public void handle(Request request, Response response) {
- if (stageShouldBackoff) {
- response.addValue("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS));
- }
- super.handle(request, response);
- }
- };
-
- final MockServerSyncStage stage = new MockServerSyncStage() {
- @Override
- public void execute() {
- // We should have installed our HTTP response observer before starting the sync.
- assertTrue(BaseResource.isHttpResponseObserver(session));
-
- doRequest();
- if (stageShouldAdvance) {
- session.advance();
- return;
- }
- session.abort(null, "Stage intentionally failed.");
- }
- };
-
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
- SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
- final GlobalSession session = new MockGlobalSession(config, callback)
- .withStage(Stage.syncBookmarks, stage);
-
- data.startHTTPServer(server);
- WaitHelper.getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- try {
- session.start();
- } catch (Exception e) {
- final AssertionFailedError error = new AssertionFailedError();
- error.initCause(e);
- WaitHelper.getTestWaiter().performNotify(error);
- }
- }
- }));
- data.stopHTTPServer();
-
- // We should have uninstalled our HTTP response observer when the session is terminated.
- assertFalse(BaseResource.isHttpResponseObserver(session));
-
- return callback;
- }
-
- @Test
- public void testOnSuccessBackoffAdvanced() throws SyncConfigurationException,
- IllegalArgumentException, NonObjectJSONException, IOException,
- CryptoException {
- MockGlobalSessionCallback callback = doTestSuccess(true, true);
-
- assertTrue(callback.calledError); // TODO: this should be calledAborted.
- assertTrue(callback.calledRequestBackoff);
- assertEquals(1000 * TEST_BACKOFF_IN_SECONDS, callback.weaveBackoff);
- }
-
- @Test
- public void testOnSuccessBackoffAborted() throws SyncConfigurationException,
- IllegalArgumentException, NonObjectJSONException, IOException,
- CryptoException {
- MockGlobalSessionCallback callback = doTestSuccess(true, false);
-
- assertTrue(callback.calledError); // TODO: this should be calledAborted.
- assertTrue(callback.calledRequestBackoff);
- assertEquals(1000 * TEST_BACKOFF_IN_SECONDS, callback.weaveBackoff);
- }
-
- @Test
- public void testOnSuccessNoBackoffAdvanced() throws SyncConfigurationException,
- IllegalArgumentException, NonObjectJSONException, IOException,
- CryptoException {
- MockGlobalSessionCallback callback = doTestSuccess(false, true);
-
- assertTrue(callback.calledSuccess);
- assertFalse(callback.calledRequestBackoff);
- }
-
- @Test
- public void testOnSuccessNoBackoffAborted() throws SyncConfigurationException,
- IllegalArgumentException, NonObjectJSONException, IOException,
- CryptoException {
- MockGlobalSessionCallback callback = doTestSuccess(false, false);
-
- assertTrue(callback.calledError); // TODO: this should be calledAborted.
- assertFalse(callback.calledRequestBackoff);
- }
-
- @Test
- public void testGenerateNewMetaGlobalNonePersisted() throws Exception {
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
- final GlobalSession session = MockPrefsGlobalSession.getSession(TEST_USERNAME, TEST_PASSWORD,
- new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY), callback, null, null);
-
- // Verify we fill in all of our known engines when none are persisted.
- session.config.enabledEngineNames = null;
- MetaGlobal mg = session.generateNewMetaGlobal();
- assertEquals(Long.valueOf(GlobalSession.STORAGE_VERSION), mg.getStorageVersion());
- assertEquals(VersionConstants.BOOKMARKS_ENGINE_VERSION, mg.getEngines().getObject("bookmarks").getIntegerSafely("version").intValue());
- assertEquals(VersionConstants.CLIENTS_ENGINE_VERSION, mg.getEngines().getObject("clients").getIntegerSafely("version").intValue());
-
- List<String> namesList = new ArrayList<String>(mg.getEnabledEngineNames());
- Collections.sort(namesList);
- String[] names = namesList.toArray(new String[namesList.size()]);
- String[] expected = new String[] { "bookmarks", "clients", "forms", "history", "passwords", "tabs" };
- assertArrayEquals(expected, names);
- }
-
- @Test
- public void testGenerateNewMetaGlobalSomePersisted() throws Exception {
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
- final GlobalSession session = MockPrefsGlobalSession.getSession(TEST_USERNAME, TEST_PASSWORD,
- new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY), callback, null, null);
-
- // Verify we preserve engines with version 0 if some are persisted.
- session.config.enabledEngineNames = new HashSet<String>();
- session.config.enabledEngineNames.add("bookmarks");
- session.config.enabledEngineNames.add("clients");
- session.config.enabledEngineNames.add("addons");
- session.config.enabledEngineNames.add("prefs");
-
- MetaGlobal mg = session.generateNewMetaGlobal();
- assertEquals(Long.valueOf(GlobalSession.STORAGE_VERSION), mg.getStorageVersion());
- assertEquals(VersionConstants.BOOKMARKS_ENGINE_VERSION, mg.getEngines().getObject("bookmarks").getIntegerSafely("version").intValue());
- assertEquals(VersionConstants.CLIENTS_ENGINE_VERSION, mg.getEngines().getObject("clients").getIntegerSafely("version").intValue());
- assertEquals(0, mg.getEngines().getObject("addons").getIntegerSafely("version").intValue());
- assertEquals(0, mg.getEngines().getObject("prefs").getIntegerSafely("version").intValue());
-
- List<String> namesList = new ArrayList<String>(mg.getEnabledEngineNames());
- Collections.sort(namesList);
- String[] names = namesList.toArray(new String[namesList.size()]);
- String[] expected = new String[] { "addons", "bookmarks", "clients", "prefs" };
- assertArrayEquals(expected, names);
- }
-
- @Test
- public void testUploadUpdatedMetaGlobal() throws Exception {
- // Set up session with meta/global.
- final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
- final GlobalSession session = MockPrefsGlobalSession.getSession(TEST_USERNAME, TEST_PASSWORD,
- new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY), callback, null, null);
- session.config.metaGlobal = session.generateNewMetaGlobal();
- session.enginesToUpdate.clear();
-
- // Set enabledEngines in meta/global, including a "new engine."
- String[] origEngines = new String[] { "bookmarks", "clients", "forms", "history", "tabs", "new-engine" };
-
- ExtendedJSONObject origEnginesJSONObject = new ExtendedJSONObject();
- for (String engineName : origEngines) {
- EngineSettings mockEngineSettings = new EngineSettings(Utils.generateGuid(), Integer.valueOf(0));
- origEnginesJSONObject.put(engineName, mockEngineSettings.toJSONObject());
- }
- session.config.metaGlobal.setEngines(origEnginesJSONObject);
-
- // Engines to remove.
- String[] toRemove = new String[] { "bookmarks", "tabs" };
- for (String name : toRemove) {
- session.removeEngineFromMetaGlobal(name);
- }
-
- // Engines to add.
- String[] toAdd = new String[] { "passwords" };
- for (String name : toAdd) {
- String syncId = Utils.generateGuid();
- session.recordForMetaGlobalUpdate(name, new EngineSettings(syncId, Integer.valueOf(1)));
- }
-
- // Update engines.
- session.uploadUpdatedMetaGlobal();
-
- // Check resulting enabledEngines.
- Set<String> expected = new HashSet<String>();
- for (String name : origEngines) {
- expected.add(name);
- }
- for (String name : toRemove) {
- expected.remove(name);
- }
- for (String name : toAdd) {
- expected.add(name);
- }
- assertEquals(expected, session.config.metaGlobal.getEnabledEngineNames());
- }
-
- public void testStageAdvance() {
- assertEquals(GlobalSession.nextStage(Stage.idle), Stage.checkPreconditions);
- assertEquals(GlobalSession.nextStage(Stage.completed), Stage.idle);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestHeaderParsing.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestHeaderParsing.java
deleted file mode 100644
index 532d60d13..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestHeaderParsing.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.Utils;
-
-import static org.junit.Assert.assertEquals;
-
-@RunWith(TestRunner.class)
-public class TestHeaderParsing {
-
- @SuppressWarnings("static-method")
- @Test
- public void testDecimalSecondsToMilliseconds() {
- assertEquals(Utils.decimalSecondsToMilliseconds(""), -1);
- assertEquals(Utils.decimalSecondsToMilliseconds("1234.1.1"), -1);
- assertEquals(Utils.decimalSecondsToMilliseconds("1234"), 1234000);
- assertEquals(Utils.decimalSecondsToMilliseconds("1234.123"), 1234123);
- assertEquals(Utils.decimalSecondsToMilliseconds("1234.12"), 1234120);
-
- assertEquals("1234.000", Utils.millisecondsToDecimalSecondsString(1234000));
- assertEquals("1234.123", Utils.millisecondsToDecimalSecondsString(1234123));
- assertEquals("1234.120", Utils.millisecondsToDecimalSecondsString(1234120));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestLineByLineHandling.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestLineByLineHandling.java
deleted file mode 100644
index b7f11adbf..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestLineByLineHandling.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncStorageCollectionRequest;
-import org.mozilla.gecko.sync.net.SyncStorageCollectionRequestDelegate;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestLineByLineHandling {
- private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private static final String TEST_SERVER = "http://localhost:" + TEST_PORT;
- private static final String LOG_TAG = "TestLineByLineHandling";
- static String STORAGE_URL = TEST_SERVER + "/1.1/c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd/storage/lines";
- private HTTPServerTestHelper data = new HTTPServerTestHelper();
-
- public ArrayList<String> lines = new ArrayList<String>();
-
- public class LineByLineMockServer extends MockServer {
- public void handle(Request request, Response response) {
- try {
- System.out.println("Handling line-by-line request...");
- PrintStream bodyStream = this.handleBasicHeaders(request, response, 200, "application/newlines");
-
- bodyStream.print("First line.\n");
- bodyStream.print("Second line.\n");
- bodyStream.print("Third line.\n");
- bodyStream.print("Fourth line.\n");
- bodyStream.close();
- } catch (IOException e) {
- System.err.println("Oops.");
- }
- }
- }
-
- public class BaseLineByLineDelegate extends
- SyncStorageCollectionRequestDelegate {
-
- @Override
- public void handleRequestProgress(String progress) {
- lines.add(progress);
- }
-
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return null;
- }
-
- @Override
- public String ifUnmodifiedSince() {
- return null;
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse res) {
- Logger.info(LOG_TAG, "Request success.");
- assertTrue(res.wasSuccessful());
- assertTrue(res.httpResponse().containsHeader("X-Weave-Timestamp"));
-
- assertEquals(lines.size(), 4);
- assertEquals(lines.get(0), "First line.");
- assertEquals(lines.get(1), "Second line.");
- assertEquals(lines.get(2), "Third line.");
- assertEquals(lines.get(3), "Fourth line.");
- data.stopHTTPServer();
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- Logger.info(LOG_TAG, "Got request failure: " + response);
- BaseResource.consumeEntity(response);
- fail("Should not be called.");
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- Logger.error(LOG_TAG, "Got request error: ", ex);
- fail("Should not be called.");
- }
- }
-
- @Test
- public void testLineByLine() throws URISyntaxException {
- BaseResource.rewriteLocalhost = false;
-
- data.startHTTPServer(new LineByLineMockServer());
- Logger.info(LOG_TAG, "Server started.");
- SyncStorageCollectionRequest r = new SyncStorageCollectionRequest(new URI(STORAGE_URL));
- SyncStorageCollectionRequestDelegate delegate = new BaseLineByLineDelegate();
- r.delegate = delegate;
- r.get();
- // Server is stopped in the callback.
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestMetaGlobal.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestMetaGlobal.java
deleted file mode 100644
index ec4c03859..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestMetaGlobal.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.MetaGlobal;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestMetaGlobal {
- private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private static final String TEST_SERVER = "http://localhost:" + TEST_PORT;
- private static final String TEST_SYNC_ID = "foobar";
-
- public static final String USER_PASS = "c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd:password";
- public static final String META_URL = TEST_SERVER + "/1.1/c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd/storage/meta/global";
- private HTTPServerTestHelper data = new HTTPServerTestHelper();
-
-
- public static final String TEST_DECLINED_META_GLOBAL_RESPONSE =
- "{\"id\":\"global\"," +
- "\"payload\":" +
- "\"{\\\"syncID\\\":\\\"zPSQTm7WBVWB\\\"," +
- "\\\"declined\\\":[\\\"bookmarks\\\"]," +
- "\\\"storageVersion\\\":5," +
- "\\\"engines\\\":{" +
- "\\\"clients\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"fDg0MS5bDtV7\\\"}," +
- "\\\"forms\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"GXF29AFprnvc\\\"}," +
- "\\\"history\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"av75g4vm-_rp\\\"}," +
- "\\\"passwords\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"LT_ACGpuKZ6a\\\"}," +
- "\\\"prefs\\\":{\\\"version\\\":2,\\\"syncID\\\":\\\"-3nsksP9wSAs\\\"}," +
- "\\\"tabs\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"W4H5lOMChkYA\\\"}}}\"," +
- "\"username\":\"5817483\"," +
- "\"modified\":1.32046073744E9}";
-
- public static final String TEST_META_GLOBAL_RESPONSE =
- "{\"id\":\"global\"," +
- "\"payload\":" +
- "\"{\\\"syncID\\\":\\\"zPSQTm7WBVWB\\\"," +
- "\\\"storageVersion\\\":5," +
- "\\\"engines\\\":{" +
- "\\\"clients\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"fDg0MS5bDtV7\\\"}," +
- "\\\"bookmarks\\\":{\\\"version\\\":2,\\\"syncID\\\":\\\"NNaQr6_F-9dm\\\"}," +
- "\\\"forms\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"GXF29AFprnvc\\\"}," +
- "\\\"history\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"av75g4vm-_rp\\\"}," +
- "\\\"passwords\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"LT_ACGpuKZ6a\\\"}," +
- "\\\"prefs\\\":{\\\"version\\\":2,\\\"syncID\\\":\\\"-3nsksP9wSAs\\\"}," +
- "\\\"tabs\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"W4H5lOMChkYA\\\"}}}\"," +
- "\"username\":\"5817483\"," +
- "\"modified\":1.32046073744E9}";
- public static final String TEST_META_GLOBAL_NO_PAYLOAD_RESPONSE = "{\"id\":\"global\"," +
- "\"username\":\"5817483\",\"modified\":1.32046073744E9}";
- public static final String TEST_META_GLOBAL_MALFORMED_PAYLOAD_RESPONSE = "{\"id\":\"global\"," +
- "\"payload\":\"{!!!}\"," +
- "\"username\":\"5817483\",\"modified\":1.32046073744E9}";
- public static final String TEST_META_GLOBAL_EMPTY_PAYLOAD_RESPONSE = "{\"id\":\"global\"," +
- "\"payload\":\"{}\"," +
- "\"username\":\"5817483\",\"modified\":1.32046073744E9}";
-
- public MetaGlobal global;
-
- @SuppressWarnings("static-method")
- @Before
- public void setUp() {
- BaseResource.rewriteLocalhost = false;
- global = new MetaGlobal(META_URL, new BasicAuthHeaderProvider(USER_PASS));
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testSyncID() {
- global.setSyncID("foobar");
- assertEquals(global.getSyncID(), "foobar");
- }
-
- public class MockMetaGlobalFetchDelegate implements MetaGlobalDelegate {
- boolean successCalled = false;
- MetaGlobal successGlobal = null;
- SyncStorageResponse successResponse = null;
- boolean failureCalled = false;
- SyncStorageResponse failureResponse = null;
- boolean errorCalled = false;
- Exception errorException = null;
- boolean missingCalled = false;
- MetaGlobal missingGlobal = null;
- SyncStorageResponse missingResponse = null;
-
- public void handleSuccess(MetaGlobal global, SyncStorageResponse response) {
- successCalled = true;
- successGlobal = global;
- successResponse = response;
- WaitHelper.getTestWaiter().performNotify();
- }
-
- public void handleFailure(SyncStorageResponse response) {
- failureCalled = true;
- failureResponse = response;
- WaitHelper.getTestWaiter().performNotify();
- }
-
- public void handleError(Exception e) {
- errorCalled = true;
- errorException = e;
- WaitHelper.getTestWaiter().performNotify();
- }
-
- public void handleMissing(MetaGlobal global, SyncStorageResponse response) {
- missingCalled = true;
- missingGlobal = global;
- missingResponse = response;
- WaitHelper.getTestWaiter().performNotify();
- }
- }
-
- public MockMetaGlobalFetchDelegate doFetch(final MetaGlobal global) {
- final MockMetaGlobalFetchDelegate delegate = new MockMetaGlobalFetchDelegate();
- WaitHelper.getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- global.fetch(delegate);
- }
- }));
-
- return delegate;
- }
-
- @Test
- public void testFetchMissing() {
- MockServer missingMetaGlobalServer = new MockServer(404, "{}");
- global.setSyncID(TEST_SYNC_ID);
- assertEquals(TEST_SYNC_ID, global.getSyncID());
-
- data.startHTTPServer(missingMetaGlobalServer);
- final MockMetaGlobalFetchDelegate delegate = doFetch(global);
- data.stopHTTPServer();
-
- assertTrue(delegate.missingCalled);
- assertEquals(404, delegate.missingResponse.getStatusCode());
- assertEquals(TEST_SYNC_ID, delegate.missingGlobal.getSyncID());
- }
-
- @Test
- public void testFetchExisting() {
- MockServer existingMetaGlobalServer = new MockServer(200, TEST_META_GLOBAL_RESPONSE);
- assertNull(global.getSyncID());
- assertNull(global.getEngines());
- assertNull(global.getStorageVersion());
-
- data.startHTTPServer(existingMetaGlobalServer);
- final MockMetaGlobalFetchDelegate delegate = doFetch(global);
- data.stopHTTPServer();
-
- assertTrue(delegate.successCalled);
- assertEquals(200, delegate.successResponse.getStatusCode());
- assertEquals("zPSQTm7WBVWB", global.getSyncID());
- assertTrue(global.getEngines() instanceof ExtendedJSONObject);
- assertEquals(Long.valueOf(5), global.getStorageVersion());
- }
-
- /**
- * A record that is valid JSON but invalid as a meta/global record will be
- * downloaded successfully, but will fail later.
- */
- @Test
- public void testFetchNoPayload() {
- MockServer existingMetaGlobalServer = new MockServer(200, TEST_META_GLOBAL_NO_PAYLOAD_RESPONSE);
-
- data.startHTTPServer(existingMetaGlobalServer);
- final MockMetaGlobalFetchDelegate delegate = doFetch(global);
- data.stopHTTPServer();
-
- assertTrue(delegate.successCalled);
- }
-
- @Test
- public void testFetchEmptyPayload() {
- MockServer existingMetaGlobalServer = new MockServer(200, TEST_META_GLOBAL_EMPTY_PAYLOAD_RESPONSE);
-
- data.startHTTPServer(existingMetaGlobalServer);
- final MockMetaGlobalFetchDelegate delegate = doFetch(global);
- data.stopHTTPServer();
-
- assertTrue(delegate.successCalled);
- }
-
- /**
- * A record that is invalid JSON will fail to download at all.
- */
- @Test
- public void testFetchMalformedPayload() {
- MockServer existingMetaGlobalServer = new MockServer(200, TEST_META_GLOBAL_MALFORMED_PAYLOAD_RESPONSE);
-
- data.startHTTPServer(existingMetaGlobalServer);
- final MockMetaGlobalFetchDelegate delegate = doFetch(global);
- data.stopHTTPServer();
-
- assertTrue(delegate.errorCalled);
- assertNotNull(delegate.errorException);
- assertEquals(NonObjectJSONException.class, delegate.errorException.getClass());
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testSetFromRecord() throws Exception {
- MetaGlobal mg = new MetaGlobal(null, null);
- mg.setFromRecord(CryptoRecord.fromJSONRecord(TEST_META_GLOBAL_RESPONSE));
- assertEquals("zPSQTm7WBVWB", mg.getSyncID());
- assertTrue(mg.getEngines() instanceof ExtendedJSONObject);
- assertEquals(Long.valueOf(5), mg.getStorageVersion());
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testAsCryptoRecord() throws Exception {
- MetaGlobal mg = new MetaGlobal(null, null);
- mg.setFromRecord(CryptoRecord.fromJSONRecord(TEST_META_GLOBAL_RESPONSE));
- CryptoRecord rec = mg.asCryptoRecord();
- assertEquals("global", rec.guid);
- mg.setFromRecord(rec);
- assertEquals("zPSQTm7WBVWB", mg.getSyncID());
- assertTrue(mg.getEngines() instanceof ExtendedJSONObject);
- assertEquals(Long.valueOf(5), mg.getStorageVersion());
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testGetEnabledEngineNames() throws Exception {
- MetaGlobal mg = new MetaGlobal(null, null);
- mg.setFromRecord(CryptoRecord.fromJSONRecord(TEST_META_GLOBAL_RESPONSE));
- assertEquals("zPSQTm7WBVWB", mg.getSyncID());
- final Set<String> actual = mg.getEnabledEngineNames();
- final Set<String> expected = new HashSet<String>();
- for (String name : new String[] { "bookmarks", "clients", "forms", "history", "passwords", "prefs", "tabs" }) {
- expected.add(name);
- }
- assertEquals(expected, actual);
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testGetEmptyDeclinedEngineNames() throws Exception {
- MetaGlobal mg = new MetaGlobal(null, null);
- mg.setFromRecord(CryptoRecord.fromJSONRecord(TEST_META_GLOBAL_RESPONSE));
- assertEquals(0, mg.getDeclinedEngineNames().size());
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testGetDeclinedEngineNames() throws Exception {
- MetaGlobal mg = new MetaGlobal(null, null);
- mg.setFromRecord(CryptoRecord.fromJSONRecord(TEST_DECLINED_META_GLOBAL_RESPONSE));
- assertEquals(1, mg.getDeclinedEngineNames().size());
- assertEquals("bookmarks", mg.getDeclinedEngineNames().iterator().next());
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testRoundtripDeclinedEngineNames() throws Exception {
- MetaGlobal mg = new MetaGlobal(null, null);
- mg.setFromRecord(CryptoRecord.fromJSONRecord(TEST_DECLINED_META_GLOBAL_RESPONSE));
- assertEquals("bookmarks", mg.getDeclinedEngineNames().iterator().next());
- assertEquals("bookmarks", mg.asCryptoRecord().payload.getArray("declined").get(0));
- MetaGlobal again = new MetaGlobal(null, null);
- again.setFromRecord(mg.asCryptoRecord());
- assertEquals("bookmarks", again.getDeclinedEngineNames().iterator().next());
- }
-
-
- public MockMetaGlobalFetchDelegate doUpload(final MetaGlobal global) {
- final MockMetaGlobalFetchDelegate delegate = new MockMetaGlobalFetchDelegate();
- WaitHelper.getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- global.upload(delegate);
- }
- }));
-
- return delegate;
- }
-
- @Test
- public void testUpload() {
- long TEST_STORAGE_VERSION = 111;
- String TEST_SYNC_ID = "testSyncID";
- global.setSyncID(TEST_SYNC_ID);
- global.setStorageVersion(Long.valueOf(TEST_STORAGE_VERSION));
-
- final AtomicBoolean mgUploaded = new AtomicBoolean(false);
- final MetaGlobal uploadedMg = new MetaGlobal(null, null);
-
- MockServer server = new MockServer() {
- public void handle(Request request, Response response) {
- if (request.getMethod().equals("PUT")) {
- try {
- ExtendedJSONObject body = new ExtendedJSONObject(request.getContent());
- System.out.println(body.toJSONString());
- assertTrue(body.containsKey("payload"));
- assertFalse(body.containsKey("default"));
-
- CryptoRecord rec = CryptoRecord.fromJSONRecord(body);
- uploadedMg.setFromRecord(rec);
- mgUploaded.set(true);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- this.handle(request, response, 200, "success");
- return;
- }
- this.handle(request, response, 404, "missing");
- }
- };
-
- data.startHTTPServer(server);
- final MockMetaGlobalFetchDelegate delegate = doUpload(global);
- data.stopHTTPServer();
-
- assertTrue(delegate.successCalled);
- assertTrue(mgUploaded.get());
- assertEquals(TEST_SYNC_ID, uploadedMg.getSyncID());
- assertEquals(TEST_STORAGE_VERSION, uploadedMg.getStorageVersion().longValue());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestResource.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestResource.java
deleted file mode 100644
index e53d02d33..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestResource.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockResourceDelegate;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.HttpResponseObserver;
-
-import java.net.URISyntaxException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestResource {
- private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private static final String TEST_SERVER = "http://localhost:" + TEST_PORT;
-
- private HTTPServerTestHelper data = new HTTPServerTestHelper();
-
- @SuppressWarnings("static-method")
- @Before
- public void setUp() {
- BaseResource.rewriteLocalhost = false;
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testLocalhostRewriting() throws URISyntaxException {
- BaseResource r = new BaseResource("http://localhost:5000/foo/bar", true);
- assertEquals("http://10.0.2.2:5000/foo/bar", r.getURI().toASCIIString());
- }
-
- @SuppressWarnings("static-method")
- public MockResourceDelegate doGet() throws URISyntaxException {
- final BaseResource r = new BaseResource(TEST_SERVER + "/foo/bar");
- MockResourceDelegate delegate = new MockResourceDelegate();
- r.delegate = delegate;
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- r.get();
- }
- });
- return delegate;
- }
-
- @Test
- public void testTrivialFetch() throws URISyntaxException {
- MockServer server = data.startHTTPServer();
- server.expectedBasicAuthHeader = MockResourceDelegate.EXPECT_BASIC;
- MockResourceDelegate delegate = doGet();
- assertTrue(delegate.handledHttpResponse);
- data.stopHTTPServer();
- }
-
- public static class MockHttpResponseObserver implements HttpResponseObserver {
- public HttpResponse response = null;
-
- @Override
- public void observeHttpResponse(HttpUriRequest request, HttpResponse response) {
- this.response = response;
- }
- }
-
- @Test
- public void testObservers() throws URISyntaxException {
- data.startHTTPServer();
- // Check that null observer doesn't fail.
- BaseResource.addHttpResponseObserver(null);
- doGet(); // HTTP server stopped in callback.
-
- // Check that multiple non-null observers gets called with reasonable HttpResponse.
- MockHttpResponseObserver observers[] = { new MockHttpResponseObserver(), new MockHttpResponseObserver() };
- for (MockHttpResponseObserver observer : observers) {
- BaseResource.addHttpResponseObserver(observer);
- assertTrue(BaseResource.isHttpResponseObserver(observer));
- assertNull(observer.response);
- }
-
- doGet(); // HTTP server stopped in callback.
-
- for (MockHttpResponseObserver observer : observers) {
- assertNotNull(observer.response);
- assertEquals(200, observer.response.getStatusLine().getStatusCode());
- }
-
- data.stopHTTPServer();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestRetryAfter.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestRetryAfter.java
deleted file mode 100644
index 429ad29d4..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestRetryAfter.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package org.mozilla.android.sync.net.test;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.ProtocolVersion;
-import ch.boye.httpclientandroidlib.impl.cookie.DateUtils;
-import ch.boye.httpclientandroidlib.message.BasicHttpResponse;
-import ch.boye.httpclientandroidlib.message.BasicStatusLine;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.net.SyncResponse;
-
-import java.util.Date;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestRetryAfter {
- private int TEST_SECONDS = 120;
-
- @Test
- public void testRetryAfterParsesSeconds() {
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
- response.addHeader("Retry-After", Long.toString(TEST_SECONDS)); // Retry-After given in seconds.
-
- final SyncResponse syncResponse = new SyncResponse(response);
- assertEquals(TEST_SECONDS, syncResponse.retryAfterInSeconds());
- }
-
- @Test
- public void testRetryAfterParsesHTTPDate() {
- Date future = new Date(System.currentTimeMillis() + TEST_SECONDS * 1000);
-
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
- response.addHeader("Retry-After", DateUtils.formatDate(future));
-
- final SyncResponse syncResponse = new SyncResponse(response);
- assertTrue(syncResponse.retryAfterInSeconds() > TEST_SECONDS - 15);
- assertTrue(syncResponse.retryAfterInSeconds() < TEST_SECONDS + 15);
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testRetryAfterParsesMalformed() {
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
- response.addHeader("Retry-After", "10X");
-
- final SyncResponse syncResponse = new SyncResponse(response);
- assertEquals(-1, syncResponse.retryAfterInSeconds());
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testRetryAfterParsesNeither() {
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
-
- final SyncResponse syncResponse = new SyncResponse(response);
- assertEquals(-1, syncResponse.retryAfterInSeconds());
- }
-
- @Test
- public void testRetryAfterParsesLargerRetryAfter() {
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
- response.addHeader("Retry-After", Long.toString(TEST_SECONDS + 1));
- response.addHeader("X-Weave-Backoff", Long.toString(TEST_SECONDS));
-
- final SyncResponse syncResponse = new SyncResponse(response);
- assertEquals(1000 * (TEST_SECONDS + 1), syncResponse.totalBackoffInMilliseconds());
- }
-
- @Test
- public void testRetryAfterParsesLargerXWeaveBackoff() {
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
- response.addHeader("Retry-After", Long.toString(TEST_SECONDS));
- response.addHeader("X-Weave-Backoff", Long.toString(TEST_SECONDS + 1));
-
- final SyncResponse syncResponse = new SyncResponse(response);
- assertEquals(1000 * (TEST_SECONDS + 1), syncResponse.totalBackoffInMilliseconds());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestServer11Repository.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestServer11Repository.java
deleted file mode 100644
index 3aa0a91ec..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestServer11Repository.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.InfoConfiguration;
-import org.mozilla.gecko.sync.repositories.Server11Repository;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
-@RunWith(TestRunner.class)
-public class TestServer11Repository {
-
- private static final String COLLECTION = "bookmarks";
- private static final String COLLECTION_URL = "http://foo.com/1.1/n6ec3u5bee3tixzp2asys7bs6fve4jfw/storage";
-
- protected final InfoCollections infoCollections = new InfoCollections();
- protected final InfoConfiguration infoConfiguration = new InfoConfiguration();
-
- public static void assertQueryEquals(String expected, URI u) {
- Assert.assertEquals(expected, u.getRawQuery());
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testCollectionURIFull() throws URISyntaxException {
- Server11Repository r = new Server11Repository(COLLECTION, COLLECTION_URL, null, infoCollections, infoConfiguration);
- assertQueryEquals("full=1&newer=5000.000", r.collectionURI(true, 5000000L, -1, null, null, null));
- assertQueryEquals("newer=1230.000", r.collectionURI(false, 1230000L, -1, null, null, null));
- assertQueryEquals("newer=5000.000&limit=10", r.collectionURI(false, 5000000L, 10, null, null, null));
- assertQueryEquals("full=1&newer=5000.000&sort=index", r.collectionURI(true, 5000000L, 0, "index", null, null));
- assertQueryEquals("full=1&ids=123,abc", r.collectionURI(true, -1L, -1, null, "123,abc", null));
- }
-
- @Test
- public void testCollectionURI() throws URISyntaxException {
- Server11Repository noTrailingSlash = new Server11Repository(COLLECTION, COLLECTION_URL, null, infoCollections, infoConfiguration);
- Server11Repository trailingSlash = new Server11Repository(COLLECTION, COLLECTION_URL + "/", null, infoCollections, infoConfiguration);
- Assert.assertEquals("http://foo.com/1.1/n6ec3u5bee3tixzp2asys7bs6fve4jfw/storage/bookmarks", noTrailingSlash.collectionURI().toASCIIString());
- Assert.assertEquals("http://foo.com/1.1/n6ec3u5bee3tixzp2asys7bs6fve4jfw/storage/bookmarks", trailingSlash.collectionURI().toASCIIString());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestSyncStorageRequest.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestSyncStorageRequest.java
deleted file mode 100644
index 0e6447c27..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestSyncStorageRequest.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import org.json.simple.JSONObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.BaseTestStorageRequestDelegate;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestSyncStorageRequest {
- private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private static final String TEST_SERVER = "http://localhost:" + TEST_PORT;
-
- private static final String LOCAL_META_URL = TEST_SERVER + "/1.1/c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd/storage/meta/global";
- private static final String LOCAL_BAD_REQUEST_URL = TEST_SERVER + "/1.1/c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd/storage/bad";
-
- private static final String EXPECTED_ERROR_CODE = "12";
- private static final String EXPECTED_RETRY_AFTER_ERROR_MESSAGE = "{error:'informative error message'}";
-
- // Corresponds to rnewman+testandroid@mozilla.com.
- private static final String TEST_USERNAME = "c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd";
- private static final String TEST_PASSWORD = "password";
- private final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD);
-
- private HTTPServerTestHelper data = new HTTPServerTestHelper();
-
- public class TestSyncStorageRequestDelegate extends
- BaseTestStorageRequestDelegate {
- public TestSyncStorageRequestDelegate(AuthHeaderProvider authHeaderProvider) {
- super(authHeaderProvider);
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse res) {
- assertTrue(res.wasSuccessful());
- assertTrue(res.httpResponse().containsHeader("X-Weave-Timestamp"));
-
- // Make sure we consume the rest of the body, so we can reuse the
- // connection. Even test code has to be correct in this regard!
- try {
- System.out.println("Success body: " + res.body());
- } catch (Exception e) {
- e.printStackTrace();
- }
- BaseResource.consumeEntity(res);
- data.stopHTTPServer();
- }
- }
-
- public class TestBadSyncStorageRequestDelegate extends
- BaseTestStorageRequestDelegate {
-
- public TestBadSyncStorageRequestDelegate(AuthHeaderProvider authHeaderProvider) {
- super(authHeaderProvider);
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse res) {
- assertTrue(!res.wasSuccessful());
- assertTrue(res.httpResponse().containsHeader("X-Weave-Timestamp"));
- try {
- String responseMessage = res.getErrorMessage();
- String expectedMessage = SyncStorageResponse.SERVER_ERROR_MESSAGES.get(EXPECTED_ERROR_CODE);
- assertEquals(expectedMessage, responseMessage);
- } catch (Exception e) {
- fail("Got exception fetching error message.");
- }
- BaseResource.consumeEntity(res);
- data.stopHTTPServer();
- }
- }
-
-
- @Test
- public void testSyncStorageRequest() throws URISyntaxException, IOException {
- BaseResource.rewriteLocalhost = false;
- data.startHTTPServer();
- SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_META_URL));
- TestSyncStorageRequestDelegate delegate = new TestSyncStorageRequestDelegate(authHeaderProvider);
- r.delegate = delegate;
- r.get();
- // Server is stopped in the callback.
- }
-
- public class ErrorMockServer extends MockServer {
- @Override
- public void handle(Request request, Response response) {
- super.handle(request, response, 400, EXPECTED_ERROR_CODE);
- }
- }
-
- @Test
- public void testErrorResponse() throws URISyntaxException {
- BaseResource.rewriteLocalhost = false;
- data.startHTTPServer(new ErrorMockServer());
- SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_BAD_REQUEST_URL));
- TestBadSyncStorageRequestDelegate delegate = new TestBadSyncStorageRequestDelegate(authHeaderProvider);
- r.delegate = delegate;
- r.post(new JSONObject());
- // Server is stopped in the callback.
- }
-
- // Test that the Retry-After header is correctly parsed and that handleRequestFailure
- // is being called.
- public class TestRetryAfterSyncStorageRequestDelegate extends BaseTestStorageRequestDelegate {
-
- public TestRetryAfterSyncStorageRequestDelegate(AuthHeaderProvider authHeaderProvider) {
- super(authHeaderProvider);
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse res) {
- assertTrue(!res.wasSuccessful());
- assertTrue(res.httpResponse().containsHeader("Retry-After"));
- assertEquals(res.retryAfterInSeconds(), 3001);
- try {
- String responseMessage = res.getErrorMessage();
- String expectedMessage = EXPECTED_RETRY_AFTER_ERROR_MESSAGE;
- assertEquals(expectedMessage, responseMessage);
- } catch (Exception e) {
- fail("Got exception fetching error message.");
- }
- BaseResource.consumeEntity(res);
- data.stopHTTPServer();
- }
- }
-
- public class RetryAfterMockServer extends MockServer {
- @Override
- public void handle(Request request, Response response) {
- String errorBody = EXPECTED_RETRY_AFTER_ERROR_MESSAGE;
- response.setValue("Retry-After", "3001");
- super.handle(request, response, 503, errorBody);
- }
- }
-
- @Test
- public void testRetryAfterResponse() throws URISyntaxException {
- BaseResource.rewriteLocalhost = false;
- data.startHTTPServer(new RetryAfterMockServer());
- SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_BAD_REQUEST_URL)); // URL not used -- we 503 every response
- TestRetryAfterSyncStorageRequestDelegate delegate = new TestRetryAfterSyncStorageRequestDelegate(authHeaderProvider);
- r.delegate = delegate;
- r.post(new JSONObject());
- // Server is stopped in the callback.
- }
-
- // Test that the X-Weave-Backoff header is correctly parsed and that handleRequestSuccess
- // is still being called.
- public class TestWeaveBackoffSyncStorageRequestDelegate extends
- TestSyncStorageRequestDelegate {
-
- public TestWeaveBackoffSyncStorageRequestDelegate(AuthHeaderProvider authHeaderProvider) {
- super(authHeaderProvider);
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse res) {
- assertTrue(res.httpResponse().containsHeader("X-Weave-Backoff"));
- assertEquals(res.weaveBackoffInSeconds(), 1801);
- super.handleRequestSuccess(res);
- }
- }
-
- public class WeaveBackoffMockServer extends MockServer {
- @Override
- public void handle(Request request, Response response) {
- response.setValue("X-Weave-Backoff", "1801");
- super.handle(request, response);
- }
- }
-
- @Test
- public void testWeaveBackoffResponse() throws URISyntaxException {
- BaseResource.rewriteLocalhost = false;
- data.startHTTPServer(new WeaveBackoffMockServer());
- SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_META_URL)); // URL re-used -- we need any successful response
- TestWeaveBackoffSyncStorageRequestDelegate delegate = new TestWeaveBackoffSyncStorageRequestDelegate(new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD));
- r.delegate = delegate;
- r.post(new JSONObject());
- // Server is stopped in the callback.
- }
-
- // Test that the X-Weave-{Quota-Remaining, Alert, Records} headers are correctly parsed and
- // that handleRequestSuccess is still being called.
- public class TestHeadersSyncStorageRequestDelegate extends
- TestSyncStorageRequestDelegate {
-
- public TestHeadersSyncStorageRequestDelegate(AuthHeaderProvider authHeaderProvider) {
- super(authHeaderProvider);
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse res) {
- assertTrue(res.httpResponse().containsHeader("X-Weave-Quota-Remaining"));
- assertTrue(res.httpResponse().containsHeader("X-Weave-Alert"));
- assertTrue(res.httpResponse().containsHeader("X-Weave-Records"));
- assertEquals(65536, res.weaveQuotaRemaining());
- assertEquals("First weave alert string", res.weaveAlert());
- assertEquals(50, res.weaveRecords());
-
- super.handleRequestSuccess(res);
- }
- }
-
- public class HeadersMockServer extends MockServer {
- @Override
- public void handle(Request request, Response response) {
- response.setValue("X-Weave-Quota-Remaining", "65536");
- response.setValue("X-Weave-Alert", "First weave alert string");
- response.addValue("X-Weave-Alert", "Second weave alert string");
- response.setValue("X-Weave-Records", "50");
-
- super.handle(request, response);
- }
- }
-
- @Test
- public void testHeadersResponse() throws URISyntaxException {
- BaseResource.rewriteLocalhost = false;
- data.startHTTPServer(new HeadersMockServer());
- SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_META_URL)); // URL re-used -- we need any successful response
- TestHeadersSyncStorageRequestDelegate delegate = new TestHeadersSyncStorageRequestDelegate(authHeaderProvider);
- r.delegate = delegate;
- r.post(new JSONObject());
- // Server is stopped in the callback.
- }
-
- public class DeleteMockServer extends MockServer {
- @Override
- public void handle(Request request, Response response) {
- assertNotNull(request.getValue("x-confirm-delete"));
- assertEquals("1", request.getValue("x-confirm-delete"));
- super.handle(request, response);
- }
- }
-
- @Test
- public void testDelete() throws URISyntaxException {
- BaseResource.rewriteLocalhost = false;
- data.startHTTPServer(new DeleteMockServer());
- SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_META_URL)); // URL re-used -- we need any successful response
- TestSyncStorageRequestDelegate delegate = new TestSyncStorageRequestDelegate(authHeaderProvider);
- r.delegate = delegate;
- r.delete();
- // Server is stopped in the callback.
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/SynchronizerHelpers.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/SynchronizerHelpers.java
deleted file mode 100644
index f67f7e334..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/SynchronizerHelpers.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import android.content.Context;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.testhelpers.WBORepository;
-import org.mozilla.gecko.sync.repositories.FetchFailedException;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
-import org.mozilla.gecko.sync.repositories.StoreFailedException;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import java.util.ArrayList;
-import java.util.concurrent.ExecutorService;
-
-public class SynchronizerHelpers {
- public static final String FAIL_SENTINEL = "Fail";
-
- /**
- * Store one at a time, failing if the guid contains FAIL_SENTINEL.
- */
- public static class FailFetchWBORepository extends WBORepository {
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- delegate.deferredCreationDelegate().onSessionCreated(new WBORepositorySession(this) {
- @Override
- public void fetchSince(long timestamp,
- final RepositorySessionFetchRecordsDelegate delegate) {
- super.fetchSince(timestamp, new RepositorySessionFetchRecordsDelegate() {
- @Override
- public void onFetchedRecord(Record record) {
- if (record.guid.contains(FAIL_SENTINEL)) {
- delegate.onFetchFailed(new FetchFailedException(), record);
- } else {
- delegate.onFetchedRecord(record);
- }
- }
-
- @Override
- public void onFetchFailed(Exception ex, Record record) {
- delegate.onFetchFailed(ex, record);
- }
-
- @Override
- public void onFetchCompleted(long fetchEnd) {
- delegate.onFetchCompleted(fetchEnd);
- }
-
- @Override
- public RepositorySessionFetchRecordsDelegate deferredFetchDelegate(ExecutorService executor) {
- return this;
- }
- });
- }
- });
- }
- }
-
- /**
- * Store one at a time, failing if the guid contains FAIL_SENTINEL.
- */
- public static class SerialFailStoreWBORepository extends WBORepository {
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- delegate.deferredCreationDelegate().onSessionCreated(new WBORepositorySession(this) {
- @Override
- public void store(final Record record) throws NoStoreDelegateException {
- if (delegate == null) {
- throw new NoStoreDelegateException();
- }
- if (record.guid.contains(FAIL_SENTINEL)) {
- delegate.onRecordStoreFailed(new StoreFailedException(), record.guid);
- } else {
- super.store(record);
- }
- }
- });
- }
- }
-
- /**
- * Store in batches, failing if any of the batch guids contains "Fail".
- * <p>
- * This will drop the final batch.
- */
- public static class BatchFailStoreWBORepository extends WBORepository {
- public final int batchSize;
- public ArrayList<Record> batch = new ArrayList<Record>();
- public boolean batchShouldFail = false;
-
- public class BatchFailStoreWBORepositorySession extends WBORepositorySession {
- public BatchFailStoreWBORepositorySession(WBORepository repository) {
- super(repository);
- }
-
- public void superStore(final Record record) throws NoStoreDelegateException {
- super.store(record);
- }
-
- @Override
- public void store(final Record record) throws NoStoreDelegateException {
- if (delegate == null) {
- throw new NoStoreDelegateException();
- }
- synchronized (batch) {
- batch.add(record);
- if (record.guid.contains("Fail")) {
- batchShouldFail = true;
- }
-
- if (batch.size() >= batchSize) {
- flush();
- }
- }
- }
-
- public void flush() {
- final ArrayList<Record> thisBatch = new ArrayList<Record>(batch);
- final boolean thisBatchShouldFail = batchShouldFail;
- batchShouldFail = false;
- batch.clear();
- storeWorkQueue.execute(new Runnable() {
- @Override
- public void run() {
- Logger.trace("XXX", "Notifying about batch. Failure? " + thisBatchShouldFail);
- for (Record batchRecord : thisBatch) {
- if (thisBatchShouldFail) {
- delegate.onRecordStoreFailed(new StoreFailedException(), batchRecord.guid);
- } else {
- try {
- superStore(batchRecord);
- } catch (NoStoreDelegateException e) {
- delegate.onRecordStoreFailed(e, batchRecord.guid);
- }
- }
- }
- }
- });
- }
-
- @Override
- public void storeDone() {
- synchronized (batch) {
- flush();
- // Do this in a Runnable so that the timestamp is grabbed after any upload.
- final Runnable r = new Runnable() {
- @Override
- public void run() {
- synchronized (batch) {
- Logger.trace("XXX", "Calling storeDone.");
- storeDone(now());
- }
- }
- };
- storeWorkQueue.execute(r);
- }
- }
- }
- public BatchFailStoreWBORepository(int batchSize) {
- super();
- this.batchSize = batchSize;
- }
-
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- delegate.deferredCreationDelegate().onSessionCreated(new BatchFailStoreWBORepositorySession(this));
- }
- }
-
- public static class TrackingWBORepository extends WBORepository {
- @Override
- public synchronized boolean shouldTrack() {
- return true;
- }
- }
-
- public static class BeginFailedException extends Exception {
- private static final long serialVersionUID = -2349459755976915096L;
- }
-
- public static class FinishFailedException extends Exception {
- private static final long serialVersionUID = -4644528423867070934L;
- }
-
- public static class BeginErrorWBORepository extends TrackingWBORepository {
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- delegate.deferredCreationDelegate().onSessionCreated(new BeginErrorWBORepositorySession(this));
- }
-
- public class BeginErrorWBORepositorySession extends WBORepositorySession {
- public BeginErrorWBORepositorySession(WBORepository repository) {
- super(repository);
- }
-
- @Override
- public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
- delegate.onBeginFailed(new BeginFailedException());
- }
- }
- }
-
- public static class FinishErrorWBORepository extends TrackingWBORepository {
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- delegate.deferredCreationDelegate().onSessionCreated(new FinishErrorWBORepositorySession(this));
- }
-
- public class FinishErrorWBORepositorySession extends WBORepositorySession {
- public FinishErrorWBORepositorySession(WBORepository repository) {
- super(repository);
- }
-
- @Override
- public void finish(final RepositorySessionFinishDelegate delegate) throws InactiveSessionException {
- delegate.onFinishFailed(new FinishFailedException());
- }
- }
- }
-
- public static class DataAvailableWBORepository extends TrackingWBORepository {
- public boolean dataAvailable = true;
-
- public DataAvailableWBORepository(boolean dataAvailable) {
- this.dataAvailable = dataAvailable;
- }
-
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- delegate.deferredCreationDelegate().onSessionCreated(new DataAvailableWBORepositorySession(this));
- }
-
- public class DataAvailableWBORepositorySession extends WBORepositorySession {
- public DataAvailableWBORepositorySession(WBORepository repository) {
- super(repository);
- }
-
- @Override
- public boolean dataAvailable() {
- return dataAvailable;
- }
- }
- }
-
- public static class ShouldSkipWBORepository extends TrackingWBORepository {
- public boolean shouldSkip = true;
-
- public ShouldSkipWBORepository(boolean shouldSkip) {
- this.shouldSkip = shouldSkip;
- }
-
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- delegate.deferredCreationDelegate().onSessionCreated(new ShouldSkipWBORepositorySession(this));
- }
-
- public class ShouldSkipWBORepositorySession extends WBORepositorySession {
- public ShouldSkipWBORepositorySession(WBORepository repository) {
- super(repository);
- }
-
- @Override
- public boolean shouldSkip() {
- return shouldSkip;
- }
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCollectionKeys.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCollectionKeys.java
deleted file mode 100644
index 76791a6ed..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCollectionKeys.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import org.json.simple.JSONArray;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.CollectionKeys;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.NoCollectionKeysSetException;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Set;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestCollectionKeys {
-
- @Test
- public void testDefaultKeys() throws CryptoException, NoCollectionKeysSetException {
- CollectionKeys ck = new CollectionKeys();
- try {
- ck.defaultKeyBundle();
- fail("defaultKeys should throw.");
- } catch (NoCollectionKeysSetException ex) {
- // Good.
- }
- KeyBundle testKeys = KeyBundle.withRandomKeys();
- ck.setDefaultKeyBundle(testKeys);
- assertEquals(testKeys, ck.defaultKeyBundle());
- }
-
- @Test
- public void testKeyForCollection() throws CryptoException, NoCollectionKeysSetException {
- CollectionKeys ck = new CollectionKeys();
- try {
- ck.keyBundleForCollection("test");
- fail("keyForCollection should throw.");
- } catch (NoCollectionKeysSetException ex) {
- // Good.
- }
- KeyBundle testKeys = KeyBundle.withRandomKeys();
- KeyBundle otherKeys = KeyBundle.withRandomKeys();
-
- ck.setDefaultKeyBundle(testKeys);
- assertEquals(testKeys, ck.defaultKeyBundle());
- assertEquals(testKeys, ck.keyBundleForCollection("test")); // Returns default.
-
- ck.setKeyBundleForCollection("test", otherKeys);
- assertEquals(otherKeys, ck.keyBundleForCollection("test")); // Returns default.
-
- }
-
- public static void assertSame(byte[] arrayOne, byte[] arrayTwo) {
- assertTrue(Arrays.equals(arrayOne, arrayTwo));
- }
-
-
- @Test
- public void testSetKeysFromWBO() throws IOException, NonObjectJSONException, CryptoException, NoCollectionKeysSetException {
- String json = "{\"default\":[\"3fI6k1exImMgAKjilmMaAWxGqEIzFX/9K5EjEgH99vc=\",\"/AMaoCX4hzic28WY94XtokNi7N4T0nv+moS1y5wlbug=\"],\"collections\":{},\"collection\":\"crypto\",\"id\":\"keys\"}";
- CryptoRecord rec = new CryptoRecord(json);
-
- KeyBundle syncKeyBundle = new KeyBundle("slyjcrjednxd6rf4cr63vqilmkus6zbe", "6m8mv8ex2brqnrmsb9fjuvfg7y");
- rec.keyBundle = syncKeyBundle;
-
- rec.encrypt();
- CollectionKeys ck = new CollectionKeys();
- ck.setKeyPairsFromWBO(rec, syncKeyBundle);
- byte[] input = "3fI6k1exImMgAKjilmMaAWxGqEIzFX/9K5EjEgH99vc=".getBytes("UTF-8");
- byte[] expected = Base64.decodeBase64(input);
- assertSame(expected, ck.defaultKeyBundle().getEncryptionKey());
- }
-
- @Test
- public void testCryptoRecordFromCollectionKeys() throws CryptoException, NoCollectionKeysSetException, IOException, NonObjectJSONException {
- CollectionKeys ck1 = CollectionKeys.generateCollectionKeys();
- assertNotNull(ck1.defaultKeyBundle());
- assertEquals(ck1.keyBundleForCollection("foobar"), ck1.defaultKeyBundle());
- CryptoRecord rec = ck1.asCryptoRecord();
- assertEquals(rec.collection, "crypto");
- assertEquals(rec.guid, "keys");
- JSONArray defaultKey = (JSONArray) rec.payload.get("default");
-
- assertSame(Base64.decodeBase64((String) (defaultKey.get(0))), ck1.defaultKeyBundle().getEncryptionKey());
- CollectionKeys ck2 = new CollectionKeys();
- ck2.setKeyPairsFromWBO(rec, null);
- assertSame(ck1.defaultKeyBundle().getEncryptionKey(), ck2.defaultKeyBundle().getEncryptionKey());
- }
-
- @Test
- public void testCreateKeysBundle() throws CryptoException, NonObjectJSONException, IOException, NoCollectionKeysSetException {
- String username = "b6evr62dptbxz7fvebek7btljyu322wp";
- String friendlyBase32SyncKey = "basuxv2426eqj7frhvpcwkavdi";
-
- KeyBundle syncKeyBundle = new KeyBundle(username, friendlyBase32SyncKey);
-
- CollectionKeys ck = CollectionKeys.generateCollectionKeys();
- CryptoRecord unencrypted = ck.asCryptoRecord();
- unencrypted.keyBundle = syncKeyBundle;
- CryptoRecord encrypted = unencrypted.encrypt();
-
- CollectionKeys ckDecrypted = new CollectionKeys();
- ckDecrypted.setKeyPairsFromWBO(encrypted, syncKeyBundle);
-
- // Compare decrypted keys to the keys that were set upon creation
- assertArrayEquals(ck.defaultKeyBundle().getEncryptionKey(), ckDecrypted.defaultKeyBundle().getEncryptionKey());
- assertArrayEquals(ck.defaultKeyBundle().getHMACKey(), ckDecrypted.defaultKeyBundle().getHMACKey());
- }
-
- @Test
- public void testDifferences() throws Exception {
- KeyBundle kb1 = KeyBundle.withRandomKeys();
- KeyBundle kb2 = KeyBundle.withRandomKeys();
- KeyBundle kb3 = KeyBundle.withRandomKeys();
- CollectionKeys a = CollectionKeys.generateCollectionKeys();
- CollectionKeys b = CollectionKeys.generateCollectionKeys();
- Set<String> diffs;
-
- a.setKeyBundleForCollection("1", kb1);
- b.setKeyBundleForCollection("1", kb1);
- diffs = CollectionKeys.differences(a, b);
- assertTrue(diffs.isEmpty());
-
- a.setKeyBundleForCollection("2", kb2);
- diffs = CollectionKeys.differences(a, b);
- assertArrayEquals(new String[] { "2" }, diffs.toArray(new String[diffs.size()]));
-
- b.setKeyBundleForCollection("3", kb3);
- diffs = CollectionKeys.differences(a, b);
- assertEquals(2, diffs.size());
- assertTrue(diffs.contains("2"));
- assertTrue(diffs.contains("3"));
-
- b.setKeyBundleForCollection("1", KeyBundle.withRandomKeys());
- diffs = CollectionKeys.differences(a, b);
- assertEquals(3, diffs.size());
-
- // This tests that explicitly setting a default key works.
- a = CollectionKeys.generateCollectionKeys();
- b = CollectionKeys.generateCollectionKeys();
- b.setDefaultKeyBundle(a.defaultKeyBundle());
- a.setKeyBundleForCollection("a", a.defaultKeyBundle());
- b.setKeyBundleForCollection("b", b.defaultKeyBundle());
- assertTrue(CollectionKeys.differences(a, b).isEmpty());
- assertTrue(CollectionKeys.differences(b, a).isEmpty());
- }
-
- @Test
- public void testEquals() throws Exception {
- KeyBundle kb1 = KeyBundle.withRandomKeys();
- KeyBundle kb2 = KeyBundle.withRandomKeys();
- CollectionKeys a = CollectionKeys.generateCollectionKeys();
- CollectionKeys b = CollectionKeys.generateCollectionKeys();
-
- // Random keys are different.
- assertFalse(a.equals(b));
- assertFalse(b.equals(a));
-
- // keys with unset default key bundles are different.
- b.setDefaultKeyBundle(null);
- assertFalse(a.equals(b));
-
- // keys with equal default key bundles and no other collections are the same.
- b.setDefaultKeyBundle(a.defaultKeyBundle());
- assertTrue(a.equals(b));
-
- // keys with equal defaults and equal collections are the same.
- a.setKeyBundleForCollection("1", kb1);
- b.setKeyBundleForCollection("1", kb1);
- assertTrue(a.equals(b));
-
- // keys with equal defaults but some collection missing are different.
- a.setKeyBundleForCollection("2", kb2);
- assertFalse(a.equals(b));
- assertFalse(b.equals(a));
-
- // keys with equal defaults and some collection set to the default are the same.
- a.setKeyBundleForCollection("2", a.defaultKeyBundle());
- b.setKeyBundleForCollection("3", b.defaultKeyBundle());
- assertTrue(a.equals(b));
- assertTrue(b.equals(a));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCommandProcessor.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCommandProcessor.java
deleted file mode 100644
index adab2d738..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCommandProcessor.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.CommandProcessor;
-import org.mozilla.gecko.sync.CommandRunner;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestCommandProcessor extends CommandProcessor {
-
- public static final String commandType = "displayURI";
- public static final String commandWithNoArgs = "{\"command\":\"displayURI\"}";
- public static final String commandWithNoType = "{\"args\":[\"https://bugzilla.mozilla.org/show_bug.cgi?id=731341\",\"PKsljsuqYbGg\"]}";
- public static final String wellFormedCommand = "{\"args\":[\"https://bugzilla.mozilla.org/show_bug.cgi?id=731341\",\"PKsljsuqYbGg\"],\"command\":\"displayURI\"}";
- public static final String wellFormedCommandWithNullArgs = "{\"args\":[\"https://bugzilla.mozilla.org/show_bug.cgi?id=731341\",null,\"PKsljsuqYbGg\",null],\"command\":\"displayURI\"}";
-
- private boolean commandExecuted;
-
- // Session is not used in these tests.
- protected final GlobalSession session = null;
-
- public class MockCommandRunner extends CommandRunner {
- public MockCommandRunner(int argCount) {
- super(argCount);
- }
-
- @Override
- public void executeCommand(final GlobalSession session, List<String> args) {
- commandExecuted = true;
- }
- }
-
- @Test
- public void testRegisterCommand() throws NonObjectJSONException, IOException {
- assertNull(commands.get(commandType));
- this.registerCommand(commandType, new MockCommandRunner(1));
- assertNotNull(commands.get(commandType));
- }
-
- @Test
- public void testProcessRegisteredCommand() throws NonObjectJSONException, IOException {
- commandExecuted = false;
- ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(wellFormedCommand);
- this.registerCommand(commandType, new MockCommandRunner(1));
- this.processCommand(session, unparsedCommand);
- assertTrue(commandExecuted);
- }
-
- @Test
- public void testProcessUnregisteredCommand() throws NonObjectJSONException, IOException {
- commandExecuted = false;
- ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(wellFormedCommand);
- this.processCommand(session, unparsedCommand);
- assertFalse(commandExecuted);
- }
-
- @Test
- public void testProcessInvalidCommand() throws NonObjectJSONException, IOException {
- ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(commandWithNoType);
- this.registerCommand(commandType, new MockCommandRunner(1));
- this.processCommand(session, unparsedCommand);
- assertFalse(commandExecuted);
- }
-
- @Test
- public void testParseCommandNoType() throws NonObjectJSONException, IOException {
- ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(commandWithNoType);
- assertNull(CommandProcessor.parseCommand(unparsedCommand));
- }
-
- @Test
- public void testParseCommandNoArgs() throws NonObjectJSONException, IOException {
- ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(commandWithNoArgs);
- assertNull(CommandProcessor.parseCommand(unparsedCommand));
- }
-
- @Test
- public void testParseWellFormedCommand() throws NonObjectJSONException, IOException {
- ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(wellFormedCommand);
- Command parsedCommand = CommandProcessor.parseCommand(unparsedCommand);
- assertNotNull(parsedCommand);
- assertEquals(2, parsedCommand.args.size());
- assertEquals(commandType, parsedCommand.commandType);
- }
-
- @Test
- public void testParseCommandNullArg() throws NonObjectJSONException, IOException {
- ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(wellFormedCommandWithNullArgs);
- Command parsedCommand = CommandProcessor.parseCommand(unparsedCommand);
- assertNotNull(parsedCommand);
- assertEquals(4, parsedCommand.args.size());
- assertEquals(commandType, parsedCommand.commandType);
- final List<String> expectedArgs = new ArrayList<String>();
- expectedArgs.add("https://bugzilla.mozilla.org/show_bug.cgi?id=731341");
- expectedArgs.add(null);
- expectedArgs.add("PKsljsuqYbGg");
- expectedArgs.add(null);
- assertEquals(expectedArgs, parsedCommand.getArgsList());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCryptoRecord.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCryptoRecord.java
deleted file mode 100644
index a6b91eaf8..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestCryptoRecord.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestCryptoRecord {
- String base64EncryptionKey = "9K/wLdXdw+nrTtXo4ZpECyHFNr4d7aYHqeg3KW9+m6Q=";
- String base64HmacKey = "MMntEfutgLTc8FlTLQFms8/xMPmCldqPlq/QQXEjx70=";
-
- @Test
- public void testBaseCryptoRecordEncrypt() throws IOException, NonObjectJSONException, CryptoException {
-
- ExtendedJSONObject clearPayload = new ExtendedJSONObject("{\"id\":\"5qRsgXWRJZXr\"," +
- "\"title\":\"Index of file:///Users/jason/Library/Application " +
- "Support/Firefox/Profiles/ksgd7wpk.LocalSyncServer/weave/logs/\"," +
- "\"histUri\":\"file:///Users/jason/Library/Application%20Support/Firefox/Profiles" +
- "/ksgd7wpk.LocalSyncServer/weave/logs/\",\"visits\":[{\"type\":1," +
- "\"date\":1319149012372425}]}");
-
- CryptoRecord record = new CryptoRecord();
- record.payload = clearPayload;
- String expectedGUID = "5qRsgXWRJZXr";
- record.guid = expectedGUID;
- record.keyBundle = KeyBundle.fromBase64EncodedKeys(base64EncryptionKey, base64HmacKey);
- record.encrypt();
- assertTrue(record.payload.get("title") == null);
- assertTrue(record.payload.get("ciphertext") != null);
- assertEquals(expectedGUID, record.guid);
- assertEquals(expectedGUID, record.toJSONObject().get("id"));
- record.decrypt();
- assertEquals(expectedGUID, record.toJSONObject().get("id"));
- }
-
- @Test
- public void testEntireRecord() throws Exception {
- // Check a raw JSON blob from a real Sync account.
- String inputString = "{\"sortindex\": 131, \"payload\": \"{\\\"ciphertext\\\":\\\"YJB4dr0vZEIWPirfU2FCJvfzeSLiOP5QWasol2R6ILUxdHsJWuUuvTZVhxYQfTVNou6hVV67jfAvi5Cs+bqhhQsv7icZTiZhPTiTdVGt+uuMotxauVA5OryNGVEZgCCTvT3upzhDFdDbJzVd9O3/gU/b7r/CmAHykX8bTlthlbWeZ8oz6gwHJB5tPRU15nM/m/qW1vyKIw5pw/ZwtAy630AieRehGIGDk+33PWqsfyuT4EUFY9/Ly+8JlnqzxfiBCunIfuXGdLuqTjJOxgrK8mI4wccRFEdFEnmHvh5x7fjl1ID52qumFNQl8zkB75C8XK25alXqwvRR6/AQSP+BgQ==\\\",\\\"IV\\\":\\\"v/0BFgicqYQsd70T39rraA==\\\",\\\"hmac\\\":\\\"59605ed696f6e0e6e062a03510cff742bf6b50d695c042e8372a93f4c2d37dac\\\"}\", \"id\": \"0-P9fabp9vJD\", \"modified\": 1326254123.65}";
- CryptoRecord record = CryptoRecord.fromJSONRecord(inputString);
- assertEquals("0-P9fabp9vJD", record.guid);
- assertEquals(1326254123650L, record.lastModified);
- assertEquals(131, record.sortIndex);
-
- String b64E = "0A7mU5SZ/tu7ZqwXW1og4qHVHN+zgEi4Xwfwjw+vEJw=";
- String b64H = "11GN34O9QWXkjR06g8t0gWE1sGgQeWL0qxxWwl8Dmxs=";
- record.keyBundle = KeyBundle.fromBase64EncodedKeys(b64E, b64H);
- record.decrypt();
-
- assertEquals("0-P9fabp9vJD", record.guid);
- assertEquals(1326254123650L, record.lastModified);
- assertEquals(131, record.sortIndex);
-
- assertEquals("Customize Firefox", record.payload.get("title"));
- assertEquals("0-P9fabp9vJD", record.payload.get("id"));
- assertTrue(record.payload.get("tags") instanceof JSONArray);
- }
-
- @Test
- public void testBaseCryptoRecordDecrypt() throws Exception {
- String base64CipherText =
- "NMsdnRulLwQsVcwxKW9XwaUe7ouJk5Wn"
- + "80QhbD80l0HEcZGCynh45qIbeYBik0lg"
- + "cHbKmlIxTJNwU+OeqipN+/j7MqhjKOGI"
- + "lvbpiPQQLC6/ffF2vbzL0nzMUuSyvaQz"
- + "yGGkSYM2xUFt06aNivoQTvU2GgGmUK6M"
- + "vadoY38hhW2LCMkoZcNfgCqJ26lO1O0s"
- + "EO6zHsk3IVz6vsKiJ2Hq6VCo7hu123wN"
- + "egmujHWQSGyf8JeudZjKzfi0OFRRvvm4"
- + "QAKyBWf0MgrW1F8SFDnVfkq8amCB7Nhd"
- + "whgLWbN+21NitNwWYknoEWe1m6hmGZDg"
- + "DT32uxzWxCV8QqqrpH/ZggViEr9uMgoy"
- + "4lYaWqP7G5WKvvechc62aqnsNEYhH26A"
- + "5QgzmlNyvB+KPFvPsYzxDnSCjOoRSLx7"
- + "GG86wT59QZw=";
- String base64IV = "GX8L37AAb2FZJMzIoXlX8w==";
- String base16Hmac =
- "b1e6c18ac30deb70236bc0d65a46f7a4"
- + "dce3b8b0e02cf92182b914e3afa5eebc";
-
- ExtendedJSONObject body = new ExtendedJSONObject();
- ExtendedJSONObject payload = new ExtendedJSONObject();
- payload.put("ciphertext", base64CipherText);
- payload.put("IV", base64IV);
- payload.put("hmac", base16Hmac);
- body.put("payload", payload.toJSONString());
- CryptoRecord record = CryptoRecord.fromJSONRecord(body);
- byte[] decodedKey = Base64.decodeBase64(base64EncryptionKey.getBytes("UTF-8"));
- byte[] decodedHMAC = Base64.decodeBase64(base64HmacKey.getBytes("UTF-8"));
- record.keyBundle = new KeyBundle(decodedKey, decodedHMAC);
-
- record.decrypt();
- String id = (String) record.payload.get("id");
- assertTrue(id.equals("5qRsgXWRJZXr"));
- }
-
- @Test
- public void testBaseCryptoRecordSyncKeyBundle() throws UnsupportedEncodingException, CryptoException {
- // These values pulled straight out of Firefox.
- String key = "6m8mv8ex2brqnrmsb9fjuvfg7y";
- String user = "c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd";
-
- // Check our friendly base32 decoding.
- assertTrue(Arrays.equals(Utils.decodeFriendlyBase32(key), Base64.decodeBase64("8xbKrJfQYwbFkguKmlSm/g==".getBytes("UTF-8"))));
- KeyBundle bundle = new KeyBundle(user, key);
- String expectedEncryptKeyBase64 = "/8RzbFT396htpZu5rwgIg2WKfyARgm7dLzsF5pwrVz8=";
- String expectedHMACKeyBase64 = "NChGjrqoXYyw8vIYP2334cvmMtsjAMUZNqFwV2LGNkM=";
- byte[] computedEncryptKey = bundle.getEncryptionKey();
- byte[] computedHMACKey = bundle.getHMACKey();
- assertTrue(Arrays.equals(computedEncryptKey, Base64.decodeBase64(expectedEncryptKeyBase64.getBytes("UTF-8"))));
- assertTrue(Arrays.equals(computedHMACKey, Base64.decodeBase64(expectedHMACKeyBase64.getBytes("UTF-8"))));
- }
-
- @Test
- public void testDecrypt() throws Exception {
- String jsonInput = "{\"sortindex\": 90, \"payload\":" +
- "\"{\\\"ciphertext\\\":\\\"F4ukf0" +
- "LM+vhffiKyjaANXeUhfmOPPmQYX1XBoG" +
- "Rh1LiHeKHB5rqjhzd7yAoxqgmFnkIgQF" +
- "YPSqRAoCxWiAeGULTX+KM4MU5drbNyR/" +
- "690JBWSyE1vQSiMGwNIbTKnOLGHKkQVY" +
- "HDpajg5BNFfvHNQ5Jx7uM9uJcmuEjCI6" +
- "GRMDKyKjhsTqCd99MONkY5rISutaWQ0e" +
- "EXFgpA9RZPv4jgWlQhe+YrVnpcrTi20b" +
- "NgKp3IfIeqEelrZ5FJd2WGZOA021d3e7" +
- "P3Z4qptefH4Q9/hySrWsELWngBaydyn/" +
- "IjsheZuKra3kJSST/4SvRZ7qXn\\\",\\" +
- "\"IV\\\":\\\"GadPajeXhpk75K2YH+L" +
- "y4w==\\\",\\\"hmac\\\":\\\"71442" +
- "d946502e3ca475c70a633d3d37f4b4e9" +
- "313a6d1041d0c0550cd354e7605\\\"}" +
- "\", \"id\": \"hkZYpC-BH4Xi\", \"" +
- "modified\": 1320183464.21}";
- String base64EncryptionKey = "K8fV6PHG8RgugfHexGesbzTeOs2o12cr" +
- "N/G3bz0Bx1M=";
- String base64HmacKey = "nbceuI6w1RJbBzh+iCJHEs8p4lElsOma" +
- "yUhx+OztVgM=";
- String expectedDecryptedText = "{\"id\":\"hkZYpC-BH4Xi\",\"histU" +
- "ri\":\"http://hathology.com/2008" +
- "/06/how-to-edit-your-path-enviro" +
- "nment-variables-on-mac-os-x/\",\"" +
- "title\":\"How To Edit Your PATH " +
- "Environment Variables On Mac OS " +
- "X\",\"visits\":[{\"date\":131898" +
- "2074310889,\"type\":1}]}";
-
- KeyBundle keyBundle = KeyBundle.fromBase64EncodedKeys(base64EncryptionKey, base64HmacKey);
-
- CryptoRecord encrypted = CryptoRecord.fromJSONRecord(jsonInput);
- encrypted.keyBundle = keyBundle;
- CryptoRecord decrypted = encrypted.decrypt();
-
- // We don't necessarily produce exactly the same JSON but we do have the same values.
- ExtendedJSONObject expectedJson = new ExtendedJSONObject(expectedDecryptedText);
- assertEquals(expectedJson.get("id"), decrypted.payload.get("id"));
- assertEquals(expectedJson.get("title"), decrypted.payload.get("title"));
- assertEquals(expectedJson.get("histUri"), decrypted.payload.get("histUri"));
- }
-
- @Test
- public void testEncryptDecrypt() throws Exception {
- String originalText = "{\"id\":\"hkZYpC-BH4Xi\",\"histU" +
- "ri\":\"http://hathology.com/2008" +
- "/06/how-to-edit-your-path-enviro" +
- "nment-variables-on-mac-os-x/\",\"" +
- "title\":\"How To Edit Your PATH " +
- "Environment Variables On Mac OS " +
- "X\",\"visits\":[{\"date\":131898" +
- "2074310889,\"type\":1}]}";
- String base64EncryptionKey = "K8fV6PHG8RgugfHexGesbzTeOs2o12cr" +
- "N/G3bz0Bx1M=";
- String base64HmacKey = "nbceuI6w1RJbBzh+iCJHEs8p4lElsOma" +
- "yUhx+OztVgM=";
-
- KeyBundle keyBundle = KeyBundle.fromBase64EncodedKeys(base64EncryptionKey, base64HmacKey);
-
- // Encrypt.
- CryptoRecord unencrypted = new CryptoRecord(originalText);
- unencrypted.keyBundle = keyBundle;
- CryptoRecord encrypted = unencrypted.encrypt();
-
- // Decrypt after round-trip through JSON.
- CryptoRecord undecrypted = CryptoRecord.fromJSONRecord(encrypted.toJSONString());
- undecrypted.keyBundle = keyBundle;
- CryptoRecord decrypted = undecrypted.decrypt();
-
- // We don't necessarily produce exactly the same JSON but we do have the same values.
- ExtendedJSONObject expectedJson = new ExtendedJSONObject(originalText);
- assertEquals(expectedJson.get("id"), decrypted.payload.get("id"));
- assertEquals(expectedJson.get("title"), decrypted.payload.get("title"));
- assertEquals(expectedJson.get("histUri"), decrypted.payload.get("histUri"));
- }
-
- @Test
- public void testDecryptKeysBundle() throws Exception {
- String jsonInput = "{\"payload\": \"{\\\"ciphertext\\" +
- "\":\\\"L1yRyZBkVYKXC1cTpeUqqfmKg" +
- "CinYV9YntGiG0PfYZSTLQ2s86WPI0VBb" +
- "QbLZfx7udk6sf6CFE4w5EgiPx0XP3Fbj" +
- "L7r4qIT0vjbAOrLKedZwA3cgiquc+PXM" +
- "Etml8B4Dfm0crJK0iROlRkb+lePAYkzI" +
- "iQn5Ba8mSWQEFoLy3zAcfCYXumA7E0Fj" +
- "XYD+TqTG5bqYJY4zvPaB9mn9y3WHw==\\" +
- "\",\\\"IV\\\":\\\"Jjb2oVI5uvvFfm" +
- "ZYRY4GaA==\\\",\\\"hmac\\\":\\\"" +
- "0b59731cb1aaedc85f54917b7058f361" +
- "60826b70050b0d70cd42b0b609b1d717" +
- "\\\"}\", \"id\": \"keys\", \"mod" +
- "ified\": 1320183463.91}";
- String username = "b6evr62dptbxz7fvebek7btljyu322wp";
- String friendlyBase32SyncKey = "basuxv2426eqj7frhvpcwkavdi";
- String expectedDecryptedText = "{\"default\":[\"K8fV6PHG8RgugfHe" +
- "xGesbzTeOs2o12crN/G3bz0Bx1M=\",\"" +
- "nbceuI6w1RJbBzh+iCJHEs8p4lElsOma" +
- "yUhx+OztVgM=\"],\"collections\":" +
- "{},\"collection\":\"crypto\",\"i" +
- "d\":\"keys\"}";
- String expectedBase64EncryptionKey = "K8fV6PHG8RgugfHexGesbzTeOs2o12cr" +
- "N/G3bz0Bx1M=";
- String expectedBase64HmacKey = "nbceuI6w1RJbBzh+iCJHEs8p4lElsOma" +
- "yUhx+OztVgM=";
-
- KeyBundle syncKeyBundle = new KeyBundle(username, friendlyBase32SyncKey);
-
- ExtendedJSONObject json = new ExtendedJSONObject(jsonInput);
- assertEquals("keys", json.get("id"));
-
- CryptoRecord encrypted = CryptoRecord.fromJSONRecord(jsonInput);
- encrypted.keyBundle = syncKeyBundle;
- CryptoRecord decrypted = encrypted.decrypt();
-
- // We don't necessarily produce exactly the same JSON but we do have the same values.
- ExtendedJSONObject expectedJson = new ExtendedJSONObject(expectedDecryptedText);
- assertEquals(expectedJson.get("id"), decrypted.payload.get("id"));
- assertEquals(expectedJson.get("default"), decrypted.payload.get("default"));
- assertEquals(expectedJson.get("collection"), decrypted.payload.get("collection"));
- assertEquals(expectedJson.get("collections"), decrypted.payload.get("collections"));
-
- // Check that the extracted keys were as expected.
- JSONArray keys = new ExtendedJSONObject(decrypted.payload.toJSONString()).getArray("default");
- KeyBundle keyBundle = KeyBundle.fromBase64EncodedKeys((String)keys.get(0), (String)keys.get(1));
-
- assertArrayEquals(Base64.decodeBase64(expectedBase64EncryptionKey.getBytes("UTF-8")), keyBundle.getEncryptionKey());
- assertArrayEquals(Base64.decodeBase64(expectedBase64HmacKey.getBytes("UTF-8")), keyBundle.getHMACKey());
- }
-
- @Test
- public void testTTL() throws UnsupportedEncodingException, CryptoException {
- Record historyRecord = new HistoryRecord();
- CryptoRecord cryptoRecord = historyRecord.getEnvelope();
- assertEquals(historyRecord.ttl, cryptoRecord.ttl);
-
- // Very important that ttls are set in outbound envelopes.
- JSONObject o = cryptoRecord.toJSONObject();
- assertEquals(cryptoRecord.ttl, o.get("ttl"));
-
- // Most important of all, outbound encrypted record envelopes.
- KeyBundle keyBundle = KeyBundle.withRandomKeys();
- cryptoRecord.keyBundle = keyBundle;
- cryptoRecord.encrypt();
- assertEquals(historyRecord.ttl, cryptoRecord.ttl); // Should be preserved.
- o = cryptoRecord.toJSONObject();
- assertEquals(cryptoRecord.ttl, o.get("ttl"));
-
- // But we should ignore negative ttls.
- Record clientRecord = new ClientRecord();
- clientRecord.ttl = -1; // Don't ttl this record.
- o = clientRecord.getEnvelope().toJSONObject();
- assertNull(o.get("ttl"));
-
- // But we should ignore negative ttls in outbound encrypted record envelopes.
- cryptoRecord = clientRecord.getEnvelope();
- cryptoRecord.keyBundle = keyBundle;
- cryptoRecord.encrypt();
- o = cryptoRecord.toJSONObject();
- assertNull(o.get("ttl"));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecord.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecord.java
deleted file mode 100644
index 473534aac..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecord.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.db.Tab;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-import org.mozilla.gecko.sync.repositories.domain.RecordParseException;
-import org.mozilla.gecko.sync.repositories.domain.TabsRecord;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestRecord {
-
- @SuppressWarnings("static-method")
- @Test
- public void testQueryRecord() throws NonObjectJSONException, IOException {
- final String expectedGUID = "Bl3n3gpKag3s";
- final String testRecord =
- "{\"id\":\"" + expectedGUID + "\"," +
- " \"type\":\"query\"," +
- " \"title\":\"Downloads\"," +
- " \"parentName\":\"\"," +
- " \"bmkUri\":\"place:transition=7&sort=4\"," +
- " \"tags\":[]," +
- " \"keyword\":null," +
- " \"description\":null," +
- " \"loadInSidebar\":false," +
- " \"parentid\":\"BxfRgGiNeITG\"}";
-
- final ExtendedJSONObject o = new ExtendedJSONObject(testRecord);
- final CryptoRecord cr = new CryptoRecord(o);
- cr.guid = expectedGUID;
- cr.lastModified = System.currentTimeMillis();
- cr.collection = "bookmarks";
-
- final BookmarkRecord r = new BookmarkRecord("Bl3n3gpKag3s", "bookmarks");
- r.initFromEnvelope(cr);
- assertEquals(expectedGUID, r.guid);
- assertEquals("query", r.type);
- assertEquals("places:uri=place%3Atransition%3D7%26sort%3D4", r.bookmarkURI);
-
- // Check that we get the same bookmark URI out the other end,
- // once we've parsed it into a CryptoRecord, a BookmarkRecord, then
- // back into a CryptoRecord.
- assertEquals("place:transition=7&sort=4", r.getEnvelope().payload.getString("bmkUri"));
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testRecordGUIDs() {
- for (int i = 0; i < 50; ++i) {
- CryptoRecord cryptoRecord = new HistoryRecord().getEnvelope();
- assertEquals(12, cryptoRecord.guid.length());
- }
- }
-
- @Test
- public void testRecordEquality() {
- long now = System.currentTimeMillis();
- BookmarkRecord bOne = new BookmarkRecord("abcdefghijkl", "bookmarks", now , false);
- BookmarkRecord bTwo = new BookmarkRecord("abcdefghijkl", "bookmarks", now , false);
- HistoryRecord hOne = new HistoryRecord("mbcdefghijkm", "history", now , false);
- HistoryRecord hTwo = new HistoryRecord("mbcdefghijkm", "history", now , false);
-
- // Identical records.
- assertFalse(bOne == bTwo);
- assertTrue(bOne.equals(bTwo));
- assertTrue(bOne.equalPayloads(bTwo));
- assertTrue(bOne.congruentWith(bTwo));
- assertTrue(bTwo.equals(bOne));
- assertTrue(bTwo.equalPayloads(bOne));
- assertTrue(bTwo.congruentWith(bOne));
-
- // Null checking.
- assertFalse(bOne.equals(null));
- assertFalse(bOne.equalPayloads(null));
- assertFalse(bOne.congruentWith(null));
-
- // Different types.
- hOne.guid = bOne.guid;
- assertFalse(bOne.equals(hOne));
- assertFalse(bOne.equalPayloads(hOne));
- assertFalse(bOne.congruentWith(hOne));
- hOne.guid = hTwo.guid;
-
- // Congruent androidID.
- bOne.androidID = 1;
- assertFalse(bOne.equals(bTwo));
- assertTrue(bOne.equalPayloads(bTwo));
- assertTrue(bOne.congruentWith(bTwo));
- assertFalse(bTwo.equals(bOne));
- assertTrue(bTwo.equalPayloads(bOne));
- assertTrue(bTwo.congruentWith(bOne));
-
- // Non-congruent androidID.
- bTwo.androidID = 2;
- assertFalse(bOne.equals(bTwo));
- assertTrue(bOne.equalPayloads(bTwo));
- assertFalse(bOne.congruentWith(bTwo));
- assertFalse(bTwo.equals(bOne));
- assertTrue(bTwo.equalPayloads(bOne));
- assertFalse(bTwo.congruentWith(bOne));
-
- // Identical androidID.
- bOne.androidID = 2;
- assertTrue(bOne.equals(bTwo));
- assertTrue(bOne.equalPayloads(bTwo));
- assertTrue(bOne.congruentWith(bTwo));
- assertTrue(bTwo.equals(bOne));
- assertTrue(bTwo.equalPayloads(bOne));
- assertTrue(bTwo.congruentWith(bOne));
-
- // Different times.
- bTwo.lastModified += 1000;
- assertFalse(bOne.equals(bTwo));
- assertTrue(bOne.equalPayloads(bTwo));
- assertTrue(bOne.congruentWith(bTwo));
- assertFalse(bTwo.equals(bOne));
- assertTrue(bTwo.equalPayloads(bOne));
- assertTrue(bTwo.congruentWith(bOne));
-
- // Add some visits.
- JSONObject v1 = fakeVisit(now - 1000);
- JSONObject v2 = fakeVisit(now - 500);
-
- hOne.fennecDateVisited = now + 2000;
- hOne.fennecVisitCount = 1;
- assertFalse(hOne.equals(hTwo));
- assertTrue(hOne.equalPayloads(hTwo));
- assertTrue(hOne.congruentWith(hTwo));
- addVisit(hOne, v1);
- assertFalse(hOne.equals(hTwo));
- assertFalse(hOne.equalPayloads(hTwo));
- assertTrue(hOne.congruentWith(hTwo));
- addVisit(hTwo, v2);
- assertFalse(hOne.equals(hTwo));
- assertFalse(hOne.equalPayloads(hTwo));
- assertTrue(hOne.congruentWith(hTwo));
-
- // Now merge the visits.
- addVisit(hTwo, v1);
- addVisit(hOne, v2);
- assertFalse(hOne.equals(hTwo));
- assertTrue(hOne.equalPayloads(hTwo));
- assertTrue(hOne.congruentWith(hTwo));
- hTwo.fennecDateVisited = hOne.fennecDateVisited;
- hTwo.fennecVisitCount = hOne.fennecVisitCount = 2;
- assertTrue(hOne.equals(hTwo));
- assertTrue(hOne.equalPayloads(hTwo));
- assertTrue(hOne.congruentWith(hTwo));
- }
-
- @SuppressWarnings("unchecked")
- private void addVisit(HistoryRecord r, JSONObject visit) {
- if (r.visits == null) {
- r.visits = new JSONArray();
- }
- r.visits.add(visit);
- }
-
- @SuppressWarnings("unchecked")
- private JSONObject fakeVisit(long time) {
- JSONObject object = new JSONObject();
- object.put("type", 1L);
- object.put("date", time * 1000);
- return object;
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testTabParsing() throws Exception {
- String json = "{\"title\":\"mozilla-central mozilla/browser/base/content/syncSetup.js\"," +
- " \"urlHistory\":[\"http://mxr.mozilla.org/mozilla-central/source/browser/base/content/syncSetup.js#72\"]," +
- " \"icon\":\"http://mxr.mozilla.org/mxr.png\"," +
- " \"lastUsed\":\"1306374531\"}";
- Tab tab = TabsRecord.tabFromJSONObject(new ExtendedJSONObject(json).object);
-
- assertEquals("mozilla-central mozilla/browser/base/content/syncSetup.js", tab.title);
- assertEquals("http://mxr.mozilla.org/mxr.png", tab.icon);
- assertEquals("http://mxr.mozilla.org/mozilla-central/source/browser/base/content/syncSetup.js#72", tab.history.get(0));
- assertEquals(1306374531000L, tab.lastUsed);
-
- String zeroJSON = "{\"title\":\"a\"," +
- " \"urlHistory\":[\"http://example.com\"]," +
- " \"icon\":\"\"," +
- " \"lastUsed\":0}";
- Tab zero = TabsRecord.tabFromJSONObject(new ExtendedJSONObject(zeroJSON).object);
-
- assertEquals("a", zero.title);
- assertEquals("", zero.icon);
- assertEquals("http://example.com", zero.history.get(0));
- assertEquals(0L, zero.lastUsed);
- }
-
- @SuppressWarnings({ "unchecked", "static-method" })
- @Test
- public void testTabsRecordCreation() throws Exception {
- final TabsRecord record = new TabsRecord("testGuid");
- record.clientName = "test client name";
-
- final JSONArray history1 = new JSONArray();
- history1.add("http://test.com/test1.html");
- final Tab tab1 = new Tab("test title 1", "http://test.com/test1.png", history1, 1000);
-
- final JSONArray history2 = new JSONArray();
- history2.add("http://test.com/test2.html#1");
- history2.add("http://test.com/test2.html#2");
- history2.add("http://test.com/test2.html#3");
- final Tab tab2 = new Tab("test title 2", "http://test.com/test2.png", history2, 2000);
-
- record.tabs = new ArrayList<Tab>();
- record.tabs.add(tab1);
- record.tabs.add(tab2);
-
- final TabsRecord parsed = new TabsRecord();
- parsed.initFromEnvelope(CryptoRecord.fromJSONRecord(record.getEnvelope().toJSONString()));
-
- assertEquals(record.guid, parsed.guid);
- assertEquals(record.clientName, parsed.clientName);
- assertEquals(record.tabs, parsed.tabs);
-
- // Verify that equality test doesn't always return true.
- parsed.tabs.get(0).history.add("http://test.com/different.html");
- assertFalse(record.tabs.equals(parsed.tabs));
- }
-
- public static class URITestBookmarkRecord extends BookmarkRecord {
- public static void doTest() {
- assertEquals("places:uri=abc%26def+baz&p1=123&p2=bar+baz",
- encodeUnsupportedTypeURI("abc&def baz", "p1", "123", "p2", "bar baz"));
- assertEquals("places:uri=abc%26def+baz&p1=123",
- encodeUnsupportedTypeURI("abc&def baz", "p1", "123", null, "bar baz"));
- assertEquals("places:p1=123",
- encodeUnsupportedTypeURI(null, "p1", "123", "p2", null));
- }
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testEncodeURI() {
- URITestBookmarkRecord.doTest();
- }
-
- private static final String payload =
- "{\"id\":\"M5bwUKK8hPyF\"," +
- "\"type\":\"livemark\"," +
- "\"siteUri\":\"http://www.bbc.co.uk/go/rss/int/news/-/news/\"," +
- "\"feedUri\":\"http://fxfeeds.mozilla.com/en-US/firefox/headlines.xml\"," +
- "\"parentName\":\"Bookmarks Toolbar\"," +
- "\"parentid\":\"toolbar\"," +
- "\"title\":\"Latest Headlines\"," +
- "\"description\":\"\"," +
- "\"children\":" +
- "[\"7oBdEZB-8BMO\", \"SUd1wktMNCTB\", \"eZe4QWzo1BcY\", \"YNBhGwhVnQsN\"," +
- "\"mNTdpgoRZMbW\", \"-L8Vci6CbkJY\", \"bVzudKSQERc1\", \"Gxl9lb4DXsmL\"," +
- "\"3Qr13GucOtEh\"]}";
-
- public class PayloadBookmarkRecord extends BookmarkRecord {
- public PayloadBookmarkRecord() {
- super("abcdefghijkl", "bookmarks", 1234, false);
- }
-
- public void doTest() throws NonObjectJSONException, IOException {
- this.initFromPayload(new ExtendedJSONObject(payload));
- assertEquals("abcdefghijkl", this.guid); // Ignores payload.
- assertEquals("livemark", this.type);
- assertEquals("Bookmarks Toolbar", this.parentName);
- assertEquals("toolbar", this.parentID);
- assertEquals("", this.description);
- assertEquals(null, this.children);
-
- final String encodedSite = "http%3A%2F%2Fwww.bbc.co.uk%2Fgo%2Frss%2Fint%2Fnews%2F-%2Fnews%2F";
- final String encodedFeed = "http%3A%2F%2Ffxfeeds.mozilla.com%2Fen-US%2Ffirefox%2Fheadlines.xml";
- final String expectedURI = "places:siteUri=" + encodedSite + "&feedUri=" + encodedFeed;
- assertEquals(expectedURI, this.bookmarkURI);
- }
- }
-
- @Test
- public void testUnusualBookmarkRecords() throws NonObjectJSONException, IOException {
- PayloadBookmarkRecord record = new PayloadBookmarkRecord();
- record.doTest();
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testTTL() {
- Record record = new HistoryRecord();
- assertEquals(HistoryRecord.HISTORY_TTL, record.ttl);
-
- // ClientRecords are transient, HistoryRecords are not.
- Record clientRecord = new ClientRecord();
- assertTrue(clientRecord.ttl < record.ttl);
-
- CryptoRecord cryptoRecord = record.getEnvelope();
- assertEquals(record.ttl, cryptoRecord.ttl);
- }
-
- @Test
- public void testStringModified() throws Exception {
- // modified member is a string, expected a floating point number with 2
- // decimal digits.
- String badJson = "{\"sortindex\":\"0\",\"payload\":\"{\\\"syncID\\\":\\\"ZJOqMBjhBthH\\\",\\\"storageVersion\\\":5,\\\"engines\\\":{\\\"clients\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"4oTBXG20rJH5\\\"},\\\"bookmarks\\\":{\\\"version\\\":2,\\\"syncID\\\":\\\"JiMJXy8xI3fr\\\"},\\\"forms\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"J17vSloroXBU\\\"},\\\"history\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"y1HgpbSc3LJT\\\"},\\\"passwords\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"v3y-RidcCuT5\\\"},\\\"prefs\\\":{\\\"version\\\":2,\\\"syncID\\\":\\\"LvfqmT7cUUm4\\\"},\\\"tabs\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"MKMRlBah2d9D\\\"},\\\"addons\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"Ih2hhRrcGjh4\\\"}}}\",\"id\":\"global\",\"modified\":\"1370689360.28\"}";
- try {
- CryptoRecord.fromJSONRecord(badJson);
- fail("Expected exception.");
- } catch (Exception e) {
- assertTrue(e instanceof RecordParseException);
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecordsChannel.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecordsChannel.java
deleted file mode 100644
index 69d3c32e7..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestRecordsChannel.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.SynchronizerHelpers.FailFetchWBORepository;
-import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionCreationDelegate;
-import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionFinishDelegate;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WBORepository;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-import org.mozilla.gecko.sync.synchronizer.RecordsChannel;
-import org.mozilla.gecko.sync.synchronizer.RecordsChannelDelegate;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestRecordsChannel {
-
- protected WBORepository remote;
- protected WBORepository local;
-
- protected RepositorySession source;
- protected RepositorySession sink;
- protected RecordsChannelDelegate rcDelegate;
-
- protected AtomicInteger numFlowFetchFailed;
- protected AtomicInteger numFlowStoreFailed;
- protected AtomicInteger numFlowCompleted;
- protected AtomicBoolean flowBeginFailed;
- protected AtomicBoolean flowFinishFailed;
-
- public void doFlow(final Repository remote, final Repository local) throws Exception {
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- remote.createSession(new ExpectSuccessRepositorySessionCreationDelegate(WaitHelper.getTestWaiter()) {
- @Override
- public void onSessionCreated(RepositorySession session) {
- source = session;
- local.createSession(new ExpectSuccessRepositorySessionCreationDelegate(WaitHelper.getTestWaiter()) {
- @Override
- public void onSessionCreated(RepositorySession session) {
- sink = session;
- WaitHelper.getTestWaiter().performNotify();
- }
- }, null);
- }
- }, null);
- }
- });
-
- assertNotNull(source);
- assertNotNull(sink);
-
- numFlowFetchFailed = new AtomicInteger(0);
- numFlowStoreFailed = new AtomicInteger(0);
- numFlowCompleted = new AtomicInteger(0);
- flowBeginFailed = new AtomicBoolean(false);
- flowFinishFailed = new AtomicBoolean(false);
-
- rcDelegate = new RecordsChannelDelegate() {
- @Override
- public void onFlowFetchFailed(RecordsChannel recordsChannel, Exception ex) {
- numFlowFetchFailed.incrementAndGet();
- }
-
- @Override
- public void onFlowStoreFailed(RecordsChannel recordsChannel, Exception ex, String recordGuid) {
- numFlowStoreFailed.incrementAndGet();
- }
-
- @Override
- public void onFlowFinishFailed(RecordsChannel recordsChannel, Exception ex) {
- flowFinishFailed.set(true);
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void onFlowCompleted(RecordsChannel recordsChannel, long fetchEnd, long storeEnd) {
- numFlowCompleted.incrementAndGet();
- try {
- sink.finish(new ExpectSuccessRepositorySessionFinishDelegate(WaitHelper.getTestWaiter()) {
- @Override
- public void onFinishSucceeded(RepositorySession session, RepositorySessionBundle bundle) {
- try {
- source.finish(new ExpectSuccessRepositorySessionFinishDelegate(WaitHelper.getTestWaiter()) {
- @Override
- public void onFinishSucceeded(RepositorySession session, RepositorySessionBundle bundle) {
- performNotify();
- }
- });
- } catch (InactiveSessionException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
- });
- } catch (InactiveSessionException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
-
- @Override
- public void onFlowBeginFailed(RecordsChannel recordsChannel, Exception ex) {
- flowBeginFailed.set(true);
- WaitHelper.getTestWaiter().performNotify();
- }
- };
-
- final RecordsChannel rc = new RecordsChannel(source, sink, rcDelegate);
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- try {
- rc.beginAndFlow();
- } catch (InvalidSessionTransitionException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
- });
- }
-
- public static final BookmarkRecord[] inbounds = new BookmarkRecord[] {
- new BookmarkRecord("inboundSucc1", "bookmarks", 1, false),
- new BookmarkRecord("inboundSucc2", "bookmarks", 1, false),
- new BookmarkRecord("inboundFail1", "bookmarks", 1, false),
- new BookmarkRecord("inboundSucc3", "bookmarks", 1, false),
- new BookmarkRecord("inboundSucc4", "bookmarks", 1, false),
- new BookmarkRecord("inboundFail2", "bookmarks", 1, false),
- };
- public static final BookmarkRecord[] outbounds = new BookmarkRecord[] {
- new BookmarkRecord("outboundSucc1", "bookmarks", 1, false),
- new BookmarkRecord("outboundSucc2", "bookmarks", 1, false),
- new BookmarkRecord("outboundSucc3", "bookmarks", 1, false),
- new BookmarkRecord("outboundSucc4", "bookmarks", 1, false),
- new BookmarkRecord("outboundSucc5", "bookmarks", 1, false),
- new BookmarkRecord("outboundFail6", "bookmarks", 1, false),
- };
-
- protected WBORepository empty() {
- WBORepository repo = new SynchronizerHelpers.TrackingWBORepository();
- return repo;
- }
-
- protected WBORepository full() {
- WBORepository repo = new SynchronizerHelpers.TrackingWBORepository();
- for (BookmarkRecord outbound : outbounds) {
- repo.wbos.put(outbound.guid, outbound);
- }
- return repo;
- }
-
- protected WBORepository failingFetch() {
- WBORepository repo = new FailFetchWBORepository();
- for (BookmarkRecord outbound : outbounds) {
- repo.wbos.put(outbound.guid, outbound);
- }
- return repo;
- }
-
- @Test
- public void testSuccess() throws Exception {
- WBORepository source = full();
- WBORepository sink = empty();
- doFlow(source, sink);
- assertEquals(1, numFlowCompleted.get());
- assertEquals(0, numFlowFetchFailed.get());
- assertEquals(0, numFlowStoreFailed.get());
- assertEquals(source.wbos, sink.wbos);
- }
-
- @Test
- public void testFetchFail() throws Exception {
- WBORepository source = failingFetch();
- WBORepository sink = empty();
- doFlow(source, sink);
- assertEquals(1, numFlowCompleted.get());
- assertTrue(numFlowFetchFailed.get() > 0);
- assertEquals(0, numFlowStoreFailed.get());
- assertTrue(sink.wbos.size() < 6);
- }
-
- @Test
- public void testStoreSerialFail() throws Exception {
- WBORepository source = full();
- WBORepository sink = new SynchronizerHelpers.SerialFailStoreWBORepository();
- doFlow(source, sink);
- assertEquals(1, numFlowCompleted.get());
- assertEquals(0, numFlowFetchFailed.get());
- assertEquals(1, numFlowStoreFailed.get());
- assertEquals(5, sink.wbos.size());
- }
-
- @Test
- public void testStoreBatchesFail() throws Exception {
- WBORepository source = full();
- WBORepository sink = new SynchronizerHelpers.BatchFailStoreWBORepository(3);
- doFlow(source, sink);
- assertEquals(1, numFlowCompleted.get());
- assertEquals(0, numFlowFetchFailed.get());
- assertEquals(3, numFlowStoreFailed.get()); // One batch fails.
- assertEquals(3, sink.wbos.size()); // One batch succeeds.
- }
-
-
- @Test
- public void testStoreOneBigBatchFail() throws Exception {
- WBORepository source = full();
- WBORepository sink = new SynchronizerHelpers.BatchFailStoreWBORepository(50);
- doFlow(source, sink);
- assertEquals(1, numFlowCompleted.get());
- assertEquals(0, numFlowFetchFailed.get());
- assertEquals(6, numFlowStoreFailed.get()); // One (big) batch fails.
- assertEquals(0, sink.wbos.size()); // No batches succeed.
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestResetCommands.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestResetCommands.java
deleted file mode 100644
index 22bcc5093..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestResetCommands.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import android.content.SharedPreferences;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.DefaultGlobalSessionCallback;
-import org.mozilla.gecko.background.testhelpers.MockPrefsGlobalSession;
-import org.mozilla.gecko.background.testhelpers.MockServerSyncStage;
-import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.CommandProcessor;
-import org.mozilla.gecko.sync.EngineSettings;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.MetaGlobalException;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-import java.io.IOException;
-import java.util.HashMap;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Test that reset commands properly invoke the reset methods on the correct stage.
- */
-@RunWith(TestRunner.class)
-public class TestResetCommands {
- private static final String TEST_USERNAME = "johndoe";
- private static final String TEST_PASSWORD = "password";
- private static final String TEST_SYNC_KEY = "abcdeabcdeabcdeabcdeabcdea";
-
- public static void performNotify() {
- WaitHelper.getTestWaiter().performNotify();
- }
-
- public static void performNotify(Throwable e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
-
- public static void performWait(Runnable runnable) {
- WaitHelper.getTestWaiter().performWait(runnable);
- }
-
- @Before
- public void setUp() {
- assertTrue(WaitHelper.getTestWaiter().isIdle());
- }
-
- @Test
- public void testHandleResetCommand() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException {
- // Create a global session.
- // Set up stage mappings for a real stage name (because they're looked up by name
- // in an enumeration) pointing to our fake stage.
- // Send a reset command.
- // Verify that reset is called on our stage.
-
- class Result {
- public boolean called = false;
- }
-
- final Result yes = new Result();
- final Result no = new Result();
- final GlobalSessionCallback callback = createGlobalSessionCallback();
-
- // So we can poke at stages separately.
- final HashMap<Stage, GlobalSyncStage> stagesToRun = new HashMap<Stage, GlobalSyncStage>();
-
- // Side-effect: modifies global command processor.
- final SharedPreferences prefs = new MockSharedPreferences();
- final SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), prefs);
- config.syncKeyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY);
- final GlobalSession session = new MockPrefsGlobalSession(config, callback, null, null) {
- @Override
- public boolean isEngineRemotelyEnabled(String engineName,
- EngineSettings engineSettings)
- throws MetaGlobalException {
- return true;
- }
-
- @Override
- public void advance() {
- // So we don't proceed and run other stages.
- }
-
- @Override
- public void prepareStages() {
- this.stages = stagesToRun;
- }
- };
-
- final MockServerSyncStage stageGetsReset = new MockServerSyncStage() {
- @Override
- public void resetLocal() {
- yes.called = true;
- }
- };
-
- final MockServerSyncStage stageNotReset = new MockServerSyncStage() {
- @Override
- public void resetLocal() {
- no.called = true;
- }
- };
-
- stagesToRun.put(Stage.syncBookmarks, stageGetsReset);
- stagesToRun.put(Stage.syncHistory, stageNotReset);
-
- final String resetBookmarks = "{\"args\":[\"bookmarks\"],\"command\":\"resetEngine\"}";
- ExtendedJSONObject unparsedCommand = new ExtendedJSONObject(resetBookmarks);
- CommandProcessor processor = CommandProcessor.getProcessor();
- processor.processCommand(session, unparsedCommand);
-
- assertTrue(yes.called);
- assertFalse(no.called);
- }
-
- public void testHandleWipeCommand() {
- // TODO
- }
-
- private static GlobalSessionCallback createGlobalSessionCallback() {
- return new DefaultGlobalSessionCallback() {
-
- @Override
- public void handleAborted(GlobalSession globalSession, String reason) {
- performNotify(new Exception("Aborted"));
- }
-
- @Override
- public void handleError(GlobalSession globalSession, Exception ex) {
- performNotify(ex);
- }
-
- @Override
- public void handleSuccess(GlobalSession globalSession) {
- }
- };
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestServer11RepositorySession.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestServer11RepositorySession.java
deleted file mode 100644
index 96a366c2d..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestServer11RepositorySession.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.SynchronizerHelpers.TrackingWBORepository;
-import org.mozilla.android.sync.test.helpers.BaseTestStorageRequestDelegate;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.InfoConfiguration;
-import org.mozilla.gecko.sync.JSONRecordFetcher;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepository;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.mozilla.gecko.sync.repositories.FetchFailedException;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.Server11Repository;
-import org.mozilla.gecko.sync.repositories.StoreFailedException;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecordFactory;
-import org.mozilla.gecko.sync.stage.SafeConstrainedServer11Repository;
-import org.mozilla.gecko.sync.synchronizer.ServerLocalSynchronizer;
-import org.mozilla.gecko.sync.synchronizer.Synchronizer;
-import org.simpleframework.http.ContentType;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestServer11RepositorySession {
-
- public class POSTMockServer extends MockServer {
- @Override
- public void handle(Request request, Response response) {
- try {
- String content = request.getContent();
- System.out.println("Content:" + content);
- } catch (IOException e) {
- e.printStackTrace();
- }
- ContentType contentType = request.getContentType();
- System.out.println("Content-Type:" + contentType);
- super.handle(request, response, 200, "{success:[]}");
- }
- }
-
- private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private static final String TEST_SERVER = "http://localhost:" + TEST_PORT + "/";
- static final String LOCAL_BASE_URL = TEST_SERVER + "1.1/n6ec3u5bee3tixzp2asys7bs6fve4jfw/";
- static final String LOCAL_INFO_BASE_URL = LOCAL_BASE_URL + "info/";
- static final String LOCAL_COUNTS_URL = LOCAL_INFO_BASE_URL + "collection_counts";
-
- // Corresponds to rnewman+atest1@mozilla.com, local.
- static final String TEST_USERNAME = "n6ec3u5bee3tixzp2asys7bs6fve4jfw";
- static final String TEST_PASSWORD = "passowrd";
- static final String SYNC_KEY = "eh7ppnb82iwr5kt3z3uyi5vr44";
-
- public final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD);
- protected final InfoCollections infoCollections = new InfoCollections();
- protected final InfoConfiguration infoConfiguration = new InfoConfiguration();
-
- // Few-second timeout so that our longer operations don't time out and cause spurious error-handling results.
- private static final int SHORT_TIMEOUT = 10000;
-
- public AuthHeaderProvider getAuthHeaderProvider() {
- return new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD);
- }
-
- private HTTPServerTestHelper data = new HTTPServerTestHelper();
-
- public class TestSyncStorageRequestDelegate extends
- BaseTestStorageRequestDelegate {
- public TestSyncStorageRequestDelegate(String username, String password) {
- super(username, password);
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse res) {
- assertTrue(res.wasSuccessful());
- assertTrue(res.httpResponse().containsHeader("X-Weave-Timestamp"));
- BaseResource.consumeEntity(res);
- data.stopHTTPServer();
- }
- }
-
- @SuppressWarnings("static-method")
- protected TrackingWBORepository getLocal(int numRecords) {
- final TrackingWBORepository local = new TrackingWBORepository();
- for (int i = 0; i < numRecords; i++) {
- BookmarkRecord outbound = new BookmarkRecord("outboundFail" + i, "bookmarks", 1, false);
- local.wbos.put(outbound.guid, outbound);
- }
- return local;
- }
-
- protected Exception doSynchronize(MockServer server) throws Exception {
- final String COLLECTION = "test";
-
- final TrackingWBORepository local = getLocal(100);
- final Server11Repository remote = new Server11Repository(COLLECTION, getCollectionURL(COLLECTION), authHeaderProvider, infoCollections, infoConfiguration);
- KeyBundle collectionKey = new KeyBundle(TEST_USERNAME, SYNC_KEY);
- Crypto5MiddlewareRepository cryptoRepo = new Crypto5MiddlewareRepository(remote, collectionKey);
- cryptoRepo.recordFactory = new BookmarkRecordFactory();
-
- final Synchronizer synchronizer = new ServerLocalSynchronizer();
- synchronizer.repositoryA = cryptoRepo;
- synchronizer.repositoryB = local;
-
- data.startHTTPServer(server);
- try {
- Exception e = TestServerLocalSynchronizer.doSynchronize(synchronizer);
- return e;
- } finally {
- data.stopHTTPServer();
- }
- }
-
- protected String getCollectionURL(String collection) {
- return LOCAL_BASE_URL + "/storage/" + collection;
- }
-
- @Test
- public void testFetchFailure() throws Exception {
- MockServer server = new MockServer(404, "error");
- Exception e = doSynchronize(server);
- assertNotNull(e);
- assertEquals(FetchFailedException.class, e.getClass());
- }
-
- @Test
- public void testStorePostSuccessWithFailingRecords() throws Exception {
- MockServer server = new MockServer(200, "{ modified: \" + " + Utils.millisecondsToDecimalSeconds(System.currentTimeMillis()) + ", " +
- "success: []," +
- "failed: { outboundFail2: [] } }");
- Exception e = doSynchronize(server);
- assertNotNull(e);
- assertEquals(StoreFailedException.class, e.getClass());
- }
-
- @Test
- public void testStorePostFailure() throws Exception {
- MockServer server = new MockServer() {
- @Override
- public void handle(Request request, Response response) {
- if (request.getMethod().equals("POST")) {
- this.handle(request, response, 404, "missing");
- }
- this.handle(request, response, 200, "success");
- return;
- }
- };
-
- Exception e = doSynchronize(server);
- assertNotNull(e);
- assertEquals(StoreFailedException.class, e.getClass());
- }
-
- @Test
- public void testConstraints() throws Exception {
- MockServer server = new MockServer() {
- @Override
- public void handle(Request request, Response response) {
- if (request.getMethod().equals("GET")) {
- if (request.getPath().getPath().endsWith("/info/collection_counts")) {
- this.handle(request, response, 200, "{\"bookmarks\": 5001}");
- }
- }
- this.handle(request, response, 400, "NOOOO");
- }
- };
- final JSONRecordFetcher countsFetcher = new JSONRecordFetcher(LOCAL_COUNTS_URL, getAuthHeaderProvider());
- String collection = "bookmarks";
- final SafeConstrainedServer11Repository remote = new SafeConstrainedServer11Repository(collection,
- getCollectionURL(collection),
- getAuthHeaderProvider(),
- infoCollections,
- infoConfiguration,
- 5000, 5000, "sortindex", countsFetcher);
-
- data.startHTTPServer(server);
- final AtomicBoolean out = new AtomicBoolean(false);
-
- // Verify that shouldSkip returns true due to a fetch of too large counts,
- // rather than due to a timeout failure waiting to fetch counts.
- try {
- WaitHelper.getTestWaiter().performWait(
- SHORT_TIMEOUT,
- new Runnable() {
- @Override
- public void run() {
- remote.createSession(new RepositorySessionCreationDelegate() {
- @Override
- public void onSessionCreated(RepositorySession session) {
- out.set(session.shouldSkip());
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void onSessionCreateFailed(Exception ex) {
- WaitHelper.getTestWaiter().performNotify(ex);
- }
-
- @Override
- public RepositorySessionCreationDelegate deferredCreationDelegate() {
- return this;
- }
- }, null);
- }
- });
- assertTrue(out.get());
- } finally {
- data.stopHTTPServer();
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestServerLocalSynchronizer.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestServerLocalSynchronizer.java
deleted file mode 100644
index 267798672..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestServerLocalSynchronizer.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.SynchronizerHelpers.BatchFailStoreWBORepository;
-import org.mozilla.android.sync.test.SynchronizerHelpers.BeginErrorWBORepository;
-import org.mozilla.android.sync.test.SynchronizerHelpers.BeginFailedException;
-import org.mozilla.android.sync.test.SynchronizerHelpers.FailFetchWBORepository;
-import org.mozilla.android.sync.test.SynchronizerHelpers.FinishErrorWBORepository;
-import org.mozilla.android.sync.test.SynchronizerHelpers.FinishFailedException;
-import org.mozilla.android.sync.test.SynchronizerHelpers.SerialFailStoreWBORepository;
-import org.mozilla.android.sync.test.SynchronizerHelpers.TrackingWBORepository;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WBORepository;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.FetchFailedException;
-import org.mozilla.gecko.sync.repositories.StoreFailedException;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-import org.mozilla.gecko.sync.synchronizer.ServerLocalSynchronizer;
-import org.mozilla.gecko.sync.synchronizer.Synchronizer;
-import org.mozilla.gecko.sync.synchronizer.SynchronizerDelegate;
-
-import java.util.ArrayList;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-@RunWith(TestRunner.class)
-public class TestServerLocalSynchronizer {
- public static final String LOG_TAG = "TestServLocSync";
-
- protected Synchronizer getSynchronizer(WBORepository remote, WBORepository local) {
- BookmarkRecord[] inbounds = new BookmarkRecord[] {
- new BookmarkRecord("inboundSucc1", "bookmarks", 1, false),
- new BookmarkRecord("inboundSucc2", "bookmarks", 1, false),
- new BookmarkRecord("inboundFail1", "bookmarks", 1, false),
- new BookmarkRecord("inboundSucc3", "bookmarks", 1, false),
- new BookmarkRecord("inboundFail2", "bookmarks", 1, false),
- new BookmarkRecord("inboundFail3", "bookmarks", 1, false),
- };
- BookmarkRecord[] outbounds = new BookmarkRecord[] {
- new BookmarkRecord("outboundFail1", "bookmarks", 1, false),
- new BookmarkRecord("outboundFail2", "bookmarks", 1, false),
- new BookmarkRecord("outboundFail3", "bookmarks", 1, false),
- new BookmarkRecord("outboundFail4", "bookmarks", 1, false),
- new BookmarkRecord("outboundFail5", "bookmarks", 1, false),
- new BookmarkRecord("outboundFail6", "bookmarks", 1, false),
- };
- for (BookmarkRecord inbound : inbounds) {
- remote.wbos.put(inbound.guid, inbound);
- }
- for (BookmarkRecord outbound : outbounds) {
- local.wbos.put(outbound.guid, outbound);
- }
-
- final Synchronizer synchronizer = new ServerLocalSynchronizer();
- synchronizer.repositoryA = remote;
- synchronizer.repositoryB = local;
- return synchronizer;
- }
-
- protected static Exception doSynchronize(final Synchronizer synchronizer) {
- final ArrayList<Exception> a = new ArrayList<Exception>();
-
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- synchronizer.synchronize(null, new SynchronizerDelegate() {
- @Override
- public void onSynchronized(Synchronizer synchronizer) {
- Logger.trace(LOG_TAG, "Got onSynchronized.");
- a.add(null);
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void onSynchronizeFailed(Synchronizer synchronizer, Exception lastException, String reason) {
- Logger.trace(LOG_TAG, "Got onSynchronizedFailed.");
- a.add(lastException);
- WaitHelper.getTestWaiter().performNotify();
- }
- });
- }
- });
-
- assertEquals(1, a.size()); // Should not be called multiple times!
- return a.get(0);
- }
-
- @Test
- public void testNoErrors() {
- WBORepository remote = new TrackingWBORepository();
- WBORepository local = new TrackingWBORepository();
-
- Synchronizer synchronizer = getSynchronizer(remote, local);
- assertNull(doSynchronize(synchronizer));
-
- assertEquals(12, local.wbos.size());
- assertEquals(12, remote.wbos.size());
- }
-
- @Test
- public void testLocalFetchErrors() {
- WBORepository remote = new TrackingWBORepository();
- WBORepository local = new FailFetchWBORepository();
-
- Synchronizer synchronizer = getSynchronizer(remote, local);
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(FetchFailedException.class, e.getClass());
-
- // Neither session gets finished successfully, so all records are dropped.
- assertEquals(6, local.wbos.size());
- assertEquals(6, remote.wbos.size());
- }
-
- @Test
- public void testRemoteFetchErrors() {
- WBORepository remote = new FailFetchWBORepository();
- WBORepository local = new TrackingWBORepository();
-
- Synchronizer synchronizer = getSynchronizer(remote, local);
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(FetchFailedException.class, e.getClass());
-
- // Neither session gets finished successfully, so all records are dropped.
- assertEquals(6, local.wbos.size());
- assertEquals(6, remote.wbos.size());
- }
-
- @Test
- public void testLocalSerialStoreErrorsAreIgnored() {
- WBORepository remote = new TrackingWBORepository();
- WBORepository local = new SerialFailStoreWBORepository();
-
- Synchronizer synchronizer = getSynchronizer(remote, local);
- assertNull(doSynchronize(synchronizer));
-
- assertEquals(9, local.wbos.size());
- assertEquals(12, remote.wbos.size());
- }
-
- @Test
- public void testLocalBatchStoreErrorsAreIgnored() {
- final int BATCH_SIZE = 3;
-
- Synchronizer synchronizer = getSynchronizer(new TrackingWBORepository(), new BatchFailStoreWBORepository(BATCH_SIZE));
-
- Exception e = doSynchronize(synchronizer);
- assertNull(e);
- }
-
- @Test
- public void testRemoteSerialStoreErrorsAreNotIgnored() throws Exception {
- Synchronizer synchronizer = getSynchronizer(new SerialFailStoreWBORepository(), new TrackingWBORepository()); // Tracking so we don't send incoming records back.
-
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(StoreFailedException.class, e.getClass());
- }
-
- @Test
- public void testRemoteBatchStoreErrorsAreNotIgnoredManyBatches() throws Exception {
- final int BATCH_SIZE = 3;
-
- Synchronizer synchronizer = getSynchronizer(new BatchFailStoreWBORepository(BATCH_SIZE), new TrackingWBORepository()); // Tracking so we don't send incoming records back.
-
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(StoreFailedException.class, e.getClass());
- }
-
- @Test
- public void testRemoteBatchStoreErrorsAreNotIgnoredOneBigBatch() throws Exception {
- final int BATCH_SIZE = 20;
-
- Synchronizer synchronizer = getSynchronizer(new BatchFailStoreWBORepository(BATCH_SIZE), new TrackingWBORepository()); // Tracking so we don't send incoming records back.
-
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(StoreFailedException.class, e.getClass());
- }
-
- @Test
- public void testSessionRemoteBeginError() {
- Synchronizer synchronizer = getSynchronizer(new BeginErrorWBORepository(), new TrackingWBORepository());
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(BeginFailedException.class, e.getClass());
- }
-
- @Test
- public void testSessionLocalBeginError() {
- Synchronizer synchronizer = getSynchronizer(new TrackingWBORepository(), new BeginErrorWBORepository());
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(BeginFailedException.class, e.getClass());
- }
-
- @Test
- public void testSessionRemoteFinishError() {
- Synchronizer synchronizer = getSynchronizer(new FinishErrorWBORepository(), new TrackingWBORepository());
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(FinishFailedException.class, e.getClass());
- }
-
- @Test
- public void testSessionLocalFinishError() {
- Synchronizer synchronizer = getSynchronizer(new TrackingWBORepository(), new FinishErrorWBORepository());
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(FinishFailedException.class, e.getClass());
- }
-
- @Test
- public void testSessionBothBeginError() {
- Synchronizer synchronizer = getSynchronizer(new BeginErrorWBORepository(), new BeginErrorWBORepository());
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(BeginFailedException.class, e.getClass());
- }
-
- @Test
- public void testSessionBothFinishError() {
- Synchronizer synchronizer = getSynchronizer(new FinishErrorWBORepository(), new FinishErrorWBORepository());
- Exception e = doSynchronize(synchronizer);
- assertNotNull(e);
- assertEquals(FinishFailedException.class, e.getClass());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSyncConfiguration.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSyncConfiguration.java
deleted file mode 100644
index 974d799de..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSyncConfiguration.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.Sync11Configuration;
-import org.mozilla.gecko.sync.SyncConfiguration;
-
-import java.net.URI;
-
-@RunWith(TestRunner.class)
-public class TestSyncConfiguration {
- @Test
- public void testURLs() throws Exception {
- final MockSharedPreferences prefs = new MockSharedPreferences();
-
- // N.B., the username isn't used in the cluster path.
- SyncConfiguration fxaConfig = new SyncConfiguration("username", null, prefs);
- fxaConfig.clusterURL = new URI("http://db1.oldsync.dev.lcip.org/1.1/174");
- Assert.assertEquals("http://db1.oldsync.dev.lcip.org/1.1/174/info/collections", fxaConfig.infoCollectionsURL());
- Assert.assertEquals("http://db1.oldsync.dev.lcip.org/1.1/174/info/collection_counts", fxaConfig.infoCollectionCountsURL());
- Assert.assertEquals("http://db1.oldsync.dev.lcip.org/1.1/174/storage/meta/global", fxaConfig.metaURL());
- Assert.assertEquals("http://db1.oldsync.dev.lcip.org/1.1/174/storage", fxaConfig.storageURL());
- Assert.assertEquals("http://db1.oldsync.dev.lcip.org/1.1/174/storage/collection", fxaConfig.collectionURI("collection").toASCIIString());
-
- SyncConfiguration oldConfig = new Sync11Configuration("username", null, prefs);
- oldConfig.clusterURL = new URI("https://db.com/internal/");
- Assert.assertEquals("https://db.com/internal/1.1/username/info/collections", oldConfig.infoCollectionsURL());
- Assert.assertEquals("https://db.com/internal/1.1/username/info/collection_counts", oldConfig.infoCollectionCountsURL());
- Assert.assertEquals("https://db.com/internal/1.1/username/storage/meta/global", oldConfig.metaURL());
- Assert.assertEquals("https://db.com/internal/1.1/username/storage", oldConfig.storageURL());
- Assert.assertEquals("https://db.com/internal/1.1/username/storage/collection", oldConfig.collectionURI("collection").toASCIIString());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSynchronizer.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSynchronizer.java
deleted file mode 100644
index 65157beee..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSynchronizer.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import android.content.Context;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.SynchronizerHelpers.TrackingWBORepository;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WBORepository;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-import org.mozilla.gecko.sync.synchronizer.Synchronizer;
-import org.mozilla.gecko.sync.synchronizer.SynchronizerDelegate;
-import org.mozilla.gecko.sync.synchronizer.SynchronizerSession;
-import org.mozilla.gecko.sync.synchronizer.SynchronizerSessionDelegate;
-
-import java.util.Date;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestSynchronizer {
- public static final String LOG_TAG = "TestSynchronizer";
-
- public static void assertInRangeInclusive(long earliest, long value, long latest) {
- assertTrue(earliest <= value);
- assertTrue(latest >= value);
- }
-
- public static void recordEquals(BookmarkRecord r, String guid, long lastModified, boolean deleted, String collection) {
- assertEquals(r.guid, guid);
- assertEquals(r.lastModified, lastModified);
- assertEquals(r.deleted, deleted);
- assertEquals(r.collection, collection);
- }
-
- public static void recordEquals(BookmarkRecord a, BookmarkRecord b) {
- assertEquals(a.guid, b.guid);
- assertEquals(a.lastModified, b.lastModified);
- assertEquals(a.deleted, b.deleted);
- assertEquals(a.collection, b.collection);
- }
-
- @Before
- public void setUp() {
- WaitHelper.resetTestWaiter();
- }
-
- @After
- public void tearDown() {
- WaitHelper.resetTestWaiter();
- }
-
- @Test
- public void testSynchronizerSession() {
- final Context context = null;
- final WBORepository repoA = new TrackingWBORepository();
- final WBORepository repoB = new TrackingWBORepository();
-
- final String collection = "bookmarks";
- final boolean deleted = false;
- final String guidA = "abcdabcdabcd";
- final String guidB = "ffffffffffff";
- final String guidC = "xxxxxxxxxxxx";
- final long lastModifiedA = 312345;
- final long lastModifiedB = 412340;
- final long lastModifiedC = 412345;
- BookmarkRecord bookmarkRecordA = new BookmarkRecord(guidA, collection, lastModifiedA, deleted);
- BookmarkRecord bookmarkRecordB = new BookmarkRecord(guidB, collection, lastModifiedB, deleted);
- BookmarkRecord bookmarkRecordC = new BookmarkRecord(guidC, collection, lastModifiedC, deleted);
-
- repoA.wbos.put(guidA, bookmarkRecordA);
- repoB.wbos.put(guidB, bookmarkRecordB);
- repoB.wbos.put(guidC, bookmarkRecordC);
- Synchronizer synchronizer = new Synchronizer();
- synchronizer.repositoryA = repoA;
- synchronizer.repositoryB = repoB;
- final SynchronizerSession syncSession = new SynchronizerSession(synchronizer, new SynchronizerSessionDelegate() {
-
- @Override
- public void onInitialized(SynchronizerSession session) {
- assertFalse(repoA.wbos.containsKey(guidB));
- assertFalse(repoA.wbos.containsKey(guidC));
- assertFalse(repoB.wbos.containsKey(guidA));
- assertTrue(repoA.wbos.containsKey(guidA));
- assertTrue(repoB.wbos.containsKey(guidB));
- assertTrue(repoB.wbos.containsKey(guidC));
- session.synchronize();
- }
-
- @Override
- public void onSynchronized(SynchronizerSession session) {
- try {
- assertEquals(1, session.getInboundCount());
- assertEquals(2, session.getOutboundCount());
- WaitHelper.getTestWaiter().performNotify();
- } catch (Throwable e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
-
- @Override
- public void onSynchronizeFailed(SynchronizerSession session,
- Exception lastException, String reason) {
- WaitHelper.getTestWaiter().performNotify(lastException);
- }
-
- @Override
- public void onSynchronizeSkipped(SynchronizerSession synchronizerSession) {
- WaitHelper.getTestWaiter().performNotify(new RuntimeException());
- }
- });
-
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- syncSession.init(context, new RepositorySessionBundle(0), new RepositorySessionBundle(0));
- }
- });
-
- // Verify contents.
- assertTrue(repoA.wbos.containsKey(guidA));
- assertTrue(repoA.wbos.containsKey(guidB));
- assertTrue(repoA.wbos.containsKey(guidC));
- assertTrue(repoB.wbos.containsKey(guidA));
- assertTrue(repoB.wbos.containsKey(guidB));
- assertTrue(repoB.wbos.containsKey(guidC));
- BookmarkRecord aa = (BookmarkRecord) repoA.wbos.get(guidA);
- BookmarkRecord ab = (BookmarkRecord) repoA.wbos.get(guidB);
- BookmarkRecord ac = (BookmarkRecord) repoA.wbos.get(guidC);
- BookmarkRecord ba = (BookmarkRecord) repoB.wbos.get(guidA);
- BookmarkRecord bb = (BookmarkRecord) repoB.wbos.get(guidB);
- BookmarkRecord bc = (BookmarkRecord) repoB.wbos.get(guidC);
- recordEquals(aa, guidA, lastModifiedA, deleted, collection);
- recordEquals(ab, guidB, lastModifiedB, deleted, collection);
- recordEquals(ac, guidC, lastModifiedC, deleted, collection);
- recordEquals(ba, guidA, lastModifiedA, deleted, collection);
- recordEquals(bb, guidB, lastModifiedB, deleted, collection);
- recordEquals(bc, guidC, lastModifiedC, deleted, collection);
- recordEquals(aa, ba);
- recordEquals(ab, bb);
- recordEquals(ac, bc);
- }
-
- public abstract class SuccessfulSynchronizerDelegate implements SynchronizerDelegate {
- public long syncAOne = 0;
- public long syncBOne = 0;
-
- @Override
- public void onSynchronizeFailed(Synchronizer synchronizer,
- Exception lastException, String reason) {
- fail("Should not fail.");
- }
- }
-
- @Test
- public void testSynchronizerPersists() {
- final Object monitor = new Object();
- final long earliest = new Date().getTime();
-
- Context context = null;
- final WBORepository repoA = new WBORepository();
- final WBORepository repoB = new WBORepository();
- Synchronizer synchronizer = new Synchronizer();
- synchronizer.bundleA = new RepositorySessionBundle(0);
- synchronizer.bundleB = new RepositorySessionBundle(0);
- synchronizer.repositoryA = repoA;
- synchronizer.repositoryB = repoB;
-
- final SuccessfulSynchronizerDelegate delegateOne = new SuccessfulSynchronizerDelegate() {
- @Override
- public void onSynchronized(Synchronizer synchronizer) {
- Logger.trace(LOG_TAG, "onSynchronized. Success!");
- syncAOne = synchronizer.bundleA.getTimestamp();
- syncBOne = synchronizer.bundleB.getTimestamp();
- synchronized (monitor) {
- monitor.notify();
- }
- }
- };
- final SuccessfulSynchronizerDelegate delegateTwo = new SuccessfulSynchronizerDelegate() {
- @Override
- public void onSynchronized(Synchronizer synchronizer) {
- Logger.trace(LOG_TAG, "onSynchronized. Success!");
- syncAOne = synchronizer.bundleA.getTimestamp();
- syncBOne = synchronizer.bundleB.getTimestamp();
- synchronized (monitor) {
- monitor.notify();
- }
- }
- };
- synchronized (monitor) {
- synchronizer.synchronize(context, delegateOne);
- try {
- monitor.wait();
- } catch (InterruptedException e) {
- fail("Interrupted.");
- }
- }
- long now = new Date().getTime();
- Logger.trace(LOG_TAG, "Earliest is " + earliest);
- Logger.trace(LOG_TAG, "syncAOne is " + delegateOne.syncAOne);
- Logger.trace(LOG_TAG, "syncBOne is " + delegateOne.syncBOne);
- Logger.trace(LOG_TAG, "Now: " + now);
- assertInRangeInclusive(earliest, delegateOne.syncAOne, now);
- assertInRangeInclusive(earliest, delegateOne.syncBOne, now);
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- fail("Thread interrupted!");
- }
- synchronized (monitor) {
- synchronizer.synchronize(context, delegateTwo);
- try {
- monitor.wait();
- } catch (InterruptedException e) {
- fail("Interrupted.");
- }
- }
- now = new Date().getTime();
- Logger.trace(LOG_TAG, "Earliest is " + earliest);
- Logger.trace(LOG_TAG, "syncAOne is " + delegateTwo.syncAOne);
- Logger.trace(LOG_TAG, "syncBOne is " + delegateTwo.syncBOne);
- Logger.trace(LOG_TAG, "Now: " + now);
- assertInRangeInclusive(earliest, delegateTwo.syncAOne, now);
- assertInRangeInclusive(earliest, delegateTwo.syncBOne, now);
- assertTrue(delegateTwo.syncAOne > delegateOne.syncAOne);
- assertTrue(delegateTwo.syncBOne > delegateOne.syncBOne);
- Logger.trace(LOG_TAG, "Reached end of test.");
- }
-
- private Synchronizer getTestSynchronizer(long tsA, long tsB) {
- WBORepository repoA = new TrackingWBORepository();
- WBORepository repoB = new TrackingWBORepository();
- Synchronizer synchronizer = new Synchronizer();
- synchronizer.bundleA = new RepositorySessionBundle(tsA);
- synchronizer.bundleB = new RepositorySessionBundle(tsB);
- synchronizer.repositoryA = repoA;
- synchronizer.repositoryB = repoB;
- return synchronizer;
- }
-
- /**
- * Let's put data in two repos and synchronize them with last sync
- * timestamps later than all of the records. Verify that no records
- * are exchanged.
- */
- @Test
- public void testSynchronizerFakeTimestamps() {
- final Context context = null;
-
- final String collection = "bookmarks";
- final boolean deleted = false;
- final String guidA = "abcdabcdabcd";
- final String guidB = "ffffffffffff";
- final long lastModifiedA = 312345;
- final long lastModifiedB = 412345;
- BookmarkRecord bookmarkRecordA = new BookmarkRecord(guidA, collection, lastModifiedA, deleted);
- BookmarkRecord bookmarkRecordB = new BookmarkRecord(guidB, collection, lastModifiedB, deleted);
-
- final Synchronizer synchronizer = getTestSynchronizer(lastModifiedA + 10, lastModifiedB + 10);
- final WBORepository repoA = (WBORepository) synchronizer.repositoryA;
- final WBORepository repoB = (WBORepository) synchronizer.repositoryB;
-
- repoA.wbos.put(guidA, bookmarkRecordA);
- repoB.wbos.put(guidB, bookmarkRecordB);
-
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- synchronizer.synchronize(context, new SynchronizerDelegate() {
-
- @Override
- public void onSynchronized(Synchronizer synchronizer) {
- try {
- // No records get sent either way.
- final SynchronizerSession synchronizerSession = synchronizer.getSynchronizerSession();
- assertNotNull(synchronizerSession);
- assertEquals(0, synchronizerSession.getInboundCount());
- assertEquals(0, synchronizerSession.getOutboundCount());
- WaitHelper.getTestWaiter().performNotify();
- } catch (Throwable e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
-
- @Override
- public void onSynchronizeFailed(Synchronizer synchronizer,
- Exception lastException, String reason) {
- WaitHelper.getTestWaiter().performNotify(lastException);
- }
- });
- }
- });
-
- // Verify contents.
- assertTrue(repoA.wbos.containsKey(guidA));
- assertTrue(repoB.wbos.containsKey(guidB));
- assertFalse(repoB.wbos.containsKey(guidA));
- assertFalse(repoA.wbos.containsKey(guidB));
- BookmarkRecord aa = (BookmarkRecord) repoA.wbos.get(guidA);
- BookmarkRecord ab = (BookmarkRecord) repoA.wbos.get(guidB);
- BookmarkRecord ba = (BookmarkRecord) repoB.wbos.get(guidA);
- BookmarkRecord bb = (BookmarkRecord) repoB.wbos.get(guidB);
- assertNull(ab);
- assertNull(ba);
- recordEquals(aa, guidA, lastModifiedA, deleted, collection);
- recordEquals(bb, guidB, lastModifiedB, deleted, collection);
- }
-
-
- @Test
- public void testSynchronizer() {
- final Context context = null;
-
- final String collection = "bookmarks";
- final boolean deleted = false;
- final String guidA = "abcdabcdabcd";
- final String guidB = "ffffffffffff";
- final String guidC = "gggggggggggg";
- final long lastModifiedA = 312345;
- final long lastModifiedB = 412340;
- final long lastModifiedC = 412345;
- BookmarkRecord bookmarkRecordA = new BookmarkRecord(guidA, collection, lastModifiedA, deleted);
- BookmarkRecord bookmarkRecordB = new BookmarkRecord(guidB, collection, lastModifiedB, deleted);
- BookmarkRecord bookmarkRecordC = new BookmarkRecord(guidC, collection, lastModifiedC, deleted);
-
- final Synchronizer synchronizer = getTestSynchronizer(0, 0);
- final WBORepository repoA = (WBORepository) synchronizer.repositoryA;
- final WBORepository repoB = (WBORepository) synchronizer.repositoryB;
-
- repoA.wbos.put(guidA, bookmarkRecordA);
- repoB.wbos.put(guidB, bookmarkRecordB);
- repoB.wbos.put(guidC, bookmarkRecordC);
-
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- synchronizer.synchronize(context, new SynchronizerDelegate() {
-
- @Override
- public void onSynchronized(Synchronizer synchronizer) {
- try {
- // No records get sent either way.
- final SynchronizerSession synchronizerSession = synchronizer.getSynchronizerSession();
- assertNotNull(synchronizerSession);
- assertEquals(1, synchronizerSession.getInboundCount());
- assertEquals(2, synchronizerSession.getOutboundCount());
- WaitHelper.getTestWaiter().performNotify();
- } catch (Throwable e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
-
- @Override
- public void onSynchronizeFailed(Synchronizer synchronizer,
- Exception lastException, String reason) {
- WaitHelper.getTestWaiter().performNotify(lastException);
- }
- });
- }
- });
-
- // Verify contents.
- assertTrue(repoA.wbos.containsKey(guidA));
- assertTrue(repoA.wbos.containsKey(guidB));
- assertTrue(repoA.wbos.containsKey(guidC));
- assertTrue(repoB.wbos.containsKey(guidA));
- assertTrue(repoB.wbos.containsKey(guidB));
- assertTrue(repoB.wbos.containsKey(guidC));
- BookmarkRecord aa = (BookmarkRecord) repoA.wbos.get(guidA);
- BookmarkRecord ab = (BookmarkRecord) repoA.wbos.get(guidB);
- BookmarkRecord ac = (BookmarkRecord) repoA.wbos.get(guidC);
- BookmarkRecord ba = (BookmarkRecord) repoB.wbos.get(guidA);
- BookmarkRecord bb = (BookmarkRecord) repoB.wbos.get(guidB);
- BookmarkRecord bc = (BookmarkRecord) repoB.wbos.get(guidC);
- recordEquals(aa, guidA, lastModifiedA, deleted, collection);
- recordEquals(ab, guidB, lastModifiedB, deleted, collection);
- recordEquals(ac, guidC, lastModifiedC, deleted, collection);
- recordEquals(ba, guidA, lastModifiedA, deleted, collection);
- recordEquals(bb, guidB, lastModifiedB, deleted, collection);
- recordEquals(bc, guidC, lastModifiedC, deleted, collection);
- recordEquals(aa, ba);
- recordEquals(ab, bb);
- recordEquals(ac, bc);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSynchronizerSession.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSynchronizerSession.java
deleted file mode 100644
index ddc3ae68e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestSynchronizerSession.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import android.content.Context;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.SynchronizerHelpers.DataAvailableWBORepository;
-import org.mozilla.android.sync.test.SynchronizerHelpers.ShouldSkipWBORepository;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WBORepository;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.SynchronizerConfiguration;
-import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-import org.mozilla.gecko.sync.synchronizer.Synchronizer;
-import org.mozilla.gecko.sync.synchronizer.SynchronizerSession;
-import org.mozilla.gecko.sync.synchronizer.SynchronizerSessionDelegate;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestSynchronizerSession {
- public static final String LOG_TAG = TestSynchronizerSession.class.getSimpleName();
-
- protected static void assertFirstContainsSecond(Map<String, Record> first, Map<String, Record> second) {
- for (Entry<String, Record> entry : second.entrySet()) {
- assertTrue("Expected key " + entry.getKey(), first.containsKey(entry.getKey()));
- Record record = first.get(entry.getKey());
- assertEquals(entry.getValue(), record);
- }
- }
-
- protected static void assertFirstDoesNotContainSecond(Map<String, Record> first, Map<String, Record> second) {
- for (Entry<String, Record> entry : second.entrySet()) {
- assertFalse("Unexpected key " + entry.getKey(), first.containsKey(entry.getKey()));
- }
- }
-
- protected WBORepository repoA = null;
- protected WBORepository repoB = null;
- protected SynchronizerSession syncSession = null;
- protected Map<String, Record> originalWbosA = null;
- protected Map<String, Record> originalWbosB = null;
-
- @Before
- public void setUp() {
- repoA = new DataAvailableWBORepository(false);
- repoB = new DataAvailableWBORepository(false);
-
- final String collection = "bookmarks";
- final boolean deleted = false;
- final String guidA = "abcdabcdabcd";
- final String guidB = "ffffffffffff";
- final String guidC = "xxxxxxxxxxxx";
- final long lastModifiedA = 312345;
- final long lastModifiedB = 412340;
- final long lastModifiedC = 412345;
- final BookmarkRecord bookmarkRecordA = new BookmarkRecord(guidA, collection, lastModifiedA, deleted);
- final BookmarkRecord bookmarkRecordB = new BookmarkRecord(guidB, collection, lastModifiedB, deleted);
- final BookmarkRecord bookmarkRecordC = new BookmarkRecord(guidC, collection, lastModifiedC, deleted);
-
- repoA.wbos.put(guidA, bookmarkRecordA);
- repoB.wbos.put(guidB, bookmarkRecordB);
- repoB.wbos.put(guidC, bookmarkRecordC);
-
- originalWbosA = new HashMap<String, Record>(repoA.wbos);
- originalWbosB = new HashMap<String, Record>(repoB.wbos);
-
- Synchronizer synchronizer = new Synchronizer();
- synchronizer.repositoryA = repoA;
- synchronizer.repositoryB = repoB;
- syncSession = new SynchronizerSession(synchronizer, new SynchronizerSessionDelegate() {
- @Override
- public void onInitialized(SynchronizerSession session) {
- session.synchronize();
- }
-
- @Override
- public void onSynchronized(SynchronizerSession session) {
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void onSynchronizeFailed(SynchronizerSession session, Exception lastException, String reason) {
- WaitHelper.getTestWaiter().performNotify(lastException);
- }
-
- @Override
- public void onSynchronizeSkipped(SynchronizerSession synchronizerSession) {
- WaitHelper.getTestWaiter().performNotify(new RuntimeException("Not expecting onSynchronizeSkipped"));
- }
- });
- }
-
- protected void logStats() {
- // Uncomment this line to print stats to console:
- // Logger.startLoggingTo(new PrintLogWriter(new PrintWriter(System.out, true)));
-
- Logger.debug(LOG_TAG, "Repo A fetch done: " + repoA.stats.fetchCompleted);
- Logger.debug(LOG_TAG, "Repo B store done: " + repoB.stats.storeCompleted);
- Logger.debug(LOG_TAG, "Repo B fetch done: " + repoB.stats.fetchCompleted);
- Logger.debug(LOG_TAG, "Repo A store done: " + repoA.stats.storeCompleted);
-
- SynchronizerConfiguration sc = syncSession.getSynchronizer().save();
- Logger.debug(LOG_TAG, "Repo A timestamp: " + sc.remoteBundle.getTimestamp());
- Logger.debug(LOG_TAG, "Repo B timestamp: " + sc.localBundle.getTimestamp());
- }
-
- protected void doTest(boolean remoteDataAvailable, boolean localDataAvailable) {
- ((DataAvailableWBORepository) repoA).dataAvailable = remoteDataAvailable;
- ((DataAvailableWBORepository) repoB).dataAvailable = localDataAvailable;
-
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- final Context context = null;
- syncSession.init(context,
- new RepositorySessionBundle(0),
- new RepositorySessionBundle(0));
- }
- });
-
- logStats();
- }
-
- @Test
- public void testSynchronizerSessionBothHaveData() {
- long before = System.currentTimeMillis();
- boolean remoteDataAvailable = true;
- boolean localDataAvailable = true;
- doTest(remoteDataAvailable, localDataAvailable);
- long after = System.currentTimeMillis();
-
- assertEquals(1, syncSession.getInboundCount());
- assertEquals(2, syncSession.getOutboundCount());
-
- // Didn't lose any records.
- assertFirstContainsSecond(repoA.wbos, originalWbosA);
- assertFirstContainsSecond(repoB.wbos, originalWbosB);
- // Got new records.
- assertFirstContainsSecond(repoA.wbos, originalWbosB);
- assertFirstContainsSecond(repoB.wbos, originalWbosA);
-
- // Timestamps updated.
- SynchronizerConfiguration sc = syncSession.getSynchronizer().save();
- TestSynchronizer.assertInRangeInclusive(before, sc.localBundle.getTimestamp(), after);
- TestSynchronizer.assertInRangeInclusive(before, sc.remoteBundle.getTimestamp(), after);
- }
-
- @Test
- public void testSynchronizerSessionOnlyLocalHasData() {
- long before = System.currentTimeMillis();
- boolean remoteDataAvailable = false;
- boolean localDataAvailable = true;
- doTest(remoteDataAvailable, localDataAvailable);
- long after = System.currentTimeMillis();
-
- // Record counts updated.
- assertEquals(0, syncSession.getInboundCount());
- assertEquals(2, syncSession.getOutboundCount());
-
- // Didn't lose any records.
- assertFirstContainsSecond(repoA.wbos, originalWbosA);
- assertFirstContainsSecond(repoB.wbos, originalWbosB);
- // Got new records.
- assertFirstContainsSecond(repoA.wbos, originalWbosB);
- // Didn't get records we shouldn't have fetched.
- assertFirstDoesNotContainSecond(repoB.wbos, originalWbosA);
-
- // Timestamps updated.
- SynchronizerConfiguration sc = syncSession.getSynchronizer().save();
- TestSynchronizer.assertInRangeInclusive(before, sc.localBundle.getTimestamp(), after);
- TestSynchronizer.assertInRangeInclusive(before, sc.remoteBundle.getTimestamp(), after);
- }
-
- @Test
- public void testSynchronizerSessionOnlyRemoteHasData() {
- long before = System.currentTimeMillis();
- boolean remoteDataAvailable = true;
- boolean localDataAvailable = false;
- doTest(remoteDataAvailable, localDataAvailable);
- long after = System.currentTimeMillis();
-
- // Record counts updated.
- assertEquals(1, syncSession.getInboundCount());
- assertEquals(0, syncSession.getOutboundCount());
-
- // Didn't lose any records.
- assertFirstContainsSecond(repoA.wbos, originalWbosA);
- assertFirstContainsSecond(repoB.wbos, originalWbosB);
- // Got new records.
- assertFirstContainsSecond(repoB.wbos, originalWbosA);
- // Didn't get records we shouldn't have fetched.
- assertFirstDoesNotContainSecond(repoA.wbos, originalWbosB);
-
- // Timestamps updated.
- SynchronizerConfiguration sc = syncSession.getSynchronizer().save();
- TestSynchronizer.assertInRangeInclusive(before, sc.localBundle.getTimestamp(), after);
- TestSynchronizer.assertInRangeInclusive(before, sc.remoteBundle.getTimestamp(), after);
- }
-
- @Test
- public void testSynchronizerSessionNeitherHaveData() {
- long before = System.currentTimeMillis();
- boolean remoteDataAvailable = false;
- boolean localDataAvailable = false;
- doTest(remoteDataAvailable, localDataAvailable);
- long after = System.currentTimeMillis();
-
- // Record counts updated.
- assertEquals(0, syncSession.getInboundCount());
- assertEquals(0, syncSession.getOutboundCount());
-
- // Didn't lose any records.
- assertFirstContainsSecond(repoA.wbos, originalWbosA);
- assertFirstContainsSecond(repoB.wbos, originalWbosB);
- // Didn't get records we shouldn't have fetched.
- assertFirstDoesNotContainSecond(repoA.wbos, originalWbosB);
- assertFirstDoesNotContainSecond(repoB.wbos, originalWbosA);
-
- // Timestamps updated.
- SynchronizerConfiguration sc = syncSession.getSynchronizer().save();
- TestSynchronizer.assertInRangeInclusive(before, sc.localBundle.getTimestamp(), after);
- TestSynchronizer.assertInRangeInclusive(before, sc.remoteBundle.getTimestamp(), after);
- }
-
- protected void doSkipTest(boolean remoteShouldSkip, boolean localShouldSkip) {
- repoA = new ShouldSkipWBORepository(remoteShouldSkip);
- repoB = new ShouldSkipWBORepository(localShouldSkip);
-
- Synchronizer synchronizer = new Synchronizer();
- synchronizer.repositoryA = repoA;
- synchronizer.repositoryB = repoB;
-
- syncSession = new SynchronizerSession(synchronizer, new SynchronizerSessionDelegate() {
- @Override
- public void onInitialized(SynchronizerSession session) {
- session.synchronize();
- }
-
- @Override
- public void onSynchronized(SynchronizerSession session) {
- WaitHelper.getTestWaiter().performNotify(new RuntimeException("Not expecting onSynchronized"));
- }
-
- @Override
- public void onSynchronizeFailed(SynchronizerSession session, Exception lastException, String reason) {
- WaitHelper.getTestWaiter().performNotify(lastException);
- }
-
- @Override
- public void onSynchronizeSkipped(SynchronizerSession synchronizerSession) {
- WaitHelper.getTestWaiter().performNotify();
- }
- });
-
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- final Context context = null;
- syncSession.init(context,
- new RepositorySessionBundle(100),
- new RepositorySessionBundle(200));
- }
- });
-
- // If we skip, we don't update timestamps or even un-bundle.
- SynchronizerConfiguration sc = syncSession.getSynchronizer().save();
- assertNotNull(sc);
- assertNull(sc.localBundle);
- assertNull(sc.remoteBundle);
- assertEquals(-1, syncSession.getInboundCount());
- assertEquals(-1, syncSession.getOutboundCount());
- }
-
- @Test
- public void testSynchronizerSessionShouldSkip() {
- // These combinations should all skip.
- doSkipTest(true, false);
-
- doSkipTest(false, true);
- doSkipTest(true, true);
-
- try {
- doSkipTest(false, false);
- fail("Expected exception.");
- } catch (WaitHelper.InnerError e) {
- assertTrue(e.innerError instanceof RuntimeException);
- assertEquals("Not expecting onSynchronized", e.innerError.getMessage());
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestUtils.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestUtils.java
deleted file mode 100644
index bc9a99dae..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestUtils.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.Utils;
-
-import java.io.UnsupportedEncodingException;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestUtils extends Utils {
-
- @Test
- public void testGenerateGUID() {
- for (int i = 0; i < 1000; ++i) {
- assertEquals(12, Utils.generateGuid().length());
- }
- }
-
- public static final byte[][] BYTE_ARRS = {
- new byte[] {' '}, // Tab.
- new byte[] {'0'},
- new byte[] {'A'},
- new byte[] {'a'},
- new byte[] {'I', 'U'},
- new byte[] {'`', 'h', 'g', ' ', 's', '`'},
- new byte[] {}
- };
- // Indices correspond with the above array.
- public static final String[] STRING_ARR = {
- "09",
- "30",
- "41",
- "61",
- "4955",
- "606867207360",
- ""
- };
-
- @Test
- public void testByte2Hex() throws Exception {
- for (int i = 0; i < BYTE_ARRS.length; ++i) {
- final byte[] b = BYTE_ARRS[i];
- final String expected = STRING_ARR[i];
- assertEquals(expected, Utils.byte2Hex(b));
- }
- }
-
- @Test
- public void testHex2Byte() throws Exception {
- for (int i = 0; i < STRING_ARR.length; ++i) {
- final String s = STRING_ARR[i];
- final byte[] expected = BYTE_ARRS[i];
- assertTrue(Arrays.equals(expected, Utils.hex2Byte(s)));
- }
- }
-
- @Test
- public void testByte2Hex2ByteAndViceVersa() throws Exception { // There and back again!
- for (int i = 0; i < BYTE_ARRS.length; ++i) {
- // byte2Hex2Byte
- final byte[] b = BYTE_ARRS[i];
- final String s = Utils.byte2Hex(b);
- assertTrue(Arrays.equals(b, Utils.hex2Byte(s)));
- }
-
- // hex2Byte2Hex
- for (int i = 0; i < STRING_ARR.length; ++i) {
- final String s = STRING_ARR[i];
- final byte[] b = Utils.hex2Byte(s);
- assertEquals(s, Utils.byte2Hex(b));
- }
- }
-
- @Test
- public void testByte2HexLength() throws Exception {
- for (int i = 0; i < BYTE_ARRS.length; ++i) {
- final byte[] b = BYTE_ARRS[i];
- final String expected = STRING_ARR[i];
- assertEquals(expected, Utils.byte2Hex(b, b.length));
- assertEquals("0" + expected, Utils.byte2Hex(b, 2 * b.length + 1));
- assertEquals("00" + expected, Utils.byte2Hex(b, 2 * b.length + 2));
- }
- }
-
- @Test
- public void testHex2ByteLength() throws Exception {
- for (int i = 0; i < STRING_ARR.length; ++i) {
- final String s = STRING_ARR[i];
- final byte[] expected = BYTE_ARRS[i];
- assertTrue(Arrays.equals(expected, Utils.hex2Byte(s)));
- final byte[] expected1 = new byte[expected.length + 1];
- System.arraycopy(expected, 0, expected1, 1, expected.length);
- assertTrue(Arrays.equals(expected1, Utils.hex2Byte("00" + s)));
- final byte[] expected2 = new byte[expected.length + 2];
- System.arraycopy(expected, 0, expected2, 2, expected.length);
- assertTrue(Arrays.equals(expected2, Utils.hex2Byte("0000" + s)));
- }
- }
-
- @Test
- public void testToCommaSeparatedString() {
- ArrayList<String> xs = new ArrayList<String>();
- assertEquals("", Utils.toCommaSeparatedString(null));
- assertEquals("", Utils.toCommaSeparatedString(xs));
- xs.add("test1");
- assertEquals("test1", Utils.toCommaSeparatedString(xs));
- xs.add("test2");
- assertEquals("test1, test2", Utils.toCommaSeparatedString(xs));
- xs.add("test3");
- assertEquals("test1, test2, test3", Utils.toCommaSeparatedString(xs));
- }
-
- @Test
- public void testUsernameFromAccount() throws NoSuchAlgorithmException, UnsupportedEncodingException {
- assertEquals("xee7ffonluzpdp66l6xgpyh2v2w6ojkc", Utils.sha1Base32("foobar@baz.com"));
- assertEquals("xee7ffonluzpdp66l6xgpyh2v2w6ojkc", Utils.usernameFromAccount("foobar@baz.com"));
- assertEquals("xee7ffonluzpdp66l6xgpyh2v2w6ojkc", Utils.usernameFromAccount("FooBar@Baz.com"));
- assertEquals("xee7ffonluzpdp66l6xgpyh2v2w6ojkc", Utils.usernameFromAccount("xee7ffonluzpdp66l6xgpyh2v2w6ojkc"));
- assertEquals("foobar", Utils.usernameFromAccount("foobar"));
- assertEquals("foobar", Utils.usernameFromAccount("FOOBAr"));
- }
-
- @Test
- public void testGetPrefsPath() throws NoSuchAlgorithmException, UnsupportedEncodingException {
- assertEquals("ore7dlrwqi6xr7honxdtpvmh6tly4r7k", Utils.sha1Base32("test.url.com:xee7ffonluzpdp66l6xgpyh2v2w6ojkc"));
-
- assertEquals("sync.prefs.ore7dlrwqi6xr7honxdtpvmh6tly4r7k", Utils.getPrefsPath("product", "foobar@baz.com", "test.url.com", "default", 0));
- assertEquals("sync.prefs.ore7dlrwqi6xr7honxdtpvmh6tly4r7k", Utils.getPrefsPath("org.mozilla.firefox_beta", "FooBar@Baz.com", "test.url.com", "default", 0));
- assertEquals("sync.prefs.ore7dlrwqi6xr7honxdtpvmh6tly4r7k", Utils.getPrefsPath("org.mozilla.firefox", "xee7ffonluzpdp66l6xgpyh2v2w6ojkc", "test.url.com", "profile", 0));
-
- assertEquals("sync.prefs.product.ore7dlrwqi6xr7honxdtpvmh6tly4r7k.default.1", Utils.getPrefsPath("product", "foobar@baz.com", "test.url.com", "default", 1));
- assertEquals("sync.prefs.with!spaces_underbars!periods.ore7dlrwqi6xr7honxdtpvmh6tly4r7k.default.1", Utils.getPrefsPath("with spaces_underbars.periods", "foobar@baz.com", "test.url.com", "default", 1));
- assertEquals("sync.prefs.org!mozilla!firefox_beta.ore7dlrwqi6xr7honxdtpvmh6tly4r7k.default.2", Utils.getPrefsPath("org.mozilla.firefox_beta", "FooBar@Baz.com", "test.url.com", "default", 2));
- assertEquals("sync.prefs.org!mozilla!firefox.ore7dlrwqi6xr7honxdtpvmh6tly4r7k.profile.3", Utils.getPrefsPath("org.mozilla.firefox", "xee7ffonluzpdp66l6xgpyh2v2w6ojkc", "test.url.com", "profile", 3));
- }
-
- @Test
- public void testObfuscateEmail() {
- assertEquals("XXX@XXX.XXX", Utils.obfuscateEmail("foo@bar.com"));
- assertEquals("XXXX@XXX.XXXX.XX", Utils.obfuscateEmail("foot@bar.test.ca"));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/BaseTestStorageRequestDelegate.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/BaseTestStorageRequestDelegate.java
deleted file mode 100644
index a87925608..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/BaseTestStorageRequestDelegate.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-
-import java.io.IOException;
-
-import static org.junit.Assert.fail;
-
-public class BaseTestStorageRequestDelegate implements
- SyncStorageRequestDelegate {
-
- protected final AuthHeaderProvider authHeaderProvider;
-
- public BaseTestStorageRequestDelegate(AuthHeaderProvider authHeaderProvider) {
- this.authHeaderProvider = authHeaderProvider;
- }
-
- public BaseTestStorageRequestDelegate(String username, String password) {
- this(new BasicAuthHeaderProvider(username, password));
- }
-
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return authHeaderProvider;
- }
-
- @Override
- public String ifUnmodifiedSince() {
- return null;
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse response) {
- BaseResource.consumeEntity(response);
- fail("Should not be called.");
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- System.out.println("Response: " + response.httpResponse().getStatusLine().getStatusCode());
- BaseResource.consumeEntity(response);
- fail("Should not be called.");
- }
-
- @Override
- public void handleRequestError(Exception e) {
- if (e instanceof IOException) {
- System.out.println("WARNING: TEST FAILURE IGNORED!");
- // Assume that this is because Jenkins doesn't have network access.
- return;
- }
- fail("Should not error.");
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessDelegate.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessDelegate.java
deleted file mode 100644
index cf3545c1e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessDelegate.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-
-public class ExpectSuccessDelegate {
- public WaitHelper waitHelper;
-
- public ExpectSuccessDelegate(WaitHelper waitHelper) {
- this.waitHelper = waitHelper;
- }
-
- public void performNotify() {
- this.waitHelper.performNotify();
- }
-
- public void performNotify(Throwable e) {
- this.waitHelper.performNotify(e);
- }
-
- public String logTag() {
- return this.getClass().getSimpleName();
- }
-
- public void log(String message) {
- Logger.info(logTag(), message);
- }
-
- public void log(String message, Throwable throwable) {
- Logger.warn(logTag(), message, throwable);
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionBeginDelegate.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionBeginDelegate.java
deleted file mode 100644
index d7cb186f8..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionBeginDelegate.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import junit.framework.AssertionFailedError;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-
-import java.util.concurrent.ExecutorService;
-
-public class ExpectSuccessRepositorySessionBeginDelegate
-extends ExpectSuccessDelegate
-implements RepositorySessionBeginDelegate {
-
- public ExpectSuccessRepositorySessionBeginDelegate(WaitHelper waitHelper) {
- super(waitHelper);
- }
-
- @Override
- public void onBeginFailed(Exception ex) {
- log("Session begin failed.", ex);
- performNotify(new AssertionFailedError("Session begin failed: " + ex.getMessage()));
- }
-
- @Override
- public void onBeginSucceeded(RepositorySession session) {
- log("Session begin succeeded.");
- performNotify();
- }
-
- @Override
- public RepositorySessionBeginDelegate deferredBeginDelegate(ExecutorService executor) {
- log("Session begin delegate deferred.");
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionCreationDelegate.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionCreationDelegate.java
deleted file mode 100644
index 8860baf77..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionCreationDelegate.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import junit.framework.AssertionFailedError;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-
-public class ExpectSuccessRepositorySessionCreationDelegate extends
- ExpectSuccessDelegate implements RepositorySessionCreationDelegate {
-
- public ExpectSuccessRepositorySessionCreationDelegate(WaitHelper waitHelper) {
- super(waitHelper);
- }
-
- @Override
- public void onSessionCreateFailed(Exception ex) {
- log("Session creation failed.", ex);
- performNotify(new AssertionFailedError("onSessionCreateFailed: session creation should not have failed."));
- }
-
- @Override
- public void onSessionCreated(RepositorySession session) {
- log("Session creation succeeded.");
- performNotify();
- }
-
- @Override
- public RepositorySessionCreationDelegate deferredCreationDelegate() {
- log("Session creation deferred.");
- return this;
- }
-
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionFetchRecordsDelegate.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionFetchRecordsDelegate.java
deleted file mode 100644
index 5f5cf8995..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionFetchRecordsDelegate.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import junit.framework.AssertionFailedError;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import java.util.ArrayList;
-import java.util.concurrent.ExecutorService;
-
-public class ExpectSuccessRepositorySessionFetchRecordsDelegate extends
- ExpectSuccessDelegate implements RepositorySessionFetchRecordsDelegate {
- public ArrayList<Record> fetchedRecords = new ArrayList<Record>();
-
- public ExpectSuccessRepositorySessionFetchRecordsDelegate(WaitHelper waitHelper) {
- super(waitHelper);
- }
-
- @Override
- public void onFetchFailed(Exception ex, Record record) {
- log("Fetch failed.", ex);
- performNotify(new AssertionFailedError("onFetchFailed: fetch should not have failed."));
- }
-
- @Override
- public void onFetchedRecord(Record record) {
- fetchedRecords.add(record);
- log("Fetched record with guid '" + record.guid + "'.");
- }
-
- @Override
- public void onFetchCompleted(long end) {
- log("Fetch completed.");
- performNotify();
- }
-
- @Override
- public RepositorySessionFetchRecordsDelegate deferredFetchDelegate(ExecutorService executor) {
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionFinishDelegate.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionFinishDelegate.java
deleted file mode 100644
index 4435d5fa2..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionFinishDelegate.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import junit.framework.AssertionFailedError;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
-
-import java.util.concurrent.ExecutorService;
-
-public class ExpectSuccessRepositorySessionFinishDelegate extends
- ExpectSuccessDelegate implements RepositorySessionFinishDelegate {
-
- public ExpectSuccessRepositorySessionFinishDelegate(WaitHelper waitHelper) {
- super(waitHelper);
- }
-
- @Override
- public void onFinishFailed(Exception ex) {
- log("Finish failed.", ex);
- performNotify(new AssertionFailedError("onFinishFailed: finish should not have failed."));
- }
-
- @Override
- public void onFinishSucceeded(RepositorySession session, RepositorySessionBundle bundle) {
- log("Finish succeeded.");
- performNotify();
- }
-
- @Override
- public RepositorySessionFinishDelegate deferredFinishDelegate(ExecutorService executor) {
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionStoreDelegate.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionStoreDelegate.java
deleted file mode 100644
index cfca180fa..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionStoreDelegate.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import junit.framework.AssertionFailedError;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
-
-import java.util.concurrent.ExecutorService;
-
-public class ExpectSuccessRepositorySessionStoreDelegate extends
- ExpectSuccessDelegate implements RepositorySessionStoreDelegate {
-
- public ExpectSuccessRepositorySessionStoreDelegate(WaitHelper waitHelper) {
- super(waitHelper);
- }
-
- @Override
- public void onRecordStoreFailed(Exception ex, String guid) {
- log("Record store failed.", ex);
- performNotify(new AssertionFailedError("onRecordStoreFailed: record store should not have failed."));
- }
-
- @Override
- public void onRecordStoreSucceeded(String guid) {
- log("Record store succeeded.");
- }
-
- @Override
- public void onStoreCompleted(long storeEnd) {
- log("Record store completed at " + storeEnd);
- }
-
- @Override
- public RepositorySessionStoreDelegate deferredStoreDelegate(ExecutorService executor) {
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositoryWipeDelegate.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositoryWipeDelegate.java
deleted file mode 100644
index 0f248dda7..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositoryWipeDelegate.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import junit.framework.AssertionFailedError;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
-
-import java.util.concurrent.ExecutorService;
-
-public class ExpectSuccessRepositoryWipeDelegate extends ExpectSuccessDelegate
- implements RepositorySessionWipeDelegate {
-
- public ExpectSuccessRepositoryWipeDelegate(WaitHelper waitHelper) {
- super(waitHelper);
- }
-
- @Override
- public void onWipeSucceeded() {
- log("Wipe succeeded.");
- performNotify();
- }
-
- @Override
- public void onWipeFailed(Exception ex) {
- log("Wipe failed.", ex);
- performNotify(new AssertionFailedError("onWipeFailed: wipe should not have failed."));
- }
-
- @Override
- public RepositorySessionWipeDelegate deferredWipeDelegate(ExecutorService executor) {
- log("Wipe deferred.");
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/HTTPServerTestHelper.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/HTTPServerTestHelper.java
deleted file mode 100644
index 1829bdd12..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/HTTPServerTestHelper.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-import org.simpleframework.http.core.ContainerSocketProcessor;
-import org.simpleframework.transport.connect.Connection;
-import org.simpleframework.transport.connect.SocketConnection;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.util.IdentityHashMap;
-import java.util.Map;
-
-import static org.junit.Assert.fail;
-
-/**
- * Test helper code to bind <code>MockServer</code> instances to ports.
- * <p>
- * Maintains a collection of running servers and (by default) throws helpful
- * errors if two servers are started "on top" of each other. The
- * <b>unchecked</b> exception thrown contains a stack trace pointing to where
- * the new server is being created and where the pre-existing server was
- * created.
- * <p>
- * Parses a system property to determine current test port, which is fixed for
- * the duration of a test execution.
- */
-public class HTTPServerTestHelper {
- private static final String LOG_TAG = "HTTPServerTestHelper";
-
- /**
- * Port to run HTTP servers on during this test execution.
- * <p>
- * Lazily initialized on first call to {@link #getTestPort}.
- */
- public static Integer testPort = null;
-
- public static final String LOCAL_HTTP_PORT_PROPERTY = "android.sync.local.http.port";
- public static final int LOCAL_HTTP_PORT_DEFAULT = 15125;
-
- public final int port;
-
- public Connection connection;
- public MockServer server;
-
- /**
- * Create a helper to bind <code>MockServer</code> instances.
- * <p>
- * Use {@link #getTestPort} to determine the port this helper will bind to.
- */
- public HTTPServerTestHelper() {
- this.port = getTestPort();
- }
-
- // For testing only.
- protected HTTPServerTestHelper(int port) {
- this.port = port;
- }
-
- /**
- * Lazily initialize test port for this test execution.
- * <p>
- * Only called from {@link #getTestPort}.
- * <p>
- * If the test port has not been determined, we try to parse it from a system
- * property; if that fails, we return the default test port.
- */
- protected synchronized static void ensureTestPort() {
- if (testPort != null) {
- return;
- }
-
- String value = System.getProperty(LOCAL_HTTP_PORT_PROPERTY);
- if (value != null) {
- try {
- testPort = Integer.valueOf(value);
- } catch (NumberFormatException e) {
- Logger.warn(LOG_TAG, "Got exception parsing local test port; ignoring. ", e);
- }
- }
-
- if (testPort == null) {
- testPort = Integer.valueOf(LOCAL_HTTP_PORT_DEFAULT);
- }
- }
-
- /**
- * The port to which all HTTP servers will be found for the duration of this
- * test execution.
- * <p>
- * We try to parse the port from a system property; if that fails, we return
- * the default test port.
- *
- * @return port number.
- */
- public synchronized static int getTestPort() {
- if (testPort == null) {
- ensureTestPort();
- }
-
- return testPort.intValue();
- }
-
- /**
- * Used to maintain a stack trace pointing to where a server was started.
- */
- public static class HTTPServerStartedError extends Error {
- private static final long serialVersionUID = -6778447718799087274L;
-
- public final HTTPServerTestHelper httpServer;
-
- public HTTPServerStartedError(HTTPServerTestHelper httpServer) {
- this.httpServer = httpServer;
- }
- }
-
- /**
- * Thrown when a server is started "on top" of another server. The cause error
- * will be an <code>HTTPServerStartedError</code> with a stack trace pointing
- * to where the pre-existing server was started.
- */
- public static class HTTPServerAlreadyRunningError extends Error {
- private static final long serialVersionUID = -6778447718799087275L;
-
- public HTTPServerAlreadyRunningError(Throwable e) {
- super(e);
- }
- }
-
- /**
- * Maintain a hash of running servers. Each value is an error with a stack
- * traces pointing to where that server was started.
- * <p>
- * We don't key on the server itself because each server is a <it>helper</it>
- * that may be started many times with different <code>MockServer</code>
- * instances.
- * <p>
- * Synchronize access on the class.
- */
- protected static Map<Connection, HTTPServerStartedError> runningServers =
- new IdentityHashMap<Connection, HTTPServerStartedError>();
-
- protected synchronized static void throwIfServerAlreadyRunning() {
- for (HTTPServerStartedError value : runningServers.values()) {
- throw new HTTPServerAlreadyRunningError(value);
- }
- }
-
- protected synchronized static void registerServerAsRunning(HTTPServerTestHelper httpServer) {
- if (httpServer == null || httpServer.connection == null) {
- throw new IllegalArgumentException("HTTPServerTestHelper or connection was null; perhaps server has not been started?");
- }
-
- HTTPServerStartedError old = runningServers.put(httpServer.connection, new HTTPServerStartedError(httpServer));
- if (old != null) {
- // Should never happen.
- throw old;
- }
- }
-
- protected synchronized static void unregisterServerAsRunning(HTTPServerTestHelper httpServer) {
- if (httpServer == null || httpServer.connection == null) {
- throw new IllegalArgumentException("HTTPServerTestHelper or connection was null; perhaps server has not been started?");
- }
-
- runningServers.remove(httpServer.connection);
- }
-
- public MockServer startHTTPServer(MockServer server, boolean allowMultipleServers) {
- BaseResource.rewriteLocalhost = false; // No sense rewriting when we're running the unit tests.
- BaseResourceDelegate.connectionTimeoutInMillis = 1000; // No sense waiting a long time for a local connection.
-
- if (!allowMultipleServers) {
- throwIfServerAlreadyRunning();
- }
-
- try {
- this.server = server;
- connection = new SocketConnection(new ContainerSocketProcessor(server));
- SocketAddress address = new InetSocketAddress(port);
- connection.connect(address);
-
- registerServerAsRunning(this);
-
- Logger.info(LOG_TAG, "Started HTTP server on port " + port + ".");
- } catch (IOException ex) {
- Logger.error(LOG_TAG, "Error starting HTTP server on port " + port + ".", ex);
- fail(ex.toString());
- }
-
- return server;
- }
-
- public MockServer startHTTPServer(MockServer server) {
- return startHTTPServer(server, false);
- }
-
- public MockServer startHTTPServer() {
- return startHTTPServer(new MockServer());
- }
-
- public void stopHTTPServer() {
- try {
- if (connection != null) {
- unregisterServerAsRunning(this);
-
- connection.close();
- }
- server = null;
- connection = null;
-
- Logger.info(LOG_TAG, "Stopped HTTP server on port " + port + ".");
-
- Logger.debug(LOG_TAG, "Closing connection pool...");
- BaseResource.shutdownConnectionManager();
- } catch (IOException ex) {
- Logger.error(LOG_TAG, "Error stopping HTTP server on port " + port + ".", ex);
- fail(ex.toString());
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockGlobalSessionCallback.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockGlobalSessionCallback.java
deleted file mode 100644
index 5d7e8edd1..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockGlobalSessionCallback.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-import java.net.URI;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * A callback for use with a GlobalSession that records what happens for later
- * inspection.
- *
- * This callback is expected to be used from within the friendly confines of a
- * WaitHelper performWait.
- */
-public class MockGlobalSessionCallback implements GlobalSessionCallback {
- protected WaitHelper testWaiter() {
- return WaitHelper.getTestWaiter();
- }
-
- public int stageCounter = Stage.values().length - 1; // Exclude starting state.
- public boolean calledSuccess = false;
- public boolean calledError = false;
- public Exception calledErrorException = null;
- public boolean calledAborted = false;
- public boolean calledRequestBackoff = false;
- public boolean calledInformUnauthorizedResponse = false;
- public boolean calledInformUpgradeRequiredResponse = false;
- public boolean calledInformMigrated = false;
- public URI calledInformUnauthorizedResponseClusterURL = null;
- public long weaveBackoff = -1;
-
- @Override
- public void handleSuccess(GlobalSession globalSession) {
- this.calledSuccess = true;
- assertEquals(0, this.stageCounter);
- this.testWaiter().performNotify();
- }
-
- @Override
- public void handleAborted(GlobalSession globalSession, String reason) {
- this.calledAborted = true;
- this.testWaiter().performNotify();
- }
-
- @Override
- public void handleError(GlobalSession globalSession, Exception ex) {
- this.calledError = true;
- this.calledErrorException = ex;
- this.testWaiter().performNotify();
- }
-
- @Override
- public void handleStageCompleted(Stage currentState,
- GlobalSession globalSession) {
- stageCounter--;
- }
-
- @Override
- public void requestBackoff(long backoff) {
- this.calledRequestBackoff = true;
- this.weaveBackoff = backoff;
- }
-
- @Override
- public void informUnauthorizedResponse(GlobalSession session, URI clusterURL) {
- this.calledInformUnauthorizedResponse = true;
- this.calledInformUnauthorizedResponseClusterURL = clusterURL;
- }
-
- @Override
- public void informUpgradeRequiredResponse(GlobalSession session) {
- this.calledInformUpgradeRequiredResponse = true;
- }
-
- @Override
- public void informMigrated(GlobalSession session) {
- this.calledInformMigrated = true;
- }
-
- @Override
- public boolean shouldBackOffStorage() {
- return false;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockResourceDelegate.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockResourceDelegate.java
deleted file mode 100644
index 2cac07904..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockResourceDelegate.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.net.ResourceDelegate;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-
-import static org.junit.Assert.assertEquals;
-
-public class MockResourceDelegate implements ResourceDelegate {
- public WaitHelper waitHelper = null;
- public static String USER_PASS = "john:password";
- public static String EXPECT_BASIC = "Basic am9objpwYXNzd29yZA==";
-
- public boolean handledHttpResponse = false;
- public HttpResponse httpResponse = null;
-
- public MockResourceDelegate(WaitHelper waitHelper) {
- this.waitHelper = waitHelper;
- }
-
- public MockResourceDelegate() {
- this.waitHelper = WaitHelper.getTestWaiter();
- }
-
- @Override
- public String getUserAgent() {
- return null;
- }
-
- @Override
- public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
- }
-
- @Override
- public int connectionTimeout() {
- return 0;
- }
-
- @Override
- public int socketTimeout() {
- return 0;
- }
-
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return new BasicAuthHeaderProvider(USER_PASS);
- }
-
- @Override
- public void handleHttpProtocolException(ClientProtocolException e) {
- waitHelper.performNotify(e);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- waitHelper.performNotify(e);
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- waitHelper.performNotify(e);
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- handledHttpResponse = true;
- httpResponse = response;
-
- assertEquals(response.getStatusLine().getStatusCode(), 200);
- BaseResource.consumeEntity(response);
- waitHelper.performNotify();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockServer.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockServer.java
deleted file mode 100644
index 4e1d6d7ad..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockServer.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.Utils;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-import org.simpleframework.http.core.Container;
-
-import java.io.IOException;
-import java.io.PrintStream;
-
-import static org.junit.Assert.assertEquals;
-
-public class MockServer implements Container {
- public static final String LOG_TAG = "MockServer";
-
- public int statusCode = 200;
- public String body = "Hello World";
-
- public MockServer() {
- }
-
- public MockServer(int statusCode, String body) {
- this.statusCode = statusCode;
- this.body = body;
- }
-
- public String expectedBasicAuthHeader;
-
- protected PrintStream handleBasicHeaders(Request request, Response response, int code, String contentType) throws IOException {
- return this.handleBasicHeaders(request, response, code, contentType, System.currentTimeMillis());
- }
-
- protected PrintStream handleBasicHeaders(Request request, Response response, int code, String contentType, long time) throws IOException {
- Logger.debug(LOG_TAG, "< Auth header: " + request.getValue("Authorization"));
-
- PrintStream bodyStream = response.getPrintStream();
- response.setCode(code);
- response.setValue("Content-Type", contentType);
- response.setValue("Server", "HelloWorld/1.0 (Simple 4.0)");
- response.setDate("Date", time);
- response.setDate("Last-Modified", time);
-
- final String timestampHeader = Utils.millisecondsToDecimalSecondsString(time);
- response.setValue("X-Weave-Timestamp", timestampHeader);
- Logger.debug(LOG_TAG, "> X-Weave-Timestamp header: " + timestampHeader);
- response.setValue("X-Last-Modified", "12345678");
- return bodyStream;
- }
-
- protected void handle(Request request, Response response, int code, String body) {
- try {
- Logger.debug(LOG_TAG, "Handling request...");
- PrintStream bodyStream = this.handleBasicHeaders(request, response, code, "application/json");
-
- if (expectedBasicAuthHeader != null) {
- Logger.debug(LOG_TAG, "Expecting auth header " + expectedBasicAuthHeader);
- assertEquals(request.getValue("Authorization"), expectedBasicAuthHeader);
- }
-
- bodyStream.println(body);
- bodyStream.close();
- } catch (IOException e) {
- Logger.error(LOG_TAG, "Oops.");
- }
- }
- public void handle(Request request, Response response) {
- this.handle(request, response, statusCode, body);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockSyncClientsEngineStage.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockSyncClientsEngineStage.java
deleted file mode 100644
index efd379e13..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockSyncClientsEngineStage.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers;
-
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.mozilla.gecko.sync.stage.SyncClientsEngineStage;
-
-import static org.junit.Assert.assertTrue;
-
-public class MockSyncClientsEngineStage extends SyncClientsEngineStage {
- public class MockClientUploadDelegate extends ClientUploadDelegate {
- HTTPServerTestHelper data;
-
- public MockClientUploadDelegate(HTTPServerTestHelper data) {
- this.data = data;
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse response) {
- assertTrue(response.wasSuccessful());
- data.stopHTTPServer();
- super.handleRequestSuccess(response);
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- BaseResource.consumeEntity(response);
- data.stopHTTPServer();
- super.handleRequestFailure(response);
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- ex.printStackTrace();
- data.stopHTTPServer();
- super.handleRequestError(ex);
- }
- }
-
- public class TestClientDownloadDelegate extends ClientDownloadDelegate {
- HTTPServerTestHelper data;
-
- public TestClientDownloadDelegate(HTTPServerTestHelper data) {
- this.data = data;
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse response) {
- assertTrue(response.wasSuccessful());
- BaseResource.consumeEntity(response);
- data.stopHTTPServer();
- super.handleRequestSuccess(response);
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- BaseResource.consumeEntity(response);
- super.handleRequestFailure(response);
- data.stopHTTPServer();
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- ex.printStackTrace();
- super.handleRequestError(ex);
- data.stopHTTPServer();
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockWBOServer.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockWBOServer.java
deleted file mode 100644
index 164274bac..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockWBOServer.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.mozilla.android.sync.test.helpers;
-
-import org.simpleframework.http.Path;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.util.HashMap;
-
-/**
- * A trivial server that collects and returns WBOs.
- *
- * @author rnewman
- *
- */
-public class MockWBOServer extends MockServer {
- public HashMap<String, HashMap<String, String> > collections;
-
- public MockWBOServer() {
- collections = new HashMap<String, HashMap<String, String> >();
- }
-
- @Override
- public void handle(Request request, Response response) {
- Path path = request.getPath();
- path.getPath(0);
- // TODO
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/test/TestHTTPServerTestHelper.java b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/test/TestHTTPServerTestHelper.java
deleted file mode 100644
index d79998cc9..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/test/TestHTTPServerTestHelper.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.test.helpers.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper.HTTPServerAlreadyRunningError;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestHTTPServerTestHelper {
- public static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
-
- protected MockServer mockServer = new MockServer();
-
- @Test
- public void testStartStop() {
- // Need to be able to start and stop multiple times.
- for (int i = 0; i < 2; i++) {
- HTTPServerTestHelper httpServer = new HTTPServerTestHelper();
-
- assertNull(httpServer.connection);
- httpServer.startHTTPServer(mockServer);
-
- assertNotNull(httpServer.connection);
- httpServer.stopHTTPServer();
- }
- }
-
- public void startAgain() {
- HTTPServerTestHelper httpServer = new HTTPServerTestHelper();
- httpServer.startHTTPServer(mockServer);
- }
-
- @Test
- public void testStartTwice() {
- HTTPServerTestHelper httpServer = new HTTPServerTestHelper();
-
- httpServer.startHTTPServer(mockServer);
- assertNotNull(httpServer.connection);
-
- // Should not be able to start multiple times.
- try {
- try {
- startAgain();
-
- fail("Expected exception.");
- } catch (Throwable e) {
- assertEquals(HTTPServerAlreadyRunningError.class, e.getClass());
-
- StringWriter sw = new StringWriter();
- e.printStackTrace(new PrintWriter(sw));
- String s = sw.toString();
-
- // Ensure we get a useful stack trace.
- // We should have the method trying to start the server the second time...
- assertTrue(s.contains("startAgain"));
- // ... as well as the the method that started the server the first time.
- assertTrue(s.contains("testStartTwice"));
- }
- } finally {
- httpServer.stopHTTPServer();
- }
- }
-
- protected static class LeakyHTTPServerTestHelper extends HTTPServerTestHelper {
- // Make this constructor public, just for this test.
- public LeakyHTTPServerTestHelper(int port) {
- super(port);
- }
- }
-
- @Test
- public void testForceStartTwice() {
- HTTPServerTestHelper httpServer1 = new HTTPServerTestHelper();
- HTTPServerTestHelper httpServer2 = new LeakyHTTPServerTestHelper(httpServer1.port + 1);
-
- // Should be able to start multiple times if we specify it.
- try {
- httpServer1.startHTTPServer(mockServer);
- assertNotNull(httpServer1.connection);
-
- httpServer2.startHTTPServer(mockServer, true);
- assertNotNull(httpServer2.connection);
- } finally {
- httpServer1.stopHTTPServer();
- httpServer2.stopHTTPServer();
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/GeckoNetworkManagerTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/GeckoNetworkManagerTest.java
deleted file mode 100644
index 8b07d7448..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/GeckoNetworkManagerTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.GeckoNetworkManager.ManagerState;
-import org.mozilla.gecko.GeckoNetworkManager.ManagerEvent;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class GeckoNetworkManagerTest {
- /**
- * Tests the transition matrix.
- */
- @Test
- public void testGetNextState() {
- ManagerState testingState;
-
- testingState = ManagerState.OffNoListeners;
- assertNull(GeckoNetworkManager.getNextState(testingState, ManagerEvent.disableNotifications));
- assertNull(GeckoNetworkManager.getNextState(testingState, ManagerEvent.stop));
- assertNull(GeckoNetworkManager.getNextState(testingState, ManagerEvent.receivedUpdate));
- assertEquals(ManagerState.OnNoListeners, GeckoNetworkManager.getNextState(testingState, ManagerEvent.start));
- assertEquals(ManagerState.OffWithListeners, GeckoNetworkManager.getNextState(testingState, ManagerEvent.enableNotifications));
-
- testingState = ManagerState.OnNoListeners;
- assertNull(GeckoNetworkManager.getNextState(testingState, ManagerEvent.start));
- assertNull(GeckoNetworkManager.getNextState(testingState, ManagerEvent.disableNotifications));
- assertEquals(ManagerState.OnWithListeners, GeckoNetworkManager.getNextState(testingState, ManagerEvent.enableNotifications));
- assertEquals(ManagerState.OffNoListeners, GeckoNetworkManager.getNextState(testingState, ManagerEvent.stop));
- assertEquals(ManagerState.OnNoListeners, GeckoNetworkManager.getNextState(testingState, ManagerEvent.receivedUpdate));
-
- testingState = ManagerState.OnWithListeners;
- assertNull(GeckoNetworkManager.getNextState(testingState, ManagerEvent.start));
- assertNull(GeckoNetworkManager.getNextState(testingState, ManagerEvent.enableNotifications));
- assertEquals(ManagerState.OffWithListeners, GeckoNetworkManager.getNextState(testingState, ManagerEvent.stop));
- assertEquals(ManagerState.OnNoListeners, GeckoNetworkManager.getNextState(testingState, ManagerEvent.disableNotifications));
- assertEquals(ManagerState.OnWithListeners, GeckoNetworkManager.getNextState(testingState, ManagerEvent.receivedUpdate));
-
- testingState = ManagerState.OffWithListeners;
- assertNull(GeckoNetworkManager.getNextState(testingState, ManagerEvent.stop));
- assertNull(GeckoNetworkManager.getNextState(testingState, ManagerEvent.enableNotifications));
- assertNull(GeckoNetworkManager.getNextState(testingState, ManagerEvent.receivedUpdate));
- assertEquals(ManagerState.OnWithListeners, GeckoNetworkManager.getNextState(testingState, ManagerEvent.start));
- assertEquals(ManagerState.OffNoListeners, GeckoNetworkManager.getNextState(testingState, ManagerEvent.disableNotifications));
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/GlobalPageMetadataTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/GlobalPageMetadataTest.java
deleted file mode 100644
index f30ee7a2c..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/GlobalPageMetadataTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko;
-
-import android.content.ContentProviderClient;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.os.RemoteException;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.db.DelegatingTestContentProvider;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserContract.PageMetadata;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.BrowserProvider;
-import org.mozilla.gecko.db.LocalBrowserDB;
-import org.robolectric.shadows.ShadowContentResolver;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class GlobalPageMetadataTest {
- @Test
- public void testQueueing() throws Exception {
- BrowserDB db = new LocalBrowserDB("default");
-
- BrowserProvider provider = new BrowserProvider();
- try {
- provider.onCreate();
- ShadowContentResolver.registerProvider(BrowserContract.AUTHORITY, new DelegatingTestContentProvider(provider));
-
- ShadowContentResolver cr = new ShadowContentResolver();
- ContentProviderClient pageMetadataClient = cr.acquireContentProviderClient(PageMetadata.CONTENT_URI);
-
- assertEquals(0, GlobalPageMetadata.getInstance().getMetadataQueueSize());
-
- // There's not history record for this uri, so test that queueing works.
- GlobalPageMetadata.getInstance().doAddOrQueue(db, pageMetadataClient, "https://mozilla.org", false, "{type: 'article'}");
-
- assertPageMetadataCountForGUID(0, "guid1", pageMetadataClient);
- assertEquals(1, GlobalPageMetadata.getInstance().getMetadataQueueSize());
-
- // Test that queue doesn't duplicate metadata for the same history item.
- GlobalPageMetadata.getInstance().doAddOrQueue(db, pageMetadataClient, "https://mozilla.org", false, "{type: 'article'}");
- assertEquals(1, GlobalPageMetadata.getInstance().getMetadataQueueSize());
-
- // Test that queue is limited to 15 metadata items.
- for (int i = 0; i < 20; i++) {
- GlobalPageMetadata.getInstance().doAddOrQueue(db, pageMetadataClient, "https://mozilla.org/" + i, false, "{type: 'article'}");
- }
- assertEquals(15, GlobalPageMetadata.getInstance().getMetadataQueueSize());
- } finally {
- provider.shutdown();
- }
- }
-
- @Test
- public void testInsertingMetadata() throws Exception {
- BrowserDB db = new LocalBrowserDB("default");
-
- // Start listening for events.
- GlobalPageMetadata.getInstance().init();
-
- BrowserProvider provider = new BrowserProvider();
- try {
- provider.onCreate();
- ShadowContentResolver.registerProvider(BrowserContract.AUTHORITY, new DelegatingTestContentProvider(provider));
-
- ShadowContentResolver cr = new ShadowContentResolver();
- ContentProviderClient historyClient = cr.acquireContentProviderClient(BrowserContract.History.CONTENT_URI);
- ContentProviderClient pageMetadataClient = cr.acquireContentProviderClient(PageMetadata.CONTENT_URI);
-
- // Insert required history item...
- ContentValues cv = new ContentValues();
- cv.put(BrowserContract.History.GUID, "guid1");
- cv.put(BrowserContract.History.URL, "https://mozilla.org");
- historyClient.insert(BrowserContract.History.CONTENT_URI, cv);
-
- // TODO: Main test runner thread finishes before EventDispatcher events are processed...
- // Fire off a message saying that history has been inserted.
- // Bundle message = new Bundle();
- // message.putString(GlobalHistory.EVENT_PARAM_URI, "https://mozilla.org");
- // EventDispatcher.getInstance().dispatch(GlobalHistory.EVENT_URI_AVAILABLE_IN_HISTORY, message);
-
- // For now, let's just try inserting again.
- GlobalPageMetadata.getInstance().doAddOrQueue(db, pageMetadataClient, "https://mozilla.org", false, "{type: 'article', description: 'test article'}");
-
- assertPageMetadataCountForGUID(1, "guid1", pageMetadataClient);
- assertPageMetadataValues(pageMetadataClient, "guid1", false, "{\"type\":\"article\",\"description\":\"test article\"}");
-
- // Test that inserting empty metadata deletes existing metadata record.
- GlobalPageMetadata.getInstance().doAddOrQueue(db, pageMetadataClient, "https://mozilla.org", false, "{}");
- assertPageMetadataCountForGUID(0, "guid1", pageMetadataClient);
-
- // Test that inserting new metadata overrides existing metadata record.
- GlobalPageMetadata.getInstance().doAddOrQueue(db, pageMetadataClient, "https://mozilla.org", true, "{type: 'article', description: 'test article', image_url: 'https://example.com/test.png'}");
- assertPageMetadataValues(pageMetadataClient, "guid1", true, "{\"type\":\"article\",\"description\":\"test article\",\"image_url\":\"https:\\/\\/example.com\\/test.png\"}");
-
- // Insert another history item...
- cv = new ContentValues();
- cv.put(BrowserContract.History.GUID, "guid2");
- cv.put(BrowserContract.History.URL, "https://planet.mozilla.org");
- historyClient.insert(BrowserContract.History.CONTENT_URI, cv);
- // Test that empty metadata doesn't get inserted for a new history.
- GlobalPageMetadata.getInstance().doAddOrQueue(db, pageMetadataClient, "https://planet.mozilla.org", false, "{}");
-
- assertPageMetadataCountForGUID(0, "guid2", pageMetadataClient);
-
- } finally {
- provider.shutdown();
- }
- }
-
- /**
- * Expects cursor to be at the correct position.
- */
- private void assertCursorValues(Cursor cursor, String json, int hasImage, String guid) {
- assertNotNull(cursor);
- assertEquals(json, cursor.getString(cursor.getColumnIndexOrThrow(PageMetadata.JSON)));
- assertEquals(hasImage, cursor.getInt(cursor.getColumnIndexOrThrow(PageMetadata.HAS_IMAGE)));
- assertEquals(guid, cursor.getString(cursor.getColumnIndexOrThrow(PageMetadata.HISTORY_GUID)));
- }
-
- private void assertPageMetadataValues(ContentProviderClient client, String guid, boolean hasImage, String json) {
- final Cursor cursor;
-
- try {
- cursor = client.query(PageMetadata.CONTENT_URI, new String[]{
- PageMetadata.HISTORY_GUID,
- PageMetadata.HAS_IMAGE,
- PageMetadata.JSON,
- PageMetadata.DATE_CREATED
- }, PageMetadata.HISTORY_GUID + " = ?", new String[]{guid}, null);
- } catch (RemoteException e) {
- fail();
- return;
- }
-
- assertNotNull(cursor);
- try {
- assertEquals(1, cursor.getCount());
- assertTrue(cursor.moveToFirst());
- assertCursorValues(cursor, json, hasImage ? 1 : 0, guid);
- } finally {
- cursor.close();
- }
- }
-
- private void assertPageMetadataCountForGUID(int expected, String guid, ContentProviderClient client) {
- final Cursor cursor;
-
- try {
- cursor = client.query(PageMetadata.CONTENT_URI, new String[]{
- PageMetadata.HISTORY_GUID,
- PageMetadata.HAS_IMAGE,
- PageMetadata.JSON,
- PageMetadata.DATE_CREATED
- }, PageMetadata.HISTORY_GUID + " = ?", new String[]{guid}, null);
- } catch (RemoteException e) {
- fail();
- return;
- }
-
- assertNotNull(cursor);
- try {
- assertEquals(expected, cursor.getCount());
- } finally {
- cursor.close();
- }
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/TestGeckoProfile.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/TestGeckoProfile.java
deleted file mode 100644
index c01c2d21a..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/TestGeckoProfile.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import android.content.Context;
-
-import org.json.JSONObject;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.util.FileUtils;
-import org.robolectric.RuntimeEnvironment;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.UUID;
-
-import static org.junit.Assert.*;
-
-/**
- * Unit test methods of the GeckoProfile class.
- */
-@RunWith(TestRunner.class)
-public class TestGeckoProfile {
- private static final String PROFILE_NAME = "profileName";
-
- private static final String CLIENT_ID_JSON_ATTR = "clientID";
- private static final String PROFILE_CREATION_DATE_JSON_ATTR = "created";
-
- @Rule
- public TemporaryFolder dirContainingProfile = new TemporaryFolder();
-
- private File profileDir;
- private GeckoProfile profile;
-
- private File clientIdFile;
- private File timesFile;
-
- @Before
- public void setUp() throws IOException {
- final Context context = RuntimeEnvironment.application;
- profileDir = dirContainingProfile.newFolder();
- profile = GeckoProfile.get(context, PROFILE_NAME, profileDir);
-
- clientIdFile = new File(profileDir, "datareporting/state.json");
- timesFile = new File(profileDir, "times.json");
- }
-
- public void assertValidClientId(final String clientId) {
- // This isn't the method we use in the main GeckoProfile code, but it should be equivalent.
- UUID.fromString(clientId); // assert: will throw if null or invalid UUID.
- }
-
- @Test
- public void testGetDir() {
- assertEquals("Profile dir argument during construction and returned value are equal",
- profileDir, profile.getDir());
- }
-
- @Test
- public void testGetClientIdFreshProfile() throws Exception {
- assertFalse("client ID file does not exist", clientIdFile.exists());
-
- // No existing client ID file: we're expected to create one.
- final String clientId = profile.getClientId();
- assertValidClientId(clientId);
- assertTrue("client ID file exists", clientIdFile.exists());
-
- assertEquals("Returned client ID is the same as the one previously returned", clientId, profile.getClientId());
- assertEquals("clientID file format matches expectations", clientId, readClientIdFromFile(clientIdFile));
- }
-
- @Test
- public void testGetClientIdFileAlreadyExists() throws Exception {
- final String validClientId = "905de1c0-0ea6-4a43-95f9-6170035f5a82";
- assertTrue("Created the parent dirs of the client ID file", clientIdFile.getParentFile().mkdirs());
- writeClientIdToFile(clientIdFile, validClientId);
-
- final String clientIdFromProfile = profile.getClientId();
- assertEquals("Client ID from method matches ID written to disk", validClientId, clientIdFromProfile);
- }
-
- @Test
- public void testGetClientIdMigrateFromFHR() throws Exception {
- final File fhrClientIdFile = new File(profileDir, "healthreport/state.json");
- final String fhrClientId = "905de1c0-0ea6-4a43-95f9-6170035f5a82";
-
- assertFalse("client ID file does not exist", clientIdFile.exists());
- assertTrue("Created FHR data directory", new File(profileDir, "healthreport").mkdirs());
- writeClientIdToFile(fhrClientIdFile, fhrClientId);
- assertEquals("Migrated Client ID equals FHR client ID", fhrClientId, profile.getClientId());
-
- // Verify migration wrote to contemporary client ID file.
- assertTrue("Client ID file created during migration", clientIdFile.exists());
- assertEquals("Migrated client ID on disk equals value returned from method",
- fhrClientId, readClientIdFromFile(clientIdFile));
-
- assertTrue("Deleted FHR clientID file", fhrClientIdFile.delete());
- assertEquals("Ensure method calls read from newly created client ID file & not FHR client ID file",
- fhrClientId, profile.getClientId());
- }
-
- @Test
- public void testGetClientIdInvalidIdOnDisk() throws Exception {
- assertTrue("Created the parent dirs of the client ID file", clientIdFile.getParentFile().mkdirs());
- writeClientIdToFile(clientIdFile, "");
- final String clientIdForEmptyString = profile.getClientId();
- assertValidClientId(clientIdForEmptyString);
- assertNotEquals("A new client ID was created when the empty String was written to disk", "", clientIdForEmptyString);
-
- writeClientIdToFile(clientIdFile, "invalidClientId");
- final String clientIdForInvalidClientId = profile.getClientId();
- assertValidClientId(clientIdForInvalidClientId);
- assertNotEquals("A new client ID was created when an invalid client ID was written to disk",
- "invalidClientId", clientIdForInvalidClientId);
- }
-
- @Test
- public void testGetClientIdMissingClientIdJSONAttr() throws Exception {
- final String validClientId = "905de1c0-0ea6-4a43-95f9-6170035f5a82";
- final JSONObject objMissingClientId = new JSONObject();
- objMissingClientId.put("irrelevantKey", validClientId);
- assertTrue("Created the parent dirs of the client ID file", clientIdFile.getParentFile().mkdirs());
- FileUtils.writeJSONObjectToFile(clientIdFile, objMissingClientId);
-
- final String clientIdForMissingAttr = profile.getClientId();
- assertValidClientId(clientIdForMissingAttr);
- assertNotEquals("Did not use other attr when JSON attr was missing", validClientId, clientIdForMissingAttr);
- }
-
- @Test
- public void testGetClientIdInvalidIdFileFormat() throws Exception {
- final String validClientId = "905de1c0-0ea6-4a43-95f9-6170035f5a82";
- assertTrue("Created the parent dirs of the client ID file", clientIdFile.getParentFile().mkdirs());
- FileUtils.writeStringToFile(clientIdFile, "clientID: \"" + validClientId + "\"");
-
- final String clientIdForInvalidFormat = profile.getClientId();
- assertValidClientId(clientIdForInvalidFormat);
- assertNotEquals("Created new ID when file format was invalid", validClientId, clientIdForInvalidFormat);
- }
-
- @Test
- public void testEnsureParentDirs() {
- final File grandParentDir = new File(profileDir, "grandParent");
- final File parentDir = new File(grandParentDir, "parent");
- final File childFile = new File(parentDir, "child");
-
- // Assert initial state.
- assertFalse("Topmost parent dir should not exist yet", grandParentDir.exists());
- assertFalse("Bottommost parent dir should not exist yet", parentDir.exists());
- assertFalse("Child file should not exist", childFile.exists());
-
- final String fakeFullPath = "grandParent/parent/child";
- assertTrue("Parent directories should be created", profile.ensureParentDirs(fakeFullPath));
- assertTrue("Topmost parent dir should have been created", grandParentDir.exists());
- assertTrue("Bottommost parent dir should have been created", parentDir.exists());
- assertFalse("Child file should not have been created", childFile.exists());
-
- // Parents already exist because this is the second time we're calling ensureParentDirs.
- assertTrue("Expect true if parent directories already exist", profile.ensureParentDirs(fakeFullPath));
-
- // Assert error condition.
- assertTrue("Ensure we can change permissions on profile dir for testing", profileDir.setReadOnly());
- assertFalse("Expect false if the parent dir could not be created", profile.ensureParentDirs("unwritableDir/child"));
- }
-
- @Test
- public void testIsClientIdValid() {
- final String[] validClientIds = new String[] {
- "905de1c0-0ea6-4a43-95f9-6170035f5a82",
- "905de1c0-0ea6-4a43-95f9-6170035f5a83",
- "57472f82-453d-4c55-b59c-d3c0e97b76a1",
- "895745d1-f31e-46c3-880e-b4dd72963d4f",
- };
- for (final String validClientId : validClientIds) {
- assertTrue("Client ID, " + validClientId + ", is valid", profile.isClientIdValid(validClientId));
- }
-
- final String[] invalidClientIds = new String[] {
- null,
- "",
- "a",
- "anInvalidClientId",
- "905de1c0-0ea6-4a43-95f9-6170035f5a820", // too long (last section)
- "905de1c0-0ea6-4a43-95f9-6170035f5a8", // too short (last section)
- "05de1c0-0ea6-4a43-95f9-6170035f5a82", // too short (first section)
- "905de1c0-0ea6-4a43-95f9-6170035f5a8!", // contains a symbol
- };
- for (final String invalidClientId : invalidClientIds) {
- assertFalse("Client ID, " + invalidClientId + ", is invalid", profile.isClientIdValid(invalidClientId));
- }
-
- // We generate client IDs using UUID - better make sure they're valid.
- for (int i = 0; i < 30; ++i) {
- final String generatedClientId = UUID.randomUUID().toString();
- assertTrue("Generated client ID from UUID, " + generatedClientId + ", is valid",
- profile.isClientIdValid(generatedClientId));
- }
- }
-
- @Test
- public void testGetProfileCreationDateFromTimesFile() throws Exception {
- final long expectedDate = System.currentTimeMillis();
- final JSONObject expectedObj = new JSONObject();
- expectedObj.put(PROFILE_CREATION_DATE_JSON_ATTR, expectedDate);
- FileUtils.writeJSONObjectToFile(timesFile, expectedObj);
-
- final Context context = RuntimeEnvironment.application;
- final long actualDate = profile.getAndPersistProfileCreationDate(context);
- assertEquals("Date from disk equals date inserted to disk", expectedDate, actualDate);
-
- final long actualDateFromDisk = readProfileCreationDateFromFile(timesFile);
- assertEquals("Date in times.json has not changed after accessing profile creation date",
- expectedDate, actualDateFromDisk);
- }
-
- @Test
- public void testGetProfileCreationDateTimesFileDoesNotExist() throws Exception {
- assertFalse("Times.json does not already exist", timesFile.exists());
-
- final Context context = RuntimeEnvironment.application;
- final long actualDate = profile.getAndPersistProfileCreationDate(context);
- // I'd prefer to mock so we can return and verify a specific value but we can't mock
- // GeckoProfile because it's final. Instead, we check if the value is at least reasonable.
- assertTrue("Date from method is positive", actualDate >= 0);
- assertTrue("Date from method is less than current time", actualDate < System.currentTimeMillis());
-
- assertTrue("Times.json exists after getting profile", timesFile.exists());
- final long actualDateFromDisk = readProfileCreationDateFromFile(timesFile);
- assertEquals("Date from disk equals returned value", actualDate, actualDateFromDisk);
- }
-
- private static long readProfileCreationDateFromFile(final File file) throws Exception {
- final JSONObject actualObj = FileUtils.readJSONObjectFromFile(file);
- return actualObj.getLong(PROFILE_CREATION_DATE_JSON_ATTR);
- }
-
- private String readClientIdFromFile(final File file) throws Exception {
- final JSONObject obj = FileUtils.readJSONObjectFromFile(file);
- return obj.getString(CLIENT_ID_JSON_ATTR);
- }
-
- private void writeClientIdToFile(final File file, final String clientId) throws Exception {
- final JSONObject obj = new JSONObject();
- obj.put(CLIENT_ID_JSON_ATTR, clientId);
- FileUtils.writeJSONObjectToFile(file, obj);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/activitystream/TestActivityStream.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/activitystream/TestActivityStream.java
deleted file mode 100644
index 71f01b437..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/activitystream/TestActivityStream.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.activitystream;
-
-import android.os.SystemClock;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.robolectric.Robolectric;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowLooper;
-
-import static org.junit.Assert.assertEquals;
-
-@RunWith(TestRunner.class)
-public class TestActivityStream {
- /**
- * Unit tests for ActivityStream.extractLabel().
- *
- * Most test cases are based on this list:
- * https://gist.github.com/nchapman/36502ad115e8825d522a66549971a3f0
- */
- @Test
- public void testExtractLabelWithPath() {
- // Empty values
- assertLabelEquals("", "", true);
- assertLabelEquals("", null, true);
-
- // Without path
- assertLabelEquals("news.ycombinator", "https://news.ycombinator.com/", true);
- assertLabelEquals("sql.telemetry.mozilla", "https://sql.telemetry.mozilla.org/", true);
- assertLabelEquals("sso.mozilla", "http://sso.mozilla.com/", true);
- assertLabelEquals("youtube", "http://youtube.com/", true);
- assertLabelEquals("images.google", "http://images.google.com/", true);
- assertLabelEquals("smile.amazon", "http://smile.amazon.com/", true);
- assertLabelEquals("localhost", "http://localhost:5000/", true);
- assertLabelEquals("independent", "http://www.independent.co.uk/", true);
-
- // With path
- assertLabelEquals("firefox", "https://addons.mozilla.org/en-US/firefox/", true);
- assertLabelEquals("activity-stream", "https://trello.com/b/KX3hV8XS/activity-stream", true);
- assertLabelEquals("activity-stream", "https://github.com/mozilla/activity-stream", true);
- assertLabelEquals("sidekiq", "https://dispatch-news.herokuapp.com/sidekiq", true);
- assertLabelEquals("nchapman", "https://github.com/nchapman/", true);
-
- // Unusable paths
- assertLabelEquals("phonebook.mozilla","https://phonebook.mozilla.org/mellon/login?ReturnTo=https%3A%2F%2Fphonebook.mozilla.org%2F&IdP=http%3A%2F%2Fwww.okta.com", true);
- assertLabelEquals("ipay.adp", "https://ipay.adp.com/iPay/index.jsf", true);
- assertLabelEquals("calendar.google", "https://calendar.google.com/calendar/render?pli=1#main_7", true);
- assertLabelEquals("myworkday", "https://www.myworkday.com/vhr_mozilla/d/home.htmld", true);
- assertLabelEquals("mail.google", "https://mail.google.com/mail/u/1/#inbox", true);
- assertLabelEquals("docs.google", "https://docs.google.com/presentation/d/11cyrcwhKTmBdEBIZ3szLO0-_Imrx2CGV2B9_LZHDrds/edit#slide=id.g15d41bb0f3_0_82", true);
-
- // Special cases
- assertLabelEquals("irccloud.mozilla", "https://irccloud.mozilla.com/#!/ircs://irc1.dmz.scl3.mozilla.com:6697/%23universal-search", true);
- }
-
- @Test
- public void testExtractLabelWithoutPath() {
- assertLabelEquals("addons.mozilla", "https://addons.mozilla.org/en-US/firefox/", false);
- assertLabelEquals("trello", "https://trello.com/b/KX3hV8XS/activity-stream", false);
- assertLabelEquals("github", "https://github.com/mozilla/activity-stream", false);
- assertLabelEquals("dispatch-news", "https://dispatch-news.herokuapp.com/sidekiq", false);
- assertLabelEquals("github", "https://github.com/nchapman/", false);
- }
-
- private void assertLabelEquals(String expectedLabel, String url, boolean usePath) {
- final String[] actualLabel = new String[1];
-
- ActivityStream.LabelCallback callback = new ActivityStream.LabelCallback() {
- @Override
- public void onLabelExtracted(String label) {
- actualLabel[0] = label;
- }
- };
-
- ActivityStream.extractLabel(RuntimeEnvironment.application, url, usePath, callback);
-
- ShadowLooper.runUiThreadTasks();
-
- assertEquals(expectedLabel, actualLabel[0]);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/common/log/writers/test/TestLogWriters.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/common/log/writers/test/TestLogWriters.java
deleted file mode 100644
index 61dd33965..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/common/log/writers/test/TestLogWriters.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.common.log.writers.test;
-
-import android.util.Log;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.common.log.writers.LevelFilteringLogWriter;
-import org.mozilla.gecko.background.common.log.writers.LogWriter;
-import org.mozilla.gecko.background.common.log.writers.PrintLogWriter;
-import org.mozilla.gecko.background.common.log.writers.SimpleTagLogWriter;
-import org.mozilla.gecko.background.common.log.writers.StringLogWriter;
-import org.mozilla.gecko.background.common.log.writers.ThreadLocalTagLogWriter;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestLogWriters {
-
- public static final String TEST_LOG_TAG_1 = "TestLogTag1";
- public static final String TEST_LOG_TAG_2 = "TestLogTag2";
-
- public static final String TEST_MESSAGE_1 = "LOG TEST MESSAGE one";
- public static final String TEST_MESSAGE_2 = "LOG TEST MESSAGE two";
- public static final String TEST_MESSAGE_3 = "LOG TEST MESSAGE three";
-
- @Before
- public void setUp() {
- Logger.stopLoggingToAll();
- }
-
- @After
- public void tearDown() {
- Logger.stopLoggingToAll();
- }
-
- @Test
- public void testStringLogWriter() {
- StringLogWriter lw = new StringLogWriter();
-
- Logger.error(TEST_LOG_TAG_1, TEST_MESSAGE_1, new RuntimeException());
- Logger.startLoggingTo(lw);
- Logger.error(TEST_LOG_TAG_1, TEST_MESSAGE_2);
- Logger.warn(TEST_LOG_TAG_1, TEST_MESSAGE_2);
- Logger.info(TEST_LOG_TAG_1, TEST_MESSAGE_2);
- Logger.debug(TEST_LOG_TAG_1, TEST_MESSAGE_2);
- Logger.trace(TEST_LOG_TAG_1, TEST_MESSAGE_2);
- Logger.stopLoggingTo(lw);
- Logger.error(TEST_LOG_TAG_2, TEST_MESSAGE_3, new RuntimeException());
-
- String s = lw.toString();
- assertFalse(s.contains("RuntimeException"));
- assertFalse(s.contains(".java"));
- assertTrue(s.contains(TEST_LOG_TAG_1));
- assertFalse(s.contains(TEST_LOG_TAG_2));
- assertFalse(s.contains(TEST_MESSAGE_1));
- assertTrue(s.contains(TEST_MESSAGE_2));
- assertFalse(s.contains(TEST_MESSAGE_3));
- }
-
- @Test
- public void testSingleTagLogWriter() {
- final String SINGLE_TAG = "XXX";
- StringLogWriter lw = new StringLogWriter();
-
- Logger.startLoggingTo(new SimpleTagLogWriter(SINGLE_TAG, lw));
- Logger.error(TEST_LOG_TAG_1, TEST_MESSAGE_1);
- Logger.warn(TEST_LOG_TAG_2, TEST_MESSAGE_2);
-
- String s = lw.toString();
- for (String line : s.split("\n")) {
- assertTrue(line.startsWith(SINGLE_TAG));
- }
- assertTrue(s.startsWith(SINGLE_TAG + " :: E :: " + TEST_LOG_TAG_1));
- }
-
- @Test
- public void testLevelFilteringLogWriter() {
- StringLogWriter lw = new StringLogWriter();
-
- assertFalse(new LevelFilteringLogWriter(Log.WARN, lw).shouldLogVerbose(TEST_LOG_TAG_1));
- assertTrue(new LevelFilteringLogWriter(Log.VERBOSE, lw).shouldLogVerbose(TEST_LOG_TAG_1));
-
- Logger.startLoggingTo(new LevelFilteringLogWriter(Log.WARN, lw));
- Logger.error(TEST_LOG_TAG_1, TEST_MESSAGE_2);
- Logger.warn(TEST_LOG_TAG_1, TEST_MESSAGE_2);
- Logger.info(TEST_LOG_TAG_1, TEST_MESSAGE_2);
- Logger.debug(TEST_LOG_TAG_1, TEST_MESSAGE_2);
- Logger.trace(TEST_LOG_TAG_1, TEST_MESSAGE_2);
-
- String s = lw.toString();
- assertTrue(s.contains(PrintLogWriter.ERROR));
- assertTrue(s.contains(PrintLogWriter.WARN));
- assertFalse(s.contains(PrintLogWriter.INFO));
- assertFalse(s.contains(PrintLogWriter.DEBUG));
- assertFalse(s.contains(PrintLogWriter.VERBOSE));
- }
-
- @Test
- public void testThreadLocalLogWriter() throws InterruptedException {
- final InheritableThreadLocal<String> logTag = new InheritableThreadLocal<String>() {
- @Override
- protected String initialValue() {
- return "PARENT";
- }
- };
-
- final StringLogWriter stringLogWriter = new StringLogWriter();
- final LogWriter logWriter = new ThreadLocalTagLogWriter(logTag, stringLogWriter);
-
- try {
- Logger.startLoggingTo(logWriter);
-
- Logger.info("parent tag before", "parent message before");
-
- int threads = 3;
- final CountDownLatch latch = new CountDownLatch(threads);
-
- for (int thread = 0; thread < threads; thread++) {
- final int threadNumber = thread;
-
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- logTag.set("CHILD" + threadNumber);
- Logger.info("child tag " + threadNumber, "child message " + threadNumber);
- } finally {
- latch.countDown();
- }
- }
- }).start();
- }
-
- latch.await();
-
- Logger.info("parent tag after", "parent message after");
-
- String s = stringLogWriter.toString();
- List<String> lines = Arrays.asList(s.split("\n"));
-
- // Because tests are run in a multi-threaded environment, we get
- // additional logs that are not generated by this test. So we test that we
- // get all the messages in a reasonable order.
- try {
- int parent1 = lines.indexOf("PARENT :: I :: parent tag before :: parent message before");
- int parent2 = lines.indexOf("PARENT :: I :: parent tag after :: parent message after");
-
- assertTrue(parent1 >= 0);
- assertTrue(parent2 >= 0);
- assertTrue(parent1 < parent2);
-
- for (int thread = 0; thread < threads; thread++) {
- int child = lines.indexOf("CHILD" + thread + " :: I :: child tag " + thread + " :: child message " + thread);
- assertTrue(child >= 0);
- assertTrue(parent1 < child);
- assertTrue(child < parent2);
- }
- } catch (Throwable e) {
- // Shouldn't happen. Let's dump to aid debugging.
- e.printStackTrace();
- assertEquals("\0", s);
- }
- } finally {
- Logger.stopLoggingTo(logWriter);
- }
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/DelegatingTestContentProvider.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/DelegatingTestContentProvider.java
deleted file mode 100644
index 91a36f7d1..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/DelegatingTestContentProvider.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.background.db;
-
-import android.content.ContentProvider;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentValues;
-import android.content.OperationApplicationException;
-import android.database.Cursor;
-import android.net.Uri;
-
-import org.mozilla.gecko.db.BrowserContract;
-
-import java.util.ArrayList;
-
-/**
- * Wrap a ContentProvider, appending &test=1 to all queries.
- */
-public class DelegatingTestContentProvider extends ContentProvider {
- protected final ContentProvider mTargetProvider;
-
- protected static Uri appendUriParam(Uri uri, String param, String value) {
- return uri.buildUpon().appendQueryParameter(param, value).build();
- }
-
- public DelegatingTestContentProvider(ContentProvider targetProvider) {
- super();
- mTargetProvider = targetProvider;
- }
-
- private Uri appendTestParam(Uri uri) {
- return appendUriParam(uri, BrowserContract.PARAM_IS_TEST, "1");
- }
-
- @Override
- public boolean onCreate() {
- return mTargetProvider.onCreate();
- }
-
- @Override
- public String getType(Uri uri) {
- return mTargetProvider.getType(uri);
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return mTargetProvider.delete(appendTestParam(uri), selection, selectionArgs);
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return mTargetProvider.insert(appendTestParam(uri), values);
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
- return mTargetProvider.update(appendTestParam(uri), values,
- selection, selectionArgs);
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- return mTargetProvider.query(appendTestParam(uri), projection, selection,
- selectionArgs, sortOrder);
- }
-
- @Override
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
- throws OperationApplicationException {
- return mTargetProvider.applyBatch(operations);
- }
-
- @Override
- public int bulkInsert(Uri uri, ContentValues[] values) {
- return mTargetProvider.bulkInsert(appendTestParam(uri), values);
- }
-
- public ContentProvider getTargetProvider() {
- return mTargetProvider;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/TestTabsProvider.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/TestTabsProvider.java
deleted file mode 100644
index f0d468e07..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/TestTabsProvider.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import android.content.ContentProviderClient;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-
-import org.json.simple.JSONArray;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.TabsProvider;
-import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
-import org.mozilla.gecko.sync.repositories.domain.TabsRecord;
-import org.robolectric.shadows.ShadowContentResolver;
-
-@RunWith(TestRunner.class)
-public class TestTabsProvider {
- public static final String TEST_CLIENT_GUID = "test guid"; // Real GUIDs never contain spaces.
- public static final String TEST_CLIENT_NAME = "test client name";
-
- public static final String CLIENTS_GUID_IS = BrowserContract.Clients.GUID + " = ?";
- public static final String TABS_CLIENT_GUID_IS = BrowserContract.Tabs.CLIENT_GUID + " = ?";
-
- protected Tab testTab1;
- protected Tab testTab2;
- protected Tab testTab3;
-
- protected TabsProvider provider;
-
- @Before
- public void setUp() {
- provider = new TabsProvider();
- provider.onCreate();
- ShadowContentResolver.registerProvider(BrowserContract.TABS_AUTHORITY, new DelegatingTestContentProvider(provider));
- }
-
- @After
- public void tearDown() throws Exception {
- provider.shutdown();
- provider = null;
- }
-
- protected ContentProviderClient getClientsClient() {
- final ShadowContentResolver cr = new ShadowContentResolver();
- return cr.acquireContentProviderClient(BrowserContractHelpers.CLIENTS_CONTENT_URI);
- }
-
- protected ContentProviderClient getTabsClient() {
- final ShadowContentResolver cr = new ShadowContentResolver();
- return cr.acquireContentProviderClient(BrowserContractHelpers.TABS_CONTENT_URI);
- }
-
- protected int deleteTestClient(final ContentProviderClient clientsClient) throws RemoteException {
- if (clientsClient == null) {
- throw new IllegalStateException("Provided ContentProviderClient is null");
- }
- return clientsClient.delete(BrowserContractHelpers.CLIENTS_CONTENT_URI, CLIENTS_GUID_IS, new String[] { TEST_CLIENT_GUID });
- }
-
- protected int deleteAllTestTabs(final ContentProviderClient tabsClient) throws RemoteException {
- if (tabsClient == null) {
- throw new IllegalStateException("Provided ContentProviderClient is null");
- }
- return tabsClient.delete(BrowserContractHelpers.TABS_CONTENT_URI, TABS_CLIENT_GUID_IS, new String[] { TEST_CLIENT_GUID });
- }
-
- protected void insertTestClient(final ContentProviderClient clientsClient) throws RemoteException {
- ContentValues cv = new ContentValues();
- cv.put(BrowserContract.Clients.GUID, TEST_CLIENT_GUID);
- cv.put(BrowserContract.Clients.NAME, TEST_CLIENT_NAME);
- clientsClient.insert(BrowserContractHelpers.CLIENTS_CONTENT_URI, cv);
- }
-
- @SuppressWarnings("unchecked")
- protected void insertSomeTestTabs(ContentProviderClient tabsClient) throws RemoteException {
- final JSONArray history1 = new JSONArray();
- history1.add("http://test.com/test1.html");
- testTab1 = new Tab("test title 1", "http://test.com/test1.png", history1, 1000);
-
- final JSONArray history2 = new JSONArray();
- history2.add("http://test.com/test2.html#1");
- history2.add("http://test.com/test2.html#2");
- history2.add("http://test.com/test2.html#3");
- testTab2 = new Tab("test title 2", "http://test.com/test2.png", history2, 2000);
-
- final JSONArray history3 = new JSONArray();
- history3.add("http://test.com/test3.html#1");
- history3.add("http://test.com/test3.html#2");
- testTab3 = new Tab("test title 3", "http://test.com/test3.png", history3, 3000);
-
- tabsClient.insert(BrowserContractHelpers.TABS_CONTENT_URI, testTab1.toContentValues(TEST_CLIENT_GUID, 0));
- tabsClient.insert(BrowserContractHelpers.TABS_CONTENT_URI, testTab2.toContentValues(TEST_CLIENT_GUID, 1));
- tabsClient.insert(BrowserContractHelpers.TABS_CONTENT_URI, testTab3.toContentValues(TEST_CLIENT_GUID, 2));
- }
-
- // Sanity.
- @Test
- public void testObtainCP() {
- final ContentProviderClient clientsClient = getClientsClient();
- Assert.assertNotNull(clientsClient);
- clientsClient.release();
-
- final ContentProviderClient tabsClient = getTabsClient();
- Assert.assertNotNull(tabsClient);
- tabsClient.release();
- }
-
- @Test
- public void testDeleteEmptyClients() throws RemoteException {
- final Uri uri = BrowserContractHelpers.CLIENTS_CONTENT_URI;
- final ContentProviderClient clientsClient = getClientsClient();
-
- // Have to ensure that it's empty…
- clientsClient.delete(uri, null, null);
-
- int deleted = clientsClient.delete(uri, null, null);
- Assert.assertEquals(0, deleted);
- }
-
- @Test
- public void testDeleteEmptyTabs() throws RemoteException {
- final ContentProviderClient tabsClient = getTabsClient();
-
- // Have to ensure that it's empty…
- deleteAllTestTabs(tabsClient);
-
- int deleted = deleteAllTestTabs(tabsClient);
- Assert.assertEquals(0, deleted);
- }
-
- @Test
- public void testStoreAndRetrieveClients() throws RemoteException {
- final Uri uri = BrowserContractHelpers.CLIENTS_CONTENT_URI;
- final ContentProviderClient clientsClient = getClientsClient();
-
- // Have to ensure that it's empty…
- clientsClient.delete(uri, null, null);
-
- final long now = System.currentTimeMillis();
- final ContentValues first = new ContentValues();
- final ContentValues second = new ContentValues();
- first.put(BrowserContract.Clients.GUID, "abcdefghijkl");
- first.put(BrowserContract.Clients.NAME, "Frist Psot");
- first.put(BrowserContract.Clients.LAST_MODIFIED, now + 1);
- second.put(BrowserContract.Clients.GUID, "mnopqrstuvwx");
- second.put(BrowserContract.Clients.NAME, "Second!!1!");
- second.put(BrowserContract.Clients.LAST_MODIFIED, now + 2);
-
- ContentValues[] values = new ContentValues[] { first, second };
- final int inserted = clientsClient.bulkInsert(uri, values);
- Assert.assertEquals(2, inserted);
-
- final String since = BrowserContract.Clients.LAST_MODIFIED + " >= ?";
- final String[] nowArg = new String[] { String.valueOf(now) };
- final String guidAscending = BrowserContract.Clients.GUID + " ASC";
- Cursor cursor = clientsClient.query(uri, null, since, nowArg, guidAscending);
-
- Assert.assertNotNull(cursor);
- try {
- Assert.assertTrue(cursor.moveToFirst());
- Assert.assertEquals(2, cursor.getCount());
-
- final String g1 = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Clients.GUID));
- final String n1 = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Clients.NAME));
- final long m1 = cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Clients.LAST_MODIFIED));
- Assert.assertEquals(first.get(BrowserContract.Clients.GUID), g1);
- Assert.assertEquals(first.get(BrowserContract.Clients.NAME), n1);
- Assert.assertEquals(now + 1, m1);
-
- Assert.assertTrue(cursor.moveToNext());
- final String g2 = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Clients.GUID));
- final String n2 = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Clients.NAME));
- final long m2 = cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Clients.LAST_MODIFIED));
- Assert.assertEquals(second.get(BrowserContract.Clients.GUID), g2);
- Assert.assertEquals(second.get(BrowserContract.Clients.NAME), n2);
- Assert.assertEquals(now + 2, m2);
-
- Assert.assertFalse(cursor.moveToNext());
- } finally {
- cursor.close();
- }
-
- int deleted = clientsClient.delete(uri, null, null);
- Assert.assertEquals(2, deleted);
- }
-
- @Test
- public void testTabFromCursor() throws Exception {
- final ContentProviderClient tabsClient = getTabsClient();
- final ContentProviderClient clientsClient = getClientsClient();
-
- deleteAllTestTabs(tabsClient);
- deleteTestClient(clientsClient);
- insertTestClient(clientsClient);
- insertSomeTestTabs(tabsClient);
-
- final String positionAscending = BrowserContract.Tabs.POSITION + " ASC";
- Cursor cursor = null;
- try {
- cursor = tabsClient.query(BrowserContractHelpers.TABS_CONTENT_URI, null, TABS_CLIENT_GUID_IS, new String[] { TEST_CLIENT_GUID }, positionAscending);
- Assert.assertEquals(3, cursor.getCount());
-
- cursor.moveToFirst();
- final Tab parsed1 = Tab.fromCursor(cursor);
- Assert.assertEquals(testTab1, parsed1);
-
- cursor.moveToNext();
- final Tab parsed2 = Tab.fromCursor(cursor);
- Assert.assertEquals(testTab2, parsed2);
-
- cursor.moveToPosition(2);
- final Tab parsed3 = Tab.fromCursor(cursor);
- Assert.assertEquals(testTab3, parsed3);
- } finally {
- cursor.close();
- }
- }
-
- @Test
- public void testDeletingClientDeletesTabs() throws Exception {
- final ContentProviderClient tabsClient = getTabsClient();
- final ContentProviderClient clientsClient = getClientsClient();
-
- deleteAllTestTabs(tabsClient);
- deleteTestClient(clientsClient);
- insertTestClient(clientsClient);
- insertSomeTestTabs(tabsClient);
-
- // Delete just the client...
- clientsClient.delete(BrowserContractHelpers.CLIENTS_CONTENT_URI, CLIENTS_GUID_IS, new String [] { TEST_CLIENT_GUID });
-
- Cursor cursor = null;
- try {
- cursor = tabsClient.query(BrowserContractHelpers.TABS_CONTENT_URI, null, TABS_CLIENT_GUID_IS, new String[] { TEST_CLIENT_GUID }, null);
- // ... and all that client's tabs should be removed.
- Assert.assertEquals(0, cursor.getCount());
- } finally {
- cursor.close();
- }
- }
-
- @Test
- public void testTabsRecordFromCursor() throws Exception {
- final ContentProviderClient tabsClient = getTabsClient();
-
- deleteAllTestTabs(tabsClient);
- insertTestClient(getClientsClient());
- insertSomeTestTabs(tabsClient);
-
- final String positionAscending = BrowserContract.Tabs.POSITION + " ASC";
- Cursor cursor = null;
- try {
- cursor = tabsClient.query(BrowserContractHelpers.TABS_CONTENT_URI, null, TABS_CLIENT_GUID_IS, new String[] { TEST_CLIENT_GUID }, positionAscending);
- Assert.assertEquals(3, cursor.getCount());
-
- cursor.moveToPosition(1);
-
- final TabsRecord tabsRecord = FennecTabsRepository.tabsRecordFromCursor(cursor, TEST_CLIENT_GUID, TEST_CLIENT_NAME);
-
- // Make sure we clean up after ourselves.
- Assert.assertEquals(1, cursor.getPosition());
-
- Assert.assertEquals(TEST_CLIENT_GUID, tabsRecord.guid);
- Assert.assertEquals(TEST_CLIENT_NAME, tabsRecord.clientName);
-
- Assert.assertEquals(3, tabsRecord.tabs.size());
- Assert.assertEquals(testTab1, tabsRecord.tabs.get(0));
- Assert.assertEquals(testTab2, tabsRecord.tabs.get(1));
- Assert.assertEquals(testTab3, tabsRecord.tabs.get(2));
-
- Assert.assertEquals(Math.max(Math.max(testTab1.lastUsed, testTab2.lastUsed), testTab3.lastUsed), tabsRecord.lastModified);
- } finally {
- cursor.close();
- }
- }
-
- // Verify that we can fetch a record when there are no local tabs at all.
- @Test
- public void testEmptyTabsRecordFromCursor() throws Exception {
- final ContentProviderClient tabsClient = getTabsClient();
-
- deleteAllTestTabs(tabsClient);
-
- final String positionAscending = BrowserContract.Tabs.POSITION + " ASC";
- Cursor cursor = null;
- try {
- cursor = tabsClient.query(BrowserContractHelpers.TABS_CONTENT_URI, null, TABS_CLIENT_GUID_IS, new String[] { TEST_CLIENT_GUID }, positionAscending);
- Assert.assertEquals(0, cursor.getCount());
-
- final TabsRecord tabsRecord = FennecTabsRepository.tabsRecordFromCursor(cursor, TEST_CLIENT_GUID, TEST_CLIENT_NAME);
-
- Assert.assertEquals(TEST_CLIENT_GUID, tabsRecord.guid);
- Assert.assertEquals(TEST_CLIENT_NAME, tabsRecord.clientName);
-
- Assert.assertNotNull(tabsRecord.tabs);
- Assert.assertEquals(0, tabsRecord.tabs.size());
-
- Assert.assertEquals(0, tabsRecord.lastModified);
- } finally {
- cursor.close();
- }
- }
-
- // Not much of a test, but verifies the tabs record at least agrees with the
- // disk data and doubles as a database inspector.
- @Test
- public void testLocalTabs() throws Exception {
- final ContentProviderClient tabsClient = getTabsClient();
-
- final String positionAscending = BrowserContract.Tabs.POSITION + " ASC";
- Cursor cursor = null;
- try {
- // Keep this in sync with the Fennec schema.
- cursor = tabsClient.query(BrowserContractHelpers.TABS_CONTENT_URI, null, BrowserContract.Tabs.CLIENT_GUID + " IS NULL", null, positionAscending);
- CursorDumper.dumpCursor(cursor);
-
- final TabsRecord tabsRecord = FennecTabsRepository.tabsRecordFromCursor(cursor, TEST_CLIENT_GUID, TEST_CLIENT_NAME);
-
- Assert.assertEquals(TEST_CLIENT_GUID, tabsRecord.guid);
- Assert.assertEquals(TEST_CLIENT_NAME, tabsRecord.clientName);
-
- Assert.assertNotNull(tabsRecord.tabs);
- Assert.assertEquals(cursor.getCount(), tabsRecord.tabs.size());
- } finally {
- cursor.close();
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/TestTabsProviderRemoteTabs.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/TestTabsProviderRemoteTabs.java
deleted file mode 100644
index e63cb9b46..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/db/TestTabsProviderRemoteTabs.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.db;
-
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.LocalTabsAccessor;
-import org.mozilla.gecko.db.RemoteClient;
-import org.mozilla.gecko.db.TabsProvider;
-import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.internal.runtime.RuntimeAdapter;
-import org.robolectric.shadows.ShadowContentResolver;
-
-import java.util.List;
-
-@RunWith(TestRunner.class)
-public class TestTabsProviderRemoteTabs {
- private static final long ONE_DAY_IN_MILLISECONDS = 1000 * 60 * 60 * 24;
- private static final long ONE_WEEK_IN_MILLISECONDS = 7 * ONE_DAY_IN_MILLISECONDS;
- private static final long THREE_WEEKS_IN_MILLISECONDS = 3 * ONE_WEEK_IN_MILLISECONDS;
-
- protected TabsProvider provider;
-
- @Before
- public void setUp() {
- provider = new TabsProvider();
- provider.onCreate();
- ShadowContentResolver.registerProvider(BrowserContract.TABS_AUTHORITY, new DelegatingTestContentProvider(provider));
- }
-
- @After
- public void tearDown() throws Exception {
- provider.shutdown();
- provider = null;
- }
-
- protected ContentProviderClient getClientsClient() {
- final ShadowContentResolver cr = new ShadowContentResolver();
- return cr.acquireContentProviderClient(BrowserContractHelpers.CLIENTS_CONTENT_URI);
- }
-
- @Test
- public void testGetClientsWithoutTabsByRecencyFromCursor() throws Exception {
- final Uri uri = BrowserContractHelpers.CLIENTS_CONTENT_URI;
- final ContentProviderClient cpc = getClientsClient();
- final LocalTabsAccessor accessor = new LocalTabsAccessor("test"); // The profile name given doesn't matter.
-
- try {
- // Delete all tabs to begin with.
- cpc.delete(uri, null, null);
- Cursor allClients = cpc.query(uri, null, null, null, null);
- try {
- Assert.assertEquals(0, allClients.getCount());
- } finally {
- allClients.close();
- }
-
- // Insert a local and remote1 client record, neither with tabs.
- final long now = System.currentTimeMillis();
- // Local client has GUID = null.
- final ContentValues local = new ContentValues();
- local.put(BrowserContract.Clients.NAME, "local");
- local.put(BrowserContract.Clients.LAST_MODIFIED, now + 1);
- // Remote clients have GUID != null.
- final ContentValues remote1 = new ContentValues();
- remote1.put(BrowserContract.Clients.GUID, "guid1");
- remote1.put(BrowserContract.Clients.NAME, "remote1");
- remote1.put(BrowserContract.Clients.LAST_MODIFIED, now + 2);
-
- final ContentValues remote2 = new ContentValues();
- remote2.put(BrowserContract.Clients.GUID, "guid2");
- remote2.put(BrowserContract.Clients.NAME, "remote2");
- remote2.put(BrowserContract.Clients.LAST_MODIFIED, now + 3);
-
- ContentValues[] values = new ContentValues[]{local, remote1, remote2};
- int inserted = cpc.bulkInsert(uri, values);
- Assert.assertEquals(3, inserted);
-
- allClients = cpc.query(BrowserContract.Clients.CONTENT_RECENCY_URI, null, null, null, null);
- try {
- CursorDumper.dumpCursor(allClients);
- // The local client is not ignored.
- Assert.assertEquals(3, allClients.getCount());
- final List<RemoteClient> clients = accessor.getClientsWithoutTabsByRecencyFromCursor(allClients);
- Assert.assertEquals(3, clients.size());
- for (RemoteClient client : clients) {
- // Each client should not have any tabs.
- Assert.assertNotNull(client.tabs);
- Assert.assertEquals(0, client.tabs.size());
- }
- // Since there are no tabs, the order should be based on last_modified.
- Assert.assertEquals("guid2", clients.get(0).guid);
- Assert.assertEquals("guid1", clients.get(1).guid);
- Assert.assertEquals(null, clients.get(2).guid);
- } finally {
- allClients.close();
- }
-
- // Now let's add a few tabs to one client. The times are chosen so that one tab's
- // last used is not relevant, and the other tab is the most recent used.
- final ContentValues remoteTab1 = new ContentValues();
- remoteTab1.put(BrowserContract.Tabs.CLIENT_GUID, "guid1");
- remoteTab1.put(BrowserContract.Tabs.TITLE, "title1");
- remoteTab1.put(BrowserContract.Tabs.URL, "http://test.com/test1");
- remoteTab1.put(BrowserContract.Tabs.HISTORY, "[\"http://test.com/test1\"]");
- remoteTab1.put(BrowserContract.Tabs.LAST_USED, now);
- remoteTab1.put(BrowserContract.Tabs.POSITION, 0);
-
- final ContentValues remoteTab2 = new ContentValues();
- remoteTab2.put(BrowserContract.Tabs.CLIENT_GUID, "guid1");
- remoteTab2.put(BrowserContract.Tabs.TITLE, "title2");
- remoteTab2.put(BrowserContract.Tabs.URL, "http://test.com/test2");
- remoteTab2.put(BrowserContract.Tabs.HISTORY, "[\"http://test.com/test2\"]");
- remoteTab2.put(BrowserContract.Tabs.LAST_USED, now + 5);
- remoteTab2.put(BrowserContract.Tabs.POSITION, 1);
-
- values = new ContentValues[]{remoteTab1, remoteTab2};
- inserted = cpc.bulkInsert(BrowserContract.Tabs.CONTENT_URI, values);
- Assert.assertEquals(2, inserted);
-
- allClients = cpc.query(BrowserContract.Clients.CONTENT_RECENCY_URI, null, BrowserContract.Clients.GUID + " IS NOT NULL", null, null);
- try {
- CursorDumper.dumpCursor(allClients);
- // The local client is ignored.
- Assert.assertEquals(2, allClients.getCount());
- final List<RemoteClient> clients = accessor.getClientsWithoutTabsByRecencyFromCursor(allClients);
- Assert.assertEquals(2, clients.size());
- for (RemoteClient client : clients) {
- // Each client should be remote and should not have any tabs.
- Assert.assertNotNull(client.guid);
- Assert.assertNotNull(client.tabs);
- Assert.assertEquals(0, client.tabs.size());
- }
- // Since now there is a tab attached to the remote2 client more recent than the
- // remote1 client modified time, it should be first.
- Assert.assertEquals("guid1", clients.get(0).guid);
- Assert.assertEquals("guid2", clients.get(1).guid);
- } finally {
- allClients.close();
- }
- } finally {
- cpc.release();
- }
- }
-
- @Test
- public void testGetRecentRemoteClientsUpToOneWeekOld() throws Exception {
- final Uri uri = BrowserContractHelpers.CLIENTS_CONTENT_URI;
- final ContentProviderClient cpc = getClientsClient();
- final LocalTabsAccessor accessor = new LocalTabsAccessor("test"); // The profile name given doesn't matter.
- final Context context = RuntimeEnvironment.application.getApplicationContext();
-
- try {
- // Start Clean
- cpc.delete(uri, null, null);
- final Cursor allClients = cpc.query(uri, null, null, null, null);
- try {
- Assert.assertEquals(0, allClients.getCount());
- } finally {
- allClients.close();
- }
-
- // Insert a local and remote1 client record, neither with tabs.
- final long now = System.currentTimeMillis();
- // Local client has GUID = null.
- final ContentValues local = new ContentValues();
- local.put(BrowserContract.Clients.NAME, "local");
- local.put(BrowserContract.Clients.LAST_MODIFIED, now + 1);
- // Remote clients have GUID != null.
- final ContentValues remote1 = new ContentValues();
- remote1.put(BrowserContract.Clients.GUID, "guid1");
- remote1.put(BrowserContract.Clients.NAME, "remote1");
- remote1.put(BrowserContract.Clients.LAST_MODIFIED, now + 2);
-
- // Insert a Remote Client that is 6 days old.
- final ContentValues remote2 = new ContentValues();
- remote2.put(BrowserContract.Clients.GUID, "guid2");
- remote2.put(BrowserContract.Clients.NAME, "remote2");
- remote2.put(BrowserContract.Clients.LAST_MODIFIED, now - ONE_WEEK_IN_MILLISECONDS + ONE_DAY_IN_MILLISECONDS);
-
- // Insert a Remote Client with the same name as previous but with more than 3 weeks old
- final ContentValues remote3 = new ContentValues();
- remote3.put(BrowserContract.Clients.GUID, "guid21");
- remote3.put(BrowserContract.Clients.NAME, "remote2");
- remote3.put(BrowserContract.Clients.LAST_MODIFIED, now - THREE_WEEKS_IN_MILLISECONDS - ONE_DAY_IN_MILLISECONDS);
-
- // Insert another remote client with the same name as previous but with 3 weeks - 1 day old.
- final ContentValues remote4 = new ContentValues();
- remote4.put(BrowserContract.Clients.GUID, "guid22");
- remote4.put(BrowserContract.Clients.NAME, "remote2");
- remote4.put(BrowserContract.Clients.LAST_MODIFIED, now - THREE_WEEKS_IN_MILLISECONDS + ONE_DAY_IN_MILLISECONDS);
-
- // Insert a Remote Client that is exactly one week old.
- final ContentValues remote5 = new ContentValues();
- remote5.put(BrowserContract.Clients.GUID, "guid3");
- remote5.put(BrowserContract.Clients.NAME, "remote3");
- remote5.put(BrowserContract.Clients.LAST_MODIFIED, now - ONE_WEEK_IN_MILLISECONDS);
-
- ContentValues[] values = new ContentValues[]{local, remote1, remote2, remote3, remote4, remote5};
- int inserted = cpc.bulkInsert(uri, values);
- Assert.assertEquals(values.length, inserted);
-
- final Cursor remoteClients =
- accessor.getRemoteClientsByRecencyCursor(context);
-
- try {
- CursorDumper.dumpCursor(remoteClients);
- // Local client is not included.
- // (remote1, guid1), (remote2, guid2), (remote3, guid3) are expected.
- Assert.assertEquals(3, remoteClients.getCount());
-
- // Check the inner data, according to recency.
- List<RemoteClient> recentRemoteClientsList =
- accessor.getClientsWithoutTabsByRecencyFromCursor(remoteClients);
- Assert.assertEquals(3, recentRemoteClientsList.size());
- Assert.assertEquals("remote1", recentRemoteClientsList.get(0).name);
- Assert.assertEquals("guid1", recentRemoteClientsList.get(0).guid);
- Assert.assertEquals("remote2", recentRemoteClientsList.get(1).name);
- Assert.assertEquals("guid2", recentRemoteClientsList.get(1).guid);
- Assert.assertEquals("remote3", recentRemoteClientsList.get(2).name);
- Assert.assertEquals("guid3", recentRemoteClientsList.get(2).guid);
- } finally {
- remoteClients.close();
- }
- } finally {
- cpc.release();
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/fxa/test/TestFxAccountClient20.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/fxa/test/TestFxAccountClient20.java
deleted file mode 100644
index d075cc0ec..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/fxa/test/TestFxAccountClient20.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.fxa.test;
-
-import junit.framework.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.fxa.FxAccountClient20;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.net.BaseResource;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
-@RunWith(TestRunner.class)
-public class TestFxAccountClient20 {
- protected static class MockFxAccountClient20 extends FxAccountClient20 {
- public MockFxAccountClient20(String serverURI, Executor executor) {
- super(serverURI, executor);
- }
-
- // Public for testing.
- @Override
- public BaseResource getBaseResource(final String path, final String... queryParameters) throws UnsupportedEncodingException, URISyntaxException {
- return super.getBaseResource(path, queryParameters);
- }
- }
-
- @Test
- public void testGetCreateAccountURI() throws Exception {
- final String TEST_SERVER = "https://test.com:4430/inner/v1/";
- final MockFxAccountClient20 client = new MockFxAccountClient20(TEST_SERVER, Executors.newSingleThreadExecutor());
- Assert.assertEquals(TEST_SERVER + "account/create", client.getBaseResource("account/create").getURIString());
- Assert.assertEquals(TEST_SERVER + "account/create?service=sync&keys=true", client.getBaseResource("account/create", "service", "sync", "keys", "true").getURIString());
- Assert.assertEquals(TEST_SERVER + "account/create?service=two+words", client.getBaseResource("account/create", "service", "two words").getURIString());
- Assert.assertEquals(TEST_SERVER + "account/create?service=symbols%2F%3A%3F%2B", client.getBaseResource("account/create", "service", "symbols/:?+").getURIString());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/fxa/test/TestFxAccountUtils.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/fxa/test/TestFxAccountUtils.java
deleted file mode 100644
index e6461776e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/fxa/test/TestFxAccountUtils.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.fxa.test;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.fxa.FxAccountUtils;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.net.SRPConstants;
-
-import java.math.BigInteger;
-
-/**
- * Test vectors from
- * <a href="https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol#stretch-KDF">https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol#stretch-KDF</a>
- * and
- * <a href="https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol/5a9bc81e499306d769ca19b40b50fa60123df15d">https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol/5a9bc81e499306d769ca19b40b50fa60123df15d</a>.
- */
-@RunWith(TestRunner.class)
-public class TestFxAccountUtils {
- protected static void assertEncoding(String base16String, String utf8String) throws Exception {
- Assert.assertEquals(base16String, FxAccountUtils.bytes(utf8String));
- }
-
- @Test
- public void testUTF8Encoding() throws Exception {
- assertEncoding("616e6472c3a9406578616d706c652e6f7267", "andré@example.org");
- assertEncoding("70c3a4737377c3b67264", "pässwörd");
- }
-
- @Test
- public void testHexModN() {
- BigInteger N = BigInteger.valueOf(14);
- Assert.assertEquals(4, N.bitLength());
- Assert.assertEquals(1, (N.bitLength() + 7)/8);
- Assert.assertEquals("00", FxAccountUtils.hexModN(BigInteger.valueOf(0), N));
- Assert.assertEquals("05", FxAccountUtils.hexModN(BigInteger.valueOf(5), N));
- Assert.assertEquals("0b", FxAccountUtils.hexModN(BigInteger.valueOf(11), N));
- Assert.assertEquals("00", FxAccountUtils.hexModN(BigInteger.valueOf(14), N));
- Assert.assertEquals("01", FxAccountUtils.hexModN(BigInteger.valueOf(15), N));
- Assert.assertEquals("02", FxAccountUtils.hexModN(BigInteger.valueOf(16), N));
- Assert.assertEquals("02", FxAccountUtils.hexModN(BigInteger.valueOf(30), N));
-
- N = BigInteger.valueOf(260);
- Assert.assertEquals("00ff", FxAccountUtils.hexModN(BigInteger.valueOf(255), N));
- Assert.assertEquals("0100", FxAccountUtils.hexModN(BigInteger.valueOf(256), N));
- Assert.assertEquals("0101", FxAccountUtils.hexModN(BigInteger.valueOf(257), N));
- Assert.assertEquals("0001", FxAccountUtils.hexModN(BigInteger.valueOf(261), N));
- }
-
- @Test
- public void testSRPVerifierFunctions() throws Exception {
- byte[] emailUTF8Bytes = Utils.hex2Byte("616e6472c3a9406578616d706c652e6f7267");
- byte[] srpPWBytes = Utils.hex2Byte("00f9b71800ab5337d51177d8fbc682a3653fa6dae5b87628eeec43a18af59a9d", 32);
- byte[] srpSaltBytes = Utils.hex2Byte("00f1000000000000000000000000000000000000000000000000000000000179", 32);
-
- String expectedX = "81925186909189958012481408070938147619474993903899664126296984459627523279550";
- BigInteger x = FxAccountUtils.srpVerifierLowercaseX(emailUTF8Bytes, srpPWBytes, srpSaltBytes);
- Assert.assertEquals(expectedX, x.toString(10));
-
- String expectedV = "11464957230405843056840989945621595830717843959177257412217395741657995431613430369165714029818141919887853709633756255809680435884948698492811770122091692817955078535761033207000504846365974552196983218225819721112680718485091921646083608065626264424771606096544316730881455897489989950697705196721477608178869100211706638584538751009854562396937282582855620488967259498367841284829152987988548996842770025110751388952323221706639434861071834212055174768483159061566055471366772641252573641352721966728239512914666806496255304380341487975080159076396759492553066357163103546373216130193328802116982288883318596822";
- BigInteger v = FxAccountUtils.srpVerifierLowercaseV(emailUTF8Bytes, srpPWBytes, srpSaltBytes, SRPConstants._2048.g, SRPConstants._2048.N);
- Assert.assertEquals(expectedV, v.toString(10));
-
- String expectedVHex = "00173ffa0263e63ccfd6791b8ee2a40f048ec94cd95aa8a3125726f9805e0c8283c658dc0b607fbb25db68e68e93f2658483049c68af7e8214c49fde2712a775b63e545160d64b00189a86708c69657da7a1678eda0cd79f86b8560ebdb1ffc221db360eab901d643a75bf1205070a5791230ae56466b8c3c1eb656e19b794f1ea0d2a077b3a755350208ea0118fec8c4b2ec344a05c66ae1449b32609ca7189451c259d65bd15b34d8729afdb5faff8af1f3437bbdc0c3d0b069a8ab2a959c90c5a43d42082c77490f3afcc10ef5648625c0605cdaace6c6fdc9e9a7e6635d619f50af7734522470502cab26a52a198f5b00a279858916507b0b4e9ef9524d6";
- Assert.assertEquals(expectedVHex, FxAccountUtils.hexModN(v, SRPConstants._2048.N));
- }
-
- @Test
- public void testGenerateSyncKeyBundle() throws Exception {
- byte[] kB = Utils.hex2Byte("d02d8fe39f28b601159c543f2deeb8f72bdf2043e8279aa08496fbd9ebaea361");
- KeyBundle bundle = FxAccountUtils.generateSyncKeyBundle(kB);
- Assert.assertEquals("rsLwECkgPYeGbYl92e23FskfIbgld9TgeifEaB9ZwTI=", Base64.encodeBase64String(bundle.getEncryptionKey()));
- Assert.assertEquals("fs75EseCD/VOLodlIGmwNabBjhTYBHFCe7CGIf0t8Tw=", Base64.encodeBase64String(bundle.getHMACKey()));
- }
-
- @Test
- public void testGeneration() throws Exception {
- byte[] quickStretchedPW = FxAccountUtils.generateQuickStretchedPW(
- Utils.hex2Byte("616e6472c3a9406578616d706c652e6f7267"),
- Utils.hex2Byte("70c3a4737377c3b67264"));
- Assert.assertEquals("e4e8889bd8bd61ad6de6b95c059d56e7b50dacdaf62bd84644af7e2add84345d",
- Utils.byte2Hex(quickStretchedPW));
- Assert.assertEquals("247b675ffb4c46310bc87e26d712153abe5e1c90ef00a4784594f97ef54f2375",
- Utils.byte2Hex(FxAccountUtils.generateAuthPW(quickStretchedPW)));
- byte[] unwrapkB = FxAccountUtils.generateUnwrapBKey(quickStretchedPW);
- Assert.assertEquals("de6a2648b78284fcb9ffa81ba95803309cfba7af583c01a8a1a63e567234dd28",
- Utils.byte2Hex(unwrapkB));
- byte[] wrapkB = Utils.hex2Byte("7effe354abecbcb234a8dfc2d7644b4ad339b525589738f2d27341bb8622ecd8");
- Assert.assertEquals("a095c51c1c6e384e8d5777d97e3c487a4fc2128a00ab395a73d57fedf41631f0",
- Utils.byte2Hex(FxAccountUtils.unwrapkB(unwrapkB, wrapkB)));
- }
-
- @Test
- public void testClientState() throws Exception {
- final String hexKB = "fd5c747806c07ce0b9d69dcfea144663e630b65ec4963596a22f24910d7dd15d";
- final byte[] byteKB = Utils.hex2Byte(hexKB);
- final String clientState = FxAccountUtils.computeClientState(byteKB);
- final String expected = "6ae94683571c7a7c54dab4700aa3995f";
- Assert.assertEquals(expected, clientState);
- }
-
- @Test
- public void testGetAudienceForURL() throws Exception {
- // Sub-domains and path components.
- Assert.assertEquals("http://sub.test.com", FxAccountUtils.getAudienceForURL("http://sub.test.com"));
- Assert.assertEquals("http://test.com", FxAccountUtils.getAudienceForURL("http://test.com/"));
- Assert.assertEquals("http://test.com", FxAccountUtils.getAudienceForURL("http://test.com/path/component"));
- Assert.assertEquals("http://test.com", FxAccountUtils.getAudienceForURL("http://test.com/path/component/"));
-
- // No port and default port.
- Assert.assertEquals("http://test.com", FxAccountUtils.getAudienceForURL("http://test.com"));
- Assert.assertEquals("http://test.com:80", FxAccountUtils.getAudienceForURL("http://test.com:80"));
-
- Assert.assertEquals("https://test.com", FxAccountUtils.getAudienceForURL("https://test.com"));
- Assert.assertEquals("https://test.com:443", FxAccountUtils.getAudienceForURL("https://test.com:443"));
-
- // Ports that are the default ports for a different scheme.
- Assert.assertEquals("https://test.com:80", FxAccountUtils.getAudienceForURL("https://test.com:80"));
- Assert.assertEquals("http://test.com:443", FxAccountUtils.getAudienceForURL("http://test.com:443"));
-
- // Arbitrary ports.
- Assert.assertEquals("http://test.com:8080", FxAccountUtils.getAudienceForURL("http://test.com:8080"));
- Assert.assertEquals("https://test.com:4430", FxAccountUtils.getAudienceForURL("https://test.com:4430"));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/test/EntityTestHelper.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/test/EntityTestHelper.java
deleted file mode 100644
index 976a8eda1..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/test/EntityTestHelper.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.test;
-
-import ch.boye.httpclientandroidlib.HttpEntity;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-public class EntityTestHelper {
- private static final int DEFAULT_SIZE = 1024;
-
- public static byte[] bytesFromEntity(final HttpEntity entity) throws IOException {
- final InputStream is = entity.getContent();
-
- if (is instanceof ByteArrayInputStream) {
- final int size = is.available();
- final byte[] buffer = new byte[size];
- is.read(buffer, 0, size);
- return buffer;
- }
-
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- final byte[] buffer = new byte[DEFAULT_SIZE];
- int len;
- while ((len = is.read(buffer, 0, DEFAULT_SIZE)) != -1) {
- bos.write(buffer, 0, len);
- }
- return bos.toByteArray();
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java
deleted file mode 100644
index d9aa936f0..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.NoCollectionKeysSetException;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SynchronizerConfiguration;
-import org.mozilla.gecko.sync.repositories.RecordFactory;
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.stage.ServerSyncStage;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-
-/**
- * A stage that joins two Repositories with no wrapping.
- */
-public abstract class BaseMockServerSyncStage extends ServerSyncStage {
-
- public Repository local;
- public Repository remote;
- public String name;
- public String collection;
- public int version = 1;
-
- @Override
- public boolean isEnabled() {
- return true;
- }
-
- @Override
- protected String getCollection() {
- return collection;
- }
-
- @Override
- protected Repository getLocalRepository() {
- return local;
- }
-
- @Override
- protected Repository getRemoteRepository() throws URISyntaxException {
- return remote;
- }
-
- @Override
- protected String getEngineName() {
- return name;
- }
-
- @Override
- public Integer getStorageVersion() {
- return version;
- }
-
- @Override
- protected RecordFactory getRecordFactory() {
- return null;
- }
-
- @Override
- protected Repository wrappedServerRepo()
- throws NoCollectionKeysSetException, URISyntaxException {
- return getRemoteRepository();
- }
-
- public SynchronizerConfiguration leakConfig()
- throws NonObjectJSONException, IOException {
- return this.getConfig();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java
deleted file mode 100644
index 48217f1b0..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.json.simple.JSONArray;
-import org.mozilla.gecko.sync.CommandProcessor.Command;
-
-public class CommandHelpers {
-
- @SuppressWarnings("unchecked")
- public static Command getCommand1() {
- JSONArray args = new JSONArray();
- args.add("argsA");
- return new Command("displayURI", args);
- }
-
- @SuppressWarnings("unchecked")
- public static Command getCommand2() {
- JSONArray args = new JSONArray();
- args.add("argsB");
- return new Command("displayURI", args);
- }
-
- @SuppressWarnings("unchecked")
- public static Command getCommand3() {
- JSONArray args = new JSONArray();
- args.add("argsC");
- return new Command("displayURI", args);
- }
-
- @SuppressWarnings("unchecked")
- public static Command getCommand4() {
- JSONArray args = new JSONArray();
- args.add("URI of Page");
- args.add("Sender ID");
- args.add("Title of Page");
- return new Command("displayURI", args);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java
deleted file mode 100644
index 373dd4eab..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-import java.net.URI;
-
-public class DefaultGlobalSessionCallback implements GlobalSessionCallback {
-
- @Override
- public void requestBackoff(long backoff) {
- }
-
- @Override
- public void informUnauthorizedResponse(GlobalSession globalSession,
- URI oldClusterURL) {
- }
- @Override
- public void informUpgradeRequiredResponse(GlobalSession session) {
- }
-
- @Override
- public void informMigrated(GlobalSession globalSession) {
- }
-
- @Override
- public void handleAborted(GlobalSession globalSession, String reason) {
- }
-
- @Override
- public void handleError(GlobalSession globalSession, Exception ex) {
- }
-
- @Override
- public void handleSuccess(GlobalSession globalSession) {
- }
-
- @Override
- public void handleStageCompleted(Stage currentState,
- GlobalSession globalSession) {
- }
-
- @Override
- public boolean shouldBackOffStorage() {
- return false;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java
deleted file mode 100644
index d8380df97..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.stage.AbstractNonRepositorySyncStage;
-
-public class MockAbstractNonRepositorySyncStage extends AbstractNonRepositorySyncStage {
- @Override
- public void execute() {
- session.advance();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java
deleted file mode 100644
index f4af51f64..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
-
-public class MockClientsDataDelegate implements ClientsDataDelegate {
- private String accountGUID;
- private String clientName;
- private int clientsCount;
- private long clientDataTimestamp = 0;
-
- @Override
- public synchronized String getAccountGUID() {
- if (accountGUID == null) {
- accountGUID = Utils.generateGuid();
- }
- return accountGUID;
- }
-
- @Override
- public synchronized String getDefaultClientName() {
- return "Default client";
- }
-
- @Override
- public synchronized void setClientName(String clientName, long now) {
- this.clientName = clientName;
- this.clientDataTimestamp = now;
- }
-
- @Override
- public synchronized String getClientName() {
- if (clientName == null) {
- setClientName(getDefaultClientName(), System.currentTimeMillis());
- }
- return clientName;
- }
-
- @Override
- public synchronized void setClientsCount(int clientsCount) {
- this.clientsCount = clientsCount;
- }
-
- @Override
- public synchronized int getClientsCount() {
- return clientsCount;
- }
-
- @Override
- public synchronized boolean isLocalGUID(String guid) {
- return getAccountGUID().equals(guid);
- }
-
- @Override
- public synchronized long getLastModifiedTimestamp() {
- return clientDataTimestamp;
- }
-
- @Override
- public String getFormFactor() {
- return "phone";
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java
deleted file mode 100644
index b1aeb7cd1..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.CommandProcessor.Command;
-import org.mozilla.gecko.sync.repositories.NullCursorException;
-import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-public class MockClientsDatabaseAccessor extends ClientsDatabaseAccessor {
- public boolean storedRecord = false;
- public boolean dbWiped = false;
- public boolean clientsTableWiped = false;
- public boolean closed = false;
- public boolean storedArrayList = false;
- public boolean storedCommand;
-
- @Override
- public void store(ClientRecord record) {
- storedRecord = true;
- }
-
- @Override
- public void store(Collection<ClientRecord> records) {
- storedArrayList = false;
- }
-
- @Override
- public void store(String accountGUID, Command command) throws NullCursorException {
- storedCommand = true;
- }
-
- @Override
- public ClientRecord fetchClient(String profileID) throws NullCursorException {
- return null;
- }
-
- @Override
- public Map<String, ClientRecord> fetchAllClients() throws NullCursorException {
- return null;
- }
-
- @Override
- public List<Command> fetchCommandsForClient(String accountGUID) throws NullCursorException {
- return null;
- }
-
- @Override
- public int clientsCount() {
- return 0;
- }
-
- @Override
- public void wipeDB() {
- dbWiped = true;
- }
-
- @Override
- public void wipeClientsTable() {
- clientsTableWiped = true;
- }
-
- @Override
- public void close() {
- closed = true;
- }
-
- public void resetVars() {
- storedRecord = dbWiped = clientsTableWiped = closed = storedArrayList = false;
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java
deleted file mode 100644
index 63afdd1ac..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.EngineSettings;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.stage.CompletedStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-import java.io.IOException;
-import java.util.HashMap;
-
-
-public class MockGlobalSession extends MockPrefsGlobalSession {
-
- public MockGlobalSession(String username, String password, KeyBundle keyBundle, GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException {
- this(new SyncConfiguration(username, new BasicAuthHeaderProvider(username, password), new MockSharedPreferences(), keyBundle), callback);
- }
-
- public MockGlobalSession(SyncConfiguration config, GlobalSessionCallback callback)
- throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
- super(config, callback, null, null);
- }
-
- @Override
- public boolean isEngineRemotelyEnabled(String engine, EngineSettings engineSettings) {
- return false;
- }
-
- @Override
- protected void prepareStages() {
- super.prepareStages();
- HashMap<Stage, GlobalSyncStage> newStages = new HashMap<Stage, GlobalSyncStage>(this.stages);
-
- for (Stage stage : this.stages.keySet()) {
- newStages.put(stage, new MockServerSyncStage());
- }
-
- // This signals that the global session is complete.
- newStages.put(Stage.completed, new CompletedStage());
-
- this.stages = newStages;
- }
-
- public MockGlobalSession withStage(Stage stage, GlobalSyncStage syncStage) {
- stages.put(stage, syncStage);
-
- return this;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
deleted file mode 100644
index c864cdf80..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
-import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-
-import java.io.IOException;
-
-/**
- * GlobalSession touches the Android prefs system. Stub that out.
- */
-public class MockPrefsGlobalSession extends GlobalSession {
-
- public MockSharedPreferences prefs;
-
- public MockPrefsGlobalSession(
- SyncConfiguration config, GlobalSessionCallback callback, Context context,
- ClientsDataDelegate clientsDelegate)
- throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
- super(config, callback, context, clientsDelegate);
- }
-
- public static MockPrefsGlobalSession getSession(
- String username, String password,
- KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
- ClientsDataDelegate clientsDelegate)
- throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
- return getSession(username, new BasicAuthHeaderProvider(username, password), null,
- syncKeyBundle, callback, context, clientsDelegate);
- }
-
- public static MockPrefsGlobalSession getSession(
- String username, AuthHeaderProvider authHeaderProvider, String prefsPath,
- KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
- ClientsDataDelegate clientsDelegate)
- throws SyncConfigurationException, IllegalArgumentException, IOException, NonObjectJSONException {
-
- final SharedPreferences prefs = new MockSharedPreferences();
- final SyncConfiguration config = new SyncConfiguration(username, authHeaderProvider, prefs);
- config.syncKeyBundle = syncKeyBundle;
- return new MockPrefsGlobalSession(config, callback, context, clientsDelegate);
- }
-
- @Override
- public Context getContext() {
- return null;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockRecord.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockRecord.java
deleted file mode 100644
index 9876b7867..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockRecord.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import java.util.Random;
-
-public class MockRecord extends Record {
- private final int payloadByteCount;
- public MockRecord(String guid, String collection, long lastModified, boolean deleted) {
- super(guid, collection, lastModified, deleted);
- // Payload used to be "foo", so let's not stray too far.
- // Perhaps some tests "depend" on that payload size.
- payloadByteCount = 3;
- }
-
- public MockRecord(String guid, String collection, long lastModified, boolean deleted, int payloadByteCount) {
- super(guid, collection, lastModified, deleted);
- this.payloadByteCount = payloadByteCount;
- }
-
- @Override
- protected void populatePayload(ExtendedJSONObject payload) {
- }
-
- @Override
- protected void initFromPayload(ExtendedJSONObject payload) {
- }
-
- @Override
- public Record copyWithIDs(String guid, long androidID) {
- MockRecord r = new MockRecord(guid, this.collection, this.lastModified, this.deleted);
- r.androidID = androidID;
- return r;
- }
-
- @Override
- public String toJSONString() {
- // Build up a randomish payload string based on the length we were asked for.
- final Random random = new Random();
- final char[] payloadChars = new char[payloadByteCount];
- for (int i = 0; i < payloadByteCount; i++) {
- payloadChars[i] = (char) (random.nextInt(26) + 'a');
- }
- final String payloadString = new String(payloadChars);
- return "{\"id\":\"" + guid + "\", \"payload\": \"" + payloadString+ "\"}";
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java
deleted file mode 100644
index 28a4e58b9..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-public class MockServerSyncStage extends BaseMockServerSyncStage {
- @Override
- public void execute() {
- session.advance();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java
deleted file mode 100644
index bc49fa7fb..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import android.content.SharedPreferences;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A programmable mock content provider.
- */
-public class MockSharedPreferences implements SharedPreferences, SharedPreferences.Editor {
- private HashMap<String, Object> mValues;
- private HashMap<String, Object> mTempValues;
-
- public MockSharedPreferences() {
- mValues = new HashMap<String, Object>();
- mTempValues = new HashMap<String, Object>();
- }
-
- public Editor edit() {
- return this;
- }
-
- public boolean contains(String key) {
- return mValues.containsKey(key);
- }
-
- public Map<String, ?> getAll() {
- return new HashMap<String, Object>(mValues);
- }
-
- public boolean getBoolean(String key, boolean defValue) {
- if (mValues.containsKey(key)) {
- return ((Boolean)mValues.get(key)).booleanValue();
- }
- return defValue;
- }
-
- public float getFloat(String key, float defValue) {
- if (mValues.containsKey(key)) {
- return ((Float)mValues.get(key)).floatValue();
- }
- return defValue;
- }
-
- public int getInt(String key, int defValue) {
- if (mValues.containsKey(key)) {
- return ((Integer)mValues.get(key)).intValue();
- }
- return defValue;
- }
-
- public long getLong(String key, long defValue) {
- if (mValues.containsKey(key)) {
- return ((Long)mValues.get(key)).longValue();
- }
- return defValue;
- }
-
- public String getString(String key, String defValue) {
- if (mValues.containsKey(key))
- return (String)mValues.get(key);
- return defValue;
- }
-
- @SuppressWarnings("unchecked")
- public Set<String> getStringSet(String key, Set<String> defValues) {
- if (mValues.containsKey(key)) {
- return (Set<String>) mValues.get(key);
- }
- return defValues;
- }
-
- public void registerOnSharedPreferenceChangeListener(
- OnSharedPreferenceChangeListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public void unregisterOnSharedPreferenceChangeListener(
- OnSharedPreferenceChangeListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public Editor putBoolean(String key, boolean value) {
- mTempValues.put(key, Boolean.valueOf(value));
- return this;
- }
-
- public Editor putFloat(String key, float value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putInt(String key, int value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putLong(String key, long value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putString(String key, String value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putStringSet(String key, Set<String> values) {
- mTempValues.put(key, values);
- return this;
- }
-
- public Editor remove(String key) {
- mTempValues.remove(key);
- return this;
- }
-
- public Editor clear() {
- mTempValues.clear();
- return this;
- }
-
- @SuppressWarnings("unchecked")
- public boolean commit() {
- mValues = (HashMap<String, Object>)mTempValues.clone();
- return true;
- }
-
- public void apply() {
- commit();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/TestRunner.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/TestRunner.java
deleted file mode 100644
index ccb5276ed..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/TestRunner.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * The MIT License
- *
- * Copyright (c) 2010 Xtreme Labs and Pivotal Labs
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.junit.runners.model.InitializationError;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-import org.robolectric.manifest.AndroidManifest;
-import org.robolectric.res.FileFsFile;
-import org.robolectric.res.FsFile;
-import org.robolectric.util.Logger;
-import org.robolectric.util.ReflectionHelpers;
-
-/**
- * Test runner customized for running unit tests either through the Gradle CLI or
- * Android Studio. The runner uses the build type and build flavor to compute the
- * resource, asset, and AndroidManifest paths.
- *
- * This test runner requires that you set the 'constants' field on the @Config
- * annotation (or the org.robolectric.Config.properties file) for your tests.
- *
- * This is a modified version of
- * https://github.com/robolectric/robolectric/blob/8676da2daa4c140679fb5903696b8191415cec8f/robolectric/src/main/java/org/robolectric/RobolectricGradleTestRunner.java
- * that uses a Gradle `buildConfigField` to find build outputs.
- * See https://github.com/robolectric/robolectric/issues/1648#issuecomment-113731011.
- */
-public class TestRunner extends RobolectricTestRunner {
- private FsFile buildFolder;
-
- public TestRunner(Class<?> klass) throws InitializationError {
- super(klass);
- }
-
- @Override
- protected AndroidManifest getAppManifest(Config config) {
- if (config.constants() == Void.class) {
- Logger.error("Field 'constants' not specified in @Config annotation");
- Logger.error("This is required when using RobolectricGradleTestRunner!");
- throw new RuntimeException("No 'constants' field in @Config annotation!");
- }
-
- buildFolder = FileFsFile.from(getBuildDir(config)).join("intermediates");
-
- final String type = getType(config);
- final String flavor = getFlavor(config);
- final String packageName = getPackageName(config);
-
- final FsFile assets = buildFolder.join("assets", flavor, type);;
- final FsFile manifest = buildFolder.join("manifests", "full", flavor, type, "AndroidManifest.xml");
-
- final FsFile res;
- if (buildFolder.join("res", "merged").exists()) {
- res = buildFolder.join("res", "merged", flavor, type);
- } else if(buildFolder.join("res").exists()) {
- res = buildFolder.join("res", flavor, type);
- } else {
- throw new IllegalStateException("No resource folder found");
- }
-
- Logger.debug("Robolectric assets directory: " + assets.getPath());
- Logger.debug(" Robolectric res directory: " + res.getPath());
- Logger.debug(" Robolectric manifest path: " + manifest.getPath());
- Logger.debug(" Robolectric package name: " + packageName);
- return new AndroidManifest(manifest, res, assets, packageName);
- }
-
- private static String getType(Config config) {
- try {
- return ReflectionHelpers.getStaticField(config.constants(), "BUILD_TYPE");
- } catch (Throwable e) {
- return null;
- }
- }
-
- private static String getFlavor(Config config) {
- try {
- return ReflectionHelpers.getStaticField(config.constants(), "FLAVOR");
- } catch (Throwable e) {
- return null;
- }
- }
-
- private static String getPackageName(Config config) {
- try {
- final String packageName = config.packageName();
- if (packageName != null && !packageName.isEmpty()) {
- return packageName;
- } else {
- return ReflectionHelpers.getStaticField(config.constants(), "APPLICATION_ID");
- }
- } catch (Throwable e) {
- return null;
- }
- }
-
- private String getBuildDir(Config config) {
- try {
- return ReflectionHelpers.getStaticField(config.constants(), "BUILD_DIR");
- } catch (Throwable e) {
- return null;
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WBORepository.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WBORepository.java
deleted file mode 100644
index 672b0a602..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WBORepository.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import android.content.Context;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
-import org.mozilla.gecko.sync.repositories.RecordFilter;
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.repositories.StoreTrackingRepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class WBORepository extends Repository {
-
- public class WBORepositoryStats {
- public long created = -1;
- public long begun = -1;
- public long fetchBegan = -1;
- public long fetchCompleted = -1;
- public long storeBegan = -1;
- public long storeCompleted = -1;
- public long finished = -1;
- }
-
- public static final String LOG_TAG = "WBORepository";
-
- // Access to stats is not guarded.
- public WBORepositoryStats stats;
-
- // Whether or not to increment the timestamp of stored records.
- public final boolean bumpTimestamps;
-
- public class WBORepositorySession extends StoreTrackingRepositorySession {
-
- protected WBORepository wboRepository;
- protected ExecutorService delegateExecutor = Executors.newSingleThreadExecutor();
- public ConcurrentHashMap<String, Record> wbos;
-
- public WBORepositorySession(WBORepository repository) {
- super(repository);
-
- wboRepository = repository;
- wbos = new ConcurrentHashMap<String, Record>();
- stats = new WBORepositoryStats();
- stats.created = now();
- }
-
- @Override
- protected synchronized void trackGUID(String guid) {
- if (wboRepository.shouldTrack()) {
- super.trackGUID(guid);
- }
- }
-
- @Override
- public void guidsSince(long timestamp,
- RepositorySessionGuidsSinceDelegate delegate) {
- throw new RuntimeException("guidsSince not implemented.");
- }
-
- @Override
- public void fetchSince(long timestamp,
- RepositorySessionFetchRecordsDelegate delegate) {
- long fetchBegan = now();
- stats.fetchBegan = fetchBegan;
- RecordFilter filter = storeTracker.getFilter();
-
- for (Entry<String, Record> entry : wbos.entrySet()) {
- Record record = entry.getValue();
- if (record.lastModified >= timestamp) {
- if (filter != null &&
- filter.excludeRecord(record)) {
- Logger.debug(LOG_TAG, "Excluding record " + record.guid);
- continue;
- }
- delegate.deferredFetchDelegate(delegateExecutor).onFetchedRecord(record);
- }
- }
- long fetchCompleted = now();
- stats.fetchCompleted = fetchCompleted;
- delegate.deferredFetchDelegate(delegateExecutor).onFetchCompleted(fetchCompleted);
- }
-
- @Override
- public void fetch(final String[] guids,
- final RepositorySessionFetchRecordsDelegate delegate) {
- long fetchBegan = now();
- stats.fetchBegan = fetchBegan;
- for (String guid : guids) {
- if (wbos.containsKey(guid)) {
- delegate.deferredFetchDelegate(delegateExecutor).onFetchedRecord(wbos.get(guid));
- }
- }
- long fetchCompleted = now();
- stats.fetchCompleted = fetchCompleted;
- delegate.deferredFetchDelegate(delegateExecutor).onFetchCompleted(fetchCompleted);
- }
-
- @Override
- public void fetchAll(final RepositorySessionFetchRecordsDelegate delegate) {
- long fetchBegan = now();
- stats.fetchBegan = fetchBegan;
- for (Entry<String, Record> entry : wbos.entrySet()) {
- Record record = entry.getValue();
- delegate.deferredFetchDelegate(delegateExecutor).onFetchedRecord(record);
- }
- long fetchCompleted = now();
- stats.fetchCompleted = fetchCompleted;
- delegate.deferredFetchDelegate(delegateExecutor).onFetchCompleted(fetchCompleted);
- }
-
- @Override
- public void store(final Record record) throws NoStoreDelegateException {
- if (delegate == null) {
- throw new NoStoreDelegateException();
- }
- final long now = now();
- if (stats.storeBegan < 0) {
- stats.storeBegan = now;
- }
- Record existing = wbos.get(record.guid);
- Logger.debug(LOG_TAG, "Existing record is " + (existing == null ? "<null>" : (existing.guid + ", " + existing)));
- if (existing != null &&
- existing.lastModified > record.lastModified) {
- Logger.debug(LOG_TAG, "Local record is newer. Not storing.");
- delegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(record.guid);
- return;
- }
- if (existing != null) {
- Logger.debug(LOG_TAG, "Replacing local record.");
- }
-
- // Store a copy of the record with an updated modified time.
- Record toStore = record.copyWithIDs(record.guid, record.androidID);
- if (bumpTimestamps) {
- toStore.lastModified = now;
- }
- wbos.put(record.guid, toStore);
-
- trackRecord(toStore);
- delegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(record.guid);
- }
-
- @Override
- public void wipe(final RepositorySessionWipeDelegate delegate) {
- if (!isActive()) {
- delegate.onWipeFailed(new InactiveSessionException(null));
- return;
- }
-
- Logger.info(LOG_TAG, "Wiping WBORepositorySession.");
- this.wbos = new ConcurrentHashMap<String, Record>();
-
- // Wipe immediately for the convenience of test code.
- wboRepository.wbos = new ConcurrentHashMap<String, Record>();
- delegate.deferredWipeDelegate(delegateExecutor).onWipeSucceeded();
- }
-
- @Override
- public void finish(RepositorySessionFinishDelegate delegate) throws InactiveSessionException {
- Logger.info(LOG_TAG, "Finishing WBORepositorySession: handing back " + this.wbos.size() + " WBOs.");
- wboRepository.wbos = this.wbos;
- stats.finished = now();
- super.finish(delegate);
- }
-
- @Override
- public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException {
- this.wbos = wboRepository.cloneWBOs();
- stats.begun = now();
- super.begin(delegate);
- }
-
- @Override
- public void storeDone(long end) {
- // TODO: this is not guaranteed to be called after all of the record
- // store callbacks have completed!
- if (stats.storeBegan < 0) {
- stats.storeBegan = end;
- }
- stats.storeCompleted = end;
- delegate.deferredStoreDelegate(delegateExecutor).onStoreCompleted(end);
- }
- }
-
- public ConcurrentHashMap<String, Record> wbos;
-
- public WBORepository(boolean bumpTimestamps) {
- super();
- this.bumpTimestamps = bumpTimestamps;
- this.wbos = new ConcurrentHashMap<String, Record>();
- }
-
- public WBORepository() {
- this(false);
- }
-
- public synchronized boolean shouldTrack() {
- return false;
- }
-
- @Override
- public void createSession(RepositorySessionCreationDelegate delegate,
- Context context) {
- delegate.deferredCreationDelegate().onSessionCreated(new WBORepositorySession(this));
- }
-
- public ConcurrentHashMap<String, Record> cloneWBOs() {
- ConcurrentHashMap<String, Record> out = new ConcurrentHashMap<String, Record>();
- for (Entry<String, Record> entry : wbos.entrySet()) {
- out.put(entry.getKey(), entry.getValue()); // Assume that records are
- // immutable.
- }
- return out;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WaitHelper.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WaitHelper.java
deleted file mode 100644
index dad748df1..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/WaitHelper.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.background.common.log.Logger;
-
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Implements waiting for asynchronous test events.
- *
- * Call WaitHelper.getTestWaiter() to get the unique instance.
- *
- * Call performWait(runnable) to execute runnable synchronously.
- * runnable *must* call performNotify() on all exit paths to signal to
- * the TestWaiter that the runnable has completed.
- *
- * @author rnewman
- * @author nalexander
- */
-public class WaitHelper {
-
- public static final String LOG_TAG = "WaitHelper";
-
- public static class Result {
- public Throwable error;
- public Result() {
- error = null;
- }
-
- public Result(Throwable error) {
- this.error = error;
- }
- }
-
- public static abstract class WaitHelperError extends Error {
- private static final long serialVersionUID = 7074690961681883619L;
- }
-
- /**
- * Immutable.
- *
- * @author rnewman
- */
- public static class TimeoutError extends WaitHelperError {
- private static final long serialVersionUID = 8591672555848651736L;
- public final int waitTimeInMillis;
-
- public TimeoutError(int waitTimeInMillis) {
- this.waitTimeInMillis = waitTimeInMillis;
- }
- }
-
- public static class MultipleNotificationsError extends WaitHelperError {
- private static final long serialVersionUID = -9072736521571635495L;
- }
-
- public static class InterruptedError extends WaitHelperError {
- private static final long serialVersionUID = 8383948170038639308L;
- }
-
- public static class InnerError extends WaitHelperError {
- private static final long serialVersionUID = 3008502618576773778L;
- public Throwable innerError;
-
- public InnerError(Throwable e) {
- innerError = e;
- if (e != null) {
- // Eclipse prints the stack trace of the cause.
- this.initCause(e);
- }
- }
- }
-
- public BlockingQueue<Result> queue = new ArrayBlockingQueue<Result>(1);
-
- /**
- * How long performWait should wait for, in milliseconds, with the
- * convention that a negative value means "wait forever".
- */
- public static int defaultWaitTimeoutInMillis = -1;
-
- public void performWait(Runnable action) throws WaitHelperError {
- this.performWait(defaultWaitTimeoutInMillis, action);
- }
-
- public void performWait(int waitTimeoutInMillis, Runnable action) throws WaitHelperError {
- Logger.debug(LOG_TAG, "performWait called.");
-
- Result result = null;
-
- try {
- if (action != null) {
- try {
- action.run();
- Logger.debug(LOG_TAG, "Action done.");
- } catch (Exception ex) {
- Logger.debug(LOG_TAG, "Performing action threw: " + ex.getMessage());
- throw new InnerError(ex);
- }
- }
-
- if (waitTimeoutInMillis < 0) {
- result = queue.take();
- } else {
- result = queue.poll(waitTimeoutInMillis, TimeUnit.MILLISECONDS);
- }
- Logger.debug(LOG_TAG, "Got result from queue: " + result);
- } catch (InterruptedException e) {
- // We were interrupted.
- Logger.debug(LOG_TAG, "performNotify interrupted with InterruptedException " + e);
- final InterruptedError interruptedError = new InterruptedError();
- interruptedError.initCause(e);
- throw interruptedError;
- }
-
- if (result == null) {
- // We timed out.
- throw new TimeoutError(waitTimeoutInMillis);
- } else if (result.error != null) {
- Logger.debug(LOG_TAG, "Notified with error: " + result.error.getMessage());
-
- // Rethrow any assertion with which we were notified.
- InnerError innerError = new InnerError(result.error);
- throw innerError;
- }
- // Success!
- }
-
- public void performNotify(final Throwable e) {
- if (e != null) {
- Logger.debug(LOG_TAG, "performNotify called with Throwable: " + e.getMessage());
- } else {
- Logger.debug(LOG_TAG, "performNotify called.");
- }
-
- if (!queue.offer(new Result(e))) {
- // This could happen if performNotify is called multiple times (which is an error).
- throw new MultipleNotificationsError();
- }
- }
-
- public void performNotify() {
- this.performNotify(null);
- }
-
- public static Runnable onThreadRunnable(final Runnable r) {
- return new Runnable() {
- @Override
- public void run() {
- new Thread(r).start();
- }
- };
- }
-
- private static WaitHelper singleWaiter = new WaitHelper();
- public static WaitHelper getTestWaiter() {
- return singleWaiter;
- }
-
- public static void resetTestWaiter() {
- singleWaiter = new WaitHelper();
- }
-
- public boolean isIdle() {
- return queue.isEmpty();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestASNUtils.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestASNUtils.java
deleted file mode 100644
index f0b1f98b5..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestASNUtils.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.browserid.test;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.browserid.ASNUtils;
-import org.mozilla.gecko.sync.Utils;
-
-import java.math.BigInteger;
-
-@RunWith(TestRunner.class)
-public class TestASNUtils {
- public void doTestEncodeDecodeArrays(int length1, int length2) {
- if (4 + length1 + length2 > 127) {
- throw new IllegalArgumentException("Total length must be < 128 - 4.");
- }
- byte[] first = Utils.generateRandomBytes(length1);
- byte[] second = Utils.generateRandomBytes(length2);
- byte[] encoded = ASNUtils.encodeTwoArraysToASN1(first, second);
- byte[][] arrays = ASNUtils.decodeTwoArraysFromASN1(encoded);
- Assert.assertArrayEquals(first, arrays[0]);
- Assert.assertArrayEquals(second, arrays[1]);
- }
-
- @Test
- public void testEncodeDecodeArrays() {
- doTestEncodeDecodeArrays(0, 0);
- doTestEncodeDecodeArrays(0, 10);
- doTestEncodeDecodeArrays(10, 0);
- doTestEncodeDecodeArrays(10, 10);
- }
-
- @Test
- public void testEncodeDecodeRandomSizeArrays() {
- for (int i = 0; i < 10; i++) {
- int length1 = Utils.generateBigIntegerLessThan(BigInteger.valueOf(50)).intValue() + 10;
- int length2 = Utils.generateBigIntegerLessThan(BigInteger.valueOf(50)).intValue() + 10;
- doTestEncodeDecodeArrays(length1, length2);
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestDSACryptoImplementation.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestDSACryptoImplementation.java
deleted file mode 100644
index 62427e5e1..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestDSACryptoImplementation.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.browserid.test;
-
-import junit.framework.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.browserid.BrowserIDKeyPair;
-import org.mozilla.gecko.browserid.DSACryptoImplementation;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-
-import java.math.BigInteger;
-
-@RunWith(TestRunner.class)
-public class TestDSACryptoImplementation {
- @Test
- public void testToJSONObject() throws Exception {
- BigInteger p = new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16);
- BigInteger q = new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16);
- BigInteger g = new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16);
- BigInteger x = new BigInteger("9516d860392003db5a4f168444903265467614db", 16);
- BigInteger y = new BigInteger("455152a0e499f5c9d11f9f1868c8b868b1443ca853843226a5a9552dd909b4bdba879acc504acb690df0348d60e63ea37e8c7f075302e0df5bcdc76a383888a0", 16);
-
- BrowserIDKeyPair keyPair = new BrowserIDKeyPair(
- DSACryptoImplementation.createPrivateKey(x, p, q, g),
- DSACryptoImplementation.createPublicKey(y, p, q, g));
-
- ExtendedJSONObject o = new ExtendedJSONObject("{\"publicKey\":{\"g\":\"678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4\",\"q\":\"962eddcc369cba8ebb260ee6b6a126d9346e38c5\",\"p\":\"fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17\",\"y\":\"455152a0e499f5c9d11f9f1868c8b868b1443ca853843226a5a9552dd909b4bdba879acc504acb690df0348d60e63ea37e8c7f075302e0df5bcdc76a383888a0\",\"algorithm\":\"DS\"},\"privateKey\":{\"g\":\"678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4\",\"q\":\"962eddcc369cba8ebb260ee6b6a126d9346e38c5\",\"p\":\"fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17\",\"x\":\"9516d860392003db5a4f168444903265467614db\",\"algorithm\":\"DS\"}}");
- Assert.assertEquals(o.getObject("privateKey"), keyPair.toJSONObject().getObject("privateKey"));
- Assert.assertEquals(o.getObject("publicKey"), keyPair.toJSONObject().getObject("publicKey"));
- }
-
- @Test
- public void testFromJSONObject() throws Exception {
- BigInteger p = new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16);
- BigInteger q = new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16);
- BigInteger g = new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16);
- BigInteger x = new BigInteger("9516d860392003db5a4f168444903265467614db", 16);
- BigInteger y = new BigInteger("455152a0e499f5c9d11f9f1868c8b868b1443ca853843226a5a9552dd909b4bdba879acc504acb690df0348d60e63ea37e8c7f075302e0df5bcdc76a383888a0", 16);
-
- BrowserIDKeyPair keyPair = new BrowserIDKeyPair(
- DSACryptoImplementation.createPrivateKey(x, p, q, g),
- DSACryptoImplementation.createPublicKey(y, p, q, g));
-
- ExtendedJSONObject o = new ExtendedJSONObject("{\"publicKey\":{\"g\":\"678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4\",\"q\":\"962eddcc369cba8ebb260ee6b6a126d9346e38c5\",\"p\":\"fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17\",\"y\":\"455152a0e499f5c9d11f9f1868c8b868b1443ca853843226a5a9552dd909b4bdba879acc504acb690df0348d60e63ea37e8c7f075302e0df5bcdc76a383888a0\",\"algorithm\":\"DS\"},\"privateKey\":{\"g\":\"678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4\",\"q\":\"962eddcc369cba8ebb260ee6b6a126d9346e38c5\",\"p\":\"fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17\",\"x\":\"9516d860392003db5a4f168444903265467614db\",\"algorithm\":\"DS\"}}");
-
- Assert.assertEquals(keyPair.getPublic().toJSONObject(), DSACryptoImplementation.createPublicKey(o.getObject("publicKey")).toJSONObject());
- Assert.assertEquals(keyPair.getPrivate().toJSONObject(), DSACryptoImplementation.createPrivateKey(o.getObject("privateKey")).toJSONObject());
- }
-
- @Test
- public void testRoundTrip() throws Exception {
- BrowserIDKeyPair keyPair = DSACryptoImplementation.generateKeyPair(512);
- ExtendedJSONObject o = keyPair.toJSONObject();
- BrowserIDKeyPair keyPair2 = DSACryptoImplementation.fromJSONObject(o);
- Assert.assertEquals(o, keyPair2.toJSONObject());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestJSONWebTokenUtils.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestJSONWebTokenUtils.java
deleted file mode 100644
index 7e1f9287e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestJSONWebTokenUtils.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.browserid.test;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.browserid.BrowserIDKeyPair;
-import org.mozilla.gecko.browserid.DSACryptoImplementation;
-import org.mozilla.gecko.browserid.JSONWebTokenUtils;
-import org.mozilla.gecko.browserid.RSACryptoImplementation;
-import org.mozilla.gecko.browserid.SigningPrivateKey;
-import org.mozilla.gecko.browserid.VerifyingPublicKey;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-
-import java.math.BigInteger;
-import java.security.GeneralSecurityException;
-
-@RunWith(TestRunner.class)
-public class TestJSONWebTokenUtils {
- public void doTestEncodeDecode(BrowserIDKeyPair keyPair) throws Exception {
- SigningPrivateKey privateKey = keyPair.getPrivate();
- VerifyingPublicKey publicKey = keyPair.getPublic();
-
- ExtendedJSONObject o = new ExtendedJSONObject();
- o.put("key", "value");
-
- String token = JSONWebTokenUtils.encode(o.toJSONString(), privateKey);
- Assert.assertNotNull(token);
-
- String payload = JSONWebTokenUtils.decode(token, publicKey);
- Assert.assertEquals(o.toJSONString(), payload);
-
- try {
- JSONWebTokenUtils.decode(token + "x", publicKey);
- Assert.fail("Expected exception.");
- } catch (GeneralSecurityException e) {
- // Do nothing.
- }
- }
-
- @Test
- public void testEncodeDecodeSuccessRSA() throws Exception {
- doTestEncodeDecode(RSACryptoImplementation.generateKeyPair(1024));
- doTestEncodeDecode(RSACryptoImplementation.generateKeyPair(2048));
- }
-
- @Test
- public void testEncodeDecodeSuccessDSA() throws Exception {
- doTestEncodeDecode(DSACryptoImplementation.generateKeyPair(512));
- doTestEncodeDecode(DSACryptoImplementation.generateKeyPair(1024));
- }
-
- public static String TEST_ASSERTION_ISSUER = "127.0.0.1";
- public static String TEST_AUDIENCE = "http://localhost:8080";
-
- @Test
- public void testRSAGeneration() throws Exception {
- // This test uses (now out-dated) MockMyID RSA data but doesn't rely on this
- // data actually being MockMyID's data.
- final BigInteger MOCKMYID_MODULUS = new BigInteger("15498874758090276039465094105837231567265546373975960480941122651107772824121527483107402353899846252489837024870191707394743196399582959425513904762996756672089693541009892030848825079649783086005554442490232900875792851786203948088457942416978976455297428077460890650409549242124655536986141363719589882160081480785048965686285142002320767066674879737238012064156675899512503143225481933864507793118457805792064445502834162315532113963746801770187685650408560424682654937744713813773896962263709692724630650952159596951348264005004375017610441835956073275708740239518011400991972811669493356682993446554779893834303");
- final BigInteger MOCKMYID_PUBLIC_EXPONENT = new BigInteger("65537");
- final BigInteger MOCKMYID_PRIVATE_EXPONENT = new BigInteger("6539906961872354450087244036236367269804254381890095841127085551577495913426869112377010004955160417265879626558436936025363204803913318582680951558904318308893730033158178650549970379367915856087364428530828396795995781364659413467784853435450762392157026962694408807947047846891301466649598749901605789115278274397848888140105306063608217776127549926721544215720872305194645129403056801987422794114703255989202755511523434098625000826968430077091984351410839837395828971692109391386427709263149504336916566097901771762648090880994773325283207496645630792248007805177873532441314470502254528486411726581424522838833");
-
- BigInteger n = new BigInteger("20332459213245328760269530796942625317006933400814022542511832260333163206808672913301254872114045771215470352093046136365629411384688395020388553744886954869033696089099714200452682590914843971683468562019706059388121176435204818734091361033445697933682779095713376909412972373727850278295874361806633955236862180792787906413536305117030045164276955491725646610368132167655556353974515423042221261732084368978523747789654468953860772774078384556028728800902433401131226904244661160767916883680495122225202542023841606998867411022088440946301191503335932960267228470933599974787151449279465703844493353175088719018221");
- BigInteger e = new BigInteger("65537");
- BigInteger d = new BigInteger("9362542596354998418106014928820888151984912891492829581578681873633736656469965533631464203894863562319612803232737938923691416707617473868582415657005943574434271946791143554652502483003923911339605326222297167404896789026986450703532494518628015811567189641735787240372075015553947628033216297520493759267733018808392882741098489889488442349031883643894014316243251108104684754879103107764521172490019661792943030921873284592436328217485953770574054344056638447333651425231219150676837203185544359148474983670261712939626697233692596362322419559401320065488125670905499610998631622562652935873085671353890279911361");
-
- long iat = 1352995809210L;
- long dur = 60 * 60 * 1000;
- long exp = iat + dur;
-
- VerifyingPublicKey mockMyIdPublicKey = RSACryptoImplementation.createPublicKey(MOCKMYID_MODULUS, MOCKMYID_PUBLIC_EXPONENT);;
- SigningPrivateKey mockMyIdPrivateKey = RSACryptoImplementation.createPrivateKey(MOCKMYID_MODULUS, MOCKMYID_PRIVATE_EXPONENT);
- VerifyingPublicKey publicKeyToSign = RSACryptoImplementation.createPublicKey(n, e);
- SigningPrivateKey privateKeyToSignWith = RSACryptoImplementation.createPrivateKey(n, d);
-
- String certificate = JSONWebTokenUtils.createCertificate(publicKeyToSign, "test@mockmyid.com", "mockmyid.com", iat, exp, mockMyIdPrivateKey);
- String assertion = JSONWebTokenUtils.createAssertion(privateKeyToSignWith, certificate, TEST_AUDIENCE, TEST_ASSERTION_ISSUER, iat, exp);
- String payload = JSONWebTokenUtils.decode(certificate, mockMyIdPublicKey);
-
- String EXPECTED_PAYLOAD = "{\"exp\":1352999409210,\"iat\":1352995809210,\"iss\":\"mockmyid.com\",\"principal\":{\"email\":\"test@mockmyid.com\"},\"public-key\":{\"e\":\"65537\",\"n\":\"20332459213245328760269530796942625317006933400814022542511832260333163206808672913301254872114045771215470352093046136365629411384688395020388553744886954869033696089099714200452682590914843971683468562019706059388121176435204818734091361033445697933682779095713376909412972373727850278295874361806633955236862180792787906413536305117030045164276955491725646610368132167655556353974515423042221261732084368978523747789654468953860772774078384556028728800902433401131226904244661160767916883680495122225202542023841606998867411022088440946301191503335932960267228470933599974787151449279465703844493353175088719018221\",\"algorithm\":\"RS\"}}";
- Assert.assertEquals(EXPECTED_PAYLOAD, payload);
-
- // Really(!) brittle tests below. The RSA signature algorithm is deterministic, so we can test the actual signature.
- String EXPECTED_CERTIFICATE = "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjEzNTI5OTk0MDkyMTAsImlhdCI6MTM1Mjk5NTgwOTIxMCwiaXNzIjoibW9ja215aWQuY29tIiwicHJpbmNpcGFsIjp7ImVtYWlsIjoidGVzdEBtb2NrbXlpZC5jb20ifSwicHVibGljLWtleSI6eyJlIjoiNjU1MzciLCJuIjoiMjAzMzI0NTkyMTMyNDUzMjg3NjAyNjk1MzA3OTY5NDI2MjUzMTcwMDY5MzM0MDA4MTQwMjI1NDI1MTE4MzIyNjAzMzMxNjMyMDY4MDg2NzI5MTMzMDEyNTQ4NzIxMTQwNDU3NzEyMTU0NzAzNTIwOTMwNDYxMzYzNjU2Mjk0MTEzODQ2ODgzOTUwMjAzODg1NTM3NDQ4ODY5NTQ4NjkwMzM2OTYwODkwOTk3MTQyMDA0NTI2ODI1OTA5MTQ4NDM5NzE2ODM0Njg1NjIwMTk3MDYwNTkzODgxMjExNzY0MzUyMDQ4MTg3MzQwOTEzNjEwMzM0NDU2OTc5MzM2ODI3NzkwOTU3MTMzNzY5MDk0MTI5NzIzNzM3Mjc4NTAyNzgyOTU4NzQzNjE4MDY2MzM5NTUyMzY4NjIxODA3OTI3ODc5MDY0MTM1MzYzMDUxMTcwMzAwNDUxNjQyNzY5NTU0OTE3MjU2NDY2MTAzNjgxMzIxNjc2NTU1NTYzNTM5NzQ1MTU0MjMwNDIyMjEyNjE3MzIwODQzNjg5Nzg1MjM3NDc3ODk2NTQ0Njg5NTM4NjA3NzI3NzQwNzgzODQ1NTYwMjg3Mjg4MDA5MDI0MzM0MDExMzEyMjY5MDQyNDQ2NjExNjA3Njc5MTY4ODM2ODA0OTUxMjIyMjUyMDI1NDIwMjM4NDE2MDY5OTg4Njc0MTEwMjIwODg0NDA5NDYzMDExOTE1MDMzMzU5MzI5NjAyNjcyMjg0NzA5MzM1OTk5NzQ3ODcxNTE0NDkyNzk0NjU3MDM4NDQ0OTMzNTMxNzUwODg3MTkwMTgyMjEiLCJhbGdvcml0aG0iOiJSUyJ9fQ.ZgT0ezITaE6rRQCxEA6OHkjwAsFdE-R8943UEmiCvKKpsbxlSlI1Iya1Oho2wrhet5bjBGM77EffzC2YwzD5qa7SrVpNwSCIW6AwnlJ6YePoNblkn0y7NQ_qThvLoaP4Vlk_XM0LbK_QPHqaWU7ldm8LF5Zp4oHgayMP4YhiyKYS2TwWWcvswT2g9IhU6YdYcF0TwT2YkJ4t3h7_sVn-OmQQu4k1KKGFLpT6HOj2EGaKmw-mzayHL0r7L3-5g_7Q83RMBe_k_4YeLG8InxO3M3GreqcaImv4XO5D-C__txfFuaLJjTzKBLrIIosckaNwp4JmN1Nf8x9t5RXHLCsrjw";
- Assert.assertEquals(EXPECTED_CERTIFICATE, certificate);
-
- String EXPECTED_ASSERTION = "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjEzNTI5OTk0MDkyMTAsImlhdCI6MTM1Mjk5NTgwOTIxMCwiaXNzIjoibW9ja215aWQuY29tIiwicHJpbmNpcGFsIjp7ImVtYWlsIjoidGVzdEBtb2NrbXlpZC5jb20ifSwicHVibGljLWtleSI6eyJlIjoiNjU1MzciLCJuIjoiMjAzMzI0NTkyMTMyNDUzMjg3NjAyNjk1MzA3OTY5NDI2MjUzMTcwMDY5MzM0MDA4MTQwMjI1NDI1MTE4MzIyNjAzMzMxNjMyMDY4MDg2NzI5MTMzMDEyNTQ4NzIxMTQwNDU3NzEyMTU0NzAzNTIwOTMwNDYxMzYzNjU2Mjk0MTEzODQ2ODgzOTUwMjAzODg1NTM3NDQ4ODY5NTQ4NjkwMzM2OTYwODkwOTk3MTQyMDA0NTI2ODI1OTA5MTQ4NDM5NzE2ODM0Njg1NjIwMTk3MDYwNTkzODgxMjExNzY0MzUyMDQ4MTg3MzQwOTEzNjEwMzM0NDU2OTc5MzM2ODI3NzkwOTU3MTMzNzY5MDk0MTI5NzIzNzM3Mjc4NTAyNzgyOTU4NzQzNjE4MDY2MzM5NTUyMzY4NjIxODA3OTI3ODc5MDY0MTM1MzYzMDUxMTcwMzAwNDUxNjQyNzY5NTU0OTE3MjU2NDY2MTAzNjgxMzIxNjc2NTU1NTYzNTM5NzQ1MTU0MjMwNDIyMjEyNjE3MzIwODQzNjg5Nzg1MjM3NDc3ODk2NTQ0Njg5NTM4NjA3NzI3NzQwNzgzODQ1NTYwMjg3Mjg4MDA5MDI0MzM0MDExMzEyMjY5MDQyNDQ2NjExNjA3Njc5MTY4ODM2ODA0OTUxMjIyMjUyMDI1NDIwMjM4NDE2MDY5OTg4Njc0MTEwMjIwODg0NDA5NDYzMDExOTE1MDMzMzU5MzI5NjAyNjcyMjg0NzA5MzM1OTk5NzQ3ODcxNTE0NDkyNzk0NjU3MDM4NDQ0OTMzNTMxNzUwODg3MTkwMTgyMjEiLCJhbGdvcml0aG0iOiJSUyJ9fQ.ZgT0ezITaE6rRQCxEA6OHkjwAsFdE-R8943UEmiCvKKpsbxlSlI1Iya1Oho2wrhet5bjBGM77EffzC2YwzD5qa7SrVpNwSCIW6AwnlJ6YePoNblkn0y7NQ_qThvLoaP4Vlk_XM0LbK_QPHqaWU7ldm8LF5Zp4oHgayMP4YhiyKYS2TwWWcvswT2g9IhU6YdYcF0TwT2YkJ4t3h7_sVn-OmQQu4k1KKGFLpT6HOj2EGaKmw-mzayHL0r7L3-5g_7Q83RMBe_k_4YeLG8InxO3M3GreqcaImv4XO5D-C__txfFuaLJjTzKBLrIIosckaNwp4JmN1Nf8x9t5RXHLCsrjw~eyJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODA4MCIsImV4cCI6MTM1Mjk5OTQwOTIxMCwiaWF0IjoxMzUyOTk1ODA5MjEwLCJpc3MiOiIxMjcuMC4wLjEifQ.gj5Q9KXR_mPEltn3SXKAjIHMOpQq0FP6NdPOB-Zu149LKhQrfXS90woVJYg8WpaasmiS6gjBFni3urq3adPktzw4RoMm1qVMvSRXXIRZzgsV_vHlSenIY0KlAk4140pAlAPcdJhB2bvKUPPDq0TLzlWHgQpheAAFMGPY1OGgwgHtsCQC_vyE2wFi8M58IGYQ-05KmWc6Zo33CJG6LjVvkTPvPTEzQKFYKwDQGc4NTkqZbCNZE6iRq4mlX9LGFddzEDiSUDmS53SwR4nfFzPQE6Q1xnU4a_BLhfNpdfOc-uHGoJGbm0ZJpLdKf7zadp34ImFA9IUBhjegingZhm2i5g";
- Assert.assertEquals(EXPECTED_ASSERTION, assertion);
- }
-
- @Test
- public void testDSAGeneration() throws Exception {
- // This test uses MockMyID DSA data but doesn't rely on this data actually
- // being MockMyID's data.
- final BigInteger MOCKMYID_x = new BigInteger("385cb3509f086e110c5e24bdd395a84b335a09ae", 16);
- final BigInteger MOCKMYID_y = new BigInteger("738ec929b559b604a232a9b55a5295afc368063bb9c20fac4e53a74970a4db7956d48e4c7ed523405f629b4cc83062f13029c4d615bbacb8b97f5e56f0c7ac9bc1d4e23809889fa061425c984061fca1826040c399715ce7ed385c4dd0d402256912451e03452d3c961614eb458f188e3e8d2782916c43dbe2e571251ce38262", 16);
- final BigInteger MOCKMYID_p = new BigInteger("ff600483db6abfc5b45eab78594b3533d550d9f1bf2a992a7a8daa6dc34f8045ad4e6e0c429d334eeeaaefd7e23d4810be00e4cc1492cba325ba81ff2d5a5b305a8d17eb3bf4a06a349d392e00d329744a5179380344e82a18c47933438f891e22aeef812d69c8f75e326cb70ea000c3f776dfdbd604638c2ef717fc26d02e17", 16);
- final BigInteger MOCKMYID_q = new BigInteger("e21e04f911d1ed7991008ecaab3bf775984309c3", 16);
- final BigInteger MOCKMYID_g = new BigInteger("c52a4a0ff3b7e61fdf1867ce84138369a6154f4afa92966e3c827e25cfa6cf508b90e5de419e1337e07a2e9e2a3cd5dea704d175f8ebf6af397d69e110b96afb17c7a03259329e4829b0d03bbc7896b15b4ade53e130858cc34d96269aa89041f409136c7242a38895c9d5bccad4f389af1d7a4bd1398bd072dffa896233397a", 16);
-
- BigInteger g = new BigInteger("f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", 16);
- BigInteger q = new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16);
- BigInteger p = new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16);
- BigInteger x = new BigInteger("b137fc5b8faaa53b170563eb03c18b46b657bb6", 16);
- BigInteger y = new BigInteger("ea809be508bc94485553efac8ef2a8debdcdb3545ce433e8bd5889ec9d0880a13b2a8af35451161e58229d1e2be69e74a7251465a394913e8e64b0c33fde39a637b6047d7370178cf4404c0a7b4c2ed31d9cfe03ab79dbcc64667e6e7bc244eb1c127c28d725db94aff29b858bdb636f1307bdf48b3c91f387c2ab588086b6c8", 16);
-
- long iat = 1380070362995L;
- long dur = 60 * 60 * 1000;
- long exp = iat + dur;
-
- VerifyingPublicKey mockMyIdPublicKey = DSACryptoImplementation.createPublicKey(MOCKMYID_y, MOCKMYID_p, MOCKMYID_q, MOCKMYID_g);
- SigningPrivateKey mockMyIdPrivateKey = DSACryptoImplementation.createPrivateKey(MOCKMYID_x, MOCKMYID_p, MOCKMYID_q, MOCKMYID_g);
- VerifyingPublicKey publicKeyToSign = DSACryptoImplementation.createPublicKey(y, p, q, g);
- SigningPrivateKey privateKeyToSignWith = DSACryptoImplementation.createPrivateKey(x, p, q, g);
-
- String certificate = JSONWebTokenUtils.createCertificate(publicKeyToSign, "test@mockmyid.com", "mockmyid.com", iat, exp, mockMyIdPrivateKey);
- String assertion = JSONWebTokenUtils.createAssertion(privateKeyToSignWith, certificate, TEST_AUDIENCE, TEST_ASSERTION_ISSUER, iat, exp);
- String payload = JSONWebTokenUtils.decode(certificate, mockMyIdPublicKey);
-
- String EXPECTED_PAYLOAD = "{\"exp\":1380073962995,\"iat\":1380070362995,\"iss\":\"mockmyid.com\",\"principal\":{\"email\":\"test@mockmyid.com\"},\"public-key\":{\"g\":\"f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a\",\"q\":\"9760508f15230bccb292b982a2eb840bf0581cf5\",\"p\":\"fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7\",\"y\":\"ea809be508bc94485553efac8ef2a8debdcdb3545ce433e8bd5889ec9d0880a13b2a8af35451161e58229d1e2be69e74a7251465a394913e8e64b0c33fde39a637b6047d7370178cf4404c0a7b4c2ed31d9cfe03ab79dbcc64667e6e7bc244eb1c127c28d725db94aff29b858bdb636f1307bdf48b3c91f387c2ab588086b6c8\",\"algorithm\":\"DS\"}}";
- Assert.assertEquals(EXPECTED_PAYLOAD, payload);
-
- // Really(!) brittle tests below. The DSA signature algorithm is not deterministic, so we can't test the actual signature.
- String EXPECTED_CERTIFICATE_PREFIX = "eyJhbGciOiJEUzEyOCJ9.eyJleHAiOjEzODAwNzM5NjI5OTUsImlhdCI6MTM4MDA3MDM2Mjk5NSwiaXNzIjoibW9ja215aWQuY29tIiwicHJpbmNpcGFsIjp7ImVtYWlsIjoidGVzdEBtb2NrbXlpZC5jb20ifSwicHVibGljLWtleSI6eyJnIjoiZjdlMWEwODVkNjliM2RkZWNiYmNhYjVjMzZiODU3Yjk3OTk0YWZiYmZhM2FlYTgyZjk1NzRjMGIzZDA3ODI2NzUxNTk1NzhlYmFkNDU5NGZlNjcxMDcxMDgxODBiNDQ5MTY3MTIzZTg0YzI4MTYxM2I3Y2YwOTMyOGNjOGE2ZTEzYzE2N2E4YjU0N2M4ZDI4ZTBhM2FlMWUyYmIzYTY3NTkxNmVhMzdmMGJmYTIxMzU2MmYxZmI2MjdhMDEyNDNiY2NhNGYxYmVhODUxOTA4OWE4ODNkZmUxNWFlNTlmMDY5MjhiNjY1ZTgwN2I1NTI1NjQwMTRjM2JmZWNmNDkyYSIsInEiOiI5NzYwNTA4ZjE1MjMwYmNjYjI5MmI5ODJhMmViODQwYmYwNTgxY2Y1IiwicCI6ImZkN2Y1MzgxMWQ3NTEyMjk1MmRmNGE5YzJlZWNlNGU3ZjYxMWI3NTIzY2VmNDQwMGMzMWUzZjgwYjY1MTI2Njk0NTVkNDAyMjUxZmI1OTNkOGQ1OGZhYmZjNWY1YmEzMGY2Y2I5YjU1NmNkNzgxM2I4MDFkMzQ2ZmYyNjY2MGI3NmI5OTUwYTVhNDlmOWZlODA0N2IxMDIyYzI0ZmJiYTlkN2ZlYjdjNjFiZjgzYjU3ZTdjNmE4YTYxNTBmMDRmYjgzZjZkM2M1MWVjMzAyMzU1NDEzNWExNjkxMzJmNjc1ZjNhZTJiNjFkNzJhZWZmMjIyMDMxOTlkZDE0ODAxYzciLCJ5IjoiZWE4MDliZTUwOGJjOTQ0ODU1NTNlZmFjOGVmMmE4ZGViZGNkYjM1NDVjZTQzM2U4YmQ1ODg5ZWM5ZDA4ODBhMTNiMmE4YWYzNTQ1MTE2MWU1ODIyOWQxZTJiZTY5ZTc0YTcyNTE0NjVhMzk0OTEzZThlNjRiMGMzM2ZkZTM5YTYzN2I2MDQ3ZDczNzAxNzhjZjQ0MDRjMGE3YjRjMmVkMzFkOWNmZTAzYWI3OWRiY2M2NDY2N2U2ZTdiYzI0NGViMWMxMjdjMjhkNzI1ZGI5NGFmZjI5Yjg1OGJkYjYzNmYxMzA3YmRmNDhiM2M5MWYzODdjMmFiNTg4MDg2YjZjOCIsImFsZ29yaXRobSI6IkRTIn19";
- String[] expectedCertificateParts = EXPECTED_CERTIFICATE_PREFIX.split("\\.");
- String[] certificateParts = certificate.split("\\.");
- Assert.assertEquals(expectedCertificateParts[0], certificateParts[0]);
- Assert.assertEquals(expectedCertificateParts[1], certificateParts[1]);
-
- String EXPECTED_ASSERTION_FRAGMENT = "eyJhbGciOiJEUzEyOCJ9.eyJhdWQiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODA4MCIsImV4cCI6MTM4MDA3Mzk2Mjk5NSwiaWF0IjoxMzgwMDcwMzYyOTk1LCJpc3MiOiIxMjcuMC4wLjEifQ";
- String[] expectedAssertionParts = EXPECTED_ASSERTION_FRAGMENT.split("\\.");
- String[] assertionParts = assertion.split("~")[1].split("\\.");
- Assert.assertEquals(expectedAssertionParts[0], assertionParts[0]);
- Assert.assertEquals(expectedAssertionParts[1], assertionParts[1]);
- }
-
- @Test
- public void testGetPayloadString() throws Exception {
- String s;
- s = JSONWebTokenUtils.getPayloadString("{}", "audience", "issuer", 1L, 2L);
- Assert.assertEquals("{\"aud\":\"audience\",\"exp\":2,\"iat\":1,\"iss\":\"issuer\"}", s);
-
- // Make sure we don't include null issuedAt.
- s = JSONWebTokenUtils.getPayloadString("{}", "audience", "issuer", null, 3L);
- Assert.assertEquals("{\"aud\":\"audience\",\"exp\":3,\"iss\":\"issuer\"}", s);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestRSACryptoImplementation.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestRSACryptoImplementation.java
deleted file mode 100644
index 6dfa88ebf..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/browserid/test/TestRSACryptoImplementation.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.browserid.test;
-
-import junit.framework.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.browserid.BrowserIDKeyPair;
-import org.mozilla.gecko.browserid.RSACryptoImplementation;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-
-import java.math.BigInteger;
-
-@RunWith(TestRunner.class)
-public class TestRSACryptoImplementation {
- @Test
- public void testToJSONObject() throws Exception {
- BigInteger n = new BigInteger("7042170764319402120473546823641395184140303948430445023576085129538272863656735924617881022040465877164076593767104512065359975488480629290310209335113577");
- BigInteger e = new BigInteger("65537");
- BigInteger d = new BigInteger("2050102629239206449128199335463237235732683202345308155771672920433658970744825199440426256856862541525088288448769859770132714705204296375901885294992205");
-
- BrowserIDKeyPair keyPair = new BrowserIDKeyPair(
- RSACryptoImplementation.createPrivateKey(n, d),
- RSACryptoImplementation.createPublicKey(n, e));
-
- ExtendedJSONObject o = new ExtendedJSONObject("{\"publicKey\":{\"e\":\"65537\",\"n\":\"7042170764319402120473546823641395184140303948430445023576085129538272863656735924617881022040465877164076593767104512065359975488480629290310209335113577\",\"algorithm\":\"RS\"},\"privateKey\":{\"d\":\"2050102629239206449128199335463237235732683202345308155771672920433658970744825199440426256856862541525088288448769859770132714705204296375901885294992205\",\"n\":\"7042170764319402120473546823641395184140303948430445023576085129538272863656735924617881022040465877164076593767104512065359975488480629290310209335113577\",\"algorithm\":\"RS\"}}");
- Assert.assertEquals(o.getObject("privateKey"), keyPair.toJSONObject().getObject("privateKey"));
- Assert.assertEquals(o.getObject("publicKey"), keyPair.toJSONObject().getObject("publicKey"));
- }
-
- @Test
- public void testFromJSONObject() throws Exception {
- BigInteger n = new BigInteger("7042170764319402120473546823641395184140303948430445023576085129538272863656735924617881022040465877164076593767104512065359975488480629290310209335113577");
- BigInteger e = new BigInteger("65537");
- BigInteger d = new BigInteger("2050102629239206449128199335463237235732683202345308155771672920433658970744825199440426256856862541525088288448769859770132714705204296375901885294992205");
-
- BrowserIDKeyPair keyPair = new BrowserIDKeyPair(
- RSACryptoImplementation.createPrivateKey(n, d),
- RSACryptoImplementation.createPublicKey(n, e));
-
- ExtendedJSONObject o = new ExtendedJSONObject("{\"publicKey\":{\"e\":\"65537\",\"n\":\"7042170764319402120473546823641395184140303948430445023576085129538272863656735924617881022040465877164076593767104512065359975488480629290310209335113577\",\"algorithm\":\"RS\"},\"privateKey\":{\"d\":\"2050102629239206449128199335463237235732683202345308155771672920433658970744825199440426256856862541525088288448769859770132714705204296375901885294992205\",\"n\":\"7042170764319402120473546823641395184140303948430445023576085129538272863656735924617881022040465877164076593767104512065359975488480629290310209335113577\",\"algorithm\":\"RS\"}}");
-
- Assert.assertEquals(keyPair.getPublic().toJSONObject(), RSACryptoImplementation.createPublicKey(o.getObject("publicKey")).toJSONObject());
- Assert.assertEquals(keyPair.getPrivate().toJSONObject(), RSACryptoImplementation.createPrivateKey(o.getObject("privateKey")).toJSONObject());
- }
-
- @Test
- public void testRoundTrip() throws Exception {
- BrowserIDKeyPair keyPair = RSACryptoImplementation.generateKeyPair(512);
- ExtendedJSONObject o = keyPair.toJSONObject();
- BrowserIDKeyPair keyPair2 = RSACryptoImplementation.fromJSONObject(o);
- Assert.assertEquals(o, keyPair2.toJSONObject());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/cleanup/TestFileCleanupController.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/cleanup/TestFileCleanupController.java
deleted file mode 100644
index 6858b65a7..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/cleanup/TestFileCleanupController.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.cleanup;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.ArrayList;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.atMost;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-/**
- * Tests functionality of the {@link FileCleanupController}.
- */
-@RunWith(TestRunner.class)
-public class TestFileCleanupController {
-
- @Test
- public void testStartIfReadyEmptySharedPrefsRunsCleanup() {
- final Context context = mock(Context.class);
- FileCleanupController.startIfReady(context, getSharedPreferences(), "");
- verify(context).startService(any(Intent.class));
- }
-
- @Test
- public void testStartIfReadyLastRunNowDoesNotRun() {
- final SharedPreferences sharedPrefs = getSharedPreferences();
- sharedPrefs.edit()
- .putLong(FileCleanupController.PREF_LAST_CLEANUP_MILLIS, System.currentTimeMillis())
- .commit(); // synchronous to finish before test runs.
-
- final Context context = mock(Context.class);
- FileCleanupController.startIfReady(context, sharedPrefs, "");
-
- verify(context, never()).startService((any(Intent.class)));
- }
-
- /**
- * Depends on {@link #testStartIfReadyEmptySharedPrefsRunsCleanup()} success –
- * i.e. we expect the cleanup to run with empty prefs.
- */
- @Test
- public void testStartIfReadyDoesNotRunTwiceInSuccession() {
- final Context context = mock(Context.class);
- final SharedPreferences sharedPrefs = getSharedPreferences();
-
- FileCleanupController.startIfReady(context, sharedPrefs, "");
- verify(context).startService(any(Intent.class));
-
- // Note: the Controller relies on SharedPrefs.apply, but
- // robolectric made this a synchronous call. Yay!
- FileCleanupController.startIfReady(context, sharedPrefs, "");
- verify(context, atMost(1)).startService(any(Intent.class));
- }
-
- @Test
- public void testGetFilesToCleanupContainsProfilePath() {
- final String profilePath = "/a/profile/path";
- final ArrayList<String> fileList = FileCleanupController.getFilesToCleanup(profilePath);
- assertNotNull("Returned file list is non-null", fileList);
-
- boolean atLeastOneStartsWithProfilePath = false;
- final String pathToCheck = profilePath + "/"; // Ensure the calling code adds a slash to divide the path.
- for (final String path : fileList) {
- if (path.startsWith(pathToCheck)) {
- // It'd be great if we could assert these individually so
- // we could display the Strings in console output.
- atLeastOneStartsWithProfilePath = true;
- }
- }
- assertTrue("At least one returned String starts with a profile path", atLeastOneStartsWithProfilePath);
- }
-
- private SharedPreferences getSharedPreferences() {
- return RuntimeEnvironment.application.getSharedPreferences("TestFileCleanupController", 0);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/cleanup/TestFileCleanupService.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/cleanup/TestFileCleanupService.java
deleted file mode 100644
index 0326adb6a..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/cleanup/TestFileCleanupService.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.cleanup;
-
-import android.content.Intent;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.*;
-
-/**
- * Tests the methods of {@link FileCleanupService}.
- */
-@RunWith(TestRunner.class)
-public class TestFileCleanupService {
- @Rule
- public final TemporaryFolder tempFolder = new TemporaryFolder();
-
- private void assertAllFilesExist(final List<File> fileList) {
- for (final File file : fileList) {
- assertTrue("File exists", file.exists());
- }
- }
-
- private void assertAllFilesDoNotExist(final List<File> fileList) {
- for (final File file : fileList) {
- assertFalse("File does not exist", file.exists());
- }
- }
-
- private void onHandleIntent(final ArrayList<String> filePaths) {
- final FileCleanupService service = new FileCleanupService();
- final Intent intent = new Intent(FileCleanupService.ACTION_DELETE_FILES);
- intent.putExtra(FileCleanupService.EXTRA_FILE_PATHS_TO_DELETE, filePaths);
- service.onHandleIntent(intent);
- }
-
- @Test
- public void testOnHandleIntentDeleteSpecifiedFiles() throws Exception {
- final int fileListCount = 3;
- final ArrayList<File> filesToDelete = generateFileList(fileListCount);
-
- final ArrayList<String> pathsToDelete = new ArrayList<>(fileListCount);
- for (final File file : filesToDelete) {
- pathsToDelete.add(file.getAbsolutePath());
- }
-
- assertAllFilesExist(filesToDelete);
- onHandleIntent(pathsToDelete);
- assertAllFilesDoNotExist(filesToDelete);
- }
-
- @Test
- public void testOnHandleIntentDoesNotDeleteUnrelatedFiles() throws Exception {
- final ArrayList<File> filesShouldNotBeDeleted = generateFileList(3);
- assertAllFilesExist(filesShouldNotBeDeleted);
- onHandleIntent(new ArrayList<String>());
- assertAllFilesExist(filesShouldNotBeDeleted);
- }
-
- @Test
- public void testOnHandleIntentDeletesEmptyDirectory() throws Exception {
- final File dir = tempFolder.newFolder();
- final ArrayList<String> filesToDelete = new ArrayList<>(1);
- filesToDelete.add(dir.getAbsolutePath());
-
- assertTrue("Empty directory exists", dir.exists());
- onHandleIntent(filesToDelete);
- assertFalse("Empty directory deleted by service", dir.exists());
- }
-
- @Test
- public void testOnHandleIntentDoesNotDeleteNonEmptyDirectory() throws Exception {
- final File dir = tempFolder.newFolder();
- final ArrayList<String> filesCannotDelete = new ArrayList<>(1);
- filesCannotDelete.add(dir.getAbsolutePath());
- assertTrue("Directory exists", dir.exists());
-
- final File fileInDir = new File(dir, "file_in_dir");
- assertTrue("File in dir created", fileInDir.createNewFile());
-
- onHandleIntent(filesCannotDelete);
- assertTrue("Non-empty directory not deleted", dir.exists());
- assertTrue("File in directory not deleted", fileInDir.exists());
- }
-
- private ArrayList<File> generateFileList(final int size) throws IOException {
- final ArrayList<File> fileList = new ArrayList<>(size);
- for (int i = 0; i < size; ++i) {
- fileList.add(tempFolder.newFile());
- }
- return fileList;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserContractTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserContractTest.java
deleted file mode 100644
index e36153d0e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserContractTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.db;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class BrowserContractTest {
- @Test
- /**
- * Test that bookmark and sorting order clauses are set correctly
- */
- public void testGetCombinedFrecencySortOrder() throws Exception {
- String sqlNoBookmarksDesc = BrowserContract.getCombinedFrecencySortOrder(false, false);
- String sqlNoBookmarksAsc = BrowserContract.getCombinedFrecencySortOrder(false, true);
- String sqlBookmarksDesc = BrowserContract.getCombinedFrecencySortOrder(true, false);
- String sqlBookmarksAsc = BrowserContract.getCombinedFrecencySortOrder(true, true);
-
- assertTrue(sqlBookmarksAsc.endsWith(" ASC"));
- assertTrue(sqlBookmarksDesc.endsWith(" DESC"));
- assertTrue(sqlNoBookmarksAsc.endsWith(" ASC"));
- assertTrue(sqlNoBookmarksDesc.endsWith(" DESC"));
-
- assertTrue(sqlBookmarksAsc.startsWith("(CASE WHEN bookmark_id > -1 THEN 100 ELSE 0 END) + "));
- assertTrue(sqlBookmarksDesc.startsWith("(CASE WHEN bookmark_id > -1 THEN 100 ELSE 0 END) + "));
- }
-
- @Test
- /**
- * Test that calculation string is correct for remote visits
- * maxFrecency=1, scaleConst=110, correct sql params for visit count and last date
- * and that time is converted to microseconds.
- */
- public void testGetRemoteFrecencySQL() throws Exception {
- long now = 1;
- String sql = BrowserContract.getRemoteFrecencySQL(now);
- String ageExpr = "(" + now * 1000 + " - remoteDateLastVisited) / 86400000000";
-
- assertEquals(
- "remoteVisitCount * MAX(1, 100 * 110 / (" + ageExpr + " * " + ageExpr + " + 110))",
- sql
- );
- }
-
- @Test
- /**
- * Test that calculation string is correct for remote visits
- * maxFrecency=2, scaleConst=225, correct sql params for visit count and last date
- * and that time is converted to microseconds.
- */
- public void testGetLocalFrecencySQL() throws Exception {
- long now = 1;
- String sql = BrowserContract.getLocalFrecencySQL(now);
- String ageExpr = "(" + now * 1000 + " - localDateLastVisited) / 86400000000";
- String visitCountExpr = "(localVisitCount + 2) * (localVisitCount + 2)";
-
- assertEquals(
- visitCountExpr + " * MAX(2, 100 * 225 / (" + ageExpr + " * " + ageExpr + " + 225))",
- sql
- );
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHighlightsTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHighlightsTest.java
deleted file mode 100644
index f8af41e32..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHighlightsTest.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.db;
-
-import android.content.ContentProviderClient;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.mozilla.gecko.sync.setup.Constants;
-
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-
-import static org.mozilla.gecko.db.BrowserContract.PARAM_PROFILE;
-
-/**
- * Unit tests for the highlights query (Activity Stream).
- */
-@RunWith(TestRunner.class)
-public class BrowserProviderHighlightsTest extends BrowserProviderHistoryVisitsTestBase {
- private ContentProviderClient highlightsClient;
- private ContentProviderClient activityStreamBlocklistClient;
- private ContentProviderClient bookmarksClient;
-
- private Uri highlightsTestUri;
- private Uri activityStreamBlocklistTestUri;
- private Uri bookmarksTestUri;
-
- private Uri expireHistoryNormalUri;
-
- @Before
- public void setUp() throws Exception {
- super.setUp();
-
- final Uri highlightsClientUri = BrowserContract.Highlights.CONTENT_URI.buildUpon()
- .appendQueryParameter(PARAM_PROFILE, Constants.DEFAULT_PROFILE)
- .build();
-
- final Uri activityStreamBlocklistClientUri = BrowserContract.ActivityStreamBlocklist.CONTENT_URI.buildUpon()
- .appendQueryParameter(PARAM_PROFILE, Constants.DEFAULT_PROFILE)
- .build();
-
- highlightsClient = contentResolver.acquireContentProviderClient(highlightsClientUri);
- activityStreamBlocklistClient = contentResolver.acquireContentProviderClient(activityStreamBlocklistClientUri);
- bookmarksClient = contentResolver.acquireContentProviderClient(BrowserContractHelpers.BOOKMARKS_CONTENT_URI);
-
- highlightsTestUri = testUri(BrowserContract.Highlights.CONTENT_URI);
- activityStreamBlocklistTestUri = testUri(BrowserContract.ActivityStreamBlocklist.CONTENT_URI);
- bookmarksTestUri = testUri(BrowserContract.Bookmarks.CONTENT_URI);
-
- expireHistoryNormalUri = testUri(BrowserContract.History.CONTENT_OLD_URI).buildUpon()
- .appendQueryParameter(
- BrowserContract.PARAM_EXPIRE_PRIORITY,
- BrowserContract.ExpirePriority.NORMAL.toString()
- ).build();
- }
-
- @After
- public void tearDown() {
- highlightsClient.release();
- activityStreamBlocklistClient.release();
- bookmarksClient.release();
-
- super.tearDown();
- }
-
- /**
- * Scenario: Empty database, no history, no bookmarks.
- *
- * Assert that:
- * - Empty cursor (not null) is returned.
- */
- @Test
- public void testEmptyDatabase() throws Exception {
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
-
- Assert.assertEquals(0, cursor.getCount());
-
- cursor.close();
- }
-
- /**
- * Scenario: The database only contains very recent history (now, 5 minutes ago, 20 minutes).
- *
- * Assert that:
- * - No highlight is returned from recent history.
- */
- @Test
- public void testOnlyRecentHistory() throws Exception {
- final long now = System.currentTimeMillis();
- final long fiveMinutesAgo = now - 1000 * 60 * 5;
- final long twentyMinutes = now - 1000 * 60 * 20;
-
- insertHistoryItem(createUniqueUrl(), createGUID(), now, 1, createUniqueTitle());
- insertHistoryItem(createUniqueUrl(), createGUID(), fiveMinutesAgo, 1, createUniqueTitle());
- insertHistoryItem(createUniqueUrl(), createGUID(), twentyMinutes, 1, createUniqueTitle());
-
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
-
- Assert.assertNotNull(cursor);
-
- Assert.assertEquals(0, cursor.getCount());
-
- cursor.close();
- }
-
- /**
- * Scenario: The database contains recent (but not too fresh) history (1 hour, 5 days).
- *
- * Assert that:
- * - Highlights are returned from history.
- */
- @Test
- public void testHighlightsArePickedFromHistory() throws Exception {
- final String url1 = createUniqueUrl();
- final String url2 = createUniqueUrl();
- final String title1 = createUniqueTitle();
- final String title2 = createUniqueTitle();
-
- final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
- final long fiveDaysAgo = System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 5;
-
- insertHistoryItem(url1, createGUID(), oneHourAgo, 1, title1);
- insertHistoryItem(url2, createGUID(), fiveDaysAgo, 1, title2);
-
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
-
- Assert.assertEquals(2, cursor.getCount());
-
- assertCursorContainsEntry(cursor, url1, title1);
- assertCursorContainsEntry(cursor, url2, title2);
-
- cursor.close();
- }
-
- /**
- * Scenario: The database contains history that is visited frequently and rarely.
- *
- * Assert that:
- * - Highlights are picked from rarely visited websites.
- * - Highlights are not picked from frequently visited websites.
- */
- @Test
- public void testOftenVisitedPagesAreNotPicked() throws Exception {
- final String url1 = createUniqueUrl();
- final String title1 = createUniqueTitle();
-
- final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
- final long fiveDaysAgo = System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 5;
-
- insertHistoryItem(url1, createGUID(), oneHourAgo, 2, title1);
- insertHistoryItem(createUniqueUrl(), createGUID(), fiveDaysAgo, 25, createUniqueTitle());
-
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
-
- // Verify that only the first URL (with one visit) is picked and the second URL with 25 visits is ignored.
-
- Assert.assertEquals(1, cursor.getCount());
-
- cursor.moveToNext();
- assertCursor(cursor, url1, title1);
-
- cursor.close();
- }
-
- /**
- * Scenario: The database contains history with and without titles.
- *
- * Assert that:
- * - History without titles is not picked for highlights.
- */
- @Test
- public void testHistoryWithoutTitlesIsNotPicked() throws Exception {
- final String url1 = createUniqueUrl();
- final String url2 = createUniqueUrl();
- final String title1 = "";
- final String title2 = createUniqueTitle();
-
- final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
- final long fiveDaysAgo = System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 5;
-
- insertHistoryItem(url1, createGUID(), oneHourAgo, 1, title1);
- insertHistoryItem(url2, createGUID(), fiveDaysAgo, 1, title2);
-
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
-
- // Only one bookmark will be picked for highlights
- Assert.assertEquals(1, cursor.getCount());
-
- cursor.moveToNext();
- assertCursor(cursor, url2, title2);
-
- cursor.close();
- }
-
- /**
- * Scenario: Database contains two bookmarks (unvisited).
- *
- * Assert that:
- * - One bookmark is picked for highlights.
- */
- @Test
- public void testPickingBookmarkForHighlights() throws Exception {
- final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
- final long fiveDaysAgo = System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 5;
-
- final String url1 = createUniqueUrl();
- final String url2 = createUniqueUrl();
- final String title1 = createUniqueTitle();
- final String title2 = createUniqueTitle();
-
- insertBookmarkItem(url1, title1, oneHourAgo);
- insertBookmarkItem(url2, title2, fiveDaysAgo);
-
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
-
- Assert.assertEquals(1, cursor.getCount());
-
- cursor.moveToNext();
- assertCursor(cursor, url1, title1);
-
- cursor.close();
- }
-
- /**
- * Scenario: Database contains an often visited bookmark.
- *
- * Assert that:
- * - Bookmark is not selected for highlights.
- */
- @Test
- public void testOftenVisitedBookmarksWillNotBePicked() throws Exception {
- final String url = createUniqueUrl();
- final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
-
- insertBookmarkItem(url, createUniqueTitle(), oneHourAgo);
- insertHistoryItem(url, createGUID(), oneHourAgo, 25, createUniqueTitle());
-
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
-
- Assert.assertEquals(0, cursor.getCount());
-
- cursor.close();
- }
-
- /**
- * Scenario: Database contains URL as bookmark and in history (not visited often).
- *
- * Assert that:
- * - URL is not picked twice (as bookmark and from history)
- */
- @Test
- public void testSameUrlIsNotPickedFromHistoryAndBookmarks() throws Exception {
- final String url = createUniqueUrl();
-
- final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
-
- // Insert bookmark that is picked for highlights
- insertBookmarkItem(url, createUniqueTitle(), oneHourAgo);
- // Insert history for same URL that would be picked for highlights too
- insertHistoryItem(url, createGUID(), oneHourAgo, 2, createUniqueTitle());
-
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
-
- Assert.assertEquals(1, cursor.getCount());
-
- cursor.close();
- }
-
- /**
- * Scenario: Database contains only old bookmarks.
- *
- * Assert that:
- * - Old bookmarks are not selected as highlight.
- */
- @Test
- public void testVeryOldBookmarksAreNotSelected() throws Exception {
- final long oneWeekAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
- final long oneMonthAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31);
- final long oneYearAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(365);
-
- insertBookmarkItem(createUniqueUrl(), createUniqueTitle(), oneWeekAgo);
- insertBookmarkItem(createUniqueUrl(), createUniqueTitle(), oneMonthAgo);
- insertBookmarkItem(createUniqueUrl(), createUniqueTitle(), oneYearAgo);
-
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
-
- Assert.assertEquals(0, cursor.getCount());
-
- cursor.close();
- }
-
- @Test
- public void testBlocklistItemsAreNotSelected() throws Exception {
- final long oneDayAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1);
-
- final String blockURL = createUniqueUrl();
-
- insertBookmarkItem(blockURL, createUniqueTitle(), oneDayAgo);
-
- Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
- Assert.assertEquals(1, cursor.getCount());
- cursor.close();
-
- insertBlocklistItem(blockURL);
-
- cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
- Assert.assertEquals(0, cursor.getCount());
- cursor.close();
- }
-
- @Test
- public void testBlocklistItemsExpire() throws Exception {
- final long oneDayAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1);
-
- final String blockURL = createUniqueUrl();
- final String blockTitle = createUniqueTitle();
-
- insertBookmarkItem(blockURL, blockTitle, oneDayAgo);
- insertBlocklistItem(blockURL);
-
- {
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
- Assert.assertEquals(0, cursor.getCount());
- cursor.close();
- }
-
- // Add (2000 / 10) items in the loop -> 201 items total
- int itemsNeeded = BrowserProvider.DEFAULT_EXPIRY_RETAIN_COUNT / BrowserProvider.ACTIVITYSTREAM_BLOCKLIST_EXPIRY_FACTOR;
- for (int i = 0; i < itemsNeeded; i++) {
- insertBlocklistItem(createUniqueUrl());
- }
-
- // We still have zero highlights: the item is still blocked
- {
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
- Assert.assertEquals(0, cursor.getCount());
- cursor.close();
- }
-
- // expire the original blocked URL - only most recent 200 items are retained
- historyClient.delete(expireHistoryNormalUri, null, null);
-
- // And the original URL is now in highlights again (note: this shouldn't happen in real life,
- // since the URL will no longer be eligible for highlights by the time we expire it)
- {
- final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
- Assert.assertNotNull(cursor);
- Assert.assertEquals(1, cursor.getCount());
-
- cursor.moveToFirst();
- assertCursor(cursor, blockURL, blockTitle);
- cursor.close();
- }
- }
-
- private void insertBookmarkItem(String url, String title, long createdAt) throws RemoteException {
- ContentValues values = new ContentValues();
-
- values.put(BrowserContract.Bookmarks.URL, url);
- values.put(BrowserContract.Bookmarks.TITLE, title);
- values.put(BrowserContract.Bookmarks.PARENT, 0);
- values.put(BrowserContract.Bookmarks.TYPE, BrowserContract.Bookmarks.TYPE_BOOKMARK);
- values.put(BrowserContract.Bookmarks.DATE_CREATED, createdAt);
-
- bookmarksClient.insert(bookmarksTestUri, values);
- }
-
- private void insertBlocklistItem(String url) throws RemoteException {
- final ContentValues values = new ContentValues();
- values.put(BrowserContract.ActivityStreamBlocklist.URL, url);
-
- activityStreamBlocklistClient.insert(activityStreamBlocklistTestUri, values);
- }
-
- private void assertCursor(Cursor cursor, String url, String title) {
- final String actualTitle = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.TITLE));
- Assert.assertEquals(title, actualTitle);
-
- final String actualUrl = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
- Assert.assertEquals(url, actualUrl);
- }
-
- private void assertCursorContainsEntry(Cursor cursor, String url, String title) {
- cursor.moveToFirst();
-
- do {
- final String actualTitle = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.TITLE));
- final String actualUrl = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
-
- if (actualTitle.equals(title) && actualUrl.equals(url)) {
- return;
- }
- } while (cursor.moveToNext());
-
- Assert.fail("Could not find entry title=" + title + ", url=" + url);
- }
-
- private String createUniqueUrl() {
- return new Uri.Builder()
- .scheme("https")
- .authority(UUID.randomUUID().toString() + ".example.org")
- .appendPath(UUID.randomUUID().toString())
- .appendPath(UUID.randomUUID().toString())
- .build()
- .toString();
- }
-
- private String createUniqueTitle() {
- return "Title " + UUID.randomUUID().toString();
- }
-
- private String createGUID() {
- return UUID.randomUUID().toString();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryTest.java
deleted file mode 100644
index 850841432..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryTest.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.db;
-
-import android.content.ContentProviderClient;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.robolectric.shadows.ShadowContentResolver;
-
-import static org.junit.Assert.*;
-
-/**
- * Testing functionality exposed by BrowserProvider ContentProvider (history, bookmarks, etc).
- * This is WIP junit4 port of robocop tests at org.mozilla.gecko.tests.testBrowserProvider.
- * See Bug 1269492
- */
-@RunWith(TestRunner.class)
-public class BrowserProviderHistoryTest extends BrowserProviderHistoryVisitsTestBase {
- private ContentProviderClient thumbnailClient;
- private Uri thumbnailTestUri;
- private Uri expireHistoryNormalUri;
- private Uri expireHistoryAggressiveUri;
-
- private static final long THREE_MONTHS = 1000L * 60L * 60L * 24L * 30L * 3L;
-
- @Before
- @Override
- public void setUp() throws Exception {
- super.setUp();
- final ShadowContentResolver cr = new ShadowContentResolver();
- thumbnailClient = cr.acquireContentProviderClient(BrowserContract.Thumbnails.CONTENT_URI);
- thumbnailTestUri = testUri(BrowserContract.Thumbnails.CONTENT_URI);
- expireHistoryNormalUri = testUri(BrowserContract.History.CONTENT_OLD_URI).buildUpon()
- .appendQueryParameter(
- BrowserContract.PARAM_EXPIRE_PRIORITY,
- BrowserContract.ExpirePriority.NORMAL.toString()
- ).build();
- expireHistoryAggressiveUri = testUri(BrowserContract.History.CONTENT_OLD_URI).buildUpon()
- .appendQueryParameter(
- BrowserContract.PARAM_EXPIRE_PRIORITY,
- BrowserContract.ExpirePriority.AGGRESSIVE.toString()
- ).build();
- }
-
- @After
- @Override
- public void tearDown() {
- thumbnailClient.release();
- super.tearDown();
- }
-
- /**
- * Test aggressive expiration on new (recent) history items
- */
- @Test
- public void testHistoryExpirationAggressiveNew() throws Exception {
- final int historyItemsCount = 3000;
- insertHistory(historyItemsCount, System.currentTimeMillis());
-
- historyClient.delete(expireHistoryAggressiveUri, null, null);
-
- /**
- * Aggressive expiration should leave 500 history items
- * See {@link BrowserProvider.AGGRESSIVE_EXPIRY_RETAIN_COUNT}
- */
- assertRowCount(historyClient, historyTestUri, 500);
-
- /**
- * Aggressive expiration should leave 15 thumbnails
- * See {@link BrowserProvider.DEFAULT_EXPIRY_THUMBNAIL_COUNT}
- */
- assertRowCount(thumbnailClient, thumbnailTestUri, 15);
- }
-
- /**
- * Test normal expiration on new (recent) history items
- */
- @Test
- public void testHistoryExpirationNormalNew() throws Exception {
- final int historyItemsCount = 3000;
- insertHistory(historyItemsCount, System.currentTimeMillis());
-
- historyClient.delete(expireHistoryNormalUri, null, null);
-
- // Normal expiration shouldn't expire new items
- assertRowCount(historyClient, historyTestUri, 3000);
-
- /**
- * Normal expiration should leave 15 thumbnails
- * See {@link BrowserProvider.DEFAULT_EXPIRY_THUMBNAIL_COUNT}
- */
- assertRowCount(thumbnailClient, thumbnailTestUri, 15);
- }
-
- /**
- * Test aggressive expiration on old history items
- */
- @Test
- public void testHistoryExpirationAggressiveOld() throws Exception {
- final int historyItemsCount = 3000;
- insertHistory(historyItemsCount, System.currentTimeMillis() - THREE_MONTHS);
-
- historyClient.delete(expireHistoryAggressiveUri, null, null);
-
- /**
- * Aggressive expiration should leave 500 history items
- * See {@link BrowserProvider.AGGRESSIVE_EXPIRY_RETAIN_COUNT}
- */
- assertRowCount(historyClient, historyTestUri, 500);
-
- /**
- * Aggressive expiration should leave 15 thumbnails
- * See {@link BrowserProvider.DEFAULT_EXPIRY_THUMBNAIL_COUNT}
- */
- assertRowCount(thumbnailClient, thumbnailTestUri, 15);
- }
-
- /**
- * Test normal expiration on old history items
- */
- @Test
- public void testHistoryExpirationNormalOld() throws Exception {
- final int historyItemsCount = 3000;
- insertHistory(historyItemsCount, System.currentTimeMillis() - THREE_MONTHS);
-
- historyClient.delete(expireHistoryNormalUri, null, null);
-
- /**
- * Normal expiration of old items should retain at most 2000 items
- * See {@link BrowserProvider.DEFAULT_EXPIRY_RETAIN_COUNT}
- */
- assertRowCount(historyClient, historyTestUri, 2000);
-
- /**
- * Normal expiration should leave 15 thumbnails
- * See {@link BrowserProvider.DEFAULT_EXPIRY_THUMBNAIL_COUNT}
- */
- assertRowCount(thumbnailClient, thumbnailTestUri, 15);
- }
-
- /**
- * Test that we update aggregates at the appropriate times. Local visit aggregates are only updated
- * when updating history record with PARAM_INCREMENT_VISITS=true. Remote aggregate values are updated
- * only if set directly. Aggregate values are not set when inserting a new history record via insertHistory.
- * Local aggregate values are set when inserting a new history record via update.
- * @throws Exception
- */
- @Test
- public void testHistoryVisitAggregates() throws Exception {
- final long baseDate = System.currentTimeMillis();
- final String url = "https://www.mozilla.org";
- final Uri historyIncrementVisitsUri = historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true")
- .appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build();
-
- // Test default values
- insertHistoryItem(url, null, baseDate, null);
- assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
- 0, 0, 0, 0, 0);
-
- // Test setting visit count on new history item creation
- final String url2 = "https://www.eff.org";
- insertHistoryItem(url2, null, baseDate, 17);
- assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url2},
- 17, 0, 0, 0, 0);
-
- // Test setting visit count on new history item creation via .update
- final String url3 = "https://www.torproject.org";
- final ContentValues cv = new ContentValues();
- cv.put(BrowserContract.History.URL, url3);
- cv.put(BrowserContract.History.VISITS, 13);
- cv.put(BrowserContract.History.DATE_LAST_VISITED, baseDate);
- historyClient.update(historyIncrementVisitsUri, cv, BrowserContract.History.URL + " = ?", new String[] {url3});
- assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url3},
- 13, 13, baseDate, 0, 0);
-
- // Test that updating meta doesn't touch aggregates
- cv.clear();
- cv.put(BrowserContract.History.TITLE, "New title");
- historyClient.update(historyTestUri, cv, BrowserContract.History.URL + " = ?", new String[] {url});
- assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
- 0, 0, 0, 0, 0);
-
- // Test that incrementing visits without specifying visit count updates local aggregate values
- final long lastVisited = System.currentTimeMillis();
- cv.clear();
- cv.put(BrowserContract.History.DATE_LAST_VISITED, lastVisited);
- historyClient.update(historyIncrementVisitsUri,
- cv, BrowserContract.History.URL + " = ?", new String[] {url});
- assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
- 1, 1, lastVisited, 0, 0);
-
- // Test that incrementing visits by a specified visit count updates local aggregate values
- // We don't support bumping visit count by more than 1. This doesn't make sense when we keep
- // detailed information about our individual visits.
- final long lastVisited2 = System.currentTimeMillis();
- cv.clear();
- cv.put(BrowserContract.History.DATE_LAST_VISITED, lastVisited2);
- cv.put(BrowserContract.History.VISITS, 10);
- historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
- cv, BrowserContract.History.URL + " = ?", new String[] {url});
- assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
- 2, 2, lastVisited2, 0, 0);
-
- // Test that we can directly update aggregate values
- // NB: visits is unchanged (2)
- final long lastVisited3 = System.currentTimeMillis();
- cv.clear();
- cv.put(BrowserContract.History.LOCAL_DATE_LAST_VISITED, lastVisited3);
- cv.put(BrowserContract.History.LOCAL_VISITS, 19);
- cv.put(BrowserContract.History.REMOTE_DATE_LAST_VISITED, lastVisited3 - 100);
- cv.put(BrowserContract.History.REMOTE_VISITS, 3);
- historyClient.update(historyTestUri, cv, BrowserContract.History.URL + " = ?", new String[] {url});
- assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
- 2, 19, lastVisited3, 3, lastVisited3 - 100);
-
- // Test that we can set remote aggregate count to a specific value
- cv.clear();
- cv.put(BrowserContract.History.REMOTE_VISITS, 5);
- historyClient.update(historyTestUri, cv, BrowserContract.History.URL + " = ?", new String[] {url});
- assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
- 2, 19, lastVisited3, 5, lastVisited3 - 100);
-
- // Test that we can increment remote aggregate value by setting a query param in the URI
- final Uri historyIncrementRemoteAggregateUri = historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_REMOTE_AGGREGATES, "true")
- .build();
- cv.clear();
- cv.put(BrowserContract.History.REMOTE_DATE_LAST_VISITED, lastVisited3);
- cv.put(BrowserContract.History.REMOTE_VISITS, 3);
- historyClient.update(historyIncrementRemoteAggregateUri, cv, BrowserContract.History.URL + " = ?", new String[] {url});
- // NB: remoteVisits=8. Previous value was 5, and we're incrementing by 3.
- assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
- 2, 19, lastVisited3, 8, lastVisited3);
-
- // Test that we throw when trying to increment REMOTE_VISITS without passing in "increment by" value
- cv.clear();
- try {
- historyClient.update(historyIncrementRemoteAggregateUri, cv, BrowserContract.History.URL + " = ?", new String[]{url});
- assertTrue("Expected to throw IllegalArgumentException", false);
- } catch (IllegalArgumentException e) {
- assertTrue(true);
-
- // NB: same values as above, to ensure throwing update didn't actually change anything.
- assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
- 2, 19, lastVisited3, 8, lastVisited3);
- }
- }
-
- private void assertHistoryAggregates(String selection, String[] selectionArg, int visits, int localVisits, long localLastVisited, int remoteVisits, long remoteLastVisited) throws Exception {
- final Cursor c = historyClient.query(historyTestUri, new String[] {
- BrowserContract.History.VISITS,
- BrowserContract.History.LOCAL_VISITS,
- BrowserContract.History.REMOTE_VISITS,
- BrowserContract.History.LOCAL_DATE_LAST_VISITED,
- BrowserContract.History.REMOTE_DATE_LAST_VISITED
- }, selection, selectionArg, null);
-
- assertNotNull(c);
- try {
- assertTrue(c.moveToFirst());
-
- final int visitsCol = c.getColumnIndexOrThrow(BrowserContract.History.VISITS);
- final int localVisitsCol = c.getColumnIndexOrThrow(BrowserContract.History.LOCAL_VISITS);
- final int remoteVisitsCol = c.getColumnIndexOrThrow(BrowserContract.History.REMOTE_VISITS);
- final int localDateLastVisitedCol = c.getColumnIndexOrThrow(BrowserContract.History.LOCAL_DATE_LAST_VISITED);
- final int remoteDateLastVisitedCol = c.getColumnIndexOrThrow(BrowserContract.History.REMOTE_DATE_LAST_VISITED);
-
- assertEquals(visits, c.getInt(visitsCol));
-
- assertEquals(localVisits, c.getInt(localVisitsCol));
- assertEquals(localLastVisited, c.getLong(localDateLastVisitedCol));
-
- assertEquals(remoteVisits, c.getInt(remoteVisitsCol));
- assertEquals(remoteLastVisited, c.getLong(remoteDateLastVisitedCol));
- } finally {
- c.close();
- }
- }
-
- /**
- * Insert <code>count</code> history records with thumbnails, and for a third of records insert a visit.
- * Inserting visits only for some of the history records is in order to ensure we're correctly JOIN-ing
- * History and Visits tables in the Combined view.
- * Will ensure that date_created and date_modified for new records are the same as last visited date.
- *
- * @param count number of history records to insert
- * @param baseTime timestamp which will be used as a basis for last visited date
- * @throws RemoteException
- */
- private void insertHistory(int count, long baseTime) throws RemoteException {
- Uri incrementUri = historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build();
-
- for (int i = 0; i < count; i++) {
- final String url = "https://www.mozilla" + i + ".org";
- insertHistoryItem(url, "testGUID" + i, baseTime - i, null);
- if (i % 3 == 0) {
- assertEquals(1, historyClient.update(incrementUri, new ContentValues(), BrowserContract.History.URL + " = ?", new String[]{url}));
- }
-
- // inserting a new entry sets the date created and modified automatically, so let's reset them
- ContentValues cv = new ContentValues();
- cv.put(BrowserContract.History.DATE_CREATED, baseTime - i);
- cv.put(BrowserContract.History.DATE_MODIFIED, baseTime - i);
- assertEquals(1, historyClient.update(historyTestUri, cv, BrowserContract.History.URL + " = ?",
- new String[] { "https://www.mozilla" + i + ".org" }));
- }
-
- // insert thumbnails for history items
- ContentValues[] thumbs = new ContentValues[count];
- for (int i = 0; i < count; i++) {
- thumbs[i] = new ContentValues();
- thumbs[i].put(BrowserContract.Thumbnails.DATA, i);
- thumbs[i].put(BrowserContract.Thumbnails.URL, "https://www.mozilla" + i + ".org");
- }
- assertEquals(count, thumbnailClient.bulkInsert(thumbnailTestUri, thumbs));
- }
-
- private void assertRowCount(final ContentProviderClient client, final Uri uri, final int count) throws RemoteException {
- final Cursor c = client.query(uri, null, null, null, null);
- assertNotNull(c);
- try {
- assertEquals(count, c.getCount());
- } finally {
- c.close();
- }
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTest.java
deleted file mode 100644
index 71c21166d..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTest.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.db;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import org.mozilla.gecko.db.BrowserContract.History;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-/**
- * Testing insertion/deletion of visits as by-product of updating history records through BrowserProvider
- */
-public class BrowserProviderHistoryVisitsTest extends BrowserProviderHistoryVisitsTestBase {
- @Test
- /**
- * Testing updating history records without affecting visits
- */
- public void testUpdateNoVisit() throws Exception {
- insertHistoryItem("https://www.mozilla.org", "testGUID");
-
- Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(0, cursor.getCount());
- cursor.close();
-
- ContentValues historyUpdate = new ContentValues();
- historyUpdate.put(History.TITLE, "Mozilla!");
- assertEquals(1,
- historyClient.update(
- historyTestUri, historyUpdate, History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- )
- );
-
- cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(0, cursor.getCount());
- cursor.close();
-
- ContentValues historyToInsert = new ContentValues();
- historyToInsert.put(History.URL, "https://www.eff.org");
- assertEquals(1,
- historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build(),
- historyToInsert, null, null
- )
- );
-
- cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(0, cursor.getCount());
- cursor.close();
- }
-
- @Test
- /**
- * Testing INCREMENT_VISITS flag for multiple history records at once
- */
- public void testUpdateMultipleHistoryIncrementVisit() throws Exception {
- insertHistoryItem("https://www.mozilla.org", "testGUID");
- insertHistoryItem("https://www.mozilla.org", "testGUID2");
-
- // test that visits get inserted when updating existing history records
- assertEquals(2, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
- new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- ));
-
- Cursor cursor = visitsClient.query(
- visitsTestUri, new String[] {BrowserContract.Visits.HISTORY_GUID}, null, null, null);
- assertNotNull(cursor);
- assertEquals(2, cursor.getCount());
- assertTrue(cursor.moveToFirst());
-
- String guid1 = cursor.getString(cursor.getColumnIndex(BrowserContract.Visits.HISTORY_GUID));
- cursor.moveToNext();
- String guid2 = cursor.getString(cursor.getColumnIndex(BrowserContract.Visits.HISTORY_GUID));
- cursor.close();
-
- assertNotEquals(guid1, guid2);
-
- assertTrue(guid1.equals("testGUID") || guid1.equals("testGUID2"));
- }
-
- @Test
- /**
- * Testing INCREMENT_VISITS flag and its interplay with INSERT_IF_NEEDED
- */
- public void testUpdateHistoryIncrementVisit() throws Exception {
- insertHistoryItem("https://www.mozilla.org", "testGUID");
-
- // test that visit gets inserted when updating an existing histor record
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
- new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- ));
-
- Cursor cursor = visitsClient.query(
- visitsTestUri, new String[] {BrowserContract.Visits.HISTORY_GUID}, null, null, null);
- assertNotNull(cursor);
- assertEquals(1, cursor.getCount());
- assertTrue(cursor.moveToFirst());
- assertEquals(
- "testGUID",
- cursor.getString(cursor.getColumnIndex(BrowserContract.Visits.HISTORY_GUID))
- );
- cursor.close();
-
- // test that visit gets inserted when updatingOrInserting a new history record
- ContentValues historyItem = new ContentValues();
- historyItem.put(History.URL, "https://www.eff.org");
-
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true")
- .appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build(),
- historyItem, null, null
- ));
-
- cursor = historyClient.query(
- historyTestUri,
- new String[] {History.GUID}, History.URL + " = ?", new String[] {"https://www.eff.org"}, null
- );
- assertNotNull(cursor);
- assertEquals(1, cursor.getCount());
- assertTrue(cursor.moveToFirst());
- String insertedGUID = cursor.getString(cursor.getColumnIndex(History.GUID));
- cursor.close();
-
- cursor = visitsClient.query(
- visitsTestUri, new String[] {BrowserContract.Visits.HISTORY_GUID}, null, null, null);
- assertNotNull(cursor);
- assertEquals(2, cursor.getCount());
- assertTrue(cursor.moveToFirst());
- assertEquals(insertedGUID,
- cursor.getString(cursor.getColumnIndex(BrowserContract.Visits.HISTORY_GUID))
- );
- cursor.close();
- }
-
- @Test
- /**
- * Test that for locally generated visits, we store their timestamps in microseconds, and not in
- * milliseconds like history does.
- */
- public void testTimestampConversionOnInsertion() throws Exception {
- insertHistoryItem("https://www.mozilla.org", "testGUID");
-
- Long lastVisited = System.currentTimeMillis();
- ContentValues updatedVisitedTime = new ContentValues();
- updatedVisitedTime.put(History.DATE_LAST_VISITED, lastVisited);
-
- // test with last visited date passed in
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
- updatedVisitedTime, History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- ));
-
- Cursor cursor = visitsClient.query(visitsTestUri, new String[] {BrowserContract.Visits.DATE_VISITED}, null, null, null);
- assertNotNull(cursor);
- assertEquals(1, cursor.getCount());
- assertTrue(cursor.moveToFirst());
-
- assertEquals(lastVisited * 1000, cursor.getLong(cursor.getColumnIndex(BrowserContract.Visits.DATE_VISITED)));
- cursor.close();
-
- // test without last visited date
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
- new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- ));
-
- cursor = visitsClient.query(visitsTestUri, new String[] {BrowserContract.Visits.DATE_VISITED}, null, null, null);
- assertNotNull(cursor);
- assertEquals(2, cursor.getCount());
- assertTrue(cursor.moveToFirst());
-
- // CP should generate time off of current time upon insertion and convert to microseconds.
- // This also tests correct ordering (DESC on date).
- assertTrue(lastVisited * 1000 < cursor.getLong(cursor.getColumnIndex(BrowserContract.Visits.DATE_VISITED)));
- cursor.close();
- }
-
- @Test
- /**
- * This should perform `DELETE FROM visits WHERE history_guid in IN (?, ?, ?, ..., ?)` sort of statement
- * SQLite has a variable count limit (999 by default), so we're testing here that our deletion
- * code does the right thing and chunks deletes to account for this limitation.
- */
- public void testDeletingLotsOfHistory() throws Exception {
- Uri incrementUri = historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build();
-
- // insert bunch of history records, and for each insert a visit
- for (int i = 0; i < 2100; i++) {
- final String url = "https://www.mozilla" + i + ".org";
- insertHistoryItem(url, "testGUID" + i);
- assertEquals(1, historyClient.update(incrementUri, new ContentValues(), History.URL + " = ?", new String[] {url}));
- }
-
- // sanity check
- Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(2100, cursor.getCount());
- cursor.close();
-
- // delete all of the history items - this will trigger chunked deletion of visits as well
- assertEquals(2100,
- historyClient.delete(historyTestUri, null, null)
- );
-
- // check that all visits where deleted
- cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(0, cursor.getCount());
- cursor.close();
- }
-
- @Test
- /**
- * Test visit deletion as by-product of history deletion - both explicit (from outside of Sync),
- * and implicit (cascaded, from Sync).
- */
- public void testDeletingHistory() throws Exception {
- insertHistoryItem("https://www.mozilla.org", "testGUID");
- insertHistoryItem("https://www.eff.org", "testGUID2");
-
- // insert some visits
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
- new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- ));
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
- new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- ));
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
- new ContentValues(), History.URL + " = ?", new String[] {"https://www.eff.org"}
- ));
-
- Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(3, cursor.getCount());
- cursor.close();
-
- // test that corresponding visit records are deleted if Sync isn't involved
- assertEquals(1,
- historyClient.delete(historyTestUri, History.URL + " = ?", new String[] {"https://www.mozilla.org"})
- );
-
- cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(1, cursor.getCount());
- cursor.close();
-
- // test that corresponding visit records are deleted if Sync is involved
- // insert some more visits
- ContentValues moz = new ContentValues();
- moz.put(History.URL, "https://www.mozilla.org");
- moz.put(History.GUID, "testGUID3");
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true")
- .appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build(),
- moz, History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- ));
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true")
- .appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build(),
- new ContentValues(), History.URL + " = ?", new String[] {"https://www.eff.org"}
- ));
-
- assertEquals(1,
- historyClient.delete(
- historyTestUri.buildUpon().appendQueryParameter(BrowserContract.PARAM_IS_SYNC, "true").build(),
- History.URL + " = ?", new String[] {"https://www.eff.org"})
- );
-
- cursor = visitsClient.query(visitsTestUri, new String[] {BrowserContract.Visits.HISTORY_GUID}, null, null, null);
- assertNotNull(cursor);
- assertEquals(1, cursor.getCount());
- assertTrue(cursor.moveToFirst());
- assertEquals("testGUID3", cursor.getString(cursor.getColumnIndex(BrowserContract.Visits.HISTORY_GUID)));
- cursor.close();
- }
-
- @Test
- /**
- * Test that changes to History GUID are cascaded to individual visits.
- * See UPDATE CASCADED on Visit's HISTORY_GUID foreign key.
- */
- public void testHistoryGUIDUpdate() throws Exception {
- insertHistoryItem("https://www.mozilla.org", "testGUID");
- insertHistoryItem("https://www.eff.org", "testGUID2");
-
- // insert some visits
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
- new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- ));
- assertEquals(1, historyClient.update(
- historyTestUri.buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
- new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- ));
-
- // change testGUID -> testGUIDNew
- ContentValues newGuid = new ContentValues();
- newGuid.put(History.GUID, "testGUIDNew");
- assertEquals(1, historyClient.update(
- historyTestUri, newGuid, History.URL + " = ?", new String[] {"https://www.mozilla.org"}
- ));
-
- Cursor cursor = visitsClient.query(visitsTestUri, null, BrowserContract.Visits.HISTORY_GUID + " = ?", new String[] {"testGUIDNew"}, null);
- assertNotNull(cursor);
- assertEquals(2, cursor.getCount());
- cursor.close();
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTestBase.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTestBase.java
deleted file mode 100644
index b8ee0bb36..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTestBase.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.db;
-
-import android.content.ContentProviderClient;
-import android.content.ContentValues;
-import android.net.Uri;
-import android.os.RemoteException;
-
-import org.junit.After;
-import org.junit.Before;
-import org.mozilla.gecko.background.db.DelegatingTestContentProvider;
-import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
-import org.robolectric.shadows.ShadowContentResolver;
-
-import java.util.UUID;
-
-public class BrowserProviderHistoryVisitsTestBase {
- /* package-private */ ShadowContentResolver contentResolver;
- /* package-private */ ContentProviderClient historyClient;
- /* package-private */ ContentProviderClient visitsClient;
- /* package-private */ Uri historyTestUri;
- /* package-private */ Uri visitsTestUri;
-
- private BrowserProvider provider;
-
- @Before
- public void setUp() throws Exception {
- provider = new BrowserProvider();
- provider.onCreate();
- ShadowContentResolver.registerProvider(BrowserContract.AUTHORITY, new DelegatingTestContentProvider(provider));
-
- contentResolver = new ShadowContentResolver();
- historyClient = contentResolver.acquireContentProviderClient(BrowserContractHelpers.HISTORY_CONTENT_URI);
- visitsClient = contentResolver.acquireContentProviderClient(BrowserContractHelpers.VISITS_CONTENT_URI);
-
- historyTestUri = testUri(BrowserContract.History.CONTENT_URI);
- visitsTestUri = testUri(BrowserContract.Visits.CONTENT_URI);
- }
-
- @After
- public void tearDown() {
- historyClient.release();
- visitsClient.release();
- provider.shutdown();
- }
-
- /* package-private */ Uri testUri(Uri baseUri) {
- return baseUri.buildUpon().appendQueryParameter(BrowserContract.PARAM_IS_TEST, "1").build();
- }
-
- /* package-private */ Uri insertHistoryItem(String url, String guid) throws RemoteException {
- return insertHistoryItem(url, guid, System.currentTimeMillis(), null, null);
- }
-
- /* package-private */ Uri insertHistoryItem(String url, String guid, Long lastVisited, Integer visitCount) throws RemoteException {
- return insertHistoryItem(url, guid, lastVisited, visitCount, null);
- }
-
- /* package-private */ Uri insertHistoryItem(String url, String guid, Long lastVisited, Integer visitCount, String title) throws RemoteException {
- ContentValues historyItem = new ContentValues();
- historyItem.put(BrowserContract.History.URL, url);
- if (guid != null) {
- historyItem.put(BrowserContract.History.GUID, guid);
- }
- if (visitCount != null) {
- historyItem.put(BrowserContract.History.VISITS, visitCount);
- }
- historyItem.put(BrowserContract.History.DATE_LAST_VISITED, lastVisited);
- if (title != null) {
- historyItem.put(BrowserContract.History.TITLE, title);
- }
-
- return historyClient.insert(historyTestUri, historyItem);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderVisitsTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderVisitsTest.java
deleted file mode 100644
index 928657e82..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderVisitsTest.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.db;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-
-import static org.junit.Assert.*;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.db.BrowserContract.Visits;
-
-@RunWith(TestRunner.class)
-/**
- * Testing direct interactions with visits through BrowserProvider
- */
-public class BrowserProviderVisitsTest extends BrowserProviderHistoryVisitsTestBase {
- @Test
- /**
- * Test that default visit parameters are set on insert.
- */
- public void testDefaultVisit() throws RemoteException {
- String url = "https://www.mozilla.org";
- String guid = "testGuid";
-
- assertNotNull(insertHistoryItem(url, guid));
-
- ContentValues visitItem = new ContentValues();
- Long visitedDate = System.currentTimeMillis();
- visitItem.put(Visits.HISTORY_GUID, guid);
- visitItem.put(Visits.DATE_VISITED, visitedDate);
- Uri insertedVisitUri = visitsClient.insert(visitsTestUri, visitItem);
- assertNotNull(insertedVisitUri);
-
- Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- try {
- assertTrue(cursor.moveToFirst());
- String insertedGuid = cursor.getString(cursor.getColumnIndex(Visits.HISTORY_GUID));
- assertEquals(guid, insertedGuid);
-
- Long insertedDate = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
- assertEquals(visitedDate, insertedDate);
-
- Integer insertedType = cursor.getInt(cursor.getColumnIndex(Visits.VISIT_TYPE));
- assertEquals(insertedType, Integer.valueOf(1));
-
- Integer insertedIsLocal = cursor.getInt(cursor.getColumnIndex(Visits.IS_LOCAL));
- assertEquals(insertedIsLocal, Integer.valueOf(1));
- } finally {
- cursor.close();
- }
- }
-
- @Test
- /**
- * Test that we can't insert visit for non-existing GUID.
- */
- public void testMissingHistoryGuid() throws RemoteException {
- ContentValues visitItem = new ContentValues();
- visitItem.put(Visits.HISTORY_GUID, "blah");
- visitItem.put(Visits.DATE_VISITED, System.currentTimeMillis());
- assertNull(visitsClient.insert(visitsTestUri, visitItem));
- }
-
- @Test
- /**
- * Test that visit insert uses non-conflict insert.
- */
- public void testNonConflictInsert() throws RemoteException {
- String url = "https://www.mozilla.org";
- String guid = "testGuid";
-
- assertNotNull(insertHistoryItem(url, guid));
-
- ContentValues visitItem = new ContentValues();
- Long visitedDate = System.currentTimeMillis();
- visitItem.put(Visits.HISTORY_GUID, guid);
- visitItem.put(Visits.DATE_VISITED, visitedDate);
- Uri insertedVisitUri = visitsClient.insert(visitsTestUri, visitItem);
- assertNotNull(insertedVisitUri);
-
- Uri insertedVisitUri2 = visitsClient.insert(visitsTestUri, visitItem);
- assertEquals(insertedVisitUri, insertedVisitUri2);
- }
-
- @Test
- /**
- * Test that non-default visit parameters won't get overridden.
- */
- public void testNonDefaultInsert() throws RemoteException {
- assertNotNull(insertHistoryItem("https://www.mozilla.org", "testGuid"));
-
- Integer typeToInsert = 5;
- Integer isLocalToInsert = 0;
-
- ContentValues visitItem = new ContentValues();
- visitItem.put(Visits.HISTORY_GUID, "testGuid");
- visitItem.put(Visits.DATE_VISITED, System.currentTimeMillis());
- visitItem.put(Visits.VISIT_TYPE, typeToInsert);
- visitItem.put(Visits.IS_LOCAL, isLocalToInsert);
-
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- try {
- assertTrue(cursor.moveToFirst());
-
- Integer insertedVisitType = cursor.getInt(cursor.getColumnIndex(Visits.VISIT_TYPE));
- assertEquals(typeToInsert, insertedVisitType);
-
- Integer insertedIsLocal = cursor.getInt(cursor.getColumnIndex(Visits.IS_LOCAL));
- assertEquals(isLocalToInsert, insertedIsLocal);
- } finally {
- cursor.close();
- }
- }
-
- @Test
- /**
- * Test that default sorting order (DATE_VISITED DESC) is set if we don't specify any sorting params
- */
- public void testDefaultSortingOrder() throws RemoteException {
- assertNotNull(insertHistoryItem("https://www.mozilla.org", "testGuid"));
-
- Long time1 = System.currentTimeMillis();
- Long time2 = time1 + 100;
- Long time3 = time1 + 200;
-
- ContentValues visitItem = new ContentValues();
- visitItem.put(Visits.DATE_VISITED, time1);
- visitItem.put(Visits.HISTORY_GUID, "testGuid");
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- visitItem.put(Visits.DATE_VISITED, time3);
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- visitItem.put(Visits.DATE_VISITED, time2);
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- try {
- assertEquals(3, cursor.getCount());
- assertTrue(cursor.moveToFirst());
-
- Long timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
- assertEquals(time3, timeInserted);
-
- cursor.moveToNext();
-
- timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
- assertEquals(time2, timeInserted);
-
- cursor.moveToNext();
-
- timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
- assertEquals(time1, timeInserted);
- } finally {
- cursor.close();
- }
- }
-
- @Test
- /**
- * Test that if we pass sorting params, they're not overridden
- */
- public void testNonDefaultSortingOrder() throws RemoteException {
- assertNotNull(insertHistoryItem("https://www.mozilla.org", "testGuid"));
-
- Long time1 = System.currentTimeMillis();
- Long time2 = time1 + 100;
- Long time3 = time1 + 200;
-
- ContentValues visitItem = new ContentValues();
- visitItem.put(Visits.DATE_VISITED, time1);
- visitItem.put(Visits.HISTORY_GUID, "testGuid");
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- visitItem.put(Visits.DATE_VISITED, time3);
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- visitItem.put(Visits.DATE_VISITED, time2);
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, Visits.DATE_VISITED + " ASC");
- assertNotNull(cursor);
- assertEquals(3, cursor.getCount());
- assertTrue(cursor.moveToFirst());
-
- Long timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
- assertEquals(time1, timeInserted);
-
- cursor.moveToNext();
-
- timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
- assertEquals(time2, timeInserted);
-
- cursor.moveToNext();
-
- timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
- assertEquals(time3, timeInserted);
-
- cursor.close();
- }
-
- @Test
- /**
- * Tests deletion of all visits, and by some selection (GUID, IS_LOCAL)
- */
- public void testVisitDeletion() throws RemoteException {
- assertNotNull(insertHistoryItem("https://www.mozilla.org", "testGuid"));
- assertNotNull(insertHistoryItem("https://www.eff.org", "testGuid2"));
-
- Long time1 = System.currentTimeMillis();
-
- ContentValues visitItem = new ContentValues();
- visitItem.put(Visits.DATE_VISITED, time1);
- visitItem.put(Visits.HISTORY_GUID, "testGuid");
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- visitItem = new ContentValues();
- visitItem.put(Visits.DATE_VISITED, time1 + 100);
- visitItem.put(Visits.HISTORY_GUID, "testGuid");
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- ContentValues visitItem2 = new ContentValues();
- visitItem2.put(Visits.DATE_VISITED, time1);
- visitItem2.put(Visits.HISTORY_GUID, "testGuid2");
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem2));
-
- Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(3, cursor.getCount());
- cursor.close();
-
- assertEquals(3, visitsClient.delete(visitsTestUri, null, null));
-
- cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(0, cursor.getCount());
- cursor.close();
-
- // test selective deletion - by IS_LOCAL
- visitItem = new ContentValues();
- visitItem.put(Visits.DATE_VISITED, time1);
- visitItem.put(Visits.HISTORY_GUID, "testGuid");
- visitItem.put(Visits.IS_LOCAL, 0);
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- visitItem = new ContentValues();
- visitItem.put(Visits.DATE_VISITED, time1 + 100);
- visitItem.put(Visits.HISTORY_GUID, "testGuid");
- visitItem.put(Visits.IS_LOCAL, 1);
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
-
- visitItem2 = new ContentValues();
- visitItem2.put(Visits.DATE_VISITED, time1);
- visitItem2.put(Visits.HISTORY_GUID, "testGuid2");
- visitItem2.put(Visits.IS_LOCAL, 0);
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem2));
-
- cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(3, cursor.getCount());
- cursor.close();
-
- assertEquals(2,
- visitsClient.delete(visitsTestUri, Visits.IS_LOCAL + " = ?", new String[]{"0"}));
- cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(1, cursor.getCount());
- assertTrue(cursor.moveToFirst());
- assertEquals(time1 + 100, cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED)));
- assertEquals("testGuid", cursor.getString(cursor.getColumnIndex(Visits.HISTORY_GUID)));
- assertEquals(1, cursor.getInt(cursor.getColumnIndex(Visits.IS_LOCAL)));
- cursor.close();
-
- // test selective deletion - by HISTORY_GUID
- assertNotNull(visitsClient.insert(visitsTestUri, visitItem2));
- cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(2, cursor.getCount());
- cursor.close();
-
- assertEquals(1,
- visitsClient.delete(visitsTestUri, Visits.HISTORY_GUID + " = ?", new String[]{"testGuid"}));
- cursor = visitsClient.query(visitsTestUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(1, cursor.getCount());
- assertTrue(cursor.moveToFirst());
- assertEquals("testGuid2", cursor.getString(cursor.getColumnIndex(Visits.HISTORY_GUID)));
- cursor.close();
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/distribution/TestReferrerDescriptor.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/distribution/TestReferrerDescriptor.java
deleted file mode 100644
index 9e553cf44..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/distribution/TestReferrerDescriptor.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.distribution;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-@RunWith(TestRunner.class)
-public class TestReferrerDescriptor {
- @Test
- public void testReferrerDescriptor() {
- String referrerString1 = "utm_source%3Dsource%26utm_content%3Dcontent%26utm_campaign%3Dcampaign%26utm_medium%3Dmedium%26utm_term%3Dterm";
- String referrerString2 = "utm_source=source&utm_content=content&utm_campaign=campaign&utm_medium=medium&utm_term=term";
- ReferrerDescriptor referrer1 = new ReferrerDescriptor(referrerString1);
- Assert.assertNotNull(referrer1);
- Assert.assertEquals(referrer1.source, "source");
- Assert.assertEquals(referrer1.content, "content");
- Assert.assertEquals(referrer1.campaign, "campaign");
- Assert.assertEquals(referrer1.medium, "medium");
- Assert.assertEquals(referrer1.term, "term");
- ReferrerDescriptor referrer2 = new ReferrerDescriptor(referrerString2);
- Assert.assertNotNull(referrer2);
- Assert.assertEquals(referrer2.source, "source");
- Assert.assertEquals(referrer2.content, "content");
- Assert.assertEquals(referrer2.campaign, "campaign");
- Assert.assertEquals(referrer2.medium, "medium");
- Assert.assertEquals(referrer2.term, "term");
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestDownloadAction.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestDownloadAction.java
deleted file mode 100644
index 2252c90c8..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestDownloadAction.java
+++ /dev/null
@@ -1,607 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.dlc;
-
-import android.content.Context;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.dlc.catalog.DownloadContent;
-import org.mozilla.gecko.dlc.catalog.DownloadContentBuilder;
-import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog;
-import org.robolectric.RuntimeEnvironment;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.util.Arrays;
-import java.util.Collections;
-
-import static org.mockito.Matchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * DownloadAction: Download content that has been scheduled during "study" or "verify".
- */
-@RunWith(TestRunner.class)
-public class TestDownloadAction {
- private static final String TEST_URL = "http://example.org";
-
- private static final int STATUS_OK = 200;
- private static final int STATUS_PARTIAL_CONTENT = 206;
-
- /**
- * Scenario: The current network is metered.
- *
- * Verify that:
- * * No download is performed on a metered network
- */
- @Test
- public void testNothingIsDoneOnMeteredNetwork() throws Exception {
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(true).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
-
- action.perform(RuntimeEnvironment.application, null);
-
- verify(action, never()).buildHttpURLConnection(anyString());
- verify(action, never()).download(anyString(), any(File.class));
- }
-
- /**
- * Scenario: No (connected) network is available.
- *
- * Verify that:
- * * No download is performed
- */
- @Test
- public void testNothingIsDoneIfNoNetworkIsAvailable() throws Exception {
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(false).when(action).isConnectedToNetwork(RuntimeEnvironment.application);
-
- action.perform(RuntimeEnvironment.application, null);
-
- verify(action, never()).isActiveNetworkMetered(any(Context.class));
- verify(action, never()).buildHttpURLConnection(anyString());
- verify(action, never()).download(anyString(), any(File.class));
- }
-
- /**
- * Scenario: Content is scheduled for download but already exists locally (with correct checksum).
- *
- * Verify that:
- * * No download is performed for existing file
- * * Content is marked as downloaded in the catalog
- */
- @Test
- public void testExistingAndVerifiedFilesAreNotDownloadedAgain() throws Exception {
- DownloadContent content = new DownloadContentBuilder().build();
-
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- doReturn(Collections.singletonList(content)).when(catalog).getScheduledDownloads();
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
-
- File file = mock(File.class);
- doReturn(true).when(file).exists();
- doReturn(file).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
- doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
- doReturn(true).when(action).verify(eq(file), anyString());
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(action, never()).download(anyString(), any(File.class));
- verify(catalog).markAsDownloaded(content);
- }
-
- /**
- * Scenario: Server returns a server error (HTTP 500).
- *
- * Verify that:
- * * Situation is treated as recoverable (RecoverableDownloadContentException)
- */
- @Test(expected=BaseAction.RecoverableDownloadContentException.class)
- public void testServerErrorsAreRecoverable() throws Exception {
- HttpURLConnection connection = mockHttpURLConnection(500, "");
-
- File temporaryFile = mock(File.class);
- doReturn(false).when(temporaryFile).exists();
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(connection).when(action).buildHttpURLConnection(anyString());
- action.download(TEST_URL, temporaryFile);
-
- verify(connection).getInputStream();
- }
-
- /**
- * Scenario: Server returns a client error (HTTP 404).
- *
- * Verify that:
- * * Situation is treated as unrecoverable (UnrecoverableDownloadContentException)
- */
- @Test(expected=BaseAction.UnrecoverableDownloadContentException.class)
- public void testClientErrorsAreUnrecoverable() throws Exception {
- HttpURLConnection connection = mockHttpURLConnection(404, "");
-
- File temporaryFile = mock(File.class);
- doReturn(false).when(temporaryFile).exists();
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(connection).when(action).buildHttpURLConnection(anyString());
- action.download(TEST_URL, temporaryFile);
-
- verify(connection).getInputStream();
- }
-
- /**
- * Scenario: A successful download has been performed.
- *
- * Verify that:
- * * The content will be extracted to the destination
- * * The content is marked as downloaded in the catalog
- */
- @Test
- public void testSuccessfulDownloadsAreMarkedAsDownloaded() throws Exception {
- DownloadContent content = new DownloadContentBuilder()
- .setKind(DownloadContent.KIND_FONT)
- .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
- .build();
-
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- doReturn(Collections.singletonList(content)).when(catalog).getScheduledDownloads();
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
-
- File file = mockNotExistingFile();
- doReturn(file).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
- doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
-
- doReturn(false).when(action).verify(eq(file), anyString());
- doNothing().when(action).download(anyString(), eq(file));
- doReturn(true).when(action).verify(eq(file), anyString());
- doNothing().when(action).extract(eq(file), eq(file), anyString());
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(action).download(anyString(), eq(file));
- verify(action).extract(eq(file), eq(file), anyString());
- verify(catalog).markAsDownloaded(content);
- }
-
- /**
- * Scenario: Pretend a partially downloaded file already exists.
- *
- * Verify that:
- * * Range header is set in request
- * * Content will be appended to existing file
- * * Content will be marked as downloaded in catalog
- */
- @Test
- public void testResumingDownloadFromExistingFile() throws Exception {
- DownloadContent content = new DownloadContentBuilder()
- .setKind(DownloadContent.KIND_FONT)
- .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
- .setSize(4223)
- .build();
-
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- doReturn(Collections.singletonList(content)).when(catalog).getScheduledDownloads();
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
-
- File temporaryFile = mockFileWithSize(1337L);
- doReturn(temporaryFile).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
-
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- doReturn(outputStream).when(action).openFile(eq(temporaryFile), anyBoolean());
-
- HttpURLConnection connection = mockHttpURLConnection(STATUS_PARTIAL_CONTENT, "HelloWorld");
- doReturn(connection).when(action).buildHttpURLConnection(anyString());
-
- File destinationFile = mockNotExistingFile();
- doReturn(destinationFile).when(action).getDestinationFile(RuntimeEnvironment.application, content);
-
- doReturn(true).when(action).verify(eq(temporaryFile), anyString());
- doNothing().when(action).extract(eq(temporaryFile), eq(destinationFile), anyString());
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(connection).getInputStream();
- verify(connection).setRequestProperty("Range", "bytes=1337-");
-
- Assert.assertEquals("HelloWorld", new String(outputStream.toByteArray(), "UTF-8"));
-
- verify(action).openFile(eq(temporaryFile), eq(true));
- verify(catalog).markAsDownloaded(content);
- verify(temporaryFile).delete();
- }
-
- /**
- * Scenario: Download fails with IOException.
- *
- * Verify that:
- * * Partially downloaded file will not be deleted
- * * Content will not be marked as downloaded in catalog
- */
- @Test
- public void testTemporaryFileIsNotDeletedAfterDownloadAborted() throws Exception {
- DownloadContent content = new DownloadContentBuilder()
- .setKind(DownloadContent.KIND_FONT)
- .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
- .setSize(4223)
- .build();
-
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- doReturn(Collections.singletonList(content)).when(catalog).getScheduledDownloads();
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
-
- File temporaryFile = mockFileWithSize(1337L);
- doReturn(temporaryFile).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
-
- ByteArrayOutputStream outputStream = spy(new ByteArrayOutputStream());
- doReturn(outputStream).when(action).openFile(eq(temporaryFile), anyBoolean());
- doThrow(IOException.class).when(outputStream).write(any(byte[].class), anyInt(), anyInt());
-
- HttpURLConnection connection = mockHttpURLConnection(STATUS_PARTIAL_CONTENT, "HelloWorld");
- doReturn(connection).when(action).buildHttpURLConnection(anyString());
-
- doReturn(mockNotExistingFile()).when(action).getDestinationFile(RuntimeEnvironment.application, content);
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(catalog, never()).markAsDownloaded(content);
- verify(action, never()).verify(any(File.class), anyString());
- verify(temporaryFile, never()).delete();
- }
-
- /**
- * Scenario: Partially downloaded file is already complete.
- *
- * Verify that:
- * * No download request is made
- * * File is treated as completed and will be verified and extracted
- * * Content is marked as downloaded in catalog
- */
- @Test
- public void testNoRequestIsSentIfFileIsAlreadyComplete() throws Exception {
- DownloadContent content = new DownloadContentBuilder()
- .setKind(DownloadContent.KIND_FONT)
- .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
- .setSize(1337L)
- .build();
-
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- doReturn(Collections.singletonList(content)).when(catalog).getScheduledDownloads();
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
-
- File temporaryFile = mockFileWithSize(1337L);
- doReturn(temporaryFile).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
-
- File destinationFile = mockNotExistingFile();
- doReturn(destinationFile).when(action).getDestinationFile(RuntimeEnvironment.application, content);
-
- doReturn(true).when(action).verify(eq(temporaryFile), anyString());
- doNothing().when(action).extract(eq(temporaryFile), eq(destinationFile), anyString());
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(action, never()).download(anyString(), eq(temporaryFile));
- verify(action).verify(eq(temporaryFile), anyString());
- verify(action).extract(eq(temporaryFile), eq(destinationFile), anyString());
- verify(catalog).markAsDownloaded(content);
- }
-
- /**
- * Scenario: Download is completed but verification (checksum) failed.
- *
- * Verify that:
- * * Downloaded file is deleted
- * * File will not be extracted
- * * Content is not marked as downloaded in the catalog
- */
- @Test
- public void testTemporaryFileWillBeDeletedIfVerificationFails() throws Exception {
- DownloadContent content = new DownloadContentBuilder()
- .setKind(DownloadContent.KIND_FONT)
- .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
- .setSize(1337L)
- .build();
-
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- doReturn(Collections.singletonList(content)).when(catalog).getScheduledDownloads();
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
- doNothing().when(action).download(anyString(), any(File.class));
- doReturn(false).when(action).verify(any(File.class), anyString());
-
- File temporaryFile = mockNotExistingFile();
- doReturn(temporaryFile).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
-
- File destinationFile = mockNotExistingFile();
- doReturn(destinationFile).when(action).getDestinationFile(RuntimeEnvironment.application, content);
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(temporaryFile).delete();
- verify(action, never()).extract(any(File.class), any(File.class), anyString());
- verify(catalog, never()).markAsDownloaded(content);
- }
-
- /**
- * Scenario: Not enough storage space for content is available.
- *
- * Verify that:
- * * No download will per performed
- */
- @Test
- public void testNoDownloadIsPerformedIfNotEnoughStorageIsAvailable() throws Exception {
- DownloadContent content = createFontWithSize(1337L);
- DownloadContentCatalog catalog = mockCatalogWithScheduledDownloads(content);
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
- doReturn(true).when(action).isConnectedToNetwork(RuntimeEnvironment.application);
-
- File temporaryFile = mockNotExistingFile();
- doReturn(temporaryFile).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
-
- File destinationFile = mockNotExistingFile();
- doReturn(destinationFile).when(action).getDestinationFile(RuntimeEnvironment.application, content);
-
- doReturn(true).when(action).hasEnoughDiskSpace(content, destinationFile, temporaryFile);
-
- verify(action, never()).buildHttpURLConnection(anyString());
- verify(action, never()).download(anyString(), any(File.class));
- verify(action, never()).verify(any(File.class), anyString());
- verify(catalog, never()).markAsDownloaded(content);
- }
-
- /**
- * Scenario: Not enough storage space for temporary file available.
- *
- * Verify that:
- * * hasEnoughDiskSpace() returns false
- */
- @Test
- public void testWithNotEnoughSpaceForTemporaryFile() throws Exception{
- DownloadContent content = createFontWithSize(2048);
- File destinationFile = mockNotExistingFile();
- File temporaryFile = mockNotExistingFileWithUsableSpace(1024);
-
- DownloadAction action = new DownloadAction(null);
- Assert.assertFalse(action.hasEnoughDiskSpace(content, destinationFile, temporaryFile));
- }
-
- /**
- * Scenario: Not enough storage space for destination file available.
- *
- * Verify that:
- * * hasEnoughDiskSpace() returns false
- */
- @Test
- public void testWithNotEnoughSpaceForDestinationFile() throws Exception {
- DownloadContent content = createFontWithSize(2048);
- File destinationFile = mockNotExistingFileWithUsableSpace(1024);
- File temporaryFile = mockNotExistingFile();
-
- DownloadAction action = new DownloadAction(null);
- Assert.assertFalse(action.hasEnoughDiskSpace(content, destinationFile, temporaryFile));
- }
-
- /**
- * Scenario: Enough storage space for temporary and destination file available.
- *
- * Verify that:
- * * hasEnoughDiskSpace() returns true
- */
- @Test
- public void testWithEnoughSpaceForEverything() throws Exception {
- DownloadContent content = createFontWithSize(2048);
- File destinationFile = mockNotExistingFileWithUsableSpace(4096);
- File temporaryFile = mockNotExistingFileWithUsableSpace(4096);
-
- DownloadAction action = new DownloadAction(null);
- Assert.assertTrue(action.hasEnoughDiskSpace(content, destinationFile, temporaryFile));
- }
-
- /**
- * Scenario: Download failed with network I/O error.
- *
- * Verify that:
- * * Error is not counted as failure
- */
- @Test
- public void testNetworkErrorIsNotCountedAsFailure() throws Exception {
- DownloadContent content = createFont();
- DownloadContentCatalog catalog = mockCatalogWithScheduledDownloads(content);
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(true).when(action).isConnectedToNetwork(RuntimeEnvironment.application);
- doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
- doReturn(mockNotExistingFile()).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
- doReturn(mockNotExistingFile()).when(action).getDestinationFile(RuntimeEnvironment.application, content);
- doReturn(true).when(action).hasEnoughDiskSpace(eq(content), any(File.class), any(File.class));
-
- HttpURLConnection connection = mockHttpURLConnection(STATUS_OK, "");
- doThrow(IOException.class).when(connection).getInputStream();
- doReturn(connection).when(action).buildHttpURLConnection(anyString());
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(catalog, never()).rememberFailure(eq(content), anyInt());
- verify(catalog, never()).markAsDownloaded(content);
- }
-
- /**
- * Scenario: Disk IO Error when extracting file.
- *
- * Verify that:
- * * Error is counted as failure
- * * After multiple errors the content is marked as permanently failed
- */
- @Test
- public void testDiskIOErrorIsCountedAsFailure() throws Exception {
- DownloadContent content = createFont();
- DownloadContentCatalog catalog = mockCatalogWithScheduledDownloads(content);
- doCallRealMethod().when(catalog).rememberFailure(eq(content), anyInt());
- doCallRealMethod().when(catalog).markAsPermanentlyFailed(content);
-
- Assert.assertEquals(DownloadContent.STATE_NONE, content.getState());
-
- DownloadAction action = spy(new DownloadAction(null));
- doReturn(true).when(action).isConnectedToNetwork(RuntimeEnvironment.application);
- doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
- doReturn(mockNotExistingFile()).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
- doReturn(mockNotExistingFile()).when(action).getDestinationFile(RuntimeEnvironment.application, content);
- doReturn(true).when(action).hasEnoughDiskSpace(eq(content), any(File.class), any(File.class));
- doNothing().when(action).download(anyString(), any(File.class));
- doReturn(true).when(action).verify(any(File.class), anyString());
-
- File destinationFile = mock(File.class);
- doReturn(false).when(destinationFile).exists();
- File parentFile = mock(File.class);
- doReturn(false).when(parentFile).mkdirs();
- doReturn(false).when(parentFile).exists();
- doReturn(parentFile).when(destinationFile).getParentFile();
- doReturn(destinationFile).when(action).getDestinationFile(RuntimeEnvironment.application, content);
-
- for (int i = 0; i < 10; i++) {
- action.perform(RuntimeEnvironment.application, catalog);
-
- Assert.assertEquals(DownloadContent.STATE_NONE, content.getState());
- }
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- Assert.assertEquals(DownloadContent.STATE_FAILED, content.getState());
- verify(catalog, times(11)).rememberFailure(eq(content), anyInt());
- }
-
- /**
- * Scenario: If the file to be downloaded is of kind - "hyphenation"
- *
- * Verify that:
- * * isHyphenationDictionary returns true for a download content with kind "hyphenation"
- * * isHyphenationDictionary returns false for a download content with unknown/different kind like "Font"
- */
- @Test
- public void testIsHyphenationDictionary() throws Exception {
- DownloadContent hyphenationContent = createHyphenationDictionary();
- Assert.assertTrue(hyphenationContent.isHyphenationDictionary());
- DownloadContent fontContent = createFont();
- Assert.assertFalse(fontContent.isHyphenationDictionary());
- DownloadContent unknownContent = createUnknownContent(1024L);
- Assert.assertFalse(unknownContent.isHyphenationDictionary());
- }
-
- /**
- * Scenario: If the content to be downloaded is known
- *
- * Verify that:
- * * isKnownContent returns true for a downloadable content with a known kind and type.
- * * isKnownContent returns false for a downloadable content with unknown kind and type.
- */
- @Test
- public void testIsKnownContent() throws Exception {
- DownloadContent fontContent = createFontWithSize(1024L);
- DownloadContent hyphenationContent = createHyphenationDictionaryWithSize(1024L);
- DownloadContent unknownContent = createUnknownContent(1024L);
- DownloadContent contentWithUnknownType = createContentWithoutType(1024L);
-
- Assert.assertTrue(fontContent.isKnownContent());
- Assert.assertTrue(hyphenationContent.isKnownContent());
- Assert.assertFalse(unknownContent.isKnownContent());
- Assert.assertFalse(contentWithUnknownType.isKnownContent());
- }
-
- private DownloadContent createUnknownContent(long size) {
- return new DownloadContentBuilder()
- .setSize(size)
- .build();
- }
-
- private DownloadContent createContentWithoutType(long size) {
- return new DownloadContentBuilder()
- .setKind(DownloadContent.KIND_HYPHENATION_DICTIONARY)
- .setSize(size)
- .build();
- }
-
- private DownloadContent createFont() {
- return createFontWithSize(102400L);
- }
-
- private DownloadContent createFontWithSize(long size) {
- return new DownloadContentBuilder()
- .setKind(DownloadContent.KIND_FONT)
- .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
- .setSize(size)
- .build();
- }
-
- private DownloadContent createHyphenationDictionary() {
- return createHyphenationDictionaryWithSize(102400L);
- }
-
- private DownloadContent createHyphenationDictionaryWithSize(long size) {
- return new DownloadContentBuilder()
- .setKind(DownloadContent.KIND_HYPHENATION_DICTIONARY)
- .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
- .setSize(size)
- .build();
- }
-
- private DownloadContentCatalog mockCatalogWithScheduledDownloads(DownloadContent... content) {
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- doReturn(Arrays.asList(content)).when(catalog).getScheduledDownloads();
- return catalog;
- }
-
- private static File mockNotExistingFile() {
- return mockFileWithUsableSpace(false, 0, Long.MAX_VALUE);
- }
-
- private static File mockNotExistingFileWithUsableSpace(long usableSpace) {
- return mockFileWithUsableSpace(false, 0, usableSpace);
- }
-
- private static File mockFileWithSize(long length) {
- return mockFileWithUsableSpace(true, length, Long.MAX_VALUE);
- }
-
- private static File mockFileWithUsableSpace(boolean exists, long length, long usableSpace) {
- File file = mock(File.class);
- doReturn(exists).when(file).exists();
- doReturn(length).when(file).length();
-
- File parentFile = mock(File.class);
- doReturn(usableSpace).when(parentFile).getUsableSpace();
- doReturn(parentFile).when(file).getParentFile();
-
- return file;
- }
-
- private static HttpURLConnection mockHttpURLConnection(int statusCode, String content) throws Exception {
- HttpURLConnection connection = mock(HttpURLConnection.class);
-
- doReturn(statusCode).when(connection).getResponseCode();
- doReturn(new ByteArrayInputStream(content.getBytes("UTF-8"))).when(connection).getInputStream();
-
- return connection;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestStudyAction.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestStudyAction.java
deleted file mode 100644
index 6b2ce83df..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestStudyAction.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.dlc;
-
-import android.content.Context;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.dlc.catalog.DownloadContent;
-import org.mozilla.gecko.dlc.catalog.DownloadContentBuilder;
-import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-/**
- * StudyAction: Scan the catalog for "new" content available for download.
- */
-@RunWith(TestRunner.class)
-public class TestStudyAction {
- /**
- * Scenario: Catalog is empty.
- *
- * Verify that:
- * * No download is scheduled
- * * Download action is not started
- */
- @Test
- public void testPerformWithEmptyCatalog() {
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- when(catalog.getContentToStudy()).thenReturn(new ArrayList<DownloadContent>());
-
- StudyAction action = spy(new StudyAction());
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(catalog).getContentToStudy();
- verify(catalog, never()).markAsDownloaded(any(DownloadContent.class));
- verify(action, never()).startDownloads(any(Context.class));
- }
-
- /**
- * Scenario: Catalog contains two items that have not been downloaded yet.
- *
- * Verify that:
- * * Both items are scheduled to be downloaded
- */
- @Test
- public void testPerformWithNewContent() {
- DownloadContent content1 = new DownloadContentBuilder()
- .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
- .setKind(DownloadContent.KIND_FONT)
- .build();
- DownloadContent content2 = new DownloadContentBuilder()
- .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
- .setKind(DownloadContent.KIND_FONT)
- .build();
-
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- when(catalog.getContentToStudy()).thenReturn(Arrays.asList(content1, content2));
-
- StudyAction action = spy(new StudyAction());
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(catalog).scheduleDownload(content1);
- verify(catalog).scheduleDownload(content2);
- }
-
- /**
- * Scenario: Catalog contains item that are scheduled for download.
- *
- * Verify that:
- * * Download action is started
- */
- @Test
- public void testStartingDownloadsAfterScheduling() {
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- when(catalog.hasScheduledDownloads()).thenReturn(true);
-
- StudyAction action = spy(new StudyAction());
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(action).startDownloads(any(Context.class));
- }
-
- /**
- * Scenario: Catalog contains unknown content.
- *
- * Verify that:
- * * Unknown content is not scheduled for download.
- */
- @Test
- public void testPerformWithUnknownContent() {
- DownloadContent content = new DownloadContentBuilder()
- .setType("Unknown-Type")
- .setKind("Unknown-Kind")
- .build();
-
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- when(catalog.getContentToStudy()).thenReturn(Collections.singletonList(content));
-
- StudyAction action = spy(new StudyAction());
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(catalog, never()).scheduleDownload(content);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestSyncAction.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestSyncAction.java
deleted file mode 100644
index 1e494975e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestSyncAction.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.dlc;
-
-import android.content.Context;
-import android.support.v4.util.ArrayMap;
-import android.support.v4.util.AtomicFile;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.dlc.catalog.DownloadContent;
-import org.mozilla.gecko.dlc.catalog.DownloadContentBuilder;
-import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog;
-import org.mozilla.gecko.util.IOUtils;
-import org.robolectric.RuntimeEnvironment;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.List;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-/**
- * SyncAction: Synchronize catalog from a (mocked) Kinto instance.
- */
-@RunWith(TestRunner.class)
-public class TestSyncAction {
- /**
- * Scenario: The server returns an empty record set.
- */
- @Test
- public void testEmptyResult() throws Exception {
- SyncAction action = spy(new SyncAction());
- doReturn(true).when(action).isSyncEnabledForClient(RuntimeEnvironment.application);
- doReturn(new JSONArray()).when(action).fetchRawCatalog(anyLong());
-
- action.perform(RuntimeEnvironment.application, mockCatalog());
-
- verify(action, never()).createContent(anyCatalog(), anyJSONObject());
- verify(action, never()).updateContent(anyCatalog(), anyJSONObject(), anyContent());
- verify(action, never()).deleteContent(anyCatalog(), anyString());
-
- verify(action, never()).startStudyAction(anyContext());
- }
-
- /**
- * Scenario: The server returns an item that is not in the catalog yet.
- */
- @Test
- public void testAddingNewContent() throws Exception {
- SyncAction action = spy(new SyncAction());
- doReturn(true).when(action).isSyncEnabledForClient(RuntimeEnvironment.application);
- doReturn(fromFile("dlc_sync_single_font.json")).when(action).fetchRawCatalog(anyLong());
-
- DownloadContentCatalog catalog = mockCatalog();
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- // A new content item has been created
- verify(action).createContent(anyCatalog(), anyJSONObject());
-
- // No content item has been updated or deleted
- verify(action, never()).updateContent(anyCatalog(), anyJSONObject(), anyContent());
- verify(action, never()).deleteContent(anyCatalog(), anyString());
-
- // A new item has been added to the catalog
- ArgumentCaptor<DownloadContent> captor = ArgumentCaptor.forClass(DownloadContent.class);
- verify(catalog).add(captor.capture());
-
- // The item matches the values from the server response
- DownloadContent content = captor.getValue();
- Assert.assertEquals("c906275c-3747-fe27-426f-6187526a6f06", content.getId());
- Assert.assertEquals("4ed509317f1bb441b185ea13bf1c9d19d1a0b396962efa3b5dc3190ad88f2067", content.getChecksum());
- Assert.assertEquals("960be4fc5a92c1dc488582b215d5d75429fd4ffbee463105d29992cd792a912e", content.getDownloadChecksum());
- Assert.assertEquals("CharisSILCompact-R.ttf", content.getFilename());
- Assert.assertEquals(DownloadContent.KIND_FONT, content.getKind());
- Assert.assertEquals("/attachments/0d28a72d-a51f-46f8-9e5a-f95c61de904e.gz", content.getLocation());
- Assert.assertEquals(DownloadContent.TYPE_ASSET_ARCHIVE, content.getType());
- Assert.assertEquals(1455710632607L, content.getLastModified());
- Assert.assertEquals(1727656L, content.getSize());
- Assert.assertEquals(DownloadContent.STATE_NONE, content.getState());
- }
-
- /**
- * Scenario: The catalog is using the old format, we want to make sure we abort cleanly.
- */
- @Test
- public void testUpdatingWithOldCatalog() throws Exception{
- SyncAction action = spy(new SyncAction());
- doReturn(true).when(action).isSyncEnabledForClient(RuntimeEnvironment.application);
- doReturn(fromFile("dlc_sync_old_format.json")).when(action).fetchRawCatalog(anyLong());
-
- DownloadContent existingContent = createTestContent("c906275c-3747-fe27-426f-6187526a6f06");
- DownloadContentCatalog catalog = spy(new MockedContentCatalog(existingContent));
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- // make sure nothing was done
- verify(action, never()).createContent(anyCatalog(), anyJSONObject());
- verify(action, never()).updateContent(anyCatalog(), anyJSONObject(), anyContent());
- verify(action, never()).deleteContent(anyCatalog(), anyString());
- verify(action, never()).startStudyAction(anyContext());
- }
-
-
- /**
- * Scenario: The catalog contains one item and the server returns a new version.
- */
- @Test
- public void testUpdatingExistingContent() throws Exception{
- SyncAction action = spy(new SyncAction());
- doReturn(true).when(action).isSyncEnabledForClient(RuntimeEnvironment.application);
- doReturn(fromFile("dlc_sync_single_font.json")).when(action).fetchRawCatalog(anyLong());
-
- DownloadContent existingContent = createTestContent("c906275c-3747-fe27-426f-6187526a6f06");
- DownloadContentCatalog catalog = spy(new MockedContentCatalog(existingContent));
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- // A content item has been updated
- verify(action).updateContent(anyCatalog(), anyJSONObject(), eq(existingContent));
-
- // No content item has been created or deleted
- verify(action, never()).createContent(anyCatalog(), anyJSONObject());
- verify(action, never()).deleteContent(anyCatalog(), anyString());
-
- // An item has been updated in the catalog
- ArgumentCaptor<DownloadContent> captor = ArgumentCaptor.forClass(DownloadContent.class);
- verify(catalog).update(captor.capture());
-
- // The item has the new values from the sever response
- DownloadContent content = captor.getValue();
- Assert.assertEquals("c906275c-3747-fe27-426f-6187526a6f06", content.getId());
- Assert.assertEquals("4ed509317f1bb441b185ea13bf1c9d19d1a0b396962efa3b5dc3190ad88f2067", content.getChecksum());
- Assert.assertEquals("960be4fc5a92c1dc488582b215d5d75429fd4ffbee463105d29992cd792a912e", content.getDownloadChecksum());
- Assert.assertEquals("CharisSILCompact-R.ttf", content.getFilename());
- Assert.assertEquals(DownloadContent.KIND_FONT, content.getKind());
- Assert.assertEquals("/attachments/0d28a72d-a51f-46f8-9e5a-f95c61de904e.gz", content.getLocation());
- Assert.assertEquals(DownloadContent.TYPE_ASSET_ARCHIVE, content.getType());
- Assert.assertEquals(1455710632607L, content.getLastModified());
- Assert.assertEquals(1727656L, content.getSize());
- Assert.assertEquals(DownloadContent.STATE_UPDATED, content.getState());
- }
-
- /**
- * Scenario: Catalog contains one item and the server returns that it has been deleted.
- */
- @Test
- public void testDeletingExistingContent() throws Exception {
- SyncAction action = spy(new SyncAction());
- doReturn(true).when(action).isSyncEnabledForClient(RuntimeEnvironment.application);
- doReturn(fromFile("dlc_sync_deleted_item.json")).when(action).fetchRawCatalog(anyLong());
-
- final String id = "c906275c-3747-fe27-426f-6187526a6f06";
- DownloadContent existingContent = createTestContent(id);
- DownloadContentCatalog catalog = spy(new MockedContentCatalog(existingContent));
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- // A content item has been deleted
- verify(action).deleteContent(anyCatalog(), eq(id));
-
- // No content item has been created or updated
- verify(action, never()).createContent(anyCatalog(), anyJSONObject());
- verify(action, never()).updateContent(anyCatalog(), anyJSONObject(), anyContent());
-
- // An item has been marked for deletion in the catalog
- ArgumentCaptor<DownloadContent> captor = ArgumentCaptor.forClass(DownloadContent.class);
- verify(catalog).markAsDeleted(captor.capture());
-
- DownloadContent content = captor.getValue();
- Assert.assertEquals(id, content.getId());
-
- List<DownloadContent> contentToDelete = catalog.getContentToDelete();
- Assert.assertEquals(1, contentToDelete.size());
- Assert.assertEquals(id, contentToDelete.get(0).getId());
- }
-
- /**
- * Create a DownloadContent object with arbitrary data.
- */
- private DownloadContent createTestContent(String id) {
- return new DownloadContentBuilder()
- .setId(id)
- .setLocation("/somewhere/something")
- .setFilename("some.file")
- .setChecksum("Some-checksum")
- .setDownloadChecksum("Some-download-checksum")
- .setLastModified(4223)
- .setType("Some-type")
- .setKind("Some-kind")
- .setSize(27)
- .setState(DownloadContent.STATE_SCHEDULED)
- .build();
- }
-
- /**
- * Create a Kinto response from a JSON file.
- */
- private JSONArray fromFile(String fileName) throws IOException, JSONException {
- URL url = getClass().getResource("/" + fileName);
- if (url == null) {
- throw new FileNotFoundException(fileName);
- }
-
- InputStream inputStream = null;
- ByteArrayOutputStream outputStream = null;
-
- try {
- inputStream = new BufferedInputStream(new FileInputStream(url.getPath()));
- outputStream = new ByteArrayOutputStream();
-
- IOUtils.copy(inputStream, outputStream);
-
- JSONObject object = new JSONObject(outputStream.toString());
-
- return object.getJSONArray("data");
- } finally {
- IOUtils.safeStreamClose(inputStream);
- IOUtils.safeStreamClose(outputStream);
- }
- }
-
- private static class MockedContentCatalog extends DownloadContentCatalog {
- public MockedContentCatalog(DownloadContent content) {
- super(mock(AtomicFile.class));
-
- ArrayMap<String, DownloadContent> map = new ArrayMap<>();
- map.put(content.getId(), content);
-
- onCatalogLoaded(map);
- }
- }
-
- private DownloadContentCatalog mockCatalog() {
- return mock(DownloadContentCatalog.class);
- }
-
- private DownloadContentCatalog anyCatalog() {
- return any(DownloadContentCatalog.class);
- }
-
- private JSONObject anyJSONObject() {
- return any(JSONObject.class);
- }
-
- private DownloadContent anyContent() {
- return any(DownloadContent.class);
- }
-
- private Context anyContext() {
- return any(Context.class);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestVerifyAction.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestVerifyAction.java
deleted file mode 100644
index 6a347376e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestVerifyAction.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.dlc;
-
-import android.content.Context;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.dlc.catalog.DownloadContent;
-import org.mozilla.gecko.dlc.catalog.DownloadContentBuilder;
-import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog;
-import org.robolectric.RuntimeEnvironment;
-
-import java.io.File;
-import java.util.Collections;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-/**
- * VerifyAction: Validate downloaded content. Does it still exist and does it have the correct checksum?
- */
-@RunWith(TestRunner.class)
-public class TestVerifyAction {
- /**
- * Scenario: Downloaded file does not exist anymore.
- *
- * Verify that:
- * * Content is re-scheduled for download.
- */
- @Test
- public void testReschedulingIfFileDoesNotExist() throws Exception {
- DownloadContent content = new DownloadContentBuilder().build();
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- when(catalog.getDownloadedContent()).thenReturn(Collections.singletonList(content));
-
- File file = mock(File.class);
- when(file.exists()).thenReturn(false);
-
- VerifyAction action = spy(new VerifyAction());
- doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(catalog).scheduleDownload(content);
- }
-
- /**
- * Scenario: Content has been scheduled for download.
- *
- * Verify that:
- * * Download action is started
- */
- @Test
- public void testStartingDownloadsAfterScheduling() {
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- when(catalog.hasScheduledDownloads()).thenReturn(true);
-
- VerifyAction action = spy(new VerifyAction());
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(action).startDownloads(any(Context.class));
- }
-
- /**
- * Scenario: Checksum of existing file does not match expectation.
- *
- * Verify that:
- * * Content is re-scheduled for download.
- */
- @Test
- public void testReschedulingIfVerificationFailed() throws Exception {
- DownloadContent content = new DownloadContentBuilder().build();
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- when(catalog.getDownloadedContent()).thenReturn(Collections.singletonList(content));
-
- File file = mock(File.class);
- when(file.exists()).thenReturn(true);
-
- VerifyAction action = spy(new VerifyAction());
- doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
- doReturn(false).when(action).verify(eq(file), anyString());
-
- action.perform(RuntimeEnvironment.application, catalog);
-
- verify(catalog).scheduleDownload(content);
- }
-
- /**
- * Scenario: Downloaded file exists and has the correct checksum.
- *
- * Verify that:
- * * No download is scheduled
- * * Download action is not started
- */
- @Test
- public void testSuccessfulVerification() throws Exception {
- DownloadContent content = new DownloadContentBuilder().build();
- DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
- when(catalog.getDownloadedContent()).thenReturn(Collections.singletonList(content));
-
- File file = mock(File.class);
- when(file.exists()).thenReturn(true);
-
- VerifyAction action = spy(new VerifyAction());
- doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
- doReturn(true).when(action).verify(eq(file), anyString());
-
- verify(catalog, never()).scheduleDownload(content);
- verify(action, never()).startDownloads(RuntimeEnvironment.application);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/catalog/TestDownloadContentBuilder.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/catalog/TestDownloadContentBuilder.java
deleted file mode 100644
index 147b5da5b..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/catalog/TestDownloadContentBuilder.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-package org.mozilla.gecko.dlc.catalog;
-
-import org.json.JSONException;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-@RunWith(TestRunner.class)
-public class TestDownloadContentBuilder {
- /**
- * Verify that the values passed to the builder are all set on the DownloadContent object.
- */
- @Test
- public void testBuilder() {
- DownloadContent content = createTestContent();
-
- Assert.assertEquals("Some-ID", content.getId());
- Assert.assertEquals("/somewhere/something", content.getLocation());
- Assert.assertEquals("some.file", content.getFilename());
- Assert.assertEquals("Some-checksum", content.getChecksum());
- Assert.assertEquals("Some-download-checksum", content.getDownloadChecksum());
- Assert.assertEquals(4223, content.getLastModified());
- Assert.assertEquals("Some-type", content.getType());
- Assert.assertEquals("Some-kind", content.getKind());
- Assert.assertEquals(27, content.getSize());
- Assert.assertEquals(DownloadContent.STATE_SCHEDULED, content.getState());
- }
-
- /**
- * Verify that a DownloadContent object exported to JSON and re-imported from JSON does not change.
- */
- public void testJSONSerializationAndDeserialization() throws JSONException {
- DownloadContent content = DownloadContentBuilder.fromJSON(DownloadContentBuilder.toJSON(createTestContent()));
-
- Assert.assertEquals("Some-ID", content.getId());
- Assert.assertEquals("/somewhere/something", content.getLocation());
- Assert.assertEquals("some.file", content.getFilename());
- Assert.assertEquals("Some-checksum", content.getChecksum());
- Assert.assertEquals("Some-download-checksum", content.getDownloadChecksum());
- Assert.assertEquals(4223, content.getLastModified());
- Assert.assertEquals("Some-type", content.getType());
- Assert.assertEquals("Some-kind", content.getKind());
- Assert.assertEquals(27, content.getSize());
- Assert.assertEquals(DownloadContent.STATE_SCHEDULED, content.getState());
- }
-
- /**
- * Create a DownloadContent object with arbitrary data.
- */
- private DownloadContent createTestContent() {
- return new DownloadContentBuilder()
- .setId("Some-ID")
- .setLocation("/somewhere/something")
- .setFilename("some.file")
- .setChecksum("Some-checksum")
- .setDownloadChecksum("Some-download-checksum")
- .setLastModified(4223)
- .setType("Some-type")
- .setKind("Some-kind")
- .setSize(27)
- .setState(DownloadContent.STATE_SCHEDULED)
- .build();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java
deleted file mode 100644
index 5b5912cdd..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.dlc.catalog;
-
-import android.support.v4.util.ArrayMap;
-import android.support.v4.util.AtomicFile;
-
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-@RunWith(TestRunner.class)
-public class TestDownloadContentCatalog {
- /**
- * Scenario: Create a new, fresh catalog.
- *
- * Verify that:
- * * Catalog has not changed
- * * Unchanged catalog will not be saved to disk
- */
- @Test
- public void testUntouchedCatalogHasNotChangedAndWillNotBePersisted() throws Exception {
- AtomicFile file = mock(AtomicFile.class);
- doReturn("{content:[]}".getBytes("UTF-8")).when(file).readFully();
-
- DownloadContentCatalog catalog = spy(new DownloadContentCatalog(file));
- catalog.loadFromDisk();
-
- Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
-
- catalog.writeToDisk();
-
- Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
-
- verify(file, never()).startWrite();
- }
-
- /**
- * Scenario: Create a new, fresh catalog.
- *
- * Verify that:
- * * Catalog is bootstrapped with items.
- */
- @Test
- public void testCatalogIsBootstrappedIfFileDoesNotExist() throws Exception {
- // The catalog is only bootstrapped if fonts are excluded from the build. If this is a build
- // with fonts included then ignore this test.
- Assume.assumeTrue("Fonts are excluded from build", AppConstants.MOZ_ANDROID_EXCLUDE_FONTS);
-
- AtomicFile file = mock(AtomicFile.class);
- doThrow(FileNotFoundException.class).when(file).readFully();
-
- DownloadContentCatalog catalog = spy(new DownloadContentCatalog(file));
- catalog.loadFromDisk();
-
- Assert.assertTrue("Catalog is not empty", catalog.getContentToStudy().size() > 0);
- }
-
- /**
- * Scenario: Schedule downloading an item from the catalog.
- *
- * Verify that:
- * * Catalog has changed
- */
- @Test
- public void testCatalogHasChangedWhenDownloadIsScheduled() throws Exception {
- DownloadContentCatalog catalog = spy(new DownloadContentCatalog(mock(AtomicFile.class)));
- DownloadContent content = new DownloadContentBuilder().build();
- catalog.onCatalogLoaded(createMapOfContent(content));
-
- Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
-
- catalog.scheduleDownload(content);
-
- Assert.assertTrue("Catalog has changed", catalog.hasCatalogChanged());
- }
-
- /**
- * Scenario: Mark an item in the catalog as downloaded.
- *
- * Verify that:
- * * Catalog has changed
- */
- @Test
- public void testCatalogHasChangedWhenContentIsDownloaded() throws Exception {
- DownloadContentCatalog catalog = spy(new DownloadContentCatalog(mock(AtomicFile.class)));
- DownloadContent content = new DownloadContentBuilder().build();
- catalog.onCatalogLoaded(createMapOfContent(content));
-
- Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
-
- catalog.markAsDownloaded(content);
-
- Assert.assertTrue("Catalog has changed", catalog.hasCatalogChanged());
- }
-
- /**
- * Scenario: Mark an item in the catalog as permanently failed.
- *
- * Verify that:
- * * Catalog has changed
- */
- @Test
- public void testCatalogHasChangedIfDownloadHasFailedPermanently() throws Exception {
- DownloadContentCatalog catalog = spy(new DownloadContentCatalog(mock(AtomicFile.class)));
- DownloadContent content = new DownloadContentBuilder().build();
- catalog.onCatalogLoaded(createMapOfContent(content));
-
- Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
-
- catalog.markAsPermanentlyFailed(content);
-
- Assert.assertTrue("Catalog has changed", catalog.hasCatalogChanged());
- }
-
- /**
- * Scenario: A changed catalog is written to disk.
- *
- * Verify that:
- * * Before write: Catalog has changed
- * * After write: Catalog has not changed.
- */
- @Test
- public void testCatalogHasNotChangedAfterWritingToDisk() throws Exception {
- AtomicFile file = mock(AtomicFile.class);
- doReturn(mock(FileOutputStream.class)).when(file).startWrite();
-
- DownloadContentCatalog catalog = spy(new DownloadContentCatalog(file));
- DownloadContent content = new DownloadContentBuilder().build();
- catalog.onCatalogLoaded(createMapOfContent(content));
-
- catalog.scheduleDownload(content);
-
- Assert.assertTrue("Catalog has changed", catalog.hasCatalogChanged());
-
- catalog.writeToDisk();
-
- Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
- }
-
- /**
- * Scenario: A catalog with multiple items in different states.
- *
- * Verify that:
- * * getContentWithoutState(), getDownloadedContent() and getScheduledDownloads() returns
- * the correct items depenending on their state.
- */
- @Test
- public void testContentClassification() {
- DownloadContentCatalog catalog = spy(new DownloadContentCatalog(mock(AtomicFile.class)));
-
- DownloadContent content1 = new DownloadContentBuilder().setId("A").setState(DownloadContent.STATE_NONE).build();
- DownloadContent content2 = new DownloadContentBuilder().setId("B").setState(DownloadContent.STATE_NONE).build();
- DownloadContent content3 = new DownloadContentBuilder().setId("C").setState(DownloadContent.STATE_SCHEDULED).build();
- DownloadContent content4 = new DownloadContentBuilder().setId("D").setState(DownloadContent.STATE_SCHEDULED).build();
- DownloadContent content5 = new DownloadContentBuilder().setId("E").setState(DownloadContent.STATE_SCHEDULED).build();
- DownloadContent content6 = new DownloadContentBuilder().setId("F").setState(DownloadContent.STATE_DOWNLOADED).build();
- DownloadContent content7 = new DownloadContentBuilder().setId("G").setState(DownloadContent.STATE_FAILED).build();
- DownloadContent content8 = new DownloadContentBuilder().setId("H").setState(DownloadContent.STATE_UPDATED).build();
- DownloadContent content9 = new DownloadContentBuilder().setId("I").setState(DownloadContent.STATE_DELETED).build();
- DownloadContent content10 = new DownloadContentBuilder().setId("J").setState(DownloadContent.STATE_DELETED).build();
-
- catalog.onCatalogLoaded(createMapOfContent(content1, content2, content3, content4, content5, content6,
- content7, content8, content9, content10));
-
- Assert.assertTrue(catalog.hasScheduledDownloads());
-
- Assert.assertEquals(3, catalog.getContentToStudy().size());
- Assert.assertEquals(1, catalog.getDownloadedContent().size());
- Assert.assertEquals(3, catalog.getScheduledDownloads().size());
- Assert.assertEquals(2, catalog.getContentToDelete().size());
-
- Assert.assertTrue(catalog.getContentToStudy().contains(content1));
- Assert.assertTrue(catalog.getContentToStudy().contains(content2));
- Assert.assertTrue(catalog.getContentToStudy().contains(content8));
-
- Assert.assertTrue(catalog.getDownloadedContent().contains(content6));
-
- Assert.assertTrue(catalog.getScheduledDownloads().contains(content3));
- Assert.assertTrue(catalog.getScheduledDownloads().contains(content4));
- Assert.assertTrue(catalog.getScheduledDownloads().contains(content5));
-
- Assert.assertTrue(catalog.getContentToDelete().contains(content9));
- Assert.assertTrue(catalog.getContentToDelete().contains(content10));
- }
-
- /**
- * Scenario: Calling rememberFailure() on a catalog with varying values
- */
- @Test
- public void testRememberingFailures() {
- DownloadContentCatalog catalog = new DownloadContentCatalog(mock(AtomicFile.class));
- Assert.assertFalse(catalog.hasCatalogChanged());
-
- DownloadContent content = new DownloadContentBuilder().build();
- Assert.assertEquals(0, content.getFailures());
-
- catalog.rememberFailure(content, 42);
- Assert.assertEquals(1, content.getFailures());
- Assert.assertTrue(catalog.hasCatalogChanged());
-
- catalog.rememberFailure(content, 42);
- Assert.assertEquals(2, content.getFailures());
-
- // Failure counter is reset if different failure has been reported
- catalog.rememberFailure(content, 23);
- Assert.assertEquals(1, content.getFailures());
-
- // Failure counter is reset after successful download
- catalog.markAsDownloaded(content);
- Assert.assertEquals(0, content.getFailures());
- }
-
- /**
- * Scenario: Content has failed multiple times with the same failure type.
- *
- * Verify that:
- * * Content is marked as permanently failed
- */
- @Test
- public void testContentWillBeMarkedAsPermanentlyFailedAfterMultipleFailures() {
- DownloadContentCatalog catalog = new DownloadContentCatalog(mock(AtomicFile.class));
-
- DownloadContent content = new DownloadContentBuilder().build();
- Assert.assertEquals(DownloadContent.STATE_NONE, content.getState());
-
- for (int i = 0; i < 10; i++) {
- catalog.rememberFailure(content, 42);
-
- Assert.assertEquals(i + 1, content.getFailures());
- Assert.assertEquals(DownloadContent.STATE_NONE, content.getState());
- }
-
- catalog.rememberFailure(content, 42);
- Assert.assertEquals(10, content.getFailures());
- Assert.assertEquals(DownloadContent.STATE_FAILED, content.getState());
- }
-
- private ArrayMap<String, DownloadContent> createMapOfContent(DownloadContent... content) {
- ArrayMap<String, DownloadContent> map = new ArrayMap<>();
- for (DownloadContent currentContent : content) {
- map.put(currentContent.getId(), currentContent);
- }
- return map;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteBlogger.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteBlogger.java
deleted file mode 100644
index 628b572ce..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteBlogger.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.feeds.knownsites;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.helpers.AssertUtil;
-
-@RunWith(TestRunner.class)
-public class TestKnownSiteBlogger {
- /**
- * Test that the search string is a substring of some known URLs.
- */
- @Test
- public void testURLSearchString() {
- final KnownSite blogger = new KnownSiteBlogger();
- final String searchString = blogger.getURLSearchString();
-
- AssertUtil.assertContains(
- "http://mykzilla.blogspot.com/",
- searchString);
-
- AssertUtil.assertContains(
- "http://example.blogspot.com",
- searchString);
-
- AssertUtil.assertContains(
- "https://mykzilla.blogspot.com/2015/06/introducing-pluotsorbet.html",
- searchString);
-
- AssertUtil.assertContains(
- "http://android-developers.blogspot.com/2016/02/android-support-library-232.html",
- searchString);
-
- AssertUtil.assertContainsNot(
- "http://www.mozilla.org",
- searchString);
- }
-
- /**
- * Test that we get a feed URL for valid Blogger URLs.
- */
- @Test
- public void testGettingFeedFromURL() {
- final KnownSite blogger = new KnownSiteBlogger();
-
- Assert.assertEquals(
- "https://mykzilla.blogspot.com/feeds/posts/default",
- blogger.getFeedFromURL("http://mykzilla.blogspot.com/"));
-
- Assert.assertEquals(
- "https://example.blogspot.com/feeds/posts/default",
- blogger.getFeedFromURL("http://example.blogspot.com"));
-
- Assert.assertEquals(
- "https://mykzilla.blogspot.com/feeds/posts/default",
- blogger.getFeedFromURL("https://mykzilla.blogspot.com/2015/06/introducing-pluotsorbet.html"));
-
- Assert.assertEquals(
- "https://android-developers.blogspot.com/feeds/posts/default",
- blogger.getFeedFromURL("http://android-developers.blogspot.com/2016/02/android-support-library-232.html"));
-
- Assert.assertEquals(
- "https://example.blogspot.com/feeds/posts/default",
- blogger.getFeedFromURL("http://example.blogspot.com/2016/03/i-moved-to-example.blogspot.com"));
-
- Assert.assertNull(blogger.getFeedFromURL("http://www.mozilla.org"));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteMedium.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteMedium.java
deleted file mode 100644
index 77f05e0d0..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteMedium.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.feeds.knownsites;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.helpers.AssertUtil;
-
-@RunWith(TestRunner.class)
-public class TestKnownSiteMedium {
- /**
- * Test that the search string is a substring of some known URLs.
- */
- @Test
- public void testURLSearchString() {
- final KnownSite medium = new KnownSiteMedium();
- final String searchString = medium.getURLSearchString();
-
- AssertUtil.assertContains(
- "https://medium.com/@Antlam/",
- searchString);
-
- AssertUtil.assertContains(
- "https://medium.com/google-developers",
- searchString);
-
- AssertUtil.assertContains(
- "http://medium.com/@brandonshin/how-slackbot-forced-us-to-workout-7b4741a2de73",
- searchString
- );
-
- AssertUtil.assertContainsNot(
- "http://www.mozilla.org",
- searchString);
- }
-
- /**
- * Test that we get a feed URL for valid Medium URLs.
- */
- @Test
- public void testGettingFeedFromURL() {
- final KnownSite medium = new KnownSiteMedium();
-
- Assert.assertEquals(
- "https://medium.com/feed/@Antlam",
- medium.getFeedFromURL("https://medium.com/@Antlam/")
- );
-
- Assert.assertEquals(
- "https://medium.com/feed/google-developers",
- medium.getFeedFromURL("https://medium.com/google-developers")
- );
-
- Assert.assertEquals(
- "https://medium.com/feed/@brandonshin",
- medium.getFeedFromURL("http://medium.com/@brandonshin/how-slackbot-forced-us-to-workout-7b4741a2de73")
- );
-
- Assert.assertNull(medium.getFeedFromURL("http://www.mozilla.org"));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteTumblr.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteTumblr.java
deleted file mode 100644
index f83272f82..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteTumblr.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.feeds.knownsites;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.helpers.AssertUtil;
-
-@RunWith(TestRunner.class)
-public class TestKnownSiteTumblr {
- /**
- * Test that the search string is a substring of some known URLs.
- */
- @Test
- public void testURLSearchString() {
- final KnownSite tumblr = new KnownSiteTumblr();
- final String searchString = tumblr.getURLSearchString();
-
- AssertUtil.assertContains(
- "http://contentnotifications.tumblr.com/",
- searchString);
-
- AssertUtil.assertContains(
- "https://contentnotifications.tumblr.com",
- searchString);
-
- AssertUtil.assertContains(
- "http://contentnotifications.tumblr.com/post/142684202402/content-notification-firefox-for-android-480",
- searchString);
-
- AssertUtil.assertContainsNot(
- "http://www.mozilla.org",
- searchString);
- }
-
- /**
- * Test that we get a feed URL for valid Medium URLs.
- */
- @Test
- public void testGettingFeedFromURL() {
- final KnownSite tumblr = new KnownSiteTumblr();
-
- Assert.assertEquals(
- "http://contentnotifications.tumblr.com/rss",
- tumblr.getFeedFromURL("http://contentnotifications.tumblr.com/")
- );
-
- Assert.assertEquals(
- "http://staff.tumblr.com/rss",
- tumblr.getFeedFromURL("https://staff.tumblr.com/post/141928246566/replies-are-back-and-the-sun-is-shining-on-the")
- );
-
- Assert.assertNull(tumblr.getFeedFromURL("https://www.tumblr.com"));
-
- Assert.assertNull(tumblr.getFeedFromURL("http://www.mozilla.org"));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/parser/TestSimpleFeedParser.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/parser/TestSimpleFeedParser.java
deleted file mode 100644
index fa2fffbad..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/parser/TestSimpleFeedParser.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.feeds.parser;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.Locale;
-
-@RunWith(TestRunner.class)
-public class TestSimpleFeedParser {
- /**
- * Parse and verify the RSS example from Wikipedia:
- * https://en.wikipedia.org/wiki/RSS#Example
- */
- @Test
- public void testRSSExample() throws Exception {
- InputStream stream = openFeed("feed_rss_wikipedia.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("RSS Title", feed.getTitle());
- Assert.assertEquals("http://www.example.com/main.html", feed.getWebsiteURL());
- Assert.assertNull(feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Example entry", item.getTitle());
- Assert.assertEquals("http://www.example.com/blog/post/1", item.getURL());
- Assert.assertEquals(1252254000000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify the ATOM example from Wikipedia:
- * https://en.wikipedia.org/wiki/Atom_%28standard%29#Example_of_an_Atom_1.0_feed
- */
- @Test
- public void testATOMExample() throws Exception {
- InputStream stream = openFeed("feed_atom_wikipedia.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Example Feed", feed.getTitle());
- Assert.assertEquals("http://example.org/", feed.getWebsiteURL());
- Assert.assertEquals("http://example.org/feed/", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Atom-Powered Robots Run Amok", item.getTitle());
- Assert.assertEquals("http://example.org/2003/12/13/atom03.html", item.getURL());
- Assert.assertEquals(1071340202000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of a Medium feed.
- */
- @Test
- public void testMediumFeed() throws Exception {
- InputStream stream = openFeed("feed_rss_medium.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Anthony Lam on Medium", feed.getTitle());
- Assert.assertEquals("https://medium.com/@antlam?source=rss-59f49b9e4b19------2", feed.getWebsiteURL());
- Assert.assertEquals("https://medium.com/feed/@antlam", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("UX thoughts for 2016", item.getTitle());
- Assert.assertEquals("https://medium.com/@antlam/ux-thoughts-for-2016-1fc1d6e515e8?source=rss-59f49b9e4b19------2", item.getURL());
- Assert.assertEquals(1452537838000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of planet.mozilla.org ATOM feed.
- */
- @Test
- public void testPlanetMozillaATOMFeed() throws Exception {
- InputStream stream = openFeed("feed_atom_planetmozilla.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Planet Mozilla", feed.getTitle());
- Assert.assertEquals("http://planet.mozilla.org/", feed.getWebsiteURL());
- Assert.assertEquals("http://planet.mozilla.org/atom.xml", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Firefox 45.0 Beta 3 Testday, February 5th", item.getTitle());
- Assert.assertEquals("https://quality.mozilla.org/2016/01/firefox-45-0-beta-3-testday-february-5th/", item.getURL());
- Assert.assertEquals(1453819255000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of planet.mozilla.org RSS 2.0 feed.
- */
- @Test
- public void testPlanetMozillaRSS20Feed() throws Exception {
- InputStream stream = openFeed("feed_rss20_planetmozilla.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Planet Mozilla", feed.getTitle());
- Assert.assertEquals("http://planet.mozilla.org/", feed.getWebsiteURL());
- Assert.assertEquals("http://planet.mozilla.org/rss20.xml", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Aaron Klotz: Announcing Mozdbgext", item.getTitle());
- Assert.assertEquals("http://dblohm7.ca/blog/2016/01/26/announcing-mozdbgext/", item.getURL());
- Assert.assertEquals(1453837500000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of planet.mozilla.org RSS 1.0 feed.
- */
- @Test
- public void testPlanetMozillaRSS10Feed() throws Exception {
- InputStream stream = openFeed("feed_rss10_planetmozilla.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Planet Mozilla", feed.getTitle());
- Assert.assertEquals("http://planet.mozilla.org/", feed.getWebsiteURL());
- Assert.assertEquals("http://planet.mozilla.org/rss10.xml", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Aaron Klotz: Announcing Mozdbgext", item.getTitle());
- Assert.assertEquals("http://dblohm7.ca/blog/2016/01/26/announcing-mozdbgext/", item.getURL());
- Assert.assertEquals(1453837500000L, item.getTimestamp());
- }
-
- /**
- * Parse an verify a snapshot of a feedburner ATOM feed.
- */
- @Test
- public void testFeedburnerAtomFeed() throws Exception {
- InputStream stream = openFeed("feed_atom_feedburner.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Android Zeitgeist", feed.getTitle());
- Assert.assertEquals("http://www.androidzeitgeist.com/", feed.getWebsiteURL());
- Assert.assertEquals("http://feeds.feedburner.com/AndroidZeitgeist", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Support for restricted profiles in Firefox 42", item.getTitle());
- Assert.assertEquals("http://feedproxy.google.com/~r/AndroidZeitgeist/~3/xaSicfGuwOU/support-restricted-profiles-firefox.html", item.getURL());
- Assert.assertEquals(1442511968239L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of a Tumblr RSS feed.
- */
- @Test
- public void testTumblrRssFeed() throws Exception {
- InputStream stream = openFeed("feed_rss_tumblr.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Tumblr Staff", feed.getTitle());
- Assert.assertEquals("http://staff.tumblr.com/", feed.getWebsiteURL());
- Assert.assertNull(feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("hardyboyscovers: Can Nancy Drew see things through and solve...", item.getTitle());
- Assert.assertEquals("http://staff.tumblr.com/post/138124026275", item.getURL());
- Assert.assertEquals(1453861812000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of a Spiegel (German news magazine) RSS feed.
- */
- @Test
- public void testSpiegelRssFeed() throws Exception {
- InputStream stream = openFeed("feed_rss_spon.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("SPIEGEL ONLINE - Schlagzeilen", feed.getTitle());
- Assert.assertEquals("http://www.spiegel.de", feed.getWebsiteURL());
- Assert.assertNull(feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Angebliche Vergewaltigung einer 13-Jährigen: Steinmeier kanzelt russischen Minister Lawrow ab", item.getTitle());
- Assert.assertEquals("http://www.spiegel.de/politik/ausland/steinmeier-kanzelt-lawrow-ab-aerger-um-angebliche-vergewaltigung-a-1074292.html#ref=rss", item.getURL());
- Assert.assertEquals(1453914976000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of a Heise (German tech news) RSS feed.
- */
- @Test
- public void testHeiseRssFeed() throws Exception {
- InputStream stream = openFeed("feed_rss_heise.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("heise online News", feed.getTitle());
- Assert.assertEquals("http://www.heise.de/newsticker/", feed.getWebsiteURL());
- Assert.assertNull(feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Google: “Dramatische Verbesserungen†für Chrome in iOS", item.getTitle());
- Assert.assertEquals("http://www.heise.de/newsticker/meldung/Google-Dramatische-Verbesserungen-fuer-Chrome-in-iOS-3085808.html?wt_mc=rss.ho.beitrag.atom", item.getURL());
- Assert.assertEquals(1453915920000L, item.getTimestamp());
- }
-
- @Test
- public void testWordpressFeed() throws Exception {
- InputStream stream = openFeed("feed_rss_wordpress.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("justasimpletest2016", feed.getTitle());
- Assert.assertEquals("https://justasimpletest2016.wordpress.com", feed.getWebsiteURL());
- Assert.assertEquals("https://justasimpletest2016.wordpress.com/feed/", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Hello World!", item.getTitle());
- Assert.assertEquals("https://justasimpletest2016.wordpress.com/2016/02/26/hello-world/", item.getURL());
- Assert.assertEquals(1456524466000L, item.getTimestamp());
- }
-
- /**
- * Parse and test a snapshot of mykzilla.blogspot.com
- */
- @Test
- public void testBloggerFeed() throws Exception {
- InputStream stream = openFeed("feed_atom_blogger.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("mykzilla", feed.getTitle());
- Assert.assertEquals("http://mykzilla.blogspot.com/", feed.getWebsiteURL());
- Assert.assertEquals("http://www.blogger.com/feeds/18929277/posts/default", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("URL Has Been Changed", item.getTitle());
- Assert.assertEquals("http://mykzilla.blogspot.com/2016/01/url-has-been-changed.html", item.getURL());
- Assert.assertEquals(1452531451366L, item.getTimestamp());
- }
-
- private InputStream openFeed(String fileName) throws URISyntaxException, FileNotFoundException, UnsupportedEncodingException {
- URL url = getClass().getResource("/" + fileName);
- if (url == null) {
- throw new FileNotFoundException(fileName);
- }
-
- return new BufferedInputStream(new FileInputStream(url.getPath()));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/TestSkewHandler.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/TestSkewHandler.java
deleted file mode 100644
index 2b4fe3e03..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/TestSkewHandler.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.fxa;
-
-import ch.boye.httpclientandroidlib.impl.cookie.DateUtils;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.fxa.SkewHandler;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.net.BaseResource;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestSkewHandler {
- public TestSkewHandler() {
- }
-
- @Test
- public void testSkewUpdating() throws Throwable {
- SkewHandler h = new SkewHandler("foo.com");
- assertEquals(0L, h.getSkewInSeconds());
- assertEquals(0L, h.getSkewInMillis());
-
- long server = 1390101197865L;
- long local = server - 4500L;
- h.updateSkewFromServerMillis(server, local);
- assertEquals(4500L, h.getSkewInMillis());
- assertEquals(4L, h.getSkewInSeconds());
-
- local = server;
- h.updateSkewFromServerMillis(server, local);
- assertEquals(0L, h.getSkewInMillis());
- assertEquals(0L, h.getSkewInSeconds());
-
- local = server + 500L;
- h.updateSkewFromServerMillis(server, local);
- assertEquals(-500L, h.getSkewInMillis());
- assertEquals(0L, h.getSkewInSeconds());
-
- String date = "Sat, 18 Jan 2014 19:16:52 PST";
- long dateInMillis = 1390101412000L; // Obviously this can differ somewhat due to precision.
- long parsed = DateUtils.parseDate(date).getTime();
- assertEquals(parsed, dateInMillis);
-
- h.updateSkewFromHTTPDateString(date, dateInMillis);
- assertEquals(0L, h.getSkewInMillis());
- assertEquals(0L, h.getSkewInSeconds());
-
- h.updateSkewFromHTTPDateString(date, dateInMillis + 1100L);
- assertEquals(-1100L, h.getSkewInMillis());
- assertEquals(Math.round(-1100L / 1000L), h.getSkewInSeconds());
- }
-
- @Test
- public void testSkewSingleton() throws Exception {
- SkewHandler h1 = SkewHandler.getSkewHandlerFromEndpointString("http://foo.com/bar");
- SkewHandler h2 = SkewHandler.getSkewHandlerForHostname("foo.com");
- SkewHandler h3 = SkewHandler.getSkewHandlerForResource(new BaseResource("http://foo.com/baz"));
- assertTrue(h1 == h2);
- assertTrue(h1 == h3);
-
- SkewHandler.getSkewHandlerForHostname("foo.com").updateSkewFromServerMillis(1390101412000L, 1390001412000L);
- final long actual = SkewHandler.getSkewHandlerForHostname("foo.com").getSkewInMillis();
- assertEquals(100000000L, actual);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/MockFxAccountClient.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/MockFxAccountClient.java
deleted file mode 100644
index 868e90cd2..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/MockFxAccountClient.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.fxa.login;
-
-import android.text.TextUtils;
-
-import org.mozilla.gecko.background.fxa.FxAccountClient;
-import org.mozilla.gecko.background.fxa.FxAccountClient20;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.AccountStatusResponse;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.RequestDelegate;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.RecoveryEmailStatusResponse;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.TwoKeys;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse;
-import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
-import org.mozilla.gecko.background.fxa.FxAccountRemoteError;
-import org.mozilla.gecko.background.fxa.FxAccountUtils;
-import org.mozilla.gecko.fxa.FxAccountDevice;
-import org.mozilla.gecko.browserid.MockMyIDTokenFactory;
-import org.mozilla.gecko.browserid.RSACryptoImplementation;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Utils;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import ch.boye.httpclientandroidlib.HttpStatus;
-import ch.boye.httpclientandroidlib.ProtocolVersion;
-import ch.boye.httpclientandroidlib.entity.StringEntity;
-import ch.boye.httpclientandroidlib.message.BasicHttpResponse;
-
-public class MockFxAccountClient implements FxAccountClient {
- protected static MockMyIDTokenFactory mockMyIdTokenFactory = new MockMyIDTokenFactory();
-
- public final String serverURI = "http://testServer.com";
-
- public final Map<String, User> users = new HashMap<String, User>();
- public final Map<String, String> sessionTokens = new HashMap<String, String>();
- public final Map<String, String> keyFetchTokens = new HashMap<String, String>();
-
- public static class User {
- public final String email;
- public final byte[] quickStretchedPW;
- public final String uid;
- public boolean verified;
- public final byte[] kA;
- public final byte[] wrapkB;
- public final Map<String, FxAccountDevice> devices;
-
- public User(String email, byte[] quickStretchedPW) {
- this.email = email;
- this.quickStretchedPW = quickStretchedPW;
- this.uid = "uid/" + this.email;
- this.verified = false;
- this.kA = Utils.generateRandomBytes(FxAccountUtils.CRYPTO_KEY_LENGTH_BYTES);
- this.wrapkB = Utils.generateRandomBytes(FxAccountUtils.CRYPTO_KEY_LENGTH_BYTES);
- this.devices = new HashMap<String, FxAccountDevice>();
- }
- }
-
- protected LoginResponse addLogin(User user, byte[] sessionToken, byte[] keyFetchToken) {
- // byte[] sessionToken = Utils.generateRandomBytes(8);
- if (sessionToken != null) {
- sessionTokens.put(Utils.byte2Hex(sessionToken), user.email);
- }
- // byte[] keyFetchToken = Utils.generateRandomBytes(8);
- if (keyFetchToken != null) {
- keyFetchTokens.put(Utils.byte2Hex(keyFetchToken), user.email);
- }
- return new LoginResponse(user.email, user.uid, user.verified, sessionToken, keyFetchToken);
- }
-
- public void addUser(String email, byte[] quickStretchedPW, boolean verified, byte[] sessionToken, byte[] keyFetchToken) {
- User user = new User(email, quickStretchedPW);
- users.put(email, user);
- if (verified) {
- verifyUser(email);
- }
- addLogin(user, sessionToken, keyFetchToken);
- }
-
- public void verifyUser(String email) {
- users.get(email).verified = true;
- }
-
- public void clearAllUserTokens() throws UnsupportedEncodingException {
- sessionTokens.clear();
- keyFetchTokens.clear();
- }
-
- protected BasicHttpResponse makeHttpResponse(int statusCode, String body) {
- BasicHttpResponse httpResponse = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), statusCode, body);
- httpResponse.setEntity(new StringEntity(body, "UTF-8"));
- return httpResponse;
- }
-
- protected <T> void handleFailure(RequestDelegate<T> requestDelegate, int code, int errno, String message) {
- requestDelegate.handleFailure(new FxAccountClientRemoteException(makeHttpResponse(code, message),
- code, errno, "Bad authorization", message, null, new ExtendedJSONObject()));
- }
-
- @Override
- public void accountStatus(String uid, RequestDelegate<AccountStatusResponse> requestDelegate) {
- boolean userFound = false;
- for (User user : users.values()) {
- if (user.uid.equals(uid)) {
- userFound = true;
- break;
- }
- }
- requestDelegate.handleSuccess(new AccountStatusResponse(userFound));
- }
-
- @Override
- public void recoveryEmailStatus(byte[] sessionToken, RequestDelegate<RecoveryEmailStatusResponse> requestDelegate) {
- String email = sessionTokens.get(Utils.byte2Hex(sessionToken));
- User user = users.get(email);
- if (email == null || user == null) {
- handleFailure(requestDelegate, HttpStatus.SC_UNAUTHORIZED, FxAccountRemoteError.INVALID_AUTHENTICATION_TOKEN, "invalid sessionToken");
- return;
- }
- requestDelegate.handleSuccess(new RecoveryEmailStatusResponse(email, user.verified));
- }
-
- @Override
- public void keys(byte[] keyFetchToken, RequestDelegate<TwoKeys> requestDelegate) {
- String email = keyFetchTokens.get(Utils.byte2Hex(keyFetchToken));
- User user = users.get(email);
- if (email == null || user == null) {
- handleFailure(requestDelegate, HttpStatus.SC_UNAUTHORIZED, FxAccountRemoteError.INVALID_AUTHENTICATION_TOKEN, "invalid keyFetchToken");
- return;
- }
- if (!user.verified) {
- handleFailure(requestDelegate, HttpStatus.SC_BAD_REQUEST, FxAccountRemoteError.ATTEMPT_TO_OPERATE_ON_AN_UNVERIFIED_ACCOUNT, "user is unverified");
- return;
- }
- requestDelegate.handleSuccess(new TwoKeys(user.kA, user.wrapkB));
- }
-
- @Override
- public void sign(byte[] sessionToken, ExtendedJSONObject publicKey, long certificateDurationInMilliseconds, RequestDelegate<String> requestDelegate) {
- String email = sessionTokens.get(Utils.byte2Hex(sessionToken));
- User user = users.get(email);
- if (email == null || user == null) {
- handleFailure(requestDelegate, HttpStatus.SC_UNAUTHORIZED, FxAccountRemoteError.INVALID_AUTHENTICATION_TOKEN, "invalid sessionToken");
- return;
- }
- if (!user.verified) {
- handleFailure(requestDelegate, HttpStatus.SC_BAD_REQUEST, FxAccountRemoteError.ATTEMPT_TO_OPERATE_ON_AN_UNVERIFIED_ACCOUNT, "user is unverified");
- return;
- }
- try {
- final long iat = System.currentTimeMillis();
- final long dur = certificateDurationInMilliseconds;
- final long exp = iat + dur;
- String certificate = mockMyIdTokenFactory.createMockMyIDCertificate(RSACryptoImplementation.createPublicKey(publicKey), "test", iat, exp);
- requestDelegate.handleSuccess(certificate);
- } catch (Exception e) {
- requestDelegate.handleError(e);
- }
- }
-
- @Override
- public void registerOrUpdateDevice(byte[] sessionToken, FxAccountDevice deviceToRegister, RequestDelegate<FxAccountDevice> requestDelegate) {
- String email = sessionTokens.get(Utils.byte2Hex(sessionToken));
- User user = users.get(email);
- if (email == null || user == null) {
- handleFailure(requestDelegate, HttpStatus.SC_UNAUTHORIZED, FxAccountRemoteError.INVALID_AUTHENTICATION_TOKEN, "invalid sessionToken");
- return;
- }
- if (!user.verified) {
- handleFailure(requestDelegate, HttpStatus.SC_BAD_REQUEST, FxAccountRemoteError.ATTEMPT_TO_OPERATE_ON_AN_UNVERIFIED_ACCOUNT, "user is unverified");
- return;
- }
- try {
- String deviceId = deviceToRegister.id;
- if (TextUtils.isEmpty(deviceId)) { // Create
- deviceId = UUID.randomUUID().toString();
- FxAccountDevice device = new FxAccountDevice(deviceToRegister.name, deviceId, deviceToRegister.type, null, null, null, null);
- requestDelegate.handleSuccess(device);
- } else { // Update
- FxAccountDevice existingDevice = user.devices.get(deviceId);
- if (existingDevice != null) {
- String deviceName = existingDevice.name;
- if (!TextUtils.isEmpty(deviceToRegister.name)) {
- deviceName = deviceToRegister.name;
- } // We could also update the other fields..
- FxAccountDevice device = new FxAccountDevice(deviceName, existingDevice.id, existingDevice.type,
- existingDevice.isCurrentDevice, existingDevice.pushCallback, existingDevice.pushPublicKey,existingDevice.pushAuthKey);
- requestDelegate.handleSuccess(device);
- } else { // Device unknown
- handleFailure(requestDelegate, HttpStatus.SC_BAD_REQUEST, FxAccountRemoteError.UNKNOWN_DEVICE, "device is unknown");
- return;
- }
- }
- } catch (Exception e) {
- requestDelegate.handleError(e);
- }
- }
-
- @Override
- public void deviceList(byte[] sessionToken, RequestDelegate<FxAccountDevice[]> requestDelegate) {
- String email = sessionTokens.get(Utils.byte2Hex(sessionToken));
- User user = users.get(email);
- if (email == null || user == null) {
- handleFailure(requestDelegate, HttpStatus.SC_UNAUTHORIZED, FxAccountRemoteError.INVALID_AUTHENTICATION_TOKEN, "invalid sessionToken");
- return;
- }
- if (!user.verified) {
- handleFailure(requestDelegate, HttpStatus.SC_BAD_REQUEST, FxAccountRemoteError.ATTEMPT_TO_OPERATE_ON_AN_UNVERIFIED_ACCOUNT, "user is unverified");
- return;
- }
- Collection<FxAccountDevice> devices = user.devices.values();
- FxAccountDevice[] devicesArray = devices.toArray(new FxAccountDevice[devices.size()]);
- requestDelegate.handleSuccess(devicesArray);
- }
-
- @Override
- public void notifyDevices(byte[] sessionToken, List<String> deviceIds, ExtendedJSONObject payload, Long TTL, RequestDelegate<ExtendedJSONObject> requestDelegate) {
- requestDelegate.handleSuccess(new ExtendedJSONObject());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java
deleted file mode 100644
index 1496f6d79..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.fxa.login;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.fxa.FxAccountClient;
-import org.mozilla.gecko.background.fxa.FxAccountUtils;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.browserid.BrowserIDKeyPair;
-import org.mozilla.gecko.browserid.RSACryptoImplementation;
-import org.mozilla.gecko.fxa.login.FxAccountLoginStateMachine.LoginStateMachineDelegate;
-import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.Transition;
-import org.mozilla.gecko.fxa.login.State.StateLabel;
-import org.mozilla.gecko.sync.Utils;
-
-import java.security.NoSuchAlgorithmException;
-import java.util.LinkedList;
-
-@RunWith(TestRunner.class)
-public class TestFxAccountLoginStateMachine {
- // private static final String TEST_AUDIENCE = "http://testAudience.com";
- private static final String TEST_EMAIL = "test@test.com";
- private static byte[] TEST_EMAIL_UTF8;
- private static final String TEST_PASSWORD = "testtest";
- private static byte[] TEST_PASSWORD_UTF8;
- private static byte[] TEST_QUICK_STRETCHED_PW;
- private static byte[] TEST_UNWRAPKB;
- private static final byte[] TEST_SESSION_TOKEN = Utils.generateRandomBytes(32);
- private static final byte[] TEST_KEY_FETCH_TOKEN = Utils.generateRandomBytes(32);
-
- protected MockFxAccountClient client;
- protected FxAccountLoginStateMachine sm;
-
- @Before
- public void setUp() throws Exception {
- if (TEST_EMAIL_UTF8 == null) {
- TEST_EMAIL_UTF8 = TEST_EMAIL.getBytes("UTF-8");
- }
- if (TEST_PASSWORD_UTF8 == null) {
- TEST_PASSWORD_UTF8 = TEST_PASSWORD.getBytes("UTF-8");
- }
- if (TEST_QUICK_STRETCHED_PW == null) {
- TEST_QUICK_STRETCHED_PW = FxAccountUtils.generateQuickStretchedPW(TEST_EMAIL_UTF8, TEST_PASSWORD_UTF8);
- }
- if (TEST_UNWRAPKB == null) {
- TEST_UNWRAPKB = FxAccountUtils.generateUnwrapBKey(TEST_QUICK_STRETCHED_PW);
- }
- client = new MockFxAccountClient();
- sm = new FxAccountLoginStateMachine();
- }
-
- protected static class Trace {
- public final LinkedList<State> states;
- public final LinkedList<Transition> transitions;
-
- public Trace(LinkedList<State> states, LinkedList<Transition> transitions) {
- this.states = states;
- this.transitions = transitions;
- }
-
- public void assertEquals(String string) {
- Assert.assertArrayEquals(string.split(", "), toString().split(", "));
- }
-
- @Override
- public String toString() {
- final LinkedList<State> states = new LinkedList<State>(this.states);
- final LinkedList<Transition> transitions = new LinkedList<Transition>(this.transitions);
- LinkedList<String> names = new LinkedList<String>();
- State state;
- while ((state = states.pollFirst()) != null) {
- names.add(state.getStateLabel().name());
- Transition transition = transitions.pollFirst();
- if (transition != null) {
- names.add(">" + transition.toString());
- }
- }
- return names.toString();
- }
-
- public String stateString() {
- LinkedList<String> names = new LinkedList<String>();
- for (State state : states) {
- names.add(state.getStateLabel().name());
- }
- return names.toString();
- }
-
- public String transitionString() {
- LinkedList<String> names = new LinkedList<String>();
- for (Transition transition : transitions) {
- names.add(transition.toString());
- }
- return names.toString();
- }
- }
-
- protected Trace trace(final State initialState, final StateLabel desiredState) {
- final LinkedList<Transition> transitions = new LinkedList<Transition>();
- final LinkedList<State> states = new LinkedList<State>();
- states.add(initialState);
-
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- sm.advance(initialState, desiredState, new LoginStateMachineDelegate() {
- @Override
- public void handleTransition(Transition transition, State state) {
- transitions.add(transition);
- states.add(state);
- }
-
- @Override
- public void handleFinal(State state) {
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public FxAccountClient getClient() {
- return client;
- }
-
- @Override
- public long getCertificateDurationInMilliseconds() {
- return 30 * 1000;
- }
-
- @Override
- public long getAssertionDurationInMilliseconds() {
- return 10 * 1000;
- }
-
- @Override
- public BrowserIDKeyPair generateKeyPair() throws NoSuchAlgorithmException {
- return RSACryptoImplementation.generateKeyPair(512);
- }
- });
- }
- });
-
- return new Trace(states, transitions);
- }
-
- @Test
- public void testEnagedUnverified() throws Exception {
- client.addUser(TEST_EMAIL, TEST_QUICK_STRETCHED_PW, false, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN);
- Trace trace = trace(new Engaged(TEST_EMAIL, "uid", true, TEST_UNWRAPKB, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN), StateLabel.Married);
- trace.assertEquals("[Engaged, >AccountNeedsVerification, Engaged]");
- }
-
- @Test
- public void testEngagedTransitionToAccountVerified() throws Exception {
- client.addUser(TEST_EMAIL, TEST_QUICK_STRETCHED_PW, true, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN);
- Trace trace = trace(new Engaged(TEST_EMAIL, "uid", false, TEST_UNWRAPKB, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN), StateLabel.Married);
- trace.assertEquals("[Engaged, >AccountVerified, Cohabiting, >LogMessage('sign succeeded'), Married]");
- }
-
- @Test
- public void testEngagedVerified() throws Exception {
- client.addUser(TEST_EMAIL, TEST_QUICK_STRETCHED_PW, true, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN);
- Trace trace = trace(new Engaged(TEST_EMAIL, "uid", true, TEST_UNWRAPKB, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN), StateLabel.Married);
- trace.assertEquals("[Engaged, >LogMessage('keys succeeded'), Cohabiting, >LogMessage('sign succeeded'), Married]");
- }
-
- @Test
- public void testPartial() throws Exception {
- client.addUser(TEST_EMAIL, TEST_QUICK_STRETCHED_PW, true, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN);
- // What if we stop at Cohabiting?
- Trace trace = trace(new Engaged(TEST_EMAIL, "uid", true, TEST_UNWRAPKB, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN), StateLabel.Cohabiting);
- trace.assertEquals("[Engaged, >LogMessage('keys succeeded'), Cohabiting]");
- }
-
- @Test
- public void testBadSessionToken() throws Exception {
- client.addUser(TEST_EMAIL, TEST_QUICK_STRETCHED_PW, true, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN);
- client.sessionTokens.clear();
- Trace trace = trace(new Engaged(TEST_EMAIL, "uid", true, TEST_UNWRAPKB, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN), StateLabel.Married);
- trace.assertEquals("[Engaged, >LogMessage('keys succeeded'), Cohabiting, >Log(<FxAccountClientRemoteException 401 [110]: invalid sessionToken>), Separated, >PasswordRequired, Separated]");
- }
-
- @Test
- public void testBadKeyFetchToken() throws Exception {
- client.addUser(TEST_EMAIL, TEST_QUICK_STRETCHED_PW, true, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN);
- client.keyFetchTokens.clear();
- Trace trace = trace(new Engaged(TEST_EMAIL, "uid", true, TEST_UNWRAPKB, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN), StateLabel.Married);
- trace.assertEquals("[Engaged, >Log(<FxAccountClientRemoteException 401 [110]: invalid keyFetchToken>), Separated, >PasswordRequired, Separated]");
- }
-
- @Test
- public void testMarried() throws Exception {
- client.addUser(TEST_EMAIL, TEST_QUICK_STRETCHED_PW, true, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN);
- Trace trace = trace(new Engaged(TEST_EMAIL, "uid", true, TEST_UNWRAPKB, TEST_SESSION_TOKEN, TEST_KEY_FETCH_TOKEN), StateLabel.Married);
- trace.assertEquals("[Engaged, >LogMessage('keys succeeded'), Cohabiting, >LogMessage('sign succeeded'), Married]");
- // What if we're already in the desired state?
- State married = trace.states.getLast();
- Assert.assertEquals(StateLabel.Married, married.getStateLabel());
- trace = trace(married, StateLabel.Married);
- trace.assertEquals("[Married]");
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/TestStateFactory.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/TestStateFactory.java
deleted file mode 100644
index 80d7d7f9f..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/fxa/login/TestStateFactory.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.fxa.login;
-
-import junit.framework.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.browserid.BrowserIDKeyPair;
-import org.mozilla.gecko.browserid.DSACryptoImplementation;
-import org.mozilla.gecko.fxa.login.State.StateLabel;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Utils;
-
-@RunWith(TestRunner.class)
-public class TestStateFactory {
- @Test
- public void testGetStateV3() throws Exception {
- MigratedFromSync11 migrated = new MigratedFromSync11("email", "uid", true, "password");
-
- // For the current version, we expect to read back what we wrote.
- ExtendedJSONObject o;
- State state;
-
- o = migrated.toJSONObject();
- Assert.assertEquals(3, o.getLong("version").intValue());
- state = StateFactory.fromJSONObject(migrated.stateLabel, o);
- Assert.assertEquals(StateLabel.MigratedFromSync11, state.stateLabel);
- Assert.assertEquals(o, state.toJSONObject());
-
- // Null passwords are OK.
- MigratedFromSync11 migratedNullPassword = new MigratedFromSync11("email", "uid", true, null);
-
- o = migratedNullPassword.toJSONObject();
- Assert.assertEquals(3, o.getLong("version").intValue());
- state = StateFactory.fromJSONObject(migratedNullPassword.stateLabel, o);
- Assert.assertEquals(StateLabel.MigratedFromSync11, state.stateLabel);
- Assert.assertEquals(o, state.toJSONObject());
- }
-
- @Test
- public void testGetStateV2() throws Exception {
- byte[] sessionToken = Utils.generateRandomBytes(32);
- byte[] kA = Utils.generateRandomBytes(32);
- byte[] kB = Utils.generateRandomBytes(32);
- BrowserIDKeyPair keyPair = DSACryptoImplementation.generateKeyPair(512);
- Cohabiting cohabiting = new Cohabiting("email", "uid", sessionToken, kA, kB, keyPair);
- String certificate = "certificate";
- Married married = new Married("email", "uid", sessionToken, kA, kB, keyPair, certificate);
-
- // For the current version, we expect to read back what we wrote.
- ExtendedJSONObject o;
- State state;
-
- o = married.toJSONObject();
- Assert.assertEquals(3, o.getLong("version").intValue());
- state = StateFactory.fromJSONObject(married.stateLabel, o);
- Assert.assertEquals(StateLabel.Married, state.stateLabel);
- Assert.assertEquals(o, state.toJSONObject());
-
- o = cohabiting.toJSONObject();
- Assert.assertEquals(3, o.getLong("version").intValue());
- state = StateFactory.fromJSONObject(cohabiting.stateLabel, o);
- Assert.assertEquals(StateLabel.Cohabiting, state.stateLabel);
- Assert.assertEquals(o, state.toJSONObject());
- }
-
- @Test
- public void testGetStateV1() throws Exception {
- // We can't rely on generating correct V1 objects (since the generation code
- // may change); so we hard code a few test examples here. These examples
- // have RSA key pairs; when they're parsed, we return DSA key pairs.
- ExtendedJSONObject o = new ExtendedJSONObject("{\"uid\":\"uid\",\"sessionToken\":\"4e2830da6ce466ddb401fbca25b96a621209eea83851254800f84cc4069ef011\",\"certificate\":\"certificate\",\"keyPair\":{\"publicKey\":{\"e\":\"65537\",\"n\":\"7598360104379019497828904063491254083855849024432238665262988260947462372141971045236693389494635158997975098558915846889960089362159921622822266839560631\",\"algorithm\":\"RS\"},\"privateKey\":{\"d\":\"6807533330618101360064115400338014782301295929300445938471117364691566605775022173055292460962170873583673516346599808612503093914221141089102289381448225\",\"n\":\"7598360104379019497828904063491254083855849024432238665262988260947462372141971045236693389494635158997975098558915846889960089362159921622822266839560631\",\"algorithm\":\"RS\"}},\"email\":\"email\",\"verified\":true,\"kB\":\"0b048f285c19067f200da7bfbe734ed213cefcd8f543f0fdd4a8ccab48cbbc89\",\"kA\":\"59a9edf2d41de8b24e69df9133bc88e96913baa75421882f4c55d842d18fc8a1\",\"version\":1}");
- // A Married state is regressed to a Cohabited state.
- Cohabiting state = (Cohabiting) StateFactory.fromJSONObject(StateLabel.Married, o);
-
- Assert.assertEquals(StateLabel.Cohabiting, state.stateLabel);
- Assert.assertEquals("uid", state.uid);
- Assert.assertEquals("4e2830da6ce466ddb401fbca25b96a621209eea83851254800f84cc4069ef011", Utils.byte2Hex(state.sessionToken));
- Assert.assertEquals("DS128", state.keyPair.getPrivate().getAlgorithm());
-
- o = new ExtendedJSONObject("{\"uid\":\"uid\",\"sessionToken\":\"4e2830da6ce466ddb401fbca25b96a621209eea83851254800f84cc4069ef011\",\"keyPair\":{\"publicKey\":{\"e\":\"65537\",\"n\":\"7598360104379019497828904063491254083855849024432238665262988260947462372141971045236693389494635158997975098558915846889960089362159921622822266839560631\",\"algorithm\":\"RS\"},\"privateKey\":{\"d\":\"6807533330618101360064115400338014782301295929300445938471117364691566605775022173055292460962170873583673516346599808612503093914221141089102289381448225\",\"n\":\"7598360104379019497828904063491254083855849024432238665262988260947462372141971045236693389494635158997975098558915846889960089362159921622822266839560631\",\"algorithm\":\"RS\"}},\"email\":\"email\",\"verified\":true,\"kB\":\"0b048f285c19067f200da7bfbe734ed213cefcd8f543f0fdd4a8ccab48cbbc89\",\"kA\":\"59a9edf2d41de8b24e69df9133bc88e96913baa75421882f4c55d842d18fc8a1\",\"version\":1}");
- state = (Cohabiting) StateFactory.fromJSONObject(StateLabel.Cohabiting, o);
-
- Assert.assertEquals(StateLabel.Cohabiting, state.stateLabel);
- Assert.assertEquals("uid", state.uid);
- Assert.assertEquals("4e2830da6ce466ddb401fbca25b96a621209eea83851254800f84cc4069ef011", Utils.byte2Hex(state.sessionToken));
- Assert.assertEquals("DS128", state.keyPair.getPrivate().getAlgorithm());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/helpers/AssertUtil.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/helpers/AssertUtil.java
deleted file mode 100644
index 8102bf1ee..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/helpers/AssertUtil.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.helpers;
-
-import org.junit.Assert;
-
-/**
- * Some additional assert methods on top of org.junit.Assert.
- */
-public class AssertUtil {
- /**
- * Asserts that the String {@code text} contains the String {@code sequence}. If it doesn't then
- * an {@link AssertionError} will be thrown.
- */
- public static void assertContains(String text, String sequence) {
- Assert.assertTrue(text.contains(sequence));
- }
-
- /**
- * Asserts that the String {@code text} contains not the String {@code sequence}. If it does
- * then an {@link AssertionError} will be thrown.
- */
- public static void assertContainsNot(String text, String sequence) {
- Assert.assertFalse(text.contains(sequence));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/home/TestHomeConfigPrefsBackendMigration.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/home/TestHomeConfigPrefsBackendMigration.java
deleted file mode 100644
index b6f12a05e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/home/TestHomeConfigPrefsBackendMigration.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-package org.mozilla.gecko.home;
-
-import android.content.Context;
-import android.util.Pair;
-import android.util.SparseArray;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.home.HomeConfig.PanelConfig;
-import org.mozilla.gecko.home.HomeConfig.PanelType;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Set;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class TestHomeConfigPrefsBackendMigration {
-
- // Each Pair consists of a list of panels that exist going into a given migration, and a list containing
- // the expected default output panel corresponding to each given input panel in the list of existing panels.
- // E.g. if a given N->N+1 migration starts with panels Foo and Bar, and removes Bar, the two lists would
- // be {Foo, Bar} and {Foo, Foo}.
- // Note: the index where each pair is inserted corresponds to the HomeConfig version before the migration.
- // The final item in this list denotes the current HomeCOnfig version, and therefore only needs to contain
- // the list of panel types that are expected by default (but no list for after the non-existent migration).
- final SparseArray<Pair<PanelType[], PanelType[]>> migrationConstellations = new SparseArray<>();
- {
- // 6->7: the recent tabs panel was merged into the combined history panel
- migrationConstellations.put(6, new Pair<>(
- /* Panels that are expected to exist before this migration happens */
- new PanelType[] {
- PanelType.TOP_SITES,
- PanelType.BOOKMARKS,
- PanelType.COMBINED_HISTORY,
- PanelType.DEPRECATED_RECENT_TABS
- },
- /* The expected default panel that is expected after the migration */
- new PanelType[] {
- PanelType.TOP_SITES, /* TOP_SITES remains the default if it was previously the default */
- PanelType.BOOKMARKS, /* same as TOP_SITES */
- PanelType.COMBINED_HISTORY, /* same as TOP_SITES */
- PanelType.COMBINED_HISTORY /* DEPRECATED_RECENT_TABS is replaced by COMBINED_HISTORY during this migration and is therefore the new default */
- }
- ));
-
- // 7->8: no changes, this was a fixup migration since 6->7 was previously botched
- migrationConstellations.put(7, new Pair<>(
- new PanelType[] {
- PanelType.TOP_SITES,
- PanelType.BOOKMARKS,
- PanelType.COMBINED_HISTORY,
- },
- new PanelType[] {
- PanelType.TOP_SITES,
- PanelType.BOOKMARKS,
- PanelType.COMBINED_HISTORY,
- }
- ));
-
- migrationConstellations.put(8, new Pair<>(
- new PanelType[] {
- PanelType.TOP_SITES,
- PanelType.BOOKMARKS,
- PanelType.COMBINED_HISTORY,
- },
- new PanelType[] {
- // Last version: no migration exists yet, we only need to define a list
- // of expected panels.
- }
- ));
- }
-
- private JSONArray createDisabledConfigsForList(Context context,
- PanelType[] panels) throws JSONException {
- final JSONArray jsonPanels = new JSONArray();
-
- for (int i = 0; i < panels.length; i++) {
- final PanelType panel = panels[i];
-
- jsonPanels.put(HomeConfig.createBuiltinPanelConfig(context, panel,
- EnumSet.of(PanelConfig.Flags.DISABLED_PANEL)).toJSON());
- }
-
- return jsonPanels;
-
- }
-
-
- private JSONArray createConfigsForList(Context context, PanelType[] panels,
- int defaultIndex) throws JSONException {
- if (defaultIndex < 0 || defaultIndex >= panels.length) {
- throw new IllegalArgumentException("defaultIndex must point to panel in the array");
- }
-
- final JSONArray jsonPanels = new JSONArray();
-
- for (int i = 0; i < panels.length; i++) {
- final PanelType panel = panels[i];
- final PanelConfig config;
-
- if (i == defaultIndex) {
- config = HomeConfig.createBuiltinPanelConfig(context, panel,
- EnumSet.of(PanelConfig.Flags.DEFAULT_PANEL));
- } else {
- config = HomeConfig.createBuiltinPanelConfig(context, panel);
- }
-
- jsonPanels.put(config.toJSON());
- }
-
- return jsonPanels;
- }
-
- private PanelType getDefaultPanel(final JSONArray jsonPanels) throws JSONException {
- assertTrue("panel list must not be empty", jsonPanels.length() > 0);
-
- for (int i = 0; i < jsonPanels.length(); i++) {
- final JSONObject jsonPanelConfig = jsonPanels.getJSONObject(i);
- final PanelConfig panelConfig = new PanelConfig(jsonPanelConfig);
-
- if (panelConfig.isDefault()) {
- return panelConfig.getType();
- }
- }
-
- return null;
- }
-
- private void checkAllPanelsAreDisabled(JSONArray jsonPanels) throws JSONException {
- for (int i = 0; i < jsonPanels.length(); i++) {
- final JSONObject jsonPanelConfig = jsonPanels.getJSONObject(i);
- final PanelConfig config = new PanelConfig(jsonPanelConfig);
-
- assertTrue("Non disabled panel \"" + config.getType().name() + "\" found in list, excpected all panels to be disabled", config.isDisabled());
- }
- }
-
- private void checkListContainsExpectedPanels(JSONArray jsonPanels,
- PanelType[] expected) throws JSONException {
- // Given the short lists we have here an ArraySet might be more appropriate, but it requires API >= 23.
- final Set<PanelType> expectedSet = new HashSet<>();
- for (PanelType panelType : expected) {
- expectedSet.add(panelType);
- }
-
- for (int i = 0; i < jsonPanels.length(); i++) {
- final JSONObject jsonPanelConfig = jsonPanels.getJSONObject(i);
- final PanelType panelType = new PanelConfig(jsonPanelConfig).getType();
-
- assertTrue("Unexpected panel of type " + panelType.name() + " found in list",
- expectedSet.contains(panelType));
-
- expectedSet.remove(panelType);
- }
-
- assertEquals("Expected panels not contained in list",
- 0, expectedSet.size());
- }
-
- @Test
- public void testMigrationRetainsDefaultAfter6() throws JSONException {
- final Context context = RuntimeEnvironment.application;
-
- final Pair<PanelType[], PanelType[]> finalConstellation = migrationConstellations.get(HomeConfigPrefsBackend.VERSION);
- assertNotNull("It looks like you added a HomeConfig migration, please add an appropriate entry to migrationConstellations",
- finalConstellation);
-
- // We want to calculate the number of iterations here to make sure we cover all provided constellations.
- // Iterating over the array and manually checking for each version could result in constellations
- // being skipped if there are any gaps in the array
- final int firstTestedVersion = HomeConfigPrefsBackend.VERSION - (migrationConstellations.size() - 1);
-
- // The last constellation is only used for the counts / expected outputs, hence we start
- // with the second-last constellation
- for (int testVersion = HomeConfigPrefsBackend.VERSION - 1; testVersion >= firstTestedVersion; testVersion--) {
-
- final Pair<PanelType[], PanelType[]> currentConstellation = migrationConstellations.get(testVersion);
- assertNotNull("No constellation for version " + testVersion + " - you must provide a constellation for every version upgrade in the list",
- currentConstellation);
-
- final PanelType[] inputList = currentConstellation.first;
- final PanelType[] expectedDefaults = currentConstellation.second;
-
- for (int i = 0; i < inputList.length; i++) {
- JSONArray jsonPanels = createConfigsForList(context, inputList, i);
-
-
- // Verify that we still have a default panel, and that it is the expected default panel
-
- // No need to pass in the prefsEditor since that is only used for the 0->1 migration
- jsonPanels = HomeConfigPrefsBackend.migratePrefsFromVersionToVersion(context, testVersion, testVersion + 1, jsonPanels, null);
-
- final PanelType oldDefaultPanelType = inputList[i];
- final PanelType expectedNewDefaultPanelType = expectedDefaults[i];
- final PanelType newDefaultPanelType = getDefaultPanel(jsonPanels);
-
- assertNotNull("No default panel set when migrating from " + testVersion + " to " + testVersion + 1 + ", with previous default as " + oldDefaultPanelType.name(),
- newDefaultPanelType);
-
- assertEquals("Migration changed to unexpected default panel - migrating from " + oldDefaultPanelType.name() + ", expected " + expectedNewDefaultPanelType.name() + " but got " + newDefaultPanelType.name(),
- newDefaultPanelType, expectedNewDefaultPanelType);
-
-
- // Verify that the panels remaining after the migration correspond to the input panels
- // for the next migration
- final PanelType[] expectedOutputList = migrationConstellations.get(testVersion + 1).first;
-
- assertEquals("Number of panels after migration doesn't match expected count",
- jsonPanels.length(), expectedOutputList.length);
-
- checkListContainsExpectedPanels(jsonPanels, expectedOutputList);
- }
- }
- }
-
- // Test that if all panels are disabled, the migration retains all panels as being disabled
- // (in addition to correctly removing panels as necessary).
- @Test
- public void testMigrationRetainsAllPanelsHiddenAfter6() throws JSONException {
- final Context context = RuntimeEnvironment.application;
-
- final Pair<PanelType[], PanelType[]> finalConstellation = migrationConstellations.get(HomeConfigPrefsBackend.VERSION);
- assertNotNull("It looks like you added a HomeConfig migration, please add an appropriate entry to migrationConstellations",
- finalConstellation);
-
- final int firstTestedVersion = HomeConfigPrefsBackend.VERSION - (migrationConstellations.size() - 1);
-
- for (int testVersion = HomeConfigPrefsBackend.VERSION - 1; testVersion >= firstTestedVersion; testVersion--) {
- final Pair<PanelType[], PanelType[]> currentConstellation = migrationConstellations.get(testVersion);
- assertNotNull("No constellation for version " + testVersion + " - you must provide a constellation for every version upgrade in the list",
- currentConstellation);
-
- final PanelType[] inputList = currentConstellation.first;
-
- JSONArray jsonPanels = createDisabledConfigsForList(context, inputList);
-
- jsonPanels = HomeConfigPrefsBackend.migratePrefsFromVersionToVersion(context, testVersion, testVersion + 1, jsonPanels, null);
-
- // All panels should remain disabled after the migration
- checkAllPanelsAreDisabled(jsonPanels);
-
- // Duplicated from previous test:
- // Verify that the panels remaining after the migration correspond to the input panels
- // for the next migration
- final PanelType[] expectedOutputList = migrationConstellations.get(testVersion + 1).first;
-
- assertEquals("Number of panels after migration doesn't match expected count",
- jsonPanels.length(), expectedOutputList.length);
-
- checkListContainsExpectedPanels(jsonPanels, expectedOutputList);
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconDescriptor.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconDescriptor.java
deleted file mode 100644
index 05e4576e5..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconDescriptor.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-@RunWith(TestRunner.class)
-public class TestIconDescriptor {
- private static final String ICON_URL = "https://www.mozilla.org/favicon.ico";
- private static final String MIME_TYPE = "image/png";
- private static final int ICON_SIZE = 64;
-
- @Test
- public void testGenericIconDescriptor() {
- final IconDescriptor descriptor = IconDescriptor.createGenericIcon(ICON_URL);
-
- Assert.assertEquals(ICON_URL, descriptor.getUrl());
- Assert.assertNull(descriptor.getMimeType());
- Assert.assertEquals(0, descriptor.getSize());
- Assert.assertEquals(IconDescriptor.TYPE_GENERIC, descriptor.getType());
- }
-
- @Test
- public void testFaviconIconDescriptor() {
- final IconDescriptor descriptor = IconDescriptor.createFavicon(ICON_URL, ICON_SIZE, MIME_TYPE);
-
- Assert.assertEquals(ICON_URL, descriptor.getUrl());
- Assert.assertEquals(MIME_TYPE, descriptor.getMimeType());
- Assert.assertEquals(ICON_SIZE, descriptor.getSize());
- Assert.assertEquals(IconDescriptor.TYPE_FAVICON, descriptor.getType());
- }
-
- @Test
- public void testTouchIconDescriptor() {
- final IconDescriptor descriptor = IconDescriptor.createTouchicon(ICON_URL, ICON_SIZE, MIME_TYPE);
-
- Assert.assertEquals(ICON_URL, descriptor.getUrl());
- Assert.assertEquals(MIME_TYPE, descriptor.getMimeType());
- Assert.assertEquals(ICON_SIZE, descriptor.getSize());
- Assert.assertEquals(IconDescriptor.TYPE_TOUCHICON, descriptor.getType());
- }
-
- @Test
- public void testLookupIconDescriptor() {
- final IconDescriptor descriptor = IconDescriptor.createLookupIcon(ICON_URL);
-
- Assert.assertEquals(ICON_URL, descriptor.getUrl());
- Assert.assertNull(descriptor.getMimeType());
- Assert.assertEquals(0, descriptor.getSize());
- Assert.assertEquals(IconDescriptor.TYPE_LOOKUP, descriptor.getType());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconDescriptorComparator.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconDescriptorComparator.java
deleted file mode 100644
index 1f4664d08..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconDescriptorComparator.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons;
-
-import org.junit.Assert;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import java.util.TreeSet;
-
-@RunWith(TestRunner.class)
-public class TestIconDescriptorComparator {
- private static final String TEST_ICON_URL_1 = "http://www.mozilla.org/favicon.ico";
- private static final String TEST_ICON_URL_2 = "http://www.example.org/favicon.ico";
- private static final String TEST_ICON_URL_3 = "http://www.example.com/favicon.ico";
-
- private static final String TEST_MIME_TYPE = "image/png";
- private static final int TEST_SIZE = 32;
-
- @Test
- public void testIconsWithTheSameUrlAreTreatedAsEqual() {
- final IconDescriptor descriptor1 = IconDescriptor.createGenericIcon(TEST_ICON_URL_1);
- final IconDescriptor descriptor2 = IconDescriptor.createGenericIcon(TEST_ICON_URL_1);
-
- final IconDescriptorComparator comparator = new IconDescriptorComparator();
-
- Assert.assertEquals(0, comparator.compare(descriptor1, descriptor2));
- Assert.assertEquals(0, comparator.compare(descriptor2, descriptor1));
- }
-
- @Test
- public void testTouchIconsAreRankedHigherThanFavicons() {
- final IconDescriptor faviconDescriptor = IconDescriptor.createFavicon(TEST_ICON_URL_1, TEST_SIZE, TEST_MIME_TYPE);
- final IconDescriptor touchIconDescriptor = IconDescriptor.createTouchicon(TEST_ICON_URL_2, TEST_SIZE, TEST_MIME_TYPE);
-
- final IconDescriptorComparator comparator = new IconDescriptorComparator();
-
- Assert.assertEquals(1, comparator.compare(faviconDescriptor, touchIconDescriptor));
- Assert.assertEquals(-1, comparator.compare(touchIconDescriptor, faviconDescriptor));
- }
-
- @Test
- public void testFaviconsAndTouchIconsAreRankedHigherThanGenericIcons() {
- final IconDescriptor genericDescriptor = IconDescriptor.createGenericIcon(TEST_ICON_URL_1);
-
- final IconDescriptor faviconDescriptor = IconDescriptor.createFavicon(TEST_ICON_URL_2, TEST_SIZE, TEST_MIME_TYPE);
- final IconDescriptor touchIconDescriptor = IconDescriptor.createTouchicon(TEST_ICON_URL_3, TEST_SIZE, TEST_MIME_TYPE);
-
- final IconDescriptorComparator comparator = new IconDescriptorComparator();
-
- Assert.assertEquals(1, comparator.compare(genericDescriptor, faviconDescriptor));
- Assert.assertEquals(-1, comparator.compare(faviconDescriptor, genericDescriptor));
-
- Assert.assertEquals(1, comparator.compare(genericDescriptor, touchIconDescriptor));
- Assert.assertEquals(-1, comparator.compare(touchIconDescriptor, genericDescriptor));
- }
-
- @Test
- public void testLookupIconsAreRankedHigherThanGenericIcons() {
- final IconDescriptor genericDescriptor = IconDescriptor.createGenericIcon(TEST_ICON_URL_1);
- final IconDescriptor lookupDescriptor = IconDescriptor.createLookupIcon(TEST_ICON_URL_2);
-
- final IconDescriptorComparator comparator = new IconDescriptorComparator();
-
- Assert.assertEquals(1, comparator.compare(genericDescriptor, lookupDescriptor));
- Assert.assertEquals(-1, comparator.compare(lookupDescriptor, genericDescriptor));
- }
-
- @Test
- public void testFaviconsAndTouchIconsAreRankedHigherThanLookupIcons() {
- final IconDescriptor lookupDescriptor = IconDescriptor.createLookupIcon(TEST_ICON_URL_1);
-
- final IconDescriptor faviconDescriptor = IconDescriptor.createFavicon(TEST_ICON_URL_2, TEST_SIZE, TEST_MIME_TYPE);
- final IconDescriptor touchIconDescriptor = IconDescriptor.createTouchicon(TEST_ICON_URL_3, TEST_SIZE, TEST_MIME_TYPE);
-
- final IconDescriptorComparator comparator = new IconDescriptorComparator();
-
- Assert.assertEquals(1, comparator.compare(lookupDescriptor, faviconDescriptor));
- Assert.assertEquals(-1, comparator.compare(faviconDescriptor, lookupDescriptor));
-
- Assert.assertEquals(1, comparator.compare(lookupDescriptor, touchIconDescriptor));
- Assert.assertEquals(-1, comparator.compare(touchIconDescriptor, lookupDescriptor));
- }
-
- @Test
- public void testLargestIconOfSameTypeIsSelected() {
- final IconDescriptor smallDescriptor = IconDescriptor.createFavicon(TEST_ICON_URL_1, 16, TEST_MIME_TYPE);
- final IconDescriptor largeDescriptor = IconDescriptor.createFavicon(TEST_ICON_URL_2, 128, TEST_MIME_TYPE);
-
- final IconDescriptorComparator comparator = new IconDescriptorComparator();
-
- Assert.assertEquals(1, comparator.compare(smallDescriptor, largeDescriptor));
- Assert.assertEquals(-1, comparator.compare(largeDescriptor, smallDescriptor));
- }
-
- @Test
- public void testContainerTypesArePreferred() {
- final IconDescriptor containerDescriptor = IconDescriptor.createFavicon(TEST_ICON_URL_1, TEST_SIZE, "image/x-icon");
- final IconDescriptor faviconDescriptor = IconDescriptor.createFavicon(TEST_ICON_URL_2, TEST_SIZE, "image/png");
-
- final IconDescriptorComparator comparator = new IconDescriptorComparator();
-
- Assert.assertEquals(1, comparator.compare(faviconDescriptor, containerDescriptor));
- Assert.assertEquals(-1, comparator.compare(containerDescriptor, faviconDescriptor));
- }
-
- @Test
- public void testWithNoDifferences() {
- final IconDescriptor descriptor1 = IconDescriptor.createFavicon(TEST_ICON_URL_1, TEST_SIZE, TEST_MIME_TYPE);
- final IconDescriptor descriptor2 = IconDescriptor.createFavicon(TEST_ICON_URL_2, TEST_SIZE, TEST_MIME_TYPE);
-
- final IconDescriptorComparator comparator = new IconDescriptorComparator();
-
- Assert.assertNotEquals(0, comparator.compare(descriptor1, descriptor2));
- Assert.assertNotEquals(0, comparator.compare(descriptor2, descriptor1));
- }
-
- @Test
- public void testWithSameObject() {
- final IconDescriptor descriptor = IconDescriptor.createTouchicon(TEST_ICON_URL_1, TEST_SIZE, TEST_MIME_TYPE);
-
- final IconDescriptorComparator comparator = new IconDescriptorComparator();
- Assert.assertEquals(0, comparator.compare(descriptor, descriptor));
- }
-
- /**
- * This test reconstructs the scenario from bug 1331808. A comparator implementation that does
- * not return a consistent order can break the implementation of remove() of the TreeSet class.
- */
- @Test
- public void testBug1331808() {
- TreeSet<IconDescriptor> set = new TreeSet<>(new IconDescriptorComparator());
-
- set.add(IconDescriptor.createFavicon("http://example.org/new-logo32.jpg", 0, ""));
- set.add(IconDescriptor.createTouchicon("http://example.org/new-logo57.jpg", 0, ""));
- set.add(IconDescriptor.createTouchicon("http://example.org/new-logo76.jpg", 76, ""));
- set.add(IconDescriptor.createTouchicon("http://example.org/new-logo120.jpg", 120, ""));
- set.add(IconDescriptor.createTouchicon("http://example.org/new-logo152.jpg", 114, ""));
- set.add(IconDescriptor.createFavicon("http://example.org/02.png", 32, ""));
- set.add(IconDescriptor.createFavicon("http://example.org/01.png", 192, ""));
- set.add(IconDescriptor.createTouchicon("http://example.org/03.png", 0, ""));
-
- for (int i = 8; i > 0; i--) {
- Assert.assertEquals("items in set before deleting: " + i, i, set.size());
- Assert.assertTrue("item removed successfully: " + i, set.remove(set.first()));
- Assert.assertEquals("items in set after deleting: " + i, i - 1, set.size());
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconRequest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconRequest.java
deleted file mode 100644
index d77ad6a53..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconRequest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons;
-
-import junit.framework.Assert;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.TreeSet;
-
-import static org.hamcrest.Matchers.any;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-@RunWith(TestRunner.class)
-public class TestIconRequest {
- private static final String TEST_PAGE_URL = "http://www.mozilla.org";
- private static final String TEST_ICON_URL_1 = "http://www.mozilla.org/favicon.ico";
- private static final String TEST_ICON_URL_2 = "http://www.example.org/favicon.ico";
-
- @Test
- public void testIconHandling() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .build();
-
- Assert.assertEquals(0, request.getIconCount());
- Assert.assertFalse(request.hasIconDescriptors());
-
- request.modify()
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL_1))
- .deferBuild();
-
- Assert.assertEquals(1, request.getIconCount());
- Assert.assertTrue(request.hasIconDescriptors());
-
- request.modify()
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL_2))
- .deferBuild();
-
- Assert.assertEquals(2, request.getIconCount());
- Assert.assertTrue(request.hasIconDescriptors());
-
- Assert.assertEquals(TEST_ICON_URL_2, request.getBestIcon().getUrl());
-
- request.moveToNextIcon();
-
- Assert.assertEquals(1, request.getIconCount());
- Assert.assertTrue(request.hasIconDescriptors());
-
- Assert.assertEquals(TEST_ICON_URL_1, request.getBestIcon().getUrl());
-
- request.moveToNextIcon();
-
- Assert.assertEquals(0, request.getIconCount());
- Assert.assertFalse(request.hasIconDescriptors());
- }
-
- /**
- * If removing an icon from the internal set failed then we want to throw an exception.
- */
- @Test(expected = IllegalStateException.class)
- public void testMoveToNextIconThrowsException() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .build();
-
- //noinspection unchecked - Creating a mock of a generic type
- request.icons = (TreeSet<IconDescriptor>) mock(TreeSet.class);
-
- //noinspection SuspiciousMethodCalls
- doReturn(false).when(request.icons).remove(anyObject());
-
- request.moveToNextIcon();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconRequestBuilder.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconRequestBuilder.java
deleted file mode 100644
index 0743b42d8..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconRequestBuilder.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons;
-
-import org.junit.Assert;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestIconRequestBuilder {
- private static final String TEST_PAGE_URL_1 = "http://www.mozilla.org";
- private static final String TEST_PAGE_URL_2 = "http://www.example.org";
- private static final String TEST_ICON_URL_1 = "http://www.mozilla.org/favicon.ico";
- private static final String TEST_ICON_URL_2 = "http://www.example.org/favicon.ico";
-
- @Test
- public void testPrivileged() {
- IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL_1)
- .build();
-
- Assert.assertFalse(request.isPrivileged());
-
- request.modify()
- .privileged(true)
- .deferBuild();
-
- Assert.assertTrue(request.isPrivileged());
- }
-
- @Test
- public void testPageUrl() {
- IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL_1)
- .build();
-
- Assert.assertEquals(TEST_PAGE_URL_1, request.getPageUrl());
-
- request.modify()
- .pageUrl(TEST_PAGE_URL_2)
- .deferBuild();
-
- Assert.assertEquals(TEST_PAGE_URL_2, request.getPageUrl());
- }
-
- @Test
- public void testIcons() {
- // Initially a request is empty.
- IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL_1)
- .build();
-
- Assert.assertEquals(0, request.getIconCount());
-
- // Adding one icon URL.
- request.modify()
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL_1))
- .deferBuild();
-
- Assert.assertEquals(1, request.getIconCount());
-
- // Adding the same icon URL again is ignored.
- request.modify()
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL_1))
- .deferBuild();
-
- Assert.assertEquals(1, request.getIconCount());
-
- // Adding another new icon URL.
- request.modify()
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL_2))
- .deferBuild();
-
- Assert.assertEquals(2, request.getIconCount());
- }
-
- @Test
- public void testSkipNetwork() {
- IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL_1)
- .build();
-
- Assert.assertFalse(request.shouldSkipNetwork());
-
- request.modify()
- .skipNetwork()
- .deferBuild();
-
- Assert.assertTrue(request.shouldSkipNetwork());
- }
-
- @Test
- public void testSkipDisk() {
- IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL_1)
- .build();
-
- Assert.assertFalse(request.shouldSkipDisk());
-
- request.modify()
- .skipDisk()
- .deferBuild();
-
- Assert.assertTrue(request.shouldSkipDisk());
- }
-
- @Test
- public void testSkipMemory() {
- IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL_1)
- .build();
-
- Assert.assertFalse(request.shouldSkipMemory());
-
- request.modify()
- .skipMemory()
- .deferBuild();
-
- Assert.assertTrue(request.shouldSkipMemory());
- }
-
- @Test
- public void testExecutionOnBackgroundThread() {
- IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL_1)
- .build();
-
- Assert.assertFalse(request.shouldRunOnBackgroundThread());
-
- request.modify()
- .executeCallbackOnBackgroundThread()
- .deferBuild();
-
- Assert.assertTrue(request.shouldRunOnBackgroundThread());
- }
-
- @Test
- public void testForLauncherIcon() {
- // This code will call into GeckoAppShell to determine the launcher icon size for this configuration
- GeckoAppShell.setApplicationContext(RuntimeEnvironment.application);
-
- IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL_1)
- .build();
-
- Assert.assertEquals(32, request.getTargetSize());
-
- request.modify()
- .forLauncherIcon()
- .deferBuild();
-
- Assert.assertEquals(48, request.getTargetSize());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconResponse.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconResponse.java
deleted file mode 100644
index 4c7faa4f8..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconResponse.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import static org.mockito.Mockito.mock;
-
-@RunWith(TestRunner.class)
-public class TestIconResponse {
- private static final String ICON_URL = "http://www.mozilla.org/favicon.ico";
-
- @Test
- public void testDefaultResponse() {
- final Bitmap bitmap = mock(Bitmap.class);
-
- final IconResponse response = IconResponse.create(bitmap);
-
- Assert.assertEquals(bitmap, response.getBitmap());
- Assert.assertFalse(response.hasUrl());
- Assert.assertNull(response.getUrl());
-
- Assert.assertFalse(response.hasColor());
- Assert.assertEquals(0, response.getColor());
-
- Assert.assertFalse(response.isGenerated());
- Assert.assertFalse(response.isFromNetwork());
- Assert.assertFalse(response.isFromDisk());
- Assert.assertFalse(response.isFromMemory());
- }
-
- @Test
- public void testNetworkResponse() {
- final Bitmap bitmap = mock(Bitmap.class);
-
- final IconResponse response = IconResponse.createFromNetwork(bitmap, ICON_URL);
-
- Assert.assertEquals(bitmap, response.getBitmap());
- Assert.assertTrue(response.hasUrl());
- Assert.assertEquals(ICON_URL, response.getUrl());
-
- Assert.assertFalse(response.hasColor());
- Assert.assertEquals(0, response.getColor());
-
- Assert.assertFalse(response.isGenerated());
- Assert.assertTrue(response.isFromNetwork());
- Assert.assertFalse(response.isFromDisk());
- Assert.assertFalse(response.isFromMemory());
- }
-
- @Test
- public void testGeneratedResponse() {
- final Bitmap bitmap = mock(Bitmap.class);
-
- final IconResponse response = IconResponse.createGenerated(bitmap, Color.CYAN);
-
- Assert.assertEquals(bitmap, response.getBitmap());
- Assert.assertFalse(response.hasUrl());
- Assert.assertNull(response.getUrl());
-
- Assert.assertTrue(response.hasColor());
- Assert.assertEquals(Color.CYAN, response.getColor());
-
- Assert.assertTrue(response.isGenerated());
- Assert.assertFalse(response.isFromNetwork());
- Assert.assertFalse(response.isFromDisk());
- Assert.assertFalse(response.isFromMemory());
- }
-
- @Test
- public void testMemoryResponse() {
- final Bitmap bitmap = mock(Bitmap.class);
-
- final IconResponse response = IconResponse.createFromMemory(bitmap, ICON_URL, Color.CYAN);
-
- Assert.assertEquals(bitmap, response.getBitmap());
- Assert.assertTrue(response.hasUrl());
- Assert.assertEquals(ICON_URL, response.getUrl());
-
- Assert.assertTrue(response.hasColor());
- Assert.assertEquals(Color.CYAN, response.getColor());
-
- Assert.assertFalse(response.isGenerated());
- Assert.assertFalse(response.isFromNetwork());
- Assert.assertFalse(response.isFromDisk());
- Assert.assertTrue(response.isFromMemory());
- }
-
- @Test
- public void testDiskResponse() {
- final Bitmap bitmap = mock(Bitmap.class);
-
- final IconResponse response = IconResponse.createFromDisk(bitmap, ICON_URL);
-
- Assert.assertEquals(bitmap, response.getBitmap());
- Assert.assertTrue(response.hasUrl());
- Assert.assertEquals(ICON_URL, response.getUrl());
-
- Assert.assertFalse(response.hasColor());
- Assert.assertEquals(0, response.getColor());
-
- Assert.assertFalse(response.isGenerated());
- Assert.assertFalse(response.isFromNetwork());
- Assert.assertTrue(response.isFromDisk());
- Assert.assertFalse(response.isFromMemory());
- }
-
- @Test
- public void testUpdatingColor() {
- final IconResponse response = IconResponse.create(mock(Bitmap.class));
-
- Assert.assertFalse(response.hasColor());
- Assert.assertEquals(0, response.getColor());
-
- response.updateColor(Color.YELLOW);
-
- Assert.assertTrue(response.hasColor());
- Assert.assertEquals(Color.YELLOW, response.getColor());
-
- response.updateColor(Color.MAGENTA);
-
- Assert.assertTrue(response.hasColor());
- Assert.assertEquals(Color.MAGENTA, response.getColor());
- }
-
- @Test
- public void testUpdatingBitmap() {
- final Bitmap originalBitmap = mock(Bitmap.class);
- final Bitmap updatedBitmap = mock(Bitmap.class);
-
- final IconResponse response = IconResponse.create(originalBitmap);
-
- Assert.assertEquals(originalBitmap, response.getBitmap());
- Assert.assertNotEquals(updatedBitmap, response.getBitmap());
-
- response.updateBitmap(updatedBitmap);
-
- Assert.assertNotEquals(originalBitmap, response.getBitmap());
- Assert.assertEquals(updatedBitmap, response.getBitmap());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconTask.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconTask.java
deleted file mode 100644
index 77a801988..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconTask.java
+++ /dev/null
@@ -1,575 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons;
-
-import android.graphics.Bitmap;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.loader.IconLoader;
-import org.mozilla.gecko.icons.preparation.Preparer;
-import org.mozilla.gecko.icons.processing.Processor;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-@RunWith(TestRunner.class)
-public class TestIconTask {
- @Test
- public void testGeneratorIsInvokedIfAllLoadersFail() {
- final List<IconLoader> loaders = Arrays.asList(
- createFailingLoader(),
- createFailingLoader(),
- createFailingLoader());
-
- final Bitmap bitmap = mock(Bitmap.class);
- final IconLoader generator = createSuccessfulLoader(bitmap);
-
- final IconRequest request = createIconRequest();
-
- final IconTask task = new IconTask(
- request,
- Collections.<Preparer>emptyList(),
- loaders,
- Collections.<Processor>emptyList(),
- generator);
-
- final IconResponse response = task.call();
-
- // Verify all loaders have been tried
- for (IconLoader loader : loaders) {
- verify(loader).load(request);
- }
-
- // Verify generator was called
- verify(generator).load(request);
-
- // Verify response contains generated bitmap
- Assert.assertEquals(bitmap, response.getBitmap());
- }
-
- @Test
- public void testGeneratorIsNotCalledIfOneLoaderWasSuccessful() {
- final List<IconLoader> loaders = Collections.singletonList(
- createSuccessfulLoader(mock(Bitmap.class)));
-
- final IconLoader generator = createSuccessfulLoader(mock(Bitmap.class));
-
- final IconRequest request = createIconRequest();
-
- final IconTask task = new IconTask(
- request,
- Collections.<Preparer>emptyList(),
- loaders,
- Collections.<Processor>emptyList(),
- generator);
-
- final IconResponse response = task.call();
-
- // Verify all loaders have been tried
- for (IconLoader loader : loaders) {
- verify(loader).load(request);
- }
-
- // Verify generator was NOT called
- verify(generator, never()).load(request);
-
- Assert.assertNotNull(response);
- }
-
- @Test
- public void testNoLoaderIsInvokedForRequestWithoutUrls() {
- final List<IconLoader> loaders = Collections.singletonList(
- createSuccessfulLoader(mock(Bitmap.class)));
-
- final Bitmap bitmap = mock(Bitmap.class);
- final IconLoader generator = createSuccessfulLoader(bitmap);
-
- final IconRequest request = createIconRequestWithoutUrls();
-
- final IconTask task = new IconTask(
- request,
- Collections.<Preparer>emptyList(),
- loaders,
- Collections.<Processor>emptyList(),
- generator);
-
- final IconResponse response = task.call();
-
- // Verify NO loaders have been called
- for (IconLoader loader : loaders) {
- verify(loader, never()).load(request);
- }
-
- // Verify generator was called
- verify(generator).load(request);
-
- // Verify response contains generated bitmap
- Assert.assertEquals(bitmap, response.getBitmap());
- }
-
- @Test
- public void testAllPreparersAreCalledBeforeLoading() {
- final List<Preparer> preparers = Arrays.asList(
- mock(Preparer.class),
- mock(Preparer.class),
- mock(Preparer.class),
- mock(Preparer.class),
- mock(Preparer.class),
- mock(Preparer.class));
-
- final IconRequest request = createIconRequest();
-
- final IconTask task = new IconTask(
- request,
- preparers,
- createListWithSuccessfulLoader(),
- Collections.<Processor>emptyList(),
- createGenerator());
-
- task.call();
-
- // Verify all preparers have been called
- for (Preparer preparer : preparers) {
- verify(preparer).prepare(request);
- }
- }
-
- @Test
- public void testSubsequentLoadersAreNotCalledAfterSuccessfulLoad() {
- final Bitmap bitmap = mock(Bitmap.class);
-
- final List<IconLoader> loaders = Arrays.asList(
- createFailingLoader(),
- createFailingLoader(),
- createSuccessfulLoader(bitmap),
- createSuccessfulLoader(mock(Bitmap.class)),
- createFailingLoader(),
- createSuccessfulLoader(mock(Bitmap.class)));
-
- final IconRequest request = createIconRequest();
-
- final IconTask task = new IconTask(
- request,
- Collections.<Preparer>emptyList(),
- loaders,
- Collections.<Processor>emptyList(),
- createGenerator());
-
- final IconResponse response = task.call();
-
- // First loaders are called
- verify(loaders.get(0)).load(request);
- verify(loaders.get(1)).load(request);
- verify(loaders.get(2)).load(request);
-
- // Loaders after successful load are not called
- verify(loaders.get(3), never()).load(request);
- verify(loaders.get(4), never()).load(request);
- verify(loaders.get(5), never()).load(request);
-
- Assert.assertNotNull(response);
- Assert.assertEquals(bitmap, response.getBitmap());
- }
-
- @Test
- public void testNoProcessorIsCalledForUnsuccessfulLoads() {
- final IconRequest request = createIconRequest();
-
- final List<IconLoader> loaders = createListWithFailingLoaders();
-
- final List<Processor> processors = Arrays.asList(
- createProcessor(),
- createProcessor(),
- createProcessor());
-
- final IconTask task = new IconTask(
- request,
- Collections.<Preparer>emptyList(),
- loaders,
- processors,
- createFailingLoader());
-
- task.call();
-
- // Verify all loaders have been tried
- for (IconLoader loader : loaders) {
- verify(loader).load(request);
- }
-
- // Verify no processor was called
- for (Processor processor : processors) {
- verify(processor, never()).process(any(IconRequest.class), any(IconResponse.class));
- }
- }
-
- @Test
- public void testAllProcessorsAreCalledAfterSuccessfulLoad() {
- final IconRequest request = createIconRequest();
-
- final List<Processor> processors = Arrays.asList(
- createProcessor(),
- createProcessor(),
- createProcessor());
-
- final IconTask task = new IconTask(
- request,
- Collections.<Preparer>emptyList(),
- createListWithSuccessfulLoader(),
- processors,
- createGenerator());
-
- IconResponse response = task.call();
-
- Assert.assertNotNull(response);
-
- // Verify that all processors have been called
- for (Processor processor : processors) {
- verify(processor).process(request, response);
- }
- }
-
- @Test
- public void testCallbackIsExecutedForSuccessfulLoads() {
- final IconCallback callback = mock(IconCallback.class);
-
- final IconRequest request = createIconRequest();
- request.setCallback(callback);
-
- final IconTask task = new IconTask(
- request,
- Collections.<Preparer>emptyList(),
- createListWithSuccessfulLoader(),
- Collections.<Processor>emptyList(),
- createGenerator());
-
- final IconResponse response = task.call();
-
- verify(callback).onIconResponse(response);
- }
-
- @Test
- public void testCallbackIsNotExecutedIfLoadingFailed() {
- final IconCallback callback = mock(IconCallback.class);
-
- final IconRequest request = createIconRequest();
- request.setCallback(callback);
-
- final IconTask task = new IconTask(
- request,
- Collections.<Preparer>emptyList(),
- createListWithFailingLoaders(),
- Collections.<Processor>emptyList(),
- createFailingLoader());
-
- task.call();
-
- verify(callback, never()).onIconResponse(any(IconResponse.class));
- }
-
- @Test
- public void testCallbackIsExecutedWithGeneratorResult() {
- final IconCallback callback = mock(IconCallback.class);
-
- final IconRequest request = createIconRequest();
- request.setCallback(callback);
-
- final IconTask task = new IconTask(
- request,
- Collections.<Preparer>emptyList(),
- createListWithFailingLoaders(),
- Collections.<Processor>emptyList(),
- createGenerator());
-
- final IconResponse response = task.call();
-
- verify(callback).onIconResponse(response);
- }
-
- @Test
- public void testTaskCancellationWhileLoading() {
- // We simulate the cancellation by injecting a loader that interrupts the thread.
- final IconLoader cancellingLoader = spy(new IconLoader() {
- @Override
- public IconResponse load(IconRequest request) {
- Thread.currentThread().interrupt();
- return null;
- }
- });
-
- final List<Preparer> preparers = createListOfPreparers();
- final List<Processor> processors = createListOfProcessors();
-
- final List<IconLoader> loaders = Arrays.asList(
- createFailingLoader(),
- createFailingLoader(),
- cancellingLoader,
- createFailingLoader(),
- createSuccessfulLoader(mock(Bitmap.class)));
-
- final IconRequest request = createIconRequest();
-
- final IconTask task = new IconTask(
- request,
- preparers,
- loaders,
- processors,
- createGenerator());
-
- final IconResponse response = task.call();
- Assert.assertNull(response);
-
- // Verify that all preparers are called
- for (Preparer preparer : preparers) {
- verify(preparer).prepare(request);
- }
-
- // Verify that first loaders are called
- verify(loaders.get(0)).load(request);
- verify(loaders.get(1)).load(request);
-
- // Verify that our loader that interrupts the thread is called
- verify(loaders.get(2)).load(request);
-
- // Verify that all other loaders are not called
- verify(loaders.get(3), never()).load(request);
- verify(loaders.get(4), never()).load(request);
-
- // Verify that no processors are called
- for (Processor processor : processors) {
- verify(processor, never()).process(eq(request), any(IconResponse.class));
- }
- }
-
- @Test
- public void testTaskCancellationWhileProcessing() {
- final Processor cancellingProcessor = spy(new Processor() {
- @Override
- public void process(IconRequest request, IconResponse response) {
- Thread.currentThread().interrupt();
- }
- });
-
- final List<Preparer> preparers = createListOfPreparers();
-
- final List<IconLoader> loaders = Arrays.asList(
- createFailingLoader(),
- createFailingLoader(),
- createSuccessfulLoader(mock(Bitmap.class)));
-
- final List<Processor> processors = Arrays.asList(
- createProcessor(),
- createProcessor(),
- cancellingProcessor,
- createProcessor(),
- createProcessor());
-
- final IconRequest request = createIconRequest();
-
- final IconTask task = new IconTask(
- request,
- preparers,
- loaders,
- processors,
- createGenerator());
-
- final IconResponse response = task.call();
- Assert.assertNull(response);
-
- // Verify that all preparers are called
- for (Preparer preparer : preparers) {
- verify(preparer).prepare(request);
- }
-
- // Verify that all loaders are called
- for (IconLoader loader : loaders) {
- verify(loader).load(request);
- }
-
- // Verify that first processors are called
- verify(processors.get(0)).process(eq(request), any(IconResponse.class));
- verify(processors.get(1)).process(eq(request), any(IconResponse.class));
-
- // Verify that cancelling processor is called
- verify(processors.get(2)).process(eq(request), any(IconResponse.class));
-
- // Verify that subsequent processors are not called
- verify(processors.get(3), never()).process(eq(request), any(IconResponse.class));
- verify(processors.get(4), never()).process(eq(request), any(IconResponse.class));
- }
-
- @Test
- public void testTaskCancellationWhilePerparing() {
- final Preparer failingPreparer = spy(new Preparer() {
- @Override
- public void prepare(IconRequest request) {
- Thread.currentThread().interrupt();
- }
- });
-
- final List<Preparer> preparers = Arrays.asList(
- mock(Preparer.class),
- mock(Preparer.class),
- failingPreparer,
- mock(Preparer.class),
- mock(Preparer.class));
-
- final List<IconLoader> loaders = createListWithSuccessfulLoader();
- final List<Processor> processors = createListOfProcessors();
-
- final IconRequest request = createIconRequest();
-
- final IconTask task = new IconTask(
- request,
- preparers,
- loaders,
- processors,
- createGenerator());
-
- final IconResponse response = task.call();
- Assert.assertNull(response);
-
- // Verify that first preparers are called
- verify(preparers.get(0)).prepare(request);
- verify(preparers.get(1)).prepare(request);
-
- // Verify that cancelling preparer is called
- verify(preparers.get(2)).prepare(request);
-
- // Verify that subsequent preparers are not called
- verify(preparers.get(3), never()).prepare(request);
- verify(preparers.get(4), never()).prepare(request);
-
- // Verify that no loaders are called
- for (IconLoader loader : loaders) {
- verify(loader, never()).load(request);
- }
-
- // Verify that no processors are called
- for (Processor processor : processors) {
- verify(processor, never()).process(eq(request), any(IconResponse.class));
- }
- }
-
- @Test
- public void testNoLoadersOrProcessorsAreExecutedForPrepareOnlyTasks() {
- final List<Preparer> preparers = createListOfPreparers();
- final List<IconLoader> loaders = createListWithSuccessfulLoader();
- final List<Processor> processors = createListOfProcessors();
- final IconLoader generator = createGenerator();
-
- final IconRequest request = createIconRequest()
- .modify()
- .prepareOnly()
- .build();
-
- final IconTask task = new IconTask(
- request,
- preparers,
- loaders,
- processors,
- generator);
-
- IconResponse response = task.call();
-
- Assert.assertNull(response);
-
- // Verify that all preparers are called
- for (Preparer preparer : preparers) {
- verify(preparer).prepare(request);
- }
-
- // Verify that no loaders are called
- for (IconLoader loader : loaders) {
- verify(loader, never()).load(request);
- }
-
- // Verify that no processors are called
- for (Processor processor : processors) {
- verify(processor, never()).process(eq(request), any(IconResponse.class));
- }
- }
-
- public List<IconLoader> createListWithSuccessfulLoader() {
- return Arrays.asList(
- createFailingLoader(),
- createFailingLoader(),
- createSuccessfulLoader(mock(Bitmap.class)),
- createFailingLoader());
- }
-
- public List<IconLoader> createListWithFailingLoaders() {
- return Arrays.asList(
- createFailingLoader(),
- createFailingLoader(),
- createFailingLoader(),
- createFailingLoader(),
- createFailingLoader());
- }
-
- public List<Preparer> createListOfPreparers() {
- return Arrays.asList(
- mock(Preparer.class),
- mock(Preparer.class),
- mock(Preparer.class),
- mock(Preparer.class),
- mock(Preparer.class));
- }
-
- public IconLoader createFailingLoader() {
- final IconLoader loader = mock(IconLoader.class);
- doReturn(null).when(loader).load(any(IconRequest.class));
- return loader;
- }
-
- public IconLoader createSuccessfulLoader(Bitmap bitmap) {
- IconResponse response = IconResponse.create(bitmap);
-
- final IconLoader loader = mock(IconLoader.class);
- doReturn(response).when(loader).load(any(IconRequest.class));
- return loader;
- }
-
- public List<Processor> createListOfProcessors() {
- return Arrays.asList(
- mock(Processor.class),
- mock(Processor.class),
- mock(Processor.class),
- mock(Processor.class),
- mock(Processor.class));
- }
-
- public IconRequest createIconRequest() {
- return Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createGenericIcon("http://www.mozilla.org/favicon.ico"))
- .build();
- }
-
- public IconRequest createIconRequestWithoutUrls() {
- return Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .build();
- }
-
- public IconLoader createGenerator() {
- return createSuccessfulLoader(mock(Bitmap.class));
- }
-
- public Processor createProcessor() {
- return mock(Processor.class);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconsHelper.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconsHelper.java
deleted file mode 100644
index f40e2f629..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/TestIconsHelper.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons;
-
-import android.annotation.SuppressLint;
-
-import junit.framework.Assert;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.util.GeckoJarReader;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestIconsHelper {
- @SuppressLint("AuthLeak") // Lint and Android Studio try to prevent developers from writing code
- // with credentials in the URL (user:password@host). But in this case
- // we explicitly want to do that, so we suppress the warnings.
- @Test
- public void testGuessDefaultFaviconURL() {
- // Empty values
-
- Assert.assertNull(IconsHelper.guessDefaultFaviconURL(null));
- Assert.assertNull(IconsHelper.guessDefaultFaviconURL(""));
- Assert.assertNull(IconsHelper.guessDefaultFaviconURL(" "));
-
- // Special about: URLs.
-
- Assert.assertEquals(
- "about:home",
- IconsHelper.guessDefaultFaviconURL("about:home"));
-
- Assert.assertEquals(
- "about:",
- IconsHelper.guessDefaultFaviconURL("about:"));
-
- Assert.assertEquals(
- "about:addons",
- IconsHelper.guessDefaultFaviconURL("about:addons"));
-
- // Non http(s) URLS
-
- final String jarUrl = GeckoJarReader.getJarURL(RuntimeEnvironment.application, "chrome/chrome/content/branding/favicon64.png");
- Assert.assertEquals(jarUrl, IconsHelper.guessDefaultFaviconURL(jarUrl));
-
- Assert.assertNull(IconsHelper.guessDefaultFaviconURL("content://some.random.provider/icons"));
-
- Assert.assertNull(IconsHelper.guessDefaultFaviconURL("ftp://ftp.public.mozilla.org/this/is/made/up"));
-
- Assert.assertNull(IconsHelper.guessDefaultFaviconURL("file:///"));
-
- Assert.assertNull(IconsHelper.guessDefaultFaviconURL("file:///system/path"));
-
- // Various http(s) URLs
-
- Assert.assertEquals("http://www.mozilla.org/favicon.ico",
- IconsHelper.guessDefaultFaviconURL("http://www.mozilla.org/"));
-
- Assert.assertEquals("https://www.mozilla.org/favicon.ico",
- IconsHelper.guessDefaultFaviconURL("https://www.mozilla.org/en-US/firefox/products/"));
-
- Assert.assertEquals("https://example.org/favicon.ico",
- IconsHelper.guessDefaultFaviconURL("https://example.org"));
-
- Assert.assertEquals("http://user:password@example.org:9991/favicon.ico",
- IconsHelper.guessDefaultFaviconURL("http://user:password@example.org:9991/status/760492829949001728"));
-
- Assert.assertEquals("https://localhost:8888/favicon.ico",
- IconsHelper.guessDefaultFaviconURL("https://localhost:8888/path/folder/file?some=query&params=none"));
-
- Assert.assertEquals("http://192.168.0.1/favicon.ico",
- IconsHelper.guessDefaultFaviconURL("http://192.168.0.1/local/action.cgi"));
-
- Assert.assertEquals("https://medium.com/favicon.ico",
- IconsHelper.guessDefaultFaviconURL("https://medium.com/firefox-mobile-engineering/firefox-for-android-hack-week-recap-f1ab12f5cc44#.rpmzz15ia"));
-
- // Some broken, partial URLs
-
- Assert.assertNull(IconsHelper.guessDefaultFaviconURL("http:"));
- Assert.assertNull(IconsHelper.guessDefaultFaviconURL("http://"));
- Assert.assertNull(IconsHelper.guessDefaultFaviconURL("https:/"));
- }
-
- @Test
- public void testIsContainerType() {
- // Empty values
- Assert.assertFalse(IconsHelper.isContainerType(null));
- Assert.assertFalse(IconsHelper.isContainerType(""));
- Assert.assertFalse(IconsHelper.isContainerType(" "));
-
- // Values that don't make any sense.
- Assert.assertFalse(IconsHelper.isContainerType("Hello World"));
- Assert.assertFalse(IconsHelper.isContainerType("no/no/no"));
- Assert.assertFalse(IconsHelper.isContainerType("42"));
-
- // Actual image MIME types that are not container types
- Assert.assertFalse(IconsHelper.isContainerType("image/png"));
- Assert.assertFalse(IconsHelper.isContainerType("application/bmp"));
- Assert.assertFalse(IconsHelper.isContainerType("image/gif"));
- Assert.assertFalse(IconsHelper.isContainerType("image/x-windows-bitmap"));
- Assert.assertFalse(IconsHelper.isContainerType("image/jpeg"));
- Assert.assertFalse(IconsHelper.isContainerType("application/x-png"));
-
- // MIME types of image container
- Assert.assertTrue(IconsHelper.isContainerType("image/vnd.microsoft.icon"));
- Assert.assertTrue(IconsHelper.isContainerType("image/ico"));
- Assert.assertTrue(IconsHelper.isContainerType("image/icon"));
- Assert.assertTrue(IconsHelper.isContainerType("image/x-icon"));
- Assert.assertTrue(IconsHelper.isContainerType("text/ico"));
- Assert.assertTrue(IconsHelper.isContainerType("application/ico"));
- }
-
- @Test
- public void testCanDecodeType() {
- // Empty values
- Assert.assertFalse(IconsHelper.canDecodeType(null));
- Assert.assertFalse(IconsHelper.canDecodeType(""));
- Assert.assertFalse(IconsHelper.canDecodeType(" "));
-
- // Some things we can't decode (or that just aren't images)
- Assert.assertFalse(IconsHelper.canDecodeType("image/svg+xml"));
- Assert.assertFalse(IconsHelper.canDecodeType("video/avi"));
- Assert.assertFalse(IconsHelper.canDecodeType("text/plain"));
- Assert.assertFalse(IconsHelper.canDecodeType("image/x-quicktime"));
- Assert.assertFalse(IconsHelper.canDecodeType("image/tiff"));
- Assert.assertFalse(IconsHelper.canDecodeType("application/zip"));
-
- // Some image MIME types we definitely can decode
- Assert.assertTrue(IconsHelper.canDecodeType("image/bmp"));
- Assert.assertTrue(IconsHelper.canDecodeType("image/x-icon"));
- Assert.assertTrue(IconsHelper.canDecodeType("image/png"));
- Assert.assertTrue(IconsHelper.canDecodeType("image/jpg"));
- Assert.assertTrue(IconsHelper.canDecodeType("image/jpeg"));
- Assert.assertTrue(IconsHelper.canDecodeType("image/ico"));
- Assert.assertTrue(IconsHelper.canDecodeType("image/icon"));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestContentProviderLoader.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestContentProviderLoader.java
deleted file mode 100644
index 58bb3ddf9..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestContentProviderLoader.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.loader;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestContentProviderLoader {
- @Test
- public void testNothingIsLoadedForHttpUrls() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createGenericIcon(
- "https://www.mozilla.org/media/img/favicon/apple-touch-icon-180x180.00050c5b754e.png"))
- .build();
-
- IconLoader loader = new ContentProviderLoader();
- IconResponse response = loader.load(request);
-
- Assert.assertNull(response);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestDataUriLoader.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestDataUriLoader.java
deleted file mode 100644
index 1fe6ad1a7..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestDataUriLoader.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.loader;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestDataUriLoader {
- @Test
- public void testNothingIsLoadedForHttpUrls() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createGenericIcon(
- "https://www.mozilla.org/media/img/favicon/apple-touch-icon-180x180.00050c5b754e.png"))
- .build();
-
- IconLoader loader = new DataUriLoader();
- IconResponse response = loader.load(request);
-
- Assert.assertNull(response);
- }
-
- @Test
- public void testIconIsLoadedFromDataUri() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createGenericIcon(
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAEklEQVR4AWP4z8AAxCDiP8N/AB3wBPxcBee7AAAAAElFTkSuQmCC"))
- .build();
-
- IconLoader loader = new DataUriLoader();
- IconResponse response = loader.load(request);
-
- Assert.assertNotNull(response);
- Assert.assertNotNull(response.getBitmap());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestDiskLoader.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestDiskLoader.java
deleted file mode 100644
index 809c35102..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestDiskLoader.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.loader;
-
-import android.graphics.Bitmap;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.mozilla.gecko.icons.storage.DiskStorage;
-import org.robolectric.RuntimeEnvironment;
-
-import java.io.OutputStream;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-@RunWith(TestRunner.class)
-public class TestDiskLoader {
- private static final String TEST_PAGE_URL = "http://www.mozilla.org";
- private static final String TEST_ICON_URL = "https://example.org/favicon.ico";
-
- @Test
- public void testLoadingFromEmptyCache() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .build();
-
- final IconLoader loader = new DiskLoader();
- final IconResponse response = loader.load(request);
-
- Assert.assertNull(response);
- }
-
- @Test
- public void testLoadingAfterAddingEntry() {
- final Bitmap bitmap = createMockedBitmap();
- final IconResponse originalResponse = IconResponse.createFromNetwork(bitmap, TEST_ICON_URL);
-
- DiskStorage.get(RuntimeEnvironment.application)
- .putIcon(originalResponse);
-
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .build();
-
- final IconLoader loader = new DiskLoader();
- final IconResponse loadedResponse = loader.load(request);
-
- Assert.assertNotNull(loadedResponse);
-
- // The responses are not the same: The original response was stored to disk and loaded from
- // disk again. It's a copy effectively.
- Assert.assertNotEquals(originalResponse, loadedResponse);
- }
-
- @Test
- public void testNothingIsLoadedIfDiskShouldBeSkipped() {
- final Bitmap bitmap = createMockedBitmap();
- final IconResponse originalResponse = IconResponse.createFromNetwork(bitmap, TEST_ICON_URL);
-
- DiskStorage.get(RuntimeEnvironment.application)
- .putIcon(originalResponse);
-
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .skipDisk()
- .build();
-
- final IconLoader loader = new DiskLoader();
- final IconResponse loadedResponse = loader.load(request);
-
- Assert.assertNull(loadedResponse);
- }
-
- private Bitmap createMockedBitmap() {
- final Bitmap bitmap = mock(Bitmap.class);
-
- doReturn(true).when(bitmap).compress(any(Bitmap.CompressFormat.class), anyInt(), any(OutputStream.class));
-
- return bitmap;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconDownloader.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconDownloader.java
deleted file mode 100644
index 533f14395..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconDownloader.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.loader;
-
-import android.content.Context;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.mozilla.gecko.icons.storage.FailureCache;
-import org.robolectric.RuntimeEnvironment;
-
-import java.net.HttpURLConnection;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-@RunWith(TestRunner.class)
-public class TestIconDownloader {
- /**
- * Scenario: A request with a non HTTP URL (data:image/*) is executed.
- *
- * Verify that:
- * * No download is performed.
- */
- @Test
- public void testDownloaderDoesNothingForNonHttpUrls() throws Exception {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createGenericIcon(
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAEklEQVR4AWP4z8AAxCDiP8N/AB3wBPxcBee7AAAAAElFTkSuQmCC"))
- .build();
-
- final IconDownloader downloader = spy(new IconDownloader());
- IconResponse response = downloader.load(request);
-
- Assert.assertNull(response);
-
- verify(downloader, never()).downloadAndDecodeImage(any(Context.class), anyString());
- verify(downloader, never()).connectTo(anyString());
- }
-
- /**
- * Scenario: Request contains an URL and server returns 301 with location header (always the same URL).
- *
- * Verify that:
- * * Download code stops and does not loop forever.
- */
- @Test
- public void testRedirectsAreFollowedButNotInCircles() throws Exception {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createFavicon(
- "https://www.mozilla.org/media/img/favicon.52506929be4c.ico",
- 32,
- "image/x-icon"))
- .build();
-
- HttpURLConnection mockedConnection = mock(HttpURLConnection.class);
- doReturn(301).when(mockedConnection).getResponseCode();
- doReturn("http://example.org/favicon.ico").when(mockedConnection).getHeaderField("Location");
-
- final IconDownloader downloader = spy(new IconDownloader());
- doReturn(mockedConnection).when(downloader).connectTo(anyString());
- IconResponse response = downloader.load(request);
-
- Assert.assertNull(response);
-
- verify(downloader).connectTo("https://www.mozilla.org/media/img/favicon.52506929be4c.ico");
- verify(downloader).connectTo("http://example.org/favicon.ico");
- }
-
- /**
- * Scenario: Request contains an URL and server returns HTTP 404.
- *
- * Verify that:
- * * URL is added to failure cache.
- */
- @Test
- public void testUrlIsAddedToFailureCacheIfServerReturnsClientError() throws Exception {
- final String faviconUrl = "https://www.mozilla.org/404.ico";
-
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createFavicon(faviconUrl, 32, "image/x-icon"))
- .build();
-
- HttpURLConnection mockedConnection = mock(HttpURLConnection.class);
- doReturn(404).when(mockedConnection).getResponseCode();
-
- Assert.assertFalse(FailureCache.get().isKnownFailure(faviconUrl));
-
- final IconDownloader downloader = spy(new IconDownloader());
- doReturn(mockedConnection).when(downloader).connectTo(anyString());
- IconResponse response = downloader.load(request);
-
- Assert.assertNull(response);
-
- Assert.assertTrue(FailureCache.get().isKnownFailure(faviconUrl));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconGenerator.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconGenerator.java
deleted file mode 100644
index 70e341365..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestIconGenerator.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.loader;
-
-import android.graphics.Bitmap;
-
-import org.junit.Assert;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestIconGenerator {
- @Test
- public void testNoIconIsGeneratorIfThereAreIconUrlsToLoadFrom() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createGenericIcon(
- "https://www.mozilla.org/media/img/favicon/apple-touch-icon-180x180.00050c5b754e.png"))
- .icon(IconDescriptor.createGenericIcon(
- "https://www.mozilla.org/media/img/favicon.52506929be4c.ico"))
- .build();
-
- IconLoader loader = new IconGenerator();
- IconResponse response = loader.load(request);
-
- Assert.assertNull(response);
- }
-
- @Test
- public void testIconIsGeneratedForLastUrl() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createGenericIcon(
- "https://www.mozilla.org/media/img/favicon/apple-touch-icon-180x180.00050c5b754e.png"))
- .build();
-
- IconLoader loader = new IconGenerator();
- IconResponse response = loader.load(request);
-
- Assert.assertNotNull(response);
- Assert.assertNotNull(response.getBitmap());
- }
-
- @Test
- public void testRepresentativeCharacter() {
- Assert.assertEquals("M", IconGenerator.getRepresentativeCharacter("https://mozilla.org"));
- Assert.assertEquals("W", IconGenerator.getRepresentativeCharacter("http://wikipedia.org"));
- Assert.assertEquals("P", IconGenerator.getRepresentativeCharacter("http://plus.google.com"));
- Assert.assertEquals("E", IconGenerator.getRepresentativeCharacter("https://en.m.wikipedia.org/wiki/Main_Page"));
-
- // Stripping common prefixes
- Assert.assertEquals("T", IconGenerator.getRepresentativeCharacter("http://www.theverge.com"));
- Assert.assertEquals("F", IconGenerator.getRepresentativeCharacter("https://m.facebook.com"));
- Assert.assertEquals("T", IconGenerator.getRepresentativeCharacter("https://mobile.twitter.com"));
-
- // Special urls
- Assert.assertEquals("?", IconGenerator.getRepresentativeCharacter("file:///"));
- Assert.assertEquals("S", IconGenerator.getRepresentativeCharacter("file:///system/"));
- Assert.assertEquals("P", IconGenerator.getRepresentativeCharacter("ftp://people.mozilla.org/test"));
-
- // No values
- Assert.assertEquals("?", IconGenerator.getRepresentativeCharacter(""));
- Assert.assertEquals("?", IconGenerator.getRepresentativeCharacter(null));
-
- // Rubbish
- Assert.assertEquals("Z", IconGenerator.getRepresentativeCharacter("zZz"));
- Assert.assertEquals("Ö", IconGenerator.getRepresentativeCharacter("ölkfdpou3rkjaslfdköasdfo8"));
- Assert.assertEquals("?", IconGenerator.getRepresentativeCharacter("_*+*'##"));
- Assert.assertEquals("ツ", IconGenerator.getRepresentativeCharacter("¯\\_(ツ)_/¯"));
- Assert.assertEquals("ಠ", IconGenerator.getRepresentativeCharacter("ಠ_ಠ Look of Disapproval"));
-
- // Non-ASCII
- Assert.assertEquals("Ä", IconGenerator.getRepresentativeCharacter("http://www.ätzend.de"));
- Assert.assertEquals("å", IconGenerator.getRepresentativeCharacter("http://åãŒãƒ‰ãƒ¡ã‚¤ãƒ³.com"));
- Assert.assertEquals("C", IconGenerator.getRepresentativeCharacter("http://√.com"));
- Assert.assertEquals("ß", IconGenerator.getRepresentativeCharacter("http://ß.de"));
- Assert.assertEquals("Ԛ", IconGenerator.getRepresentativeCharacter("http://ԛәлп.com/")); // cyrillic
-
- // Punycode
- Assert.assertEquals("X", IconGenerator.getRepresentativeCharacter("http://xn--tzend-fra.de")); // ätzend.de
- Assert.assertEquals("X", IconGenerator.getRepresentativeCharacter("http://xn--V8jxj3d1dzdz08w.com")); // åãŒãƒ‰ãƒ¡ã‚¤ãƒ³.com
-
- // Numbers
- Assert.assertEquals("1", IconGenerator.getRepresentativeCharacter("https://www.1and1.com/"));
-
- // IP
- Assert.assertEquals("1", IconGenerator.getRepresentativeCharacter("https://192.168.0.1"));
- }
-
- @Test
- public void testPickColor() {
- final int color = IconGenerator.pickColor("http://m.facebook.com");
-
- // Color does not change
- for (int i = 0; i < 100; i++) {
- Assert.assertEquals(color, IconGenerator.pickColor("http://m.facebook.com"));
- }
-
- // Color is stable for "similar" hosts.
- Assert.assertEquals(color, IconGenerator.pickColor("https://m.facebook.com"));
- Assert.assertEquals(color, IconGenerator.pickColor("http://facebook.com"));
- Assert.assertEquals(color, IconGenerator.pickColor("http://www.facebook.com"));
- Assert.assertEquals(color, IconGenerator.pickColor("http://www.facebook.com/foo/bar/foobar?mobile=1"));
- }
-
- @Test
- public void testGeneratingFavicon() {
- final IconResponse response = IconGenerator.generate(RuntimeEnvironment.application, "http://m.facebook.com");
- final Bitmap bitmap = response.getBitmap();
-
- Assert.assertNotNull(bitmap);
-
- final int size = RuntimeEnvironment.application.getResources().getDimensionPixelSize(R.dimen.favicon_bg);
- Assert.assertEquals(size, bitmap.getWidth());
- Assert.assertEquals(size, bitmap.getHeight());
-
- Assert.assertEquals(Bitmap.Config.ARGB_8888, bitmap.getConfig());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestJarLoader.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestJarLoader.java
deleted file mode 100644
index 48f0c26eb..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestJarLoader.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.loader;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestJarLoader {
- @Test
- public void testNothingIsLoadedForHttpUrls() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createGenericIcon(
- "https://www.mozilla.org/media/img/favicon/apple-touch-icon-180x180.00050c5b754e.png"))
- .build();
-
- IconLoader loader = new JarLoader();
- IconResponse response = loader.load(request);
-
- Assert.assertNull(response);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestLegacyLoader.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestLegacyLoader.java
deleted file mode 100644
index eecf76788..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestLegacyLoader.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.loader;
-
-import android.graphics.Bitmap;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.background.db.DelegatingTestContentProvider;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.BrowserProvider;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowContentResolver;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-@RunWith(TestRunner.class)
-public class TestLegacyLoader {
- private static final String TEST_PAGE_URL = "http://www.mozilla.org";
- private static final String TEST_ICON_URL = "https://example.org/favicon.ico";
- private static final String TEST_ICON_URL_2 = "https://example.com/page/favicon.ico";
- private static final String TEST_ICON_URL_3 = "https://example.net/icon/favicon.ico";
-
- @Test
- public void testDatabaseIsQueriesForNormalRequestsWithNetworkSkipped() {
- // We're going to query BrowserProvider via LegacyLoader, and will access a database.
- // We need to ensure we close our db connection properly.
- // This is the only test in this class that actually accesses a database. If that changes,
- // move BrowserProvider registration into a @Before method, and provider.shutdown into @After.
- final BrowserProvider provider = new BrowserProvider();
- provider.onCreate();
- ShadowContentResolver.registerProvider(BrowserContract.AUTHORITY, new DelegatingTestContentProvider(provider));
- try {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .skipNetwork()
- .build();
-
- final LegacyLoader loader = spy(new LegacyLoader());
- final IconResponse response = loader.load(request);
-
- verify(loader).loadBitmapFromDatabase(request);
- Assert.assertNull(response);
- // Close any open db connections.
- } finally {
- provider.shutdown();
- }
- }
-
- @Test
- public void testNothingIsLoadedIfNetworkIsNotSkipped() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .build();
-
- final LegacyLoader loader = spy(new LegacyLoader());
- final IconResponse response = loader.load(request);
-
- verify(loader, never()).loadBitmapFromDatabase(request);
-
- Assert.assertNull(response);
- }
-
- @Test
- public void testNothingIsLoadedIfDiskSHouldBeSkipped() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .skipDisk()
- .build();
-
- final LegacyLoader loader = spy(new LegacyLoader());
- final IconResponse response = loader.load(request);
-
- verify(loader, never()).loadBitmapFromDatabase(request);
-
- Assert.assertNull(response);
- }
-
- @Test
- public void testLoadedBitmapIsReturnedAsResponse() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .skipNetwork()
- .build();
-
- final Bitmap bitmap = mock(Bitmap.class);
-
- final LegacyLoader loader = spy(new LegacyLoader());
- doReturn(bitmap).when(loader).loadBitmapFromDatabase(request);
-
- final IconResponse response = loader.load(request);
-
- Assert.assertNotNull(response);
- Assert.assertEquals(bitmap, response.getBitmap());
- }
-
- @Test
- public void testLoaderOnlyLoadsIfThereIsOneIconLeft() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL_2))
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL_3))
- .skipNetwork()
- .build();
-
- final LegacyLoader loader = spy(new LegacyLoader());
- doReturn(mock(Bitmap.class)).when(loader).loadBitmapFromDatabase(request);
-
- // First load doesn't load an icon.
- Assert.assertNull(loader.load(request));
-
- // Second load doesn't load an icon.
- removeFirstIcon(request);
- Assert.assertNull(loader.load(request));
-
- // Now only one icon is left and a response will be returned.
- removeFirstIcon(request);
- Assert.assertNotNull(loader.load(request));
- }
-
- private void removeFirstIcon(IconRequest request) {
- final Iterator<IconDescriptor> iterator = request.getIconIterator();
- if (iterator.hasNext()) {
- iterator.next();
- iterator.remove();
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestMemoryLoader.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestMemoryLoader.java
deleted file mode 100644
index 414ac8cc7..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/loader/TestMemoryLoader.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.loader;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-
-import junit.framework.Assert;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.mozilla.gecko.icons.storage.MemoryStorage;
-import org.robolectric.RuntimeEnvironment;
-
-import static org.mockito.Mockito.mock;
-
-@RunWith(TestRunner.class)
-public class TestMemoryLoader {
- private static final String TEST_PAGE_URL = "http://www.mozilla.org";
- private static final String TEST_ICON_URL = "https://example.org/favicon.ico";
-
- @Before
- public void setUp() {
- // Make sure to start with an empty memory cache.
- MemoryStorage.get().evictAll();
- }
-
- @Test
- public void testStoringAndLoadingFromMemory() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .build();
-
- final IconLoader loader = new MemoryLoader();
-
- Assert.assertNull(loader.load(request));
-
- final Bitmap bitmap = mock(Bitmap.class);
- final IconResponse response = IconResponse.create(bitmap);
- response.updateColor(Color.MAGENTA);
-
- MemoryStorage.get().putIcon(TEST_ICON_URL, response);
-
- final IconResponse loadedResponse = loader.load(request);
-
- Assert.assertNotNull(loadedResponse);
- Assert.assertEquals(bitmap, loadedResponse.getBitmap());
- Assert.assertEquals(Color.MAGENTA, loadedResponse.getColor());
- }
-
- @Test
- public void testNothingIsLoadedIfMemoryShouldBeSkipped() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .skipMemory()
- .build();
-
- final IconLoader loader = new MemoryLoader();
-
- Assert.assertNull(loader.load(request));
-
- final Bitmap bitmap = mock(Bitmap.class);
- final IconResponse response = IconResponse.create(bitmap);
-
- MemoryStorage.get().putIcon(TEST_ICON_URL, response);
-
- Assert.assertNull(loader.load(request));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestAboutPagesPreparer.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestAboutPagesPreparer.java
deleted file mode 100644
index f0d4cb7e2..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestAboutPagesPreparer.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-package org.mozilla.gecko.icons.preparation;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.AboutPages;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.Icons;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestAboutPagesPreparer {
- private static final String[] ABOUT_PAGES = {
- AboutPages.ACCOUNTS,
- AboutPages.ADDONS,
- AboutPages.CONFIG,
- AboutPages.DOWNLOADS,
- AboutPages.FIREFOX,
- AboutPages.HEALTHREPORT,
- AboutPages.HOME,
- AboutPages.UPDATER
- };
-
- @Test
- public void testPreparerAddsUrlsForAllAboutPages() {
- final Preparer preparer = new AboutPagesPreparer();
-
- for (String url : ABOUT_PAGES) {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(url)
- .build();
-
- Assert.assertEquals(0, request.getIconCount());
-
- preparer.prepare(request);
-
- Assert.assertEquals("Added icon URL for URL: " + url, 1, request.getIconCount());
- }
- }
-
- @Test
- public void testPrepareDoesNotAddUrlForGenericHttpUrl() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .build();
-
- Assert.assertEquals(0, request.getIconCount());
-
- final Preparer preparer = new AboutPagesPreparer();
- preparer.prepare(request);
-
- Assert.assertEquals(0, request.getIconCount());
- }
-
- @Test
- public void testAddedUrlHasJarScheme() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(AboutPages.DOWNLOADS)
- .build();
-
- final Preparer preparer = new AboutPagesPreparer();
- preparer.prepare(request);
-
- Assert.assertEquals(1, request.getIconCount());
-
- final String url = request.getBestIcon().getUrl();
- Assert.assertNotNull(url);
- Assert.assertTrue(url.startsWith("jar:jar:"));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestAddDefaultIconUrl.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestAddDefaultIconUrl.java
deleted file mode 100644
index ce5e82d0b..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestAddDefaultIconUrl.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.preparation;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.Icons;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.Iterator;
-
-@RunWith(TestRunner.class)
-public class TestAddDefaultIconUrl {
- @Test
- public void testAddingDefaultUrl() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createTouchicon(
- "https://www.mozilla.org/media/img/favicon/apple-touch-icon-180x180.00050c5b754e.png",
- 180,
- "image/png"))
- .icon(IconDescriptor.createFavicon(
- "https://www.mozilla.org/media/img/favicon.52506929be4c.ico",
- 32,
- "image/x-icon"))
- .icon(IconDescriptor.createFavicon(
- "jar:jar:wtf.png",
- 16,
- "image/png"))
- .build();
-
-
- Assert.assertEquals(3, request.getIconCount());
- Assert.assertFalse(containsUrl(request, "http://www.mozilla.org/favicon.ico"));
-
- Preparer preparer = new AddDefaultIconUrl();
- preparer.prepare(request);
-
- Assert.assertEquals(4, request.getIconCount());
- Assert.assertTrue(containsUrl(request, "http://www.mozilla.org/favicon.ico"));
- }
-
- @Test
- public void testDefaultUrlIsNotAddedIfItAlreadyExists() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl("http://www.mozilla.org")
- .icon(IconDescriptor.createFavicon(
- "http://www.mozilla.org/favicon.ico",
- 32,
- "image/x-icon"))
- .build();
-
- Assert.assertEquals(1, request.getIconCount());
-
- Preparer preparer = new AddDefaultIconUrl();
- preparer.prepare(request);
-
- Assert.assertEquals(1, request.getIconCount());
- }
-
- private boolean containsUrl(IconRequest request, String url) {
- final Iterator<IconDescriptor> iterator = request.getIconIterator();
-
- while (iterator.hasNext()) {
- IconDescriptor descriptor = iterator.next();
-
- if (descriptor.getUrl().equals(url)) {
- return true;
- }
- }
-
- return false;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterKnownFailureUrls.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterKnownFailureUrls.java
deleted file mode 100644
index 67584c4cf..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterKnownFailureUrls.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.preparation;
-
-import junit.framework.Assert;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.Icons;
-import org.mozilla.gecko.icons.storage.FailureCache;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestFilterKnownFailureUrls {
- private static final String TEST_PAGE_URL = "http://www.mozilla.org";
- private static final String TEST_ICON_URL = "https://example.org/favicon.ico";
-
- @Before
- public void setUp() {
- // Make sure we always start with an empty cache.
- FailureCache.get().evictAll();
- }
-
- @Test
- public void testFilterDoesNothingByDefault() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .build();
-
- Assert.assertEquals(1, request.getIconCount());
-
- final Preparer preparer = new FilterKnownFailureUrls();
- preparer.prepare(request);
-
- Assert.assertEquals(1, request.getIconCount());
- }
-
- @Test
- public void testFilterKnownFailureUrls() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .build();
-
- Assert.assertEquals(1, request.getIconCount());
-
- FailureCache.get().rememberFailure(TEST_ICON_URL);
-
- final Preparer preparer = new FilterKnownFailureUrls();
- preparer.prepare(request);
-
- Assert.assertEquals(0, request.getIconCount());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterMimeTypes.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterMimeTypes.java
deleted file mode 100644
index e8339b4e9..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterMimeTypes.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.preparation;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.Icons;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestFilterMimeTypes {
- private static final String TEST_PAGE_URL = "http://www.mozilla.org";
- private static final String TEST_ICON_URL = "https://example.org/favicon.ico";
- private static final String TEST_ICON_URL_2 = "https://mozilla.org/favicon.ico";
-
- @Test
- public void testUrlsWithoutMimeTypesAreNotFiltered() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_URL))
- .build();
-
- Assert.assertEquals(1, request.getIconCount());
-
- final Preparer preparer = new FilterMimeTypes();
- preparer.prepare(request);
-
- Assert.assertEquals(1, request.getIconCount());
- }
-
- @Test
- public void testUnknownMimeTypesAreFiltered() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createFavicon(TEST_ICON_URL, 256, "image/zaphod"))
- .icon(IconDescriptor.createFavicon(TEST_ICON_URL_2, 128, "audio/mpeg"))
- .build();
-
- Assert.assertEquals(2, request.getIconCount());
-
- final Preparer preparer = new FilterMimeTypes();
- preparer.prepare(request);
-
- Assert.assertEquals(0, request.getIconCount());
- }
-
- @Test
- public void testKnownMimeTypesAreNotFiltered() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createFavicon(TEST_ICON_URL, 256, "image/x-icon"))
- .icon(IconDescriptor.createFavicon(TEST_ICON_URL_2, 128, "image/png"))
- .build();
-
- Assert.assertEquals(2, request.getIconCount());
-
- final Preparer preparer = new FilterMimeTypes();
- preparer.prepare(request);
-
- Assert.assertEquals(2, request.getIconCount());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterPrivilegedUrls.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterPrivilegedUrls.java
deleted file mode 100644
index 53fcbd05a..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestFilterPrivilegedUrls.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.mozilla.gecko.icons.preparation;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.Icons;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.Iterator;
-
-@RunWith(TestRunner.class)
-public class TestFilterPrivilegedUrls {
- private static final String TEST_PAGE_URL = "http://www.mozilla.org";
-
- private static final String TEST_ICON_HTTP_URL = "https://www.mozilla.org/media/img/favicon/apple-touch-icon-180x180.00050c5b754e.png";
- private static final String TEST_ICON_HTTP_URL_2 = "https://www.mozilla.org/media/img/favicon.52506929be4c.ico";
- private static final String TEST_ICON_JAR_URL = "jar:jar:wtf.png";
-
- @Test
- public void testFiltering() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_HTTP_URL))
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_HTTP_URL_2))
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_JAR_URL))
- .build();
-
- Assert.assertEquals(3, request.getIconCount());
-
- Assert.assertTrue(containsUrl(request, TEST_ICON_HTTP_URL));
- Assert.assertTrue(containsUrl(request, TEST_ICON_HTTP_URL_2));
- Assert.assertTrue(containsUrl(request, TEST_ICON_JAR_URL));
-
- Preparer preparer = new FilterPrivilegedUrls();
- preparer.prepare(request);
-
- Assert.assertEquals(2, request.getIconCount());
-
- Assert.assertTrue(containsUrl(request, TEST_ICON_HTTP_URL));
- Assert.assertTrue(containsUrl(request, TEST_ICON_HTTP_URL_2));
- Assert.assertFalse(containsUrl(request, TEST_ICON_JAR_URL));
- }
-
- @Test
- public void testNothingIsFilteredForPrivilegedRequests() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_HTTP_URL))
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_HTTP_URL_2))
- .icon(IconDescriptor.createGenericIcon(TEST_ICON_JAR_URL))
- .privileged(true)
- .build();
-
- Assert.assertEquals(3, request.getIconCount());
-
- Assert.assertTrue(containsUrl(request, TEST_ICON_HTTP_URL));
- Assert.assertTrue(containsUrl(request, TEST_ICON_HTTP_URL_2));
- Assert.assertTrue(containsUrl(request, TEST_ICON_JAR_URL));
-
- Preparer preparer = new FilterPrivilegedUrls();
- preparer.prepare(request);
-
- Assert.assertEquals(3, request.getIconCount());
-
- Assert.assertTrue(containsUrl(request, TEST_ICON_HTTP_URL));
- Assert.assertTrue(containsUrl(request, TEST_ICON_HTTP_URL_2));
- Assert.assertTrue(containsUrl(request, TEST_ICON_JAR_URL));
- }
-
- private boolean containsUrl(IconRequest request, String url) {
- final Iterator<IconDescriptor> iterator = request.getIconIterator();
-
- while (iterator.hasNext()) {
- IconDescriptor descriptor = iterator.next();
-
- if (descriptor.getUrl().equals(url)) {
- return true;
- }
- }
-
- return false;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestLookupIconUrl.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestLookupIconUrl.java
deleted file mode 100644
index 99bac076b..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/preparation/TestLookupIconUrl.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.preparation;
-
-import junit.framework.Assert;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.Icons;
-import org.mozilla.gecko.icons.storage.DiskStorage;
-import org.mozilla.gecko.icons.storage.MemoryStorage;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestLookupIconUrl {
- private static final String TEST_PAGE_URL = "http://www.mozilla.org";
-
- private static final String TEST_ICON_URL_1 = "http://www.mozilla.org/favicon.ico";
- private static final String TEST_ICON_URL_2 = "http://example.org/favicon.ico";
- private static final String TEST_ICON_URL_3 = "http://example.com/favicon.ico";
- private static final String TEST_ICON_URL_4 = "http://example.net/favicon.ico";
-
-
- @Before
- public void setUp() {
- MemoryStorage.get().evictAll();
- }
-
- @Test
- public void testNoIconUrlIsAddedByDefault() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .build();
-
- Assert.assertEquals(0, request.getIconCount());
-
- Preparer preparer = new LookupIconUrl();
- preparer.prepare(request);
-
- Assert.assertEquals(0, request.getIconCount());
- }
-
- @Test
- public void testIconUrlIsAddedFromMemory() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .build();
-
- MemoryStorage.get().putMapping(request, TEST_ICON_URL_1);
-
- Assert.assertEquals(0, request.getIconCount());
-
- Preparer preparer = new LookupIconUrl();
- preparer.prepare(request);
-
- Assert.assertEquals(1, request.getIconCount());
-
- Assert.assertEquals(TEST_ICON_URL_1, request.getBestIcon().getUrl());
- }
-
- @Test
- public void testIconUrlIsAddedFromDisk() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .build();
-
- DiskStorage.get(RuntimeEnvironment.application).putMapping(request, TEST_ICON_URL_2);
-
- Assert.assertEquals(0, request.getIconCount());
-
- Preparer preparer = new LookupIconUrl();
- preparer.prepare(request);
-
- Assert.assertEquals(1, request.getIconCount());
-
- Assert.assertEquals(TEST_ICON_URL_2, request.getBestIcon().getUrl());
- }
-
- @Test
- public void testIconUrlIsAddedFromMemoryBeforeUsingDiskStorage() {
- final IconRequest request = Icons.with(RuntimeEnvironment.application)
- .pageUrl(TEST_PAGE_URL)
- .build();
-
- MemoryStorage.get().putMapping(request, TEST_ICON_URL_3);
- DiskStorage.get(RuntimeEnvironment.application).putMapping(request, TEST_ICON_URL_4);
-
- Assert.assertEquals(0, request.getIconCount());
-
- Preparer preparer = new LookupIconUrl();
- preparer.prepare(request);
-
- Assert.assertEquals(1, request.getIconCount());
-
- Assert.assertEquals(TEST_ICON_URL_3, request.getBestIcon().getUrl());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestColorProcessor.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestColorProcessor.java
deleted file mode 100644
index 6057c0776..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestColorProcessor.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.processing;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconResponse;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-@RunWith(TestRunner.class)
-public class TestColorProcessor {
- @Test
- public void testExtractingColor() {
- final IconResponse response = IconResponse.create(createRedBitmapMock());
-
- Assert.assertFalse(response.hasColor());
- Assert.assertEquals(0, response.getColor());
-
- final Processor processor = new ColorProcessor();
- processor.process(null, response);
-
- Assert.assertTrue(response.hasColor());
- Assert.assertEquals(Color.RED, response.getColor());
- }
-
- private Bitmap createRedBitmapMock() {
- final Bitmap bitmap = mock(Bitmap.class);
-
- doReturn(1).when(bitmap).getWidth();
- doReturn(1).when(bitmap).getHeight();
-
- doAnswer(new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) throws Throwable {
- Object[] args = invocation.getArguments();
- int[] pixels = (int[]) args[0];
- for (int i = 0; i < pixels.length; i++) {
- pixels[i] = Color.RED;
- }
- return null;
- }
- }).when(bitmap).getPixels(any(int[].class), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt());
-
- return bitmap;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestDiskProcessor.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestDiskProcessor.java
deleted file mode 100644
index eea5c9bf6..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestDiskProcessor.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.processing;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-
-import junit.framework.Assert;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.mozilla.gecko.icons.storage.DiskStorage;
-import org.robolectric.RuntimeEnvironment;
-
-import java.io.OutputStream;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-@RunWith(TestRunner.class)
-public class TestDiskProcessor {
- private static final String PAGE_URL = "https://www.mozilla.org";
- private static final String ICON_URL = "https://www.mozilla.org/favicon.ico";
-
- @Test
- public void testNetworkResponseIsStoredInCache() {
- final IconRequest request = createTestRequest();
- final IconResponse response = createTestNetworkResponse();
-
- final DiskStorage storage = DiskStorage.get(RuntimeEnvironment.application);
- Assert.assertNull(storage.getIcon(ICON_URL));
-
- final Processor processor = new DiskProcessor();
- processor.process(request, response);
-
- Assert.assertNotNull(storage.getIcon(ICON_URL));
- }
-
- @Test
- public void testGeneratedResponseIsNotStored() {
- final IconRequest request = createTestRequest();
- final IconResponse response = createGeneratedResponse();
-
- final DiskStorage storage = DiskStorage.get(RuntimeEnvironment.application);
- Assert.assertNull(storage.getIcon(ICON_URL));
-
- final Processor processor = new DiskProcessor();
- processor.process(request, response);
-
- Assert.assertNull(storage.getIcon(ICON_URL));
- }
-
- @Test
- public void testNothingIsStoredIfDiskShouldBeSkipped() {
- final IconRequest request = createTestRequest()
- .modify()
- .skipDisk()
- .build();
- final IconResponse response = createTestNetworkResponse();
-
- final DiskStorage storage = DiskStorage.get(RuntimeEnvironment.application);
- Assert.assertNull(storage.getIcon(ICON_URL));
-
- final Processor processor = new DiskProcessor();
- processor.process(request, response);
-
- Assert.assertNull(storage.getIcon(ICON_URL));
- }
-
- private IconRequest createTestRequest() {
- return Icons.with(RuntimeEnvironment.application)
- .pageUrl(PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(ICON_URL))
- .build();
- }
-
- public IconResponse createTestNetworkResponse() {
- return IconResponse.createFromNetwork(createMockedBitmap(), ICON_URL);
- }
-
- public IconResponse createGeneratedResponse() {
- return IconResponse.createGenerated(createMockedBitmap(), Color.WHITE);
- }
-
- private Bitmap createMockedBitmap() {
- final Bitmap bitmap = mock(Bitmap.class);
-
- doReturn(true).when(bitmap).compress(any(Bitmap.CompressFormat.class), anyInt(), any(OutputStream.class));
-
- return bitmap;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestMemoryProcessor.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestMemoryProcessor.java
deleted file mode 100644
index fbc1e0baf..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestMemoryProcessor.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.processing;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.mozilla.gecko.icons.storage.MemoryStorage;
-import org.robolectric.RuntimeEnvironment;
-
-import static org.mockito.Mockito.mock;
-
-@RunWith(TestRunner.class)
-public class TestMemoryProcessor {
- private static final String PAGE_URL = "https://www.mozilla.org";
- private static final String ICON_URL = "https://www.mozilla.org/favicon.ico";
- private static final String DATA_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAEklEQVR4AWP4z8AAxCDiP8N/AB3wBPxcBee7AAAAAElFTkSuQmCC";
-
- @Before
- public void setUp() {
- MemoryStorage.get().evictAll();
- }
-
- @Test
- public void testResponsesAreStoredInMemory() {
- final IconRequest request = createTestRequest();
-
- Assert.assertNull(MemoryStorage.get().getIcon(ICON_URL));
- Assert.assertNull(MemoryStorage.get().getMapping(PAGE_URL));
-
- final Processor processor = new MemoryProcessor();
- processor.process(request, createTestResponse());
-
- Assert.assertNotNull(MemoryStorage.get().getIcon(ICON_URL));
- Assert.assertNotNull(MemoryStorage.get().getMapping(PAGE_URL));
- }
-
- @Test
- public void testNothingIsStoredIfMemoryShouldBeSkipped() {
- final IconRequest request = createTestRequest()
- .modify()
- .skipMemory()
- .build();
-
- Assert.assertNull(MemoryStorage.get().getIcon(ICON_URL));
- Assert.assertNull(MemoryStorage.get().getMapping(PAGE_URL));
-
- final Processor processor = new MemoryProcessor();
- processor.process(request, createTestResponse());
-
- Assert.assertNull(MemoryStorage.get().getIcon(ICON_URL));
- Assert.assertNull(MemoryStorage.get().getMapping(PAGE_URL));
- }
-
- @Test
- public void testNothingIsStoredForRequestsWithoutUrl() {
- final IconRequest request = createTestRequestWithoutIconUrl();
-
- Assert.assertNull(MemoryStorage.get().getIcon(ICON_URL));
- Assert.assertNull(MemoryStorage.get().getMapping(PAGE_URL));
-
- final Processor processor = new MemoryProcessor();
- processor.process(request, createTestResponse());
-
- Assert.assertNull(MemoryStorage.get().getIcon(ICON_URL));
- Assert.assertNull(MemoryStorage.get().getMapping(PAGE_URL));
- }
-
- @Test
- public void testNothingIsStoredForGeneratedResponses() {
- final IconRequest request = createTestRequest();
-
- Assert.assertNull(MemoryStorage.get().getIcon(ICON_URL));
- Assert.assertNull(MemoryStorage.get().getMapping(PAGE_URL));
-
- final Processor processor = new MemoryProcessor();
- processor.process(request, createGeneratedTestResponse());
-
- Assert.assertNull(MemoryStorage.get().getIcon(ICON_URL));
- Assert.assertNull(MemoryStorage.get().getMapping(PAGE_URL));
- }
-
- @Test
- public void testNothingIsStoredForDataUris() {
- final IconRequest request = createDataUriTestRequest();
-
- Assert.assertNull(MemoryStorage.get().getIcon(DATA_URL));
- Assert.assertNull(MemoryStorage.get().getMapping(PAGE_URL));
-
- final Processor processor = new MemoryProcessor();
- processor.process(request, createTestResponse());
-
- Assert.assertNull(MemoryStorage.get().getIcon(DATA_URL));
- Assert.assertNull(MemoryStorage.get().getMapping(PAGE_URL));
- }
-
- private IconRequest createTestRequest() {
- return Icons.with(RuntimeEnvironment.application)
- .pageUrl(PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(ICON_URL))
- .build();
- }
-
- private IconRequest createTestRequestWithoutIconUrl() {
- return Icons.with(RuntimeEnvironment.application)
- .pageUrl(PAGE_URL)
- .build();
- }
-
- private IconRequest createDataUriTestRequest() {
- return Icons.with(RuntimeEnvironment.application)
- .pageUrl(PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(DATA_URL))
- .build();
- }
-
- private IconResponse createTestResponse() {
- return IconResponse.create(mock(Bitmap.class));
- }
-
- private IconResponse createGeneratedTestResponse() {
- return IconResponse.createGenerated(mock(Bitmap.class), Color.GREEN);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestResizingProcessor.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestResizingProcessor.java
deleted file mode 100644
index dbcb4e2ee..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/icons/processing/TestResizingProcessor.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.icons.processing;
-
-import android.graphics.Bitmap;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.icons.IconDescriptor;
-import org.mozilla.gecko.icons.IconRequest;
-import org.mozilla.gecko.icons.IconResponse;
-import org.mozilla.gecko.icons.Icons;
-import org.robolectric.RuntimeEnvironment;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-@RunWith(TestRunner.class)
-public class TestResizingProcessor {
- private static final String PAGE_URL = "https://www.mozilla.org";
- private static final String ICON_URL = "https://www.mozilla.org/favicon.ico";
-
- @Test
- public void testBitmapIsNotResizedIfItAlreadyHasTheTargetSize() {
- final IconRequest request = createTestRequest();
-
- final Bitmap bitmap = createBitmapMock(request.getTargetSize());
- final IconResponse response = spy(IconResponse.create(bitmap));
-
- final ResizingProcessor processor = spy(new ResizingProcessor());
- processor.process(request, response);
-
- verify(processor, never()).resize(any(Bitmap.class), anyInt());
- verify(bitmap, never()).recycle();
- verify(response, never()).updateBitmap(any(Bitmap.class));
- }
-
- @Test
- public void testLargerBitmapsAreResized() {
- final IconRequest request = createTestRequest();
-
- final Bitmap bitmap = createBitmapMock(request.getTargetSize() * 2);
- final IconResponse response = spy(IconResponse.create(bitmap));
-
- final ResizingProcessor processor = spy(new ResizingProcessor());
- final Bitmap resizedBitmap = mock(Bitmap.class);
- doReturn(resizedBitmap).when(processor).resize(any(Bitmap.class), anyInt());
- processor.process(request, response);
-
- verify(processor).resize(bitmap, request.getTargetSize());
- verify(bitmap).recycle();
- verify(response).updateBitmap(resizedBitmap);
- }
-
- @Test
- public void testBitmapIsUpscaledToTargetSize() {
- final IconRequest request = createTestRequest();
-
- final Bitmap bitmap = createBitmapMock(request.getTargetSize() / 2 + 1);
- final IconResponse response = spy(IconResponse.create(bitmap));
-
- final ResizingProcessor processor = spy(new ResizingProcessor());
- final Bitmap resizedBitmap = mock(Bitmap.class);
- doReturn(resizedBitmap).when(processor).resize(any(Bitmap.class), anyInt());
- processor.process(request, response);
-
- verify(processor).resize(bitmap, request.getTargetSize());
- verify(bitmap).recycle();
- verify(response).updateBitmap(resizedBitmap);
- }
-
- @Test
- public void testBitmapIsNotScaledMoreThanTwoTimesTheSize() {
- final IconRequest request = createTestRequest();
-
- final Bitmap bitmap = createBitmapMock(5);
- final IconResponse response = spy(IconResponse.create(bitmap));
-
- final ResizingProcessor processor = spy(new ResizingProcessor());
- final Bitmap resizedBitmap = mock(Bitmap.class);
- doReturn(resizedBitmap).when(processor).resize(any(Bitmap.class), anyInt());
- processor.process(request, response);
-
- verify(processor).resize(bitmap, 10);
- verify(bitmap).recycle();
- verify(response).updateBitmap(resizedBitmap);
- }
-
- private IconRequest createTestRequest() {
- return Icons.with(RuntimeEnvironment.application)
- .pageUrl(PAGE_URL)
- .icon(IconDescriptor.createGenericIcon(ICON_URL))
- .build();
- }
-
- private Bitmap createBitmapMock(int size) {
- final Bitmap bitmap = mock(Bitmap.class);
-
- doReturn(size).when(bitmap).getWidth();
- doReturn(size).when(bitmap).getHeight();
-
- return bitmap;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/permissions/TestPermissions.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/permissions/TestPermissions.java
deleted file mode 100644
index 07fbab493..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/permissions/TestPermissions.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.permissions;
-
-import android.Manifest;
-import android.app.Activity;
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Matchers;
-
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import static org.mockito.Mockito.*;
-
-@RunWith(TestRunner.class)
-public class TestPermissions {
- @Test
- public void testSuccessRunnableIsExecutedIfPermissionsAreGranted() {
- Permissions.setPermissionHelper(mockGrantingHelper());
-
- Runnable onPermissionsGranted = mock(Runnable.class);
- Runnable onPermissionsDenied = mock(Runnable.class);
-
- Permissions.from(mockActivity())
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .andFallback(onPermissionsDenied)
- .run(onPermissionsGranted);
-
- verify(onPermissionsDenied, never()).run();
- verify(onPermissionsGranted).run();
- }
-
- @Test
- public void testFallbackRunnableIsExecutedIfPermissionsAreDenied() {
- Permissions.setPermissionHelper(mockDenyingHelper());
-
- Runnable onPermissionsGranted = mock(Runnable.class);
- Runnable onPermissionsDenied = mock(Runnable.class);
-
- Activity activity = mockActivity();
-
- Permissions.from(activity)
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .andFallback(onPermissionsDenied)
- .run(onPermissionsGranted);
-
- Permissions.onRequestPermissionsResult(activity, new String[]{
- Manifest.permission.WRITE_EXTERNAL_STORAGE
- }, new int[]{
- PackageManager.PERMISSION_DENIED
- });
-
- verify(onPermissionsDenied).run();
- verify(onPermissionsGranted, never()).run();
- }
-
- @Test
- public void testPromptingForNotGrantedPermissions() {
- Activity activity = mockActivity();
-
- PermissionsHelper helper = mockDenyingHelper();
- Permissions.setPermissionHelper(helper);
-
- Permissions.from(activity)
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .andFallback(mock(Runnable.class))
- .run(mock(Runnable.class));
-
- verify(helper).prompt(anyActivity(), any(String[].class));
-
- Permissions.onRequestPermissionsResult(activity, new String[0], new int[0]);
- }
-
- @Test
- public void testMultipleRequestsAreQueuedAndDispatchedSequentially() {
- Activity activity = mockActivity();
-
- PermissionsHelper helper = mockDenyingHelper();
- Permissions.setPermissionHelper(helper);
-
- Runnable onFirstPermissionGranted = mock(Runnable.class);
- Runnable onSecondPermissionDenied = mock(Runnable.class);
-
- Permissions.from(activity)
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .andFallback(mock(Runnable.class))
- .run(onFirstPermissionGranted);
-
- Permissions.from(activity)
- .withPermissions(Manifest.permission.CAMERA)
- .andFallback(onSecondPermissionDenied)
- .run(mock(Runnable.class));
-
-
- Permissions.onRequestPermissionsResult(activity, new String[] {
- Manifest.permission.WRITE_EXTERNAL_STORAGE
- }, new int[] {
- PackageManager.PERMISSION_GRANTED
- });
-
- verify(onFirstPermissionGranted).run();
- verify(onSecondPermissionDenied, never()).run(); // Second request is queued but not executed yet
-
- Permissions.onRequestPermissionsResult(activity, new String[]{
- Manifest.permission.CAMERA
- }, new int[]{
- PackageManager.PERMISSION_DENIED
- });
-
- verify(onFirstPermissionGranted).run();
- verify(onSecondPermissionDenied).run();
-
- verify(helper, times(2)).prompt(anyActivity(), any(String[].class));
- }
-
- @Test
- public void testSecondRequestWillNotPromptIfPermissionHasBeenGranted() {
- Activity activity = mockActivity();
-
- PermissionsHelper helper = mock(PermissionsHelper.class);
- Permissions.setPermissionHelper(helper);
- when(helper.hasPermissions(anyContext(), anyPermissions()))
- .thenReturn(false)
- .thenReturn(false)
- .thenReturn(true); // Revaluation is successful
-
- Permissions.from(activity)
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .andFallback(mock(Runnable.class))
- .run(mock(Runnable.class));
-
- Permissions.from(activity)
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .andFallback(mock(Runnable.class))
- .run(mock(Runnable.class));
-
- Permissions.onRequestPermissionsResult(activity, new String[]{
- Manifest.permission.WRITE_EXTERNAL_STORAGE
- }, new int[]{
- PackageManager.PERMISSION_GRANTED
- });
-
- verify(helper, times(1)).prompt(anyActivity(), any(String[].class));
- }
-
- @Test
- public void testEmptyPermissionsArrayWillExecuteRunnableAndNotTryToPrompt() {
- PermissionsHelper helper = spy(new PermissionsHelper());
- Permissions.setPermissionHelper(helper);
-
- Runnable onPermissionGranted = mock(Runnable.class);
- Runnable onPermissionDenied = mock(Runnable.class);
-
- Permissions.from(mockActivity())
- .withPermissions()
- .andFallback(onPermissionDenied)
- .run(onPermissionGranted);
-
- verify(onPermissionGranted).run();
- verify(onPermissionDenied, never()).run();
- verify(helper, never()).prompt(anyActivity(), any(String[].class));
- }
-
- @Test
- public void testDoNotPromptBehavior() {
- PermissionsHelper helper = mockDenyingHelper();
- Permissions.setPermissionHelper(helper);
-
- Permissions.from(mockActivity())
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .doNotPrompt()
- .andFallback(mock(Runnable.class))
- .run(mock(Runnable.class));
-
- verify(helper, never()).prompt(anyActivity(), any(String[].class));
- }
-
- @Test(expected = IllegalStateException.class)
- public void testThrowsExceptionIfNeedstoPromptWithNonActivityContext() {
- Permissions.setPermissionHelper(mockDenyingHelper());
-
- Permissions.from(mock(Context.class))
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .andFallback(mock(Runnable.class))
- .run(mock(Runnable.class));
- }
-
- @Test
- public void testDoNotPromptIfFalse() {
- Activity activity = mockActivity();
-
- PermissionsHelper helper = mockDenyingHelper();
- Permissions.setPermissionHelper(helper);
-
- Permissions.from(activity)
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .doNotPromptIf(false)
- .andFallback(mock(Runnable.class))
- .run(mock(Runnable.class));
-
- verify(helper).prompt(anyActivity(), any(String[].class));
-
- Permissions.onRequestPermissionsResult(activity, new String[0], new int[0]);
- }
-
- @Test
- public void testDoNotPromptIfTrue() {
- PermissionsHelper helper = mockDenyingHelper();
- Permissions.setPermissionHelper(helper);
-
- Permissions.from(mockActivity())
- .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .doNotPromptIf(true)
- .andFallback(mock(Runnable.class))
- .run(mock(Runnable.class));
-
- verify(helper, never()).prompt(anyActivity(), any(String[].class));
- }
-
- private Activity mockActivity() {
- return mock(Activity.class);
- }
-
- private PermissionsHelper mockGrantingHelper() {
- PermissionsHelper helper = mock(PermissionsHelper.class);
- doReturn(true).when(helper).hasPermissions(any(Context.class), anyPermissions());
- return helper;
- }
-
- private PermissionsHelper mockDenyingHelper() {
- PermissionsHelper helper = mock(PermissionsHelper.class);
- doReturn(false).when(helper).hasPermissions(any(Context.class), anyPermissions());
- return helper;
- }
-
- private String anyPermissions() {
- return Matchers.anyVararg();
- }
-
- private Activity anyActivity() {
- return any(Activity.class);
- }
-
- private Context anyContext() {
- return any(Context.class);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/TestPushManager.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/TestPushManager.java
deleted file mode 100644
index 42ae0f543..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/TestPushManager.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.push;
-
-import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.gcm.GcmTokenClient;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.UUID;
-
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Matchers.isNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-@RunWith(TestRunner.class)
-public class TestPushManager {
- private PushState state;
- private GcmTokenClient gcmTokenClient;
- private PushClient pushClient;
- private PushManager manager;
-
- @Before
- public void setUp() throws Exception {
- state = new PushState(RuntimeEnvironment.application, "test.json");
- gcmTokenClient = mock(GcmTokenClient.class);
- doReturn(new Fetched("opaque-gcm-token", System.currentTimeMillis())).when(gcmTokenClient).getToken(anyString(), anyBoolean());
-
- // Configure a mock PushClient.
- pushClient = mock(PushClient.class);
- doReturn(new RegisterUserAgentResponse("opaque-uaid", "opaque-secret"))
- .when(pushClient)
- .registerUserAgent(anyString());
-
- doReturn(new SubscribeChannelResponse("opaque-chid", "https://localhost:8085/opaque-push-endpoint"))
- .when(pushClient)
- .subscribeChannel(anyString(), anyString(), isNull(String.class));
-
- PushManager.PushClientFactory pushClientFactory = mock(PushManager.PushClientFactory.class);
- doReturn(pushClient).when(pushClientFactory).getPushClient(anyString(), anyBoolean());
-
- manager = new PushManager(state, gcmTokenClient, pushClientFactory);
- }
-
- private void assertOnlyConfigured(PushRegistration registration, String endpoint, boolean debug) {
- Assert.assertNotNull(registration);
- Assert.assertEquals(registration.autopushEndpoint, endpoint);
- Assert.assertEquals(registration.debug, debug);
- Assert.assertNull(registration.uaid.value);
- }
-
- private void assertRegistered(PushRegistration registration, String endpoint, boolean debug) {
- Assert.assertNotNull(registration);
- Assert.assertEquals(registration.autopushEndpoint, endpoint);
- Assert.assertEquals(registration.debug, debug);
- Assert.assertNotNull(registration.uaid.value);
- }
-
- private void assertSubscribed(PushSubscription subscription) {
- Assert.assertNotNull(subscription);
- Assert.assertNotNull(subscription.chid);
- }
-
- @Test
- public void testConfigure() throws Exception {
- PushRegistration registration = manager.configure("default", "http://localhost:8081", false, System.currentTimeMillis());
- assertOnlyConfigured(registration, "http://localhost:8081", false);
-
- registration = manager.configure("default", "http://localhost:8082", true, System.currentTimeMillis());
- assertOnlyConfigured(registration, "http://localhost:8082", true);
- }
-
- @Test(expected=PushManager.ProfileNeedsConfigurationException.class)
- public void testRegisterBeforeConfigure() throws Exception {
- PushRegistration registration = state.getRegistration("default");
- Assert.assertNull(registration);
-
- // Trying to register a User Agent fails before configuration.
- manager.registerUserAgent("default", System.currentTimeMillis());
- }
-
- @Test
- public void testRegister() throws Exception {
- PushRegistration registration = manager.configure("default", "http://localhost:8082", false, System.currentTimeMillis());
- assertOnlyConfigured(registration, "http://localhost:8082", false);
-
- // Let's register a User Agent, so that we can witness unregistration.
- registration = manager.registerUserAgent("default", System.currentTimeMillis());
- assertRegistered(registration, "http://localhost:8082", false);
-
- // Changing the debug flag should update but not try to unregister the User Agent.
- registration = manager.configure("default", "http://localhost:8082", true, System.currentTimeMillis());
- assertRegistered(registration, "http://localhost:8082", true);
-
- // Changing the configuration endpoint should update and try to unregister the User Agent.
- registration = manager.configure("default", "http://localhost:8083", true, System.currentTimeMillis());
- assertOnlyConfigured(registration, "http://localhost:8083", true);
- }
-
- @Test
- public void testRegisterMultipleProfiles() throws Exception {
- PushRegistration registration1 = manager.configure("default1", "http://localhost:8081", true, System.currentTimeMillis());
- PushRegistration registration2 = manager.configure("default2", "http://localhost:8082", true, System.currentTimeMillis());
- assertOnlyConfigured(registration1, "http://localhost:8081", true);
- assertOnlyConfigured(registration2, "http://localhost:8082", true);
- verify(gcmTokenClient, times(0)).getToken(anyString(), anyBoolean());
-
- registration1 = manager.registerUserAgent("default1", System.currentTimeMillis());
- assertRegistered(registration1, "http://localhost:8081", true);
-
- registration2 = manager.registerUserAgent("default2", System.currentTimeMillis());
- assertRegistered(registration2, "http://localhost:8082", true);
-
- // Just the debug flag should not unregister the User Agent.
- registration1 = manager.configure("default1", "http://localhost:8081", false, System.currentTimeMillis());
- assertRegistered(registration1, "http://localhost:8081", false);
-
- // But the configuration endpoint should unregister the correct User Agent.
- registration2 = manager.configure("default2", "http://localhost:8083", false, System.currentTimeMillis());
- }
-
- @Test
- public void testSubscribeChannel() throws Exception {
- manager.configure("default", "http://localhost:8080", false, System.currentTimeMillis());
- PushRegistration registration = manager.registerUserAgent("default", System.currentTimeMillis());
- assertRegistered(registration, "http://localhost:8080", false);
-
- // We should be able to register with non-null serviceData.
- final JSONObject webpushData = new JSONObject();
- webpushData.put("version", 5);
- PushSubscription subscription = manager.subscribeChannel("default", "webpush", webpushData, null, System.currentTimeMillis());
- assertSubscribed(subscription);
-
- subscription = manager.registrationForSubscription(subscription.chid).getSubscription(subscription.chid);
- Assert.assertNotNull(subscription);
- Assert.assertEquals(5, subscription.serviceData.get("version"));
-
- // We should be able to register with null serviceData.
- subscription = manager.subscribeChannel("default", "sync", null, null, System.currentTimeMillis());
- assertSubscribed(subscription);
-
- subscription = manager.registrationForSubscription(subscription.chid).getSubscription(subscription.chid);
- Assert.assertNotNull(subscription);
- Assert.assertNull(subscription.serviceData);
- }
-
- @Test
- public void testUnsubscribeChannel() throws Exception {
- manager.configure("default", "http://localhost:8080", false, System.currentTimeMillis());
- PushRegistration registration = manager.registerUserAgent("default", System.currentTimeMillis());
- assertRegistered(registration, "http://localhost:8080", false);
-
- // We should be able to register with non-null serviceData.
- final JSONObject webpushData = new JSONObject();
- webpushData.put("version", 5);
- PushSubscription subscription = manager.subscribeChannel("default", "webpush", webpushData, null, System.currentTimeMillis());
- assertSubscribed(subscription);
-
- // No exception is success.
- manager.unsubscribeChannel(subscription.chid);
- }
-
- public void testUnsubscribeUnknownChannel() throws Exception {
- manager.configure("default", "http://localhost:8080", false, System.currentTimeMillis());
- PushRegistration registration = manager.registerUserAgent("default", System.currentTimeMillis());
- assertRegistered(registration, "http://localhost:8080", false);
-
- doThrow(new RuntimeException())
- .when(pushClient)
- .unsubscribeChannel(anyString(), anyString(), anyString());
-
- // Un-subscribing from an unknown channel succeeds: we just ignore the request.
- manager.unsubscribeChannel(UUID.randomUUID().toString());
- }
-
- @Test
- public void testStartupBeforeConfiguration() throws Exception {
- verify(gcmTokenClient, never()).getToken(anyString(), anyBoolean());
- manager.startup(System.currentTimeMillis());
- verify(gcmTokenClient, times(1)).getToken(AppConstants.MOZ_ANDROID_GCM_SENDERID, false);
- }
-
- @Test
- public void testStartupBeforeRegistration() throws Exception {
- PushRegistration registration = manager.configure("default", "http://localhost:8080", true, System.currentTimeMillis());
- assertOnlyConfigured(registration, "http://localhost:8080", true);
-
- manager.startup(System.currentTimeMillis());
- verify(gcmTokenClient, times(1)).getToken(anyString(), anyBoolean());
- }
-
- @Test
- public void testStartupAfterRegistration() throws Exception {
- PushRegistration registration = manager.configure("default", "http://localhost:8080", true, System.currentTimeMillis());
- assertOnlyConfigured(registration, "http://localhost:8080", true);
-
- registration = manager.registerUserAgent("default", System.currentTimeMillis());
- assertRegistered(registration, "http://localhost:8080", true);
-
- manager.startup(System.currentTimeMillis());
-
- // Rather tautological.
- PushRegistration updatedRegistration = manager.state.getRegistration("default");
- Assert.assertEquals(registration.uaid, updatedRegistration.uaid);
- }
-
- @Test
- public void testStartupAfterSubscription() throws Exception {
- PushRegistration registration = manager.configure("default", "http://localhost:8080", true, System.currentTimeMillis());
- assertOnlyConfigured(registration, "http://localhost:8080", true);
-
- registration = manager.registerUserAgent("default", System.currentTimeMillis());
- assertRegistered(registration, "http://localhost:8080", true);
-
- PushSubscription subscription = manager.subscribeChannel("default", "webpush", null, null, System.currentTimeMillis());
- assertSubscribed(subscription);
-
- manager.startup(System.currentTimeMillis());
-
- // Rather tautological.
- registration = manager.registrationForSubscription(subscription.chid);
- PushSubscription updatedSubscription = registration.getSubscription(subscription.chid);
- Assert.assertEquals(subscription.chid, updatedSubscription.chid);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/TestPushState.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/TestPushState.java
deleted file mode 100644
index cb7c7ec68..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/TestPushState.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.push;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.io.File;
-import java.io.FileOutputStream;
-
-@RunWith(TestRunner.class)
-public class TestPushState {
- @Test
- public void testRoundTrip() throws Exception {
- final PushState state = new PushState(RuntimeEnvironment.application, "test.json");
- // Fresh state should have no registrations (and no subscriptions).
- Assert.assertTrue(state.registrations.isEmpty());
-
- final PushRegistration registration = new PushRegistration("endpoint", true, Fetched.now("uaid"), "secret");
- final PushSubscription subscription = new PushSubscription("chid", "profileName", "webpushEndpoint", "service", null);
- registration.putSubscription("chid", subscription);
- state.putRegistration("profileName", registration);
- Assert.assertEquals(1, state.registrations.size());
- state.checkpoint();
-
- final PushState readState = new PushState(RuntimeEnvironment.application, "test.json");
- Assert.assertEquals(1, readState.registrations.size());
- final PushRegistration storedRegistration = readState.getRegistration("profileName");
- Assert.assertEquals(registration, storedRegistration);
-
- Assert.assertEquals(1, storedRegistration.subscriptions.size());
- final PushSubscription storedSubscription = storedRegistration.getSubscription("chid");
- Assert.assertEquals(subscription, storedSubscription);
- }
-
- @Test
- public void testMissingRegistration() throws Exception {
- final PushState state = new PushState(RuntimeEnvironment.application, "testMissingRegistration.json");
- Assert.assertNull(state.getRegistration("missingProfileName"));
- }
-
- @Test
- public void testMissingSubscription() throws Exception {
- final PushRegistration registration = new PushRegistration("endpoint", true, Fetched.now("uaid"), "secret");
- Assert.assertNull(registration.getSubscription("missingChid"));
- }
-
- @Test
- public void testCorruptedJSON() throws Exception {
- // Write some malformed JSON.
- // TODO: use mcomella's helpers!
- final File file = new File(RuntimeEnvironment.application.getApplicationInfo().dataDir, "testCorruptedJSON.json");
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(file);
- fos.write("}".getBytes("UTF-8"));
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
-
- final PushState state = new PushState(RuntimeEnvironment.application, "testCorruptedJSON.json");
- Assert.assertTrue(state.getRegistrations().isEmpty());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/autopush/test/TestAutopushClient.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/autopush/test/TestAutopushClient.java
deleted file mode 100644
index 93e0d14e5..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/autopush/test/TestAutopushClient.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.push.autopush.test;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.push.autopush.AutopushClient;
-import org.mozilla.gecko.push.autopush.AutopushClientException;
-import org.mozilla.gecko.sync.Utils;
-
-@RunWith(TestRunner.class)
-public class TestAutopushClient {
- @Test
- public void testGetSenderID() throws Exception {
- final AutopushClient client = new AutopushClient("https://updates-autopush-dev.stage.mozaws.net/v1/gcm/829133274407",
- Utils.newSynchronousExecutor());
- Assert.assertEquals("829133274407", client.getSenderIDFromServerURI());
- }
-
- @Test(expected=AutopushClientException.class)
- public void testGetNoSenderID() throws Exception {
- final AutopushClient client = new AutopushClient("https://updates-autopush-dev.stage.mozaws.net/v1/gcm",
- Utils.newSynchronousExecutor());
- client.getSenderIDFromServerURI();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/autopush/test/TestLiveAutopushClient.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/autopush/test/TestLiveAutopushClient.java
deleted file mode 100644
index 102ea34e4..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/push/autopush/test/TestLiveAutopushClient.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.push.autopush.test;
-
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.PublicKey;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.fxa.FxAccountUtils;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.push.RegisterUserAgentResponse;
-import org.mozilla.gecko.push.SubscribeChannelResponse;
-import org.mozilla.gecko.push.autopush.AutopushClient;
-import org.mozilla.gecko.push.autopush.AutopushClient.RequestDelegate;
-import org.mozilla.gecko.push.autopush.AutopushClientException;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.net.BaseResource;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.CoreMatchers.startsWith;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-/**
- * This test straddles an awkward line: it uses Mockito, but doesn't actually mock the service
- * endpoint. That's why it's a <b>live</b> test: most of its value is checking that the client
- * implementation and the upstream server implementation are corresponding correctly.
- */
-@RunWith(TestRunner.class)
-@Ignore("Live test that requires network connection -- remove this line to run this test.")
-public class TestLiveAutopushClient {
- final String serverURL = "https://updates-autopush.stage.mozaws.net/v1/gcm/829133274407";
-
- protected AutopushClient client;
-
- @Before
- public void setUp() throws Exception {
- BaseResource.rewriteLocalhost = false;
- client = new AutopushClient(serverURL, Utils.newSynchronousExecutor());
- }
-
- protected <T> T assertSuccess(RequestDelegate<T> delegate, Class<T> klass) {
- verify(delegate, never()).handleError(any(Exception.class));
- verify(delegate, never()).handleFailure(any(AutopushClientException.class));
-
- final ArgumentCaptor<T> register = ArgumentCaptor.forClass(klass);
- verify(delegate).handleSuccess(register.capture());
-
- return register.getValue();
- }
-
- protected <T> AutopushClientException assertFailure(RequestDelegate<T> delegate, Class<T> klass) {
- verify(delegate, never()).handleError(any(Exception.class));
- verify(delegate, never()).handleSuccess(any(klass));
-
- final ArgumentCaptor<AutopushClientException> failure = ArgumentCaptor.forClass(AutopushClientException.class);
- verify(delegate).handleFailure(failure.capture());
-
- return failure.getValue();
- }
-
- @Test
- public void testUserAgent() throws Exception {
- final RequestDelegate<RegisterUserAgentResponse> registerDelegate = mock(RequestDelegate.class);
- client.registerUserAgent(Utils.generateGuid(), registerDelegate);
-
- final RegisterUserAgentResponse registerResponse = assertSuccess(registerDelegate, RegisterUserAgentResponse.class);
- Assert.assertNotNull(registerResponse);
- Assert.assertNotNull(registerResponse.uaid);
- Assert.assertNotNull(registerResponse.secret);
-
- // Reregistering with a new GUID should succeed.
- final RequestDelegate<Void> reregisterDelegate = mock(RequestDelegate.class);
- client.reregisterUserAgent(registerResponse.uaid, registerResponse.secret, Utils.generateGuid(), reregisterDelegate);
-
- Assert.assertNull(assertSuccess(reregisterDelegate, Void.class));
-
- // Unregistering should succeed.
- final RequestDelegate<Void> unregisterDelegate = mock(RequestDelegate.class);
- client.unregisterUserAgent(registerResponse.uaid, registerResponse.secret, unregisterDelegate);
-
- Assert.assertNull(assertSuccess(unregisterDelegate, Void.class));
-
- // Trying to unregister a second time should give a 404.
- final RequestDelegate<Void> reunregisterDelegate = mock(RequestDelegate.class);
- client.unregisterUserAgent(registerResponse.uaid, registerResponse.secret, reunregisterDelegate);
-
- final AutopushClientException failureException = assertFailure(reunregisterDelegate, Void.class);
- Assert.assertThat(failureException, instanceOf(AutopushClientException.AutopushClientRemoteException.class));
- Assert.assertTrue(((AutopushClientException.AutopushClientRemoteException) failureException).isGone());
- }
-
- @Test
- public void testChannel() throws Exception {
- final RequestDelegate<RegisterUserAgentResponse> registerDelegate = mock(RequestDelegate.class);
- client.registerUserAgent(Utils.generateGuid(), registerDelegate);
-
- final RegisterUserAgentResponse registerResponse = assertSuccess(registerDelegate, RegisterUserAgentResponse.class);
- Assert.assertNotNull(registerResponse);
- Assert.assertNotNull(registerResponse.uaid);
- Assert.assertNotNull(registerResponse.secret);
-
- // We should be able to subscribe to a channel.
- final RequestDelegate<SubscribeChannelResponse> subscribeDelegate = mock(RequestDelegate.class);
- client.subscribeChannel(registerResponse.uaid, registerResponse.secret, null, subscribeDelegate);
-
- final SubscribeChannelResponse subscribeResponse = assertSuccess(subscribeDelegate, SubscribeChannelResponse.class);
- Assert.assertNotNull(subscribeResponse);
- Assert.assertNotNull(subscribeResponse.channelID);
- Assert.assertNotNull(subscribeResponse.endpoint);
- Assert.assertThat(subscribeResponse.endpoint, startsWith(FxAccountUtils.getAudienceForURL(serverURL)));
- Assert.assertThat(subscribeResponse.endpoint, containsString("/v1/"));
-
- // And we should be able to unsubscribe.
- final RequestDelegate<Void> unsubscribeDelegate = mock(RequestDelegate.class);
- client.unsubscribeChannel(registerResponse.uaid, registerResponse.secret, subscribeResponse.channelID, unsubscribeDelegate);
-
- Assert.assertNull(assertSuccess(unsubscribeDelegate, Void.class));
-
- // We should be able to create a restricted subscription by specifying
- // an ECDSA public key using the P-256 curve.
- final RequestDelegate<SubscribeChannelResponse> subscribeWithKeyDelegate = mock(RequestDelegate.class);
- final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA");
- keyPairGenerator.initialize(256);
- final KeyPair keyPair = keyPairGenerator.generateKeyPair();
- final PublicKey publicKey = keyPair.getPublic();
- String appServerKey = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
- client.subscribeChannel(registerResponse.uaid, registerResponse.secret, appServerKey, subscribeWithKeyDelegate);
-
- final SubscribeChannelResponse subscribeWithKeyResponse = assertSuccess(subscribeWithKeyDelegate, SubscribeChannelResponse.class);
- Assert.assertNotNull(subscribeWithKeyResponse);
- Assert.assertNotNull(subscribeWithKeyResponse.channelID);
- Assert.assertNotNull(subscribeWithKeyResponse.endpoint);
- Assert.assertThat(subscribeWithKeyResponse.endpoint, startsWith(FxAccountUtils.getAudienceForURL(serverURL)));
- Assert.assertThat(subscribeWithKeyResponse.endpoint, containsString("/v2/"));
-
- // And we should be able to drop the restricted subscription.
- final RequestDelegate<Void> unsubscribeWithKeyDelegate = mock(RequestDelegate.class);
- client.unsubscribeChannel(registerResponse.uaid, registerResponse.secret, subscribeWithKeyResponse.channelID, unsubscribeWithKeyDelegate);
-
- Assert.assertNull(assertSuccess(unsubscribeWithKeyDelegate, Void.class));
-
- // Trying to unsubscribe a second time should give a 410.
- final RequestDelegate<Void> reunsubscribeDelegate = mock(RequestDelegate.class);
- client.unsubscribeChannel(registerResponse.uaid, registerResponse.secret, subscribeResponse.channelID, reunsubscribeDelegate);
-
- final AutopushClientException reunsubscribeFailureException = assertFailure(reunsubscribeDelegate, Void.class);
- Assert.assertThat(reunsubscribeFailureException, instanceOf(AutopushClientException.AutopushClientRemoteException.class));
- Assert.assertTrue(((AutopushClientException.AutopushClientRemoteException) reunsubscribeFailureException).isGone());
-
- // Trying to unsubscribe from a non-existent channel should give a 404. Right now it gives a 401!
- final RequestDelegate<Void> badUnsubscribeDelegate = mock(RequestDelegate.class);
- client.unsubscribeChannel(registerResponse.uaid + "BAD", registerResponse.secret, subscribeResponse.channelID, badUnsubscribeDelegate);
-
- final AutopushClientException badUnsubscribeFailureException = assertFailure(badUnsubscribeDelegate, Void.class);
- Assert.assertThat(badUnsubscribeFailureException, instanceOf(AutopushClientException.AutopushClientRemoteException.class));
- Assert.assertTrue(((AutopushClientException.AutopushClientRemoteException) badUnsubscribeFailureException).isInvalidAuthentication());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestBase32.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestBase32.java
deleted file mode 100644
index 7047d67d3..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestBase32.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.crypto.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.apache.commons.codec.binary.Base32;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.Utils;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestBase32 {
-
- public static void assertSame(byte[] arrayOne, byte[] arrayTwo) {
- assertTrue(Arrays.equals(arrayOne, arrayTwo));
- }
-
- @Test
- public void testBase32() throws UnsupportedEncodingException {
- byte[] decoded = new Base32().decode("MZXW6YTBOI======");
- byte[] expected = "foobar".getBytes();
- assertSame(decoded, expected);
-
- byte[] encoded = new Base32().encode("fooba".getBytes());
- expected = "MZXW6YTB".getBytes();
- assertSame(encoded, expected);
- }
-
- @Test
- public void testFriendlyBase32() {
- // These checks are drawn from Firefox, test_utils_encodeBase32.js.
- byte[] decoded = Utils.decodeFriendlyBase32("mzxw6ytb9jrgcztpn5rgc4tcme");
- byte[] expected = "foobarbafoobarba".getBytes();
- assertEquals(decoded.length, 16);
- assertSame(decoded, expected);
-
- // These are real values extracted from the Service object in a Firefox profile.
- String base32Key = "6m8mv8ex2brqnrmsb9fjuvfg7y";
- String expectedHex = "f316caac97d06306c5920b8a9a54a6fe";
-
- byte[] computedBytes = Utils.decodeFriendlyBase32(base32Key);
- byte[] expectedBytes = Utils.hex2Byte(expectedHex);
-
- assertSame(computedBytes, expectedBytes);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java
deleted file mode 100644
index 3e8d90e2f..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.crypto.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.CryptoInfo;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-
-import java.io.UnsupportedEncodingException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestCryptoInfo {
-
- @Test
- public void testEncryptedHMACIsSet() throws CryptoException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException {
- KeyBundle kb = KeyBundle.withRandomKeys();
- CryptoInfo encrypted = CryptoInfo.encrypt("plaintext".getBytes("UTF-8"), kb);
- assertSame(kb, encrypted.getKeys());
- assertTrue(encrypted.generatedHMACIsHMAC());
- }
-
- @Test
- public void testRandomEncryptedDecrypted() throws CryptoException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException {
- KeyBundle kb = KeyBundle.withRandomKeys();
- byte[] plaintext = "plaintext".getBytes("UTF-8");
- CryptoInfo info = CryptoInfo.encrypt(plaintext, kb);
- byte[] iv = info.getIV();
- info.decrypt();
- assertArrayEquals(plaintext, info.getMessage());
- assertSame(null, info.getHMAC());
- assertArrayEquals(iv, info.getIV());
- assertSame(kb, info.getKeys());
- }
-
- @Test
- public void testDecrypt() throws CryptoException {
- String base64CipherText = "NMsdnRulLwQsVcwxKW9XwaUe7ouJk5Wn" +
- "80QhbD80l0HEcZGCynh45qIbeYBik0lg" +
- "cHbKmlIxTJNwU+OeqipN+/j7MqhjKOGI" +
- "lvbpiPQQLC6/ffF2vbzL0nzMUuSyvaQz" +
- "yGGkSYM2xUFt06aNivoQTvU2GgGmUK6M" +
- "vadoY38hhW2LCMkoZcNfgCqJ26lO1O0s" +
- "EO6zHsk3IVz6vsKiJ2Hq6VCo7hu123wN" +
- "egmujHWQSGyf8JeudZjKzfi0OFRRvvm4" +
- "QAKyBWf0MgrW1F8SFDnVfkq8amCB7Nhd" +
- "whgLWbN+21NitNwWYknoEWe1m6hmGZDg" +
- "DT32uxzWxCV8QqqrpH/ZggViEr9uMgoy" +
- "4lYaWqP7G5WKvvechc62aqnsNEYhH26A" +
- "5QgzmlNyvB+KPFvPsYzxDnSCjOoRSLx7" +
- "GG86wT59QZw=";
- String base64IV = "GX8L37AAb2FZJMzIoXlX8w==";
- String base16Hmac = "b1e6c18ac30deb70236bc0d65a46f7a4" +
- "dce3b8b0e02cf92182b914e3afa5eebc";
- String base64EncryptionKey = "9K/wLdXdw+nrTtXo4ZpECyHFNr4d7aYH" +
- "qeg3KW9+m6Q=";
- String base64HmacKey = "MMntEfutgLTc8FlTLQFms8/xMPmCldqP" +
- "lq/QQXEjx70=";
- String base64ExpectedBytes = "eyJpZCI6IjVxUnNnWFdSSlpYciIsImhp" +
- "c3RVcmkiOiJmaWxlOi8vL1VzZXJzL2ph" +
- "c29uL0xpYnJhcnkvQXBwbGljYXRpb24l" +
- "MjBTdXBwb3J0L0ZpcmVmb3gvUHJvZmls" +
- "ZXMva3NnZDd3cGsuTG9jYWxTeW5jU2Vy" +
- "dmVyL3dlYXZlL2xvZ3MvIiwidGl0bGUi" +
- "OiJJbmRleCBvZiBmaWxlOi8vL1VzZXJz" +
- "L2phc29uL0xpYnJhcnkvQXBwbGljYXRp" +
- "b24gU3VwcG9ydC9GaXJlZm94L1Byb2Zp" +
- "bGVzL2tzZ2Q3d3BrLkxvY2FsU3luY1Nl" +
- "cnZlci93ZWF2ZS9sb2dzLyIsInZpc2l0" +
- "cyI6W3siZGF0ZSI6MTMxOTE0OTAxMjM3" +
- "MjQyNSwidHlwZSI6MX1dfQ==";
-
- CryptoInfo decrypted = CryptoInfo.decrypt(
- Base64.decodeBase64(base64CipherText),
- Base64.decodeBase64(base64IV),
- Utils.hex2Byte(base16Hmac),
- new KeyBundle(
- Base64.decodeBase64(base64EncryptionKey),
- Base64.decodeBase64(base64HmacKey))
- );
-
- assertArrayEquals(decrypted.getMessage(), Base64.decodeBase64(base64ExpectedBytes));
- }
-
- @Test
- public void testEncrypt() throws CryptoException {
- String base64CipherText = "NMsdnRulLwQsVcwxKW9XwaUe7ouJk5Wn" +
- "80QhbD80l0HEcZGCynh45qIbeYBik0lg" +
- "cHbKmlIxTJNwU+OeqipN+/j7MqhjKOGI" +
- "lvbpiPQQLC6/ffF2vbzL0nzMUuSyvaQz" +
- "yGGkSYM2xUFt06aNivoQTvU2GgGmUK6M" +
- "vadoY38hhW2LCMkoZcNfgCqJ26lO1O0s" +
- "EO6zHsk3IVz6vsKiJ2Hq6VCo7hu123wN" +
- "egmujHWQSGyf8JeudZjKzfi0OFRRvvm4" +
- "QAKyBWf0MgrW1F8SFDnVfkq8amCB7Nhd" +
- "whgLWbN+21NitNwWYknoEWe1m6hmGZDg" +
- "DT32uxzWxCV8QqqrpH/ZggViEr9uMgoy" +
- "4lYaWqP7G5WKvvechc62aqnsNEYhH26A" +
- "5QgzmlNyvB+KPFvPsYzxDnSCjOoRSLx7" +
- "GG86wT59QZw=";
- String base64IV = "GX8L37AAb2FZJMzIoXlX8w==";
- String base16Hmac = "b1e6c18ac30deb70236bc0d65a46f7a4" +
- "dce3b8b0e02cf92182b914e3afa5eebc";
- String base64EncryptionKey = "9K/wLdXdw+nrTtXo4ZpECyHFNr4d7aYH" +
- "qeg3KW9+m6Q=";
- String base64HmacKey = "MMntEfutgLTc8FlTLQFms8/xMPmCldqP" +
- "lq/QQXEjx70=";
- String base64ExpectedBytes = "eyJpZCI6IjVxUnNnWFdSSlpYciIsImhp" +
- "c3RVcmkiOiJmaWxlOi8vL1VzZXJzL2ph" +
- "c29uL0xpYnJhcnkvQXBwbGljYXRpb24l" +
- "MjBTdXBwb3J0L0ZpcmVmb3gvUHJvZmls" +
- "ZXMva3NnZDd3cGsuTG9jYWxTeW5jU2Vy" +
- "dmVyL3dlYXZlL2xvZ3MvIiwidGl0bGUi" +
- "OiJJbmRleCBvZiBmaWxlOi8vL1VzZXJz" +
- "L2phc29uL0xpYnJhcnkvQXBwbGljYXRp" +
- "b24gU3VwcG9ydC9GaXJlZm94L1Byb2Zp" +
- "bGVzL2tzZ2Q3d3BrLkxvY2FsU3luY1Nl" +
- "cnZlci93ZWF2ZS9sb2dzLyIsInZpc2l0" +
- "cyI6W3siZGF0ZSI6MTMxOTE0OTAxMjM3" +
- "MjQyNSwidHlwZSI6MX1dfQ==";
-
- CryptoInfo encrypted = CryptoInfo.encrypt(
- Base64.decodeBase64(base64ExpectedBytes),
- Base64.decodeBase64(base64IV),
- new KeyBundle(
- Base64.decodeBase64(base64EncryptionKey),
- Base64.decodeBase64(base64HmacKey))
- );
-
- assertArrayEquals(Base64.decodeBase64(base64CipherText), encrypted.getMessage());
- assertArrayEquals(Utils.hex2Byte(base16Hmac), encrypted.getHMAC());
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestHKDF.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestHKDF.java
deleted file mode 100644
index 09973eeff..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestHKDF.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.crypto.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.HKDF;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-
-import java.util.Arrays;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-/*
- * This class tests the HKDF.java class.
- * The tests are the 3 HMAC-based test cases
- * from the RFC 5869 specification.
- */
-@RunWith(TestRunner.class)
-public class TestHKDF {
- @Test
- public void testCase1() {
- String IKM = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
- String salt = "000102030405060708090a0b0c";
- String info = "f0f1f2f3f4f5f6f7f8f9";
- int L = 42;
- String PRK = "077709362c2e32df0ddc3f0dc47bba63" +
- "90b6c73bb50f9c3122ec844ad7c2b3e5";
- String OKM = "3cb25f25faacd57a90434f64d0362f2a" +
- "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" +
- "34007208d5b887185865";
-
- assertTrue(doStep1(IKM, salt, PRK));
- assertTrue(doStep2(PRK, info, L, OKM));
- }
-
- @Test
- public void testCase2() {
- String IKM = "000102030405060708090a0b0c0d0e0f" +
- "101112131415161718191a1b1c1d1e1f" +
- "202122232425262728292a2b2c2d2e2f" +
- "303132333435363738393a3b3c3d3e3f" +
- "404142434445464748494a4b4c4d4e4f";
- String salt = "606162636465666768696a6b6c6d6e6f" +
- "707172737475767778797a7b7c7d7e7f" +
- "808182838485868788898a8b8c8d8e8f" +
- "909192939495969798999a9b9c9d9e9f" +
- "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf";
- String info = "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" +
- "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" +
- "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" +
- "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" +
- "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
- int L = 82;
- String PRK = "06a6b88c5853361a06104c9ceb35b45c" +
- "ef760014904671014a193f40c15fc244";
- String OKM = "b11e398dc80327a1c8e7f78c596a4934" +
- "4f012eda2d4efad8a050cc4c19afa97c" +
- "59045a99cac7827271cb41c65e590e09" +
- "da3275600c2f09b8367793a9aca3db71" +
- "cc30c58179ec3e87c14c01d5c1f3434f" +
- "1d87";
-
- assertTrue(doStep1(IKM, salt, PRK));
- assertTrue(doStep2(PRK, info, L, OKM));
- }
-
- @Test
- public void testCase3() {
- String IKM = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
- String salt = "";
- String info = "";
- int L = 42;
- String PRK = "19ef24a32c717b167f33a91d6f648bdf" +
- "96596776afdb6377ac434c1c293ccb04";
- String OKM = "8da4e775a563c18f715f802a063c5a31" +
- "b8a11f5c5ee1879ec3454e5f3c738d2d" +
- "9d201395faa4b61a96c8";
-
- assertTrue(doStep1(IKM, salt, PRK));
- assertTrue(doStep2(PRK, info, L, OKM));
- }
-
- /*
- * Tests the code for getting the keys necessary to
- * decrypt the crypto keys bundle for Mozilla Sync.
- *
- * This operation is just a tailored version of the
- * standard to get only the 2 keys we need.
- */
- @Test
- public void testGetCryptoKeysBundleKeys() {
- String username = "smqvooxj664hmrkrv6bw4r4vkegjhkns";
- String friendlyBase32SyncKey = "gbh7teqqcgyzd65svjgibd7tqy";
- String base64EncryptionKey = "069EnS3EtDK4y1tZ1AyKX+U7WEsWRp9bRIKLdW/7aoE=";
- String base64HmacKey = "LF2YCS1QCgSNCf0BCQvQ06SGH8jqJDi9dKj0O+b0fwI=";
-
- KeyBundle bundle = null;
- try {
- bundle = new KeyBundle(username, friendlyBase32SyncKey);
- } catch (Exception e) {
- fail("Unexpected exception " + e);
- }
-
- byte[] expectedEncryptionKey = Base64.decodeBase64(base64EncryptionKey);
- byte[] expectedHMACKey = Base64.decodeBase64(base64HmacKey);
- assertTrue(Arrays.equals(bundle.getEncryptionKey(), expectedEncryptionKey));
- assertTrue(Arrays.equals(bundle.getHMACKey(), expectedHMACKey));
- }
-
- /*
- * Helper to do step 1 of RFC 5869.
- */
- private boolean doStep1(String IKM, String salt, String PRK) {
- try {
- byte[] prkResult = HKDF.hkdfExtract(Utils.hex2Byte(salt), Utils.hex2Byte(IKM));
- byte[] prkExpect = Utils.hex2Byte(PRK);
- return Arrays.equals(prkResult, prkExpect);
- } catch (Exception e) {
- fail("Unexpected exception " + e);
- }
- return false;
- }
-
- /*
- * Helper to do step 2 of RFC 5869.
- */
- private boolean doStep2(String PRK, String info, int L, String OKM) {
- try {
- byte[] okmResult = HKDF.hkdfExpand(Utils.hex2Byte(PRK), Utils.hex2Byte(info), L);
- byte[] okmExpect = Utils.hex2Byte(OKM);
- return Arrays.equals(okmResult, okmExpect);
- } catch (Exception e) {
- fail("Unexpected exception " + e);
- }
- return false;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java
deleted file mode 100644
index 3c3edb9f8..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.crypto.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestKeyBundle {
- @Test
- public void testCreateKeyBundle() throws UnsupportedEncodingException, CryptoException {
- String username = "smqvooxj664hmrkrv6bw4r4vkegjhkns";
- String friendlyBase32SyncKey = "gbh7teqqcgyzd65svjgibd7tqy";
- String base64EncryptionKey = "069EnS3EtDK4y1tZ1AyKX+U7WEsWRp9b" +
- "RIKLdW/7aoE=";
- String base64HmacKey = "LF2YCS1QCgSNCf0BCQvQ06SGH8jqJDi9" +
- "dKj0O+b0fwI=";
-
- KeyBundle keys = new KeyBundle(username, friendlyBase32SyncKey);
- assertArrayEquals(keys.getEncryptionKey(), Base64.decodeBase64(base64EncryptionKey.getBytes("UTF-8")));
- assertArrayEquals(keys.getHMACKey(), Base64.decodeBase64(base64HmacKey.getBytes("UTF-8")));
- }
-
- /*
- * Basic sanity check to make sure length of keys is correct (32 bytes).
- * Also make sure that the two keys are different.
- */
- @Test
- public void testGenerateRandomKeys() throws CryptoException {
- KeyBundle keys = KeyBundle.withRandomKeys();
-
- assertEquals(32, keys.getEncryptionKey().length);
- assertEquals(32, keys.getHMACKey().length);
-
- boolean equal = Arrays.equals(keys.getEncryptionKey(), keys.getHMACKey());
- assertEquals(false, equal);
- }
-
- @Test
- public void testEquals() throws CryptoException {
- KeyBundle k = KeyBundle.withRandomKeys();
- KeyBundle o = KeyBundle.withRandomKeys();
- assertFalse(k.equals("test"));
- assertFalse(k.equals(o));
- assertTrue(k.equals(k));
- assertTrue(o.equals(o));
- o.setHMACKey(k.getHMACKey());
- assertFalse(o.equals(k));
- o.setEncryptionKey(k.getEncryptionKey());
- assertTrue(o.equals(k));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestPBKDF2.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestPBKDF2.java
deleted file mode 100644
index d2d1d8271..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestPBKDF2.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.crypto.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.PBKDF2;
-
-import java.io.UnsupportedEncodingException;
-import java.security.GeneralSecurityException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Test PBKDF2 implementations against vectors from
- * <dl>
- * <dt>SHA-256</dt>
- * <dd><a href="https://github.com/ircmaxell/PHP-PasswordLib/blob/master/test/Data/Vectors/pbkdf2-draft-josefsson-sha256.test-vectors">https://github.com/ircmaxell/PHP-PasswordLib/blob/master/test/Data/Vectors/pbkdf2-draft-josefsson-sha256.test-vectors</a></dd>
- * <dd><a href="https://gitorious.org/scrypt/nettle-scrypt/blobs/37c0d5288e991604fe33dba2f1724986a8dddf56/testsuite/pbkdf2-test.c">https://gitorious.org/scrypt/nettle-scrypt/blobs/37c0d5288e991604fe33dba2f1724986a8dddf56/testsuite/pbkdf2-test.c</a></dd>
- * </dl>
- */
-@RunWith(TestRunner.class)
-public class TestPBKDF2 {
-
- @Test
- public final void testPBKDF2SHA256A() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "password";
- String s = "salt";
- int dkLen = 32;
-
- checkPBKDF2SHA256(p, s, 1, dkLen, "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b");
- checkPBKDF2SHA256(p, s, 4096, dkLen, "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a");
- }
-
- @Test
- public final void testPBKDF2SHA256B() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "passwordPASSWORDpassword";
- String s = "saltSALTsaltSALTsaltSALTsaltSALTsalt";
- int dkLen = 40;
-
- checkPBKDF2SHA256(p, s, 4096, dkLen, "348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9");
- }
-
- @Test
- public final void testPBKDF2SHA256scryptA() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "passwd";
- String s = "salt";
- int dkLen = 64;
-
- checkPBKDF2SHA256(p, s, 1, dkLen, "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783");
- }
-
- /*
- // This test takes eight seconds or so to run, so we don't run it.
- @Test
- public final void testPBKDF2SHA256scryptB() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "Password";
- String s = "NaCl";
- int dkLen = 64;
-
- checkPBKDF2SHA256(p, s, 80000, dkLen, "4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d");
- }
- */
-
- @Test
- public final void testPBKDF2SHA256C() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "pass\0word";
- String s = "sa\0lt";
- int dkLen = 16;
-
- checkPBKDF2SHA256(p, s, 4096, dkLen, "89b69d0516f829893c696226650a8687");
- }
-
- /*
- // This test takes two or three minutes to run, so we don't run it.
- public final void testPBKDF2SHA256D() throws UnsupportedEncodingException, GeneralSecurityException {
- String p = "password";
- String s = "salt";
- int dkLen = 32;
-
- checkPBKDF2SHA256(p, s, 16777216, dkLen, "cf81c66fe8cfc04d1f31ecb65dab4089f7f179e89b3b0bcb17ad10e3ac6eba46");
- }
- */
-
- /*
- // This test takes eight seconds or so to run, so we don't run it.
- @Test
- public final void testTimePBKDF2SHA256() throws UnsupportedEncodingException, GeneralSecurityException {
- checkPBKDF2SHA256("password", "salt", 80000, 32, null);
- }
- */
-
- private void checkPBKDF2SHA256(String p, String s, int c, int dkLen,
- final String expectedStr)
- throws GeneralSecurityException, UnsupportedEncodingException {
- long start = System.currentTimeMillis();
- byte[] key = PBKDF2.pbkdf2SHA256(p.getBytes("US-ASCII"), s.getBytes("US-ASCII"), c, dkLen);
- assertNotNull(key);
-
- long end = System.currentTimeMillis();
-
- System.err.println("SHA-256 " + c + " took " + (end - start) + "ms");
- if (expectedStr == null) {
- return;
- }
-
- assertEquals(dkLen, Utils.hex2Byte(expectedStr).length);
- assertExpectedBytes(expectedStr, key);
- }
-
- public static void assertExpectedBytes(final String expectedStr, byte[] key) {
- assertEquals(expectedStr, Utils.byte2Hex(key));
- byte[] expected = Utils.hex2Byte(expectedStr);
-
- assertEquals(expected.length, key.length);
- for (int i = 0; i < key.length; i++) {
- assertEquals(expected[i], key[i]);
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestPersistedCrypto5Keys.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestPersistedCrypto5Keys.java
deleted file mode 100644
index f5ffc5a8a..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestPersistedCrypto5Keys.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.crypto.test;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.CollectionKeys;
-import org.mozilla.gecko.sync.NoCollectionKeysSetException;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.crypto.PersistedCrypto5Keys;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-@RunWith(TestRunner.class)
-public class TestPersistedCrypto5Keys {
- MockSharedPreferences prefs = null;
-
- @Before
- public void setUp() {
- prefs = new MockSharedPreferences();
- }
-
- @Test
- public void testPersistLastModified() throws CryptoException, NoCollectionKeysSetException {
- long LAST_MODIFIED = System.currentTimeMillis();
- KeyBundle syncKeyBundle = KeyBundle.withRandomKeys();
- PersistedCrypto5Keys persisted = new PersistedCrypto5Keys(prefs, syncKeyBundle);
-
- // Test fresh start.
- assertEquals(-1, persisted.lastModified());
-
- // Test persisting.
- persisted.persistLastModified(LAST_MODIFIED);
- assertEquals(LAST_MODIFIED, persisted.lastModified());
-
- // Test clearing.
- persisted.persistLastModified(0);
- assertEquals(-1, persisted.lastModified());
- }
-
- @Test
- public void testPersistKeys() throws CryptoException, NoCollectionKeysSetException {
- KeyBundle syncKeyBundle = KeyBundle.withRandomKeys();
- KeyBundle testKeyBundle = KeyBundle.withRandomKeys();
-
- PersistedCrypto5Keys persisted = new PersistedCrypto5Keys(prefs, syncKeyBundle);
-
- // Test fresh start.
- assertNull(persisted.keys());
-
- // Test persisting.
- CollectionKeys keys = new CollectionKeys();
- keys.setDefaultKeyBundle(syncKeyBundle);
- keys.setKeyBundleForCollection("test", testKeyBundle);
- persisted.persistKeys(keys);
-
- CollectionKeys persistedKeys = persisted.keys();
- assertNotNull(persistedKeys);
- assertArrayEquals(syncKeyBundle.getEncryptionKey(), persistedKeys.defaultKeyBundle().getEncryptionKey());
- assertArrayEquals(syncKeyBundle.getHMACKey(), persistedKeys.defaultKeyBundle().getHMACKey());
- assertArrayEquals(testKeyBundle.getEncryptionKey(), persistedKeys.keyBundleForCollection("test").getEncryptionKey());
- assertArrayEquals(testKeyBundle.getHMACKey(), persistedKeys.keyBundleForCollection("test").getHMACKey());
-
- // Test clearing.
- persisted.persistKeys(null);
- assertNull(persisted.keys());
-
- // Test loading a persisted bundle with wrong syncKeyBundle.
- persisted.persistKeys(keys);
- assertNotNull(persisted.keys());
-
- persisted = new PersistedCrypto5Keys(prefs, testKeyBundle);
- assertNull(persisted.keys());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestSRPConstants.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestSRPConstants.java
deleted file mode 100644
index 9188bba24..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/crypto/test/TestSRPConstants.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.crypto.test;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.net.SRPConstants;
-
-import java.math.BigInteger;
-
-@RunWith(TestRunner.class)
-public class TestSRPConstants extends SRPConstants {
- public void assertSRPConstants(SRPConstants.Parameters params, int bitLength) {
- Assert.assertNotNull(params.g);
- Assert.assertNotNull(params.N);
- Assert.assertEquals(bitLength, bitLength);
- Assert.assertEquals(bitLength / 8, params.byteLength);
- Assert.assertEquals(bitLength / 4, params.hexLength);
- BigInteger N = params.N;
- BigInteger g = params.g;
- // Each prime N is of the form 2*q + 1, with q also prime.
- BigInteger q = N.subtract(new BigInteger("1")).divide(new BigInteger("2"));
- // Check that g is a generator: the order of g is exactly 2*q (not 2, not q).
- Assert.assertFalse(new BigInteger("1").equals(g.modPow(new BigInteger("2"), N)));
- Assert.assertFalse(new BigInteger("1").equals(g.modPow(q, N)));
- Assert.assertTrue(new BigInteger("1").equals(g.modPow((N.subtract(new BigInteger("1"))), N)));
- // Even probable primality checking is too expensive to do here.
- // Assert.assertTrue(N.isProbablePrime(3));
- // Assert.assertTrue(q.isProbablePrime(3));
- }
-
- @Test
- public void testConstants() {
- assertSRPConstants(SRPConstants._1024, 1024);
- assertSRPConstants(SRPConstants._1536, 1536);
- assertSRPConstants(SRPConstants._2048, 2048);
- assertSRPConstants(SRPConstants._3072, 3072);
- assertSRPConstants(SRPConstants._4096, 4096);
- assertSRPConstants(SRPConstants._6144, 6144);
- assertSRPConstants(SRPConstants._8192, 8192);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/middleware/test/TestCrypto5MiddlewareRepositorySession.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/middleware/test/TestCrypto5MiddlewareRepositorySession.java
deleted file mode 100644
index d38a4caf2..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/middleware/test/TestCrypto5MiddlewareRepositorySession.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.middleware.test;
-
-import junit.framework.AssertionFailedError;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionBeginDelegate;
-import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionCreationDelegate;
-import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionFetchRecordsDelegate;
-import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionFinishDelegate;
-import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositorySessionStoreDelegate;
-import org.mozilla.android.sync.test.helpers.ExpectSuccessRepositoryWipeDelegate;
-import org.mozilla.gecko.background.testhelpers.MockRecord;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WBORepository;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepository;
-import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepositorySession;
-import org.mozilla.gecko.sync.repositories.InactiveSessionException;
-import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
-import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestCrypto5MiddlewareRepositorySession {
- public static WaitHelper getTestWaiter() {
- return WaitHelper.getTestWaiter();
- }
-
- public static void performWait(Runnable runnable) {
- getTestWaiter().performWait(runnable);
- }
-
- protected static void performNotify(InactiveSessionException e) {
- final AssertionFailedError failed = new AssertionFailedError("Inactive session.");
- failed.initCause(e);
- getTestWaiter().performNotify(failed);
- }
-
- protected static void performNotify(InvalidSessionTransitionException e) {
- final AssertionFailedError failed = new AssertionFailedError("Invalid session transition.");
- failed.initCause(e);
- getTestWaiter().performNotify(failed);
- }
-
- public Runnable onThreadRunnable(Runnable runnable) {
- return WaitHelper.onThreadRunnable(runnable);
- }
-
- public WBORepository wboRepo;
- public KeyBundle keyBundle;
- public Crypto5MiddlewareRepository cmwRepo;
- public Crypto5MiddlewareRepositorySession cmwSession;
-
- @Before
- public void setUp() throws CryptoException {
- wboRepo = new WBORepository();
- keyBundle = KeyBundle.withRandomKeys();
- cmwRepo = new Crypto5MiddlewareRepository(wboRepo, keyBundle);
- cmwSession = null;
- }
-
- /**
- * Run `runnable` in performWait(... onBeginSucceeded { } ).
- *
- * The Crypto5MiddlewareRepositorySession is available in self.cmwSession.
- *
- * @param runnable
- */
- public void runInOnBeginSucceeded(final Runnable runnable) {
- final TestCrypto5MiddlewareRepositorySession self = this;
- performWait(onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- cmwRepo.createSession(new ExpectSuccessRepositorySessionCreationDelegate(getTestWaiter()) {
- @Override
- public void onSessionCreated(RepositorySession session) {
- self.cmwSession = (Crypto5MiddlewareRepositorySession)session;
- assertSame(RepositorySession.SessionStatus.UNSTARTED, cmwSession.getStatus());
-
- try {
- session.begin(new ExpectSuccessRepositorySessionBeginDelegate(getTestWaiter()) {
- @Override
- public void onBeginSucceeded(RepositorySession _session) {
- assertSame(self.cmwSession, _session);
- runnable.run();
- }
- });
- } catch (InvalidSessionTransitionException e) {
- TestCrypto5MiddlewareRepositorySession.performNotify(e);
- }
- }
- }, null);
- }
- }));
- }
-
- @Test
- /**
- * Verify that the status is actually being advanced.
- */
- public void testStatus() {
- runInOnBeginSucceeded(new Runnable() {
- @Override public void run() {
- assertSame(RepositorySession.SessionStatus.ACTIVE, cmwSession.getStatus());
- try {
- cmwSession.finish(new ExpectSuccessRepositorySessionFinishDelegate(getTestWaiter()));
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- });
- assertSame(RepositorySession.SessionStatus.DONE, cmwSession.getStatus());
- }
-
- @Test
- /**
- * Verify that wipe is actually wiping the underlying repository.
- */
- public void testWipe() {
- Record record = new MockRecord("nncdefghiaaa", "coll", System.currentTimeMillis(), false);
- wboRepo.wbos.put(record.guid, record);
- assertEquals(1, wboRepo.wbos.size());
-
- runInOnBeginSucceeded(new Runnable() {
- @Override public void run() {
- cmwSession.wipe(new ExpectSuccessRepositoryWipeDelegate(getTestWaiter()));
- }
- });
- performWait(onThreadRunnable(new Runnable() {
- @Override public void run() {
- try {
- cmwSession.finish(new ExpectSuccessRepositorySessionFinishDelegate(getTestWaiter()));
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- }));
- assertEquals(0, wboRepo.wbos.size());
- }
-
- @Test
- /**
- * Verify that store is actually writing encrypted data to the underlying repository.
- */
- public void testStoreEncrypts() throws NonObjectJSONException, CryptoException, IOException {
- final BookmarkRecord record = new BookmarkRecord("nncdefghiaaa", "coll", System.currentTimeMillis(), false);
- record.title = "unencrypted title";
-
- runInOnBeginSucceeded(new Runnable() {
- @Override public void run() {
- try {
- try {
- cmwSession.setStoreDelegate(new ExpectSuccessRepositorySessionStoreDelegate(getTestWaiter()));
- cmwSession.store(record);
- } catch (NoStoreDelegateException e) {
- getTestWaiter().performNotify(new AssertionFailedError("Should not happen."));
- }
- cmwSession.storeDone();
- cmwSession.finish(new ExpectSuccessRepositorySessionFinishDelegate(getTestWaiter()));
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- });
- assertEquals(1, wboRepo.wbos.size());
- assertTrue(wboRepo.wbos.containsKey(record.guid));
-
- Record storedRecord = wboRepo.wbos.get(record.guid);
- CryptoRecord cryptoRecord = (CryptoRecord)storedRecord;
- assertSame(cryptoRecord.keyBundle, keyBundle);
-
- cryptoRecord = cryptoRecord.decrypt();
- BookmarkRecord decryptedRecord = new BookmarkRecord();
- decryptedRecord.initFromEnvelope(cryptoRecord);
- assertEquals(record.title, decryptedRecord.title);
- }
-
- @Test
- /**
- * Verify that fetch is actually retrieving encrypted data from the underlying repository and is correctly decrypting it.
- */
- public void testFetchDecrypts() throws UnsupportedEncodingException, CryptoException {
- final BookmarkRecord record1 = new BookmarkRecord("nncdefghiaaa", "coll", System.currentTimeMillis(), false);
- record1.title = "unencrypted title";
- final BookmarkRecord record2 = new BookmarkRecord("XXXXXXXXXXXX", "coll", System.currentTimeMillis(), false);
- record2.title = "unencrypted second title";
-
- CryptoRecord encryptedRecord1 = record1.getEnvelope();
- encryptedRecord1.keyBundle = keyBundle;
- encryptedRecord1 = encryptedRecord1.encrypt();
- wboRepo.wbos.put(record1.guid, encryptedRecord1);
-
- CryptoRecord encryptedRecord2 = record2.getEnvelope();
- encryptedRecord2.keyBundle = keyBundle;
- encryptedRecord2 = encryptedRecord2.encrypt();
- wboRepo.wbos.put(record2.guid, encryptedRecord2);
-
- final ExpectSuccessRepositorySessionFetchRecordsDelegate fetchRecordsDelegate = new ExpectSuccessRepositorySessionFetchRecordsDelegate(getTestWaiter());
- runInOnBeginSucceeded(new Runnable() {
- @Override public void run() {
- try {
- cmwSession.fetch(new String[] { record1.guid }, fetchRecordsDelegate);
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- });
- performWait(onThreadRunnable(new Runnable() {
- @Override public void run() {
- try {
- cmwSession.finish(new ExpectSuccessRepositorySessionFinishDelegate(getTestWaiter()));
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- }));
-
- assertEquals(1, fetchRecordsDelegate.fetchedRecords.size());
- BookmarkRecord decryptedRecord = new BookmarkRecord();
- decryptedRecord.initFromEnvelope((CryptoRecord)fetchRecordsDelegate.fetchedRecords.get(0));
- assertEquals(record1.title, decryptedRecord.title);
- }
-
- @Test
- /**
- * Verify that fetchAll is actually retrieving encrypted data from the underlying repository and is correctly decrypting it.
- */
- public void testFetchAllDecrypts() throws UnsupportedEncodingException, CryptoException {
- final BookmarkRecord record1 = new BookmarkRecord("nncdefghiaaa", "coll", System.currentTimeMillis(), false);
- record1.title = "unencrypted title";
- final BookmarkRecord record2 = new BookmarkRecord("XXXXXXXXXXXX", "coll", System.currentTimeMillis(), false);
- record2.title = "unencrypted second title";
-
- CryptoRecord encryptedRecord1 = record1.getEnvelope();
- encryptedRecord1.keyBundle = keyBundle;
- encryptedRecord1 = encryptedRecord1.encrypt();
- wboRepo.wbos.put(record1.guid, encryptedRecord1);
-
- CryptoRecord encryptedRecord2 = record2.getEnvelope();
- encryptedRecord2.keyBundle = keyBundle;
- encryptedRecord2 = encryptedRecord2.encrypt();
- wboRepo.wbos.put(record2.guid, encryptedRecord2);
-
- final ExpectSuccessRepositorySessionFetchRecordsDelegate fetchAllRecordsDelegate = new ExpectSuccessRepositorySessionFetchRecordsDelegate(getTestWaiter());
- runInOnBeginSucceeded(new Runnable() {
- @Override public void run() {
- cmwSession.fetchAll(fetchAllRecordsDelegate);
- }
- });
- performWait(onThreadRunnable(new Runnable() {
- @Override public void run() {
- try {
- cmwSession.finish(new ExpectSuccessRepositorySessionFinishDelegate(getTestWaiter()));
- } catch (InactiveSessionException e) {
- performNotify(e);
- }
- }
- }));
-
- assertEquals(2, fetchAllRecordsDelegate.fetchedRecords.size());
- BookmarkRecord decryptedRecord1 = new BookmarkRecord();
- decryptedRecord1.initFromEnvelope((CryptoRecord)fetchAllRecordsDelegate.fetchedRecords.get(0));
- BookmarkRecord decryptedRecord2 = new BookmarkRecord();
- decryptedRecord2.initFromEnvelope((CryptoRecord)fetchAllRecordsDelegate.fetchedRecords.get(1));
-
- // We should get two different decrypted records
- assertFalse(decryptedRecord1.guid.equals(decryptedRecord2.guid));
- assertFalse(decryptedRecord1.title.equals(decryptedRecord2.title));
- // And we should know about both.
- assertTrue(record1.title.equals(decryptedRecord1.title) || record1.title.equals(decryptedRecord2.title));
- assertTrue(record2.title.equals(decryptedRecord1.title) || record2.title.equals(decryptedRecord2.title));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java
deleted file mode 100644
index 675351be9..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.net.test;
-
-import ch.boye.httpclientandroidlib.client.methods.HttpGet;
-import ch.boye.httpclientandroidlib.client.methods.HttpPost;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.net.HMACAuthHeaderProvider;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
-import static org.junit.Assert.assertEquals;
-
-@RunWith(TestRunner.class)
-public class TestHMACAuthHeaderProvider {
- // Expose a few protected static member functions as public for testing.
- protected static class LeakyHMACAuthHeaderProvider extends HMACAuthHeaderProvider {
- public LeakyHMACAuthHeaderProvider(String identifier, String key) {
- super(identifier, key);
- }
-
- public static String getRequestString(HttpUriRequest request, long timestampInSeconds, String nonce, String extra) {
- return HMACAuthHeaderProvider.getRequestString(request, timestampInSeconds, nonce, extra);
- }
-
- public static String getSignature(String requestString, String key)
- throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
- return HMACAuthHeaderProvider.getSignature(requestString, key);
- }
- }
-
- @Test
- public void testGetRequestStringSpecExample1() throws Exception {
- long timestamp = 1336363200;
- String nonceString = "dj83hs9s";
- String extra = "";
- URI uri = new URI("http://example.com/resource/1?b=1&a=2");
-
- HttpUriRequest req = new HttpGet(uri);
-
- String expected = "1336363200\n" +
- "dj83hs9s\n" +
- "GET\n" +
- "/resource/1?b=1&a=2\n" +
- "example.com\n" +
- "80\n" +
- "\n";
-
- assertEquals(expected, LeakyHMACAuthHeaderProvider.getRequestString(req, timestamp, nonceString, extra));
- }
-
- @Test
- public void testGetRequestStringSpecExample2() throws Exception {
- long timestamp = 264095;
- String nonceString = "7d8f3e4a";
- String extra = "a,b,c";
- URI uri = new URI("http://example.com/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q");
-
- HttpUriRequest req = new HttpPost(uri);
-
- String expected = "264095\n" +
- "7d8f3e4a\n" +
- "POST\n" +
- "/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q\n" +
- "example.com\n" +
- "80\n" +
- "a,b,c\n";
-
- assertEquals(expected, LeakyHMACAuthHeaderProvider.getRequestString(req, timestamp, nonceString, extra));
- }
-
- @Test
- public void testPort() throws Exception {
- long timestamp = 264095;
- String nonceString = "7d8f3e4a";
- String extra = "a,b,c";
- URI uri = new URI("http://example.com:88/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q");
-
- HttpUriRequest req = new HttpPost(uri);
-
- String expected = "264095\n" +
- "7d8f3e4a\n" +
- "POST\n" +
- "/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q\n" +
- "example.com\n" +
- "88\n" +
- "a,b,c\n";
-
- assertEquals(expected, LeakyHMACAuthHeaderProvider.getRequestString(req, timestamp, nonceString, extra));
- }
-
- @Test
- public void testHTTPS() throws Exception {
- long timestamp = 264095;
- String nonceString = "7d8f3e4a";
- String extra = "a,b,c";
- URI uri = new URI("https://example.com/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q");
-
- HttpUriRequest req = new HttpPost(uri);
-
- String expected = "264095\n" +
- "7d8f3e4a\n" +
- "POST\n" +
- "/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q\n" +
- "example.com\n" +
- "443\n" +
- "a,b,c\n";
-
- assertEquals(expected, LeakyHMACAuthHeaderProvider.getRequestString(req, timestamp, nonceString, extra));
- }
-
- @Test
- public void testSpecSignatureExample() throws Exception {
- String extra = "";
- long timestampInSeconds = 1336363200;
- String nonceString = "dj83hs9s";
-
- URI uri = new URI("http://example.com/resource/1?b=1&a=2");
- HttpRequestBase req = new HttpGet(uri);
-
- String requestString = LeakyHMACAuthHeaderProvider.getRequestString(req, timestampInSeconds, nonceString, extra);
-
- String expected = "1336363200\n" +
- "dj83hs9s\n" +
- "GET\n" +
- "/resource/1?b=1&a=2\n" +
- "example.com\n" +
- "80\n" +
- "\n";
-
- assertEquals(expected, requestString);
-
- // There appears to be an error in the current spec.
- // Spec is at https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-1.1
- // Error is reported at http://www.ietf.org/mail-archive/web/oauth/current/msg09741.html
- // assertEquals("bhCQXTVyfj5cmA9uKkPFx1zeOXM=", HMACAuthHeaderProvider.getSignature(requestString, keyString));
- }
-
- @Test
- public void testCompatibleWithDesktopFirefox() throws Exception {
- // These are test values used in the FF Sync Client testsuite.
-
- // String identifier = "vmo1txkttblmn51u2p3zk2xiy16hgvm5ok8qiv1yyi86ffjzy9zj0ez9x6wnvbx7";
- String keyString = "b8u1cc5iiio5o319og7hh8faf2gi5ym4aq0zwf112cv1287an65fudu5zj7zo7dz";
-
- String extra = "";
- long timestampInSeconds = 1329181221;
- String nonceString = "wGX71";
-
- URI uri = new URI("http://10.250.2.176/alias/");
- HttpRequestBase req = new HttpGet(uri);
-
- String requestString = LeakyHMACAuthHeaderProvider.getRequestString(req, timestampInSeconds, nonceString, extra);
-
- assertEquals("jzh5chjQc2zFEvLbyHnPdX11Yck=", LeakyHMACAuthHeaderProvider.getSignature(requestString, keyString));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java
deleted file mode 100644
index 3dab313a0..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.net.test;
-
-import ch.boye.httpclientandroidlib.Header;
-import ch.boye.httpclientandroidlib.client.methods.HttpGet;
-import ch.boye.httpclientandroidlib.client.methods.HttpPost;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
-import ch.boye.httpclientandroidlib.entity.StringEntity;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-import ch.boye.httpclientandroidlib.message.BasicHeader;
-import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.net.HawkAuthHeaderProvider;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * These test vectors were taken from
- * <a href="https://github.com/hueniverse/hawk/blob/871cc597973110900467bd3dfb84a3c892f678fb/README.md">https://github.com/hueniverse/hawk/blob/871cc597973110900467bd3dfb84a3c892f678fb/README.md</a>.
- */
-@RunWith(TestRunner.class)
-public class TestHawkAuthHeaderProvider {
- // Expose a few protected static member functions as public for testing.
- protected static class LeakyHawkAuthHeaderProvider extends HawkAuthHeaderProvider {
- public LeakyHawkAuthHeaderProvider(String tokenId, byte[] reqHMACKey) {
- // getAuthHeader takes includePayloadHash as a parameter.
- super(tokenId, reqHMACKey, false, 0L);
- }
-
- // Public for testing.
- public static String getRequestString(HttpUriRequest request, String type, long timestamp, String nonce, String hash, String extra, String app, String dlg) {
- return HawkAuthHeaderProvider.getRequestString(request, type, timestamp, nonce, hash, extra, app, dlg);
- }
-
- // Public for testing.
- public static String getSignature(String requestString, String key)
- throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
- return HawkAuthHeaderProvider.getSignature(requestString.getBytes("UTF-8"), key.getBytes("UTF-8"));
- }
-
- // Public for testing.
- @Override
- public Header getAuthHeader(HttpRequestBase request, BasicHttpContext context, DefaultHttpClient client,
- long timestamp, String nonce, String extra, boolean includePayloadHash)
- throws InvalidKeyException, NoSuchAlgorithmException, IOException {
- return super.getAuthHeader(request, context, client, timestamp, nonce, extra, includePayloadHash);
- }
-
- // Public for testing.
- public static String getBaseContentType(Header contentTypeHeader) {
- return HawkAuthHeaderProvider.getBaseContentType(contentTypeHeader);
- }
- }
-
- @Test
- public void testSpecRequestString() throws Exception {
- long timestamp = 1353832234;
- String nonce = "j4h3g2";
- String extra = "some-app-ext-data";
- String hash = null;
- String app = null;
- String dlg = null;
-
- URI uri = new URI("http://example.com:8000/resource/1?b=1&a=2");
- HttpUriRequest req = new HttpGet(uri);
-
- String expected = "hawk.1.header\n" +
- "1353832234\n" +
- "j4h3g2\n" +
- "GET\n" +
- "/resource/1?b=1&a=2\n" +
- "example.com\n" +
- "8000\n" +
- "\n" +
- "some-app-ext-data\n";
-
- // LeakyHawkAuthHeaderProvider.
- assertEquals(expected, LeakyHawkAuthHeaderProvider.getRequestString(req, "header", timestamp, nonce, hash, extra, app, dlg));
- }
-
- @Test
- public void testSpecSignatureExample() throws Exception {
- String input = "hawk.1.header\n" +
- "1353832234\n" +
- "j4h3g2\n" +
- "GET\n" +
- "/resource/1?b=1&a=2\n" +
- "example.com\n" +
- "8000\n" +
- "\n" +
- "some-app-ext-data\n";
-
- assertEquals("6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=", LeakyHawkAuthHeaderProvider.getSignature(input, "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn"));
- }
-
- @Test
- public void testSpecPayloadExample() throws Exception {
- LeakyHawkAuthHeaderProvider provider = new LeakyHawkAuthHeaderProvider("dh37fgj492je", "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes("UTF-8"));
- URI uri = new URI("http://example.com:8000/resource/1?b=1&a=2");
- HttpPost req = new HttpPost(uri);
- String body = "Thank you for flying Hawk";
- req.setEntity(new StringEntity(body));
- Header header = provider.getAuthHeader(req, null, null, 1353832234L, "j4h3g2", "some-app-ext-data", true);
- String expected = "Hawk id=\"dh37fgj492je\", ts=\"1353832234\", nonce=\"j4h3g2\", hash=\"Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\", ext=\"some-app-ext-data\", mac=\"aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw=\"";
- assertEquals("Authorization", header.getName());
- assertEquals(expected, header.getValue());
- }
-
- @Test
- public void testSpecAuthorizationHeader() throws Exception {
- LeakyHawkAuthHeaderProvider provider = new LeakyHawkAuthHeaderProvider("dh37fgj492je", "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes("UTF-8"));
- URI uri = new URI("http://example.com:8000/resource/1?b=1&a=2");
- HttpGet req = new HttpGet(uri);
- Header header = provider.getAuthHeader(req, null, null, 1353832234L, "j4h3g2", "some-app-ext-data", false);
- String expected = "Hawk id=\"dh37fgj492je\", ts=\"1353832234\", nonce=\"j4h3g2\", ext=\"some-app-ext-data\", mac=\"6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=\"";
- assertEquals("Authorization", header.getName());
- assertEquals(expected, header.getValue());
-
- // For a non-POST, non-PUT request, a request to include the payload verification hash is silently ignored.
- header = provider.getAuthHeader(req, null, null, 1353832234L, "j4h3g2", "some-app-ext-data", true);
- assertEquals("Authorization", header.getName());
- assertEquals(expected, header.getValue());
- }
-
- @Test
- public void testGetBaseContentType() throws Exception {
- assertEquals("text/plain", LeakyHawkAuthHeaderProvider.getBaseContentType(new BasicHeader("Content-Type", "text/plain")));
- assertEquals("text/plain", LeakyHawkAuthHeaderProvider.getBaseContentType(new BasicHeader("Content-Type", "text/plain;one")));
- assertEquals("text/plain", LeakyHawkAuthHeaderProvider.getBaseContentType(new BasicHeader("Content-Type", "text/plain;one;two")));
- assertEquals("text/html", LeakyHawkAuthHeaderProvider.getBaseContentType(new BasicHeader("Content-Type", "text/html;charset=UTF-8")));
- assertEquals("text/html", LeakyHawkAuthHeaderProvider.getBaseContentType(new BasicHeader("Content-Type", "text/html; charset=UTF-8")));
- assertEquals("text/html", LeakyHawkAuthHeaderProvider.getBaseContentType(new BasicHeader("Content-Type", "text/html ;charset=UTF-8")));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java
deleted file mode 100644
index 8f136e3d0..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.net.test;
-
-import ch.boye.httpclientandroidlib.Header;
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.entity.StringEntity;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-import ch.boye.httpclientandroidlib.message.BasicHeader;
-import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
-import org.junit.Assert;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-import org.mozilla.gecko.sync.net.HawkAuthHeaderProvider;
-import org.mozilla.gecko.sync.net.Resource;
-import org.mozilla.gecko.sync.net.SyncResponse;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.security.GeneralSecurityException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-
-public class TestLiveHawkAuth {
- /**
- * Hawk comes with an example/usage.js server. Modify it to serve indefinitely,
- * un-comment the following line, and verify that the port and credentials
- * have not changed; then the following test should pass.
- */
- // @org.junit.Test
- public void testHawkUsage() throws Exception {
- // Id and credentials are hard-coded in example/usage.js.
- final String id = "dh37fgj492je";
- final byte[] key = "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes("UTF-8");
- final BaseResource resource = new BaseResource("http://localhost:8000/", false);
-
- // Basic GET.
- resource.delegate = new TestBaseResourceDelegate(resource, new HawkAuthHeaderProvider(id, key, false, 0L));
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- resource.get();
- }
- });
-
- // PUT with payload verification.
- resource.delegate = new TestBaseResourceDelegate(resource, new HawkAuthHeaderProvider(id, key, true, 0L));
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- try {
- resource.put(new StringEntity("Thank you for flying Hawk"));
- } catch (UnsupportedEncodingException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
- });
-
- // PUT with a large (32k or so) body and payload verification.
- final StringBuilder sb = new StringBuilder();
- for (int i = 0; i < 16000; i++) {
- sb.append(Integer.valueOf(i % 100).toString());
- }
- resource.delegate = new TestBaseResourceDelegate(resource, new HawkAuthHeaderProvider(id, key, true, 0L));
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- try {
- resource.put(new StringEntity(sb.toString()));
- } catch (UnsupportedEncodingException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
- });
-
- // PUT without payload verification.
- resource.delegate = new TestBaseResourceDelegate(resource, new HawkAuthHeaderProvider(id, key, false, 0L));
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- try {
- resource.put(new StringEntity("Thank you for flying Hawk"));
- } catch (UnsupportedEncodingException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
- });
-
- // PUT with *bad* payload verification.
- HawkAuthHeaderProvider provider = new HawkAuthHeaderProvider(id, key, true, 0L) {
- @Override
- public Header getAuthHeader(HttpRequestBase request, BasicHttpContext context, DefaultHttpClient client) throws GeneralSecurityException {
- Header header = super.getAuthHeader(request, context, client);
- // Here's a cheap way of breaking the hash.
- String newValue = header.getValue().replaceAll("hash=\"....", "hash=\"XXXX");
- return new BasicHeader(header.getName(), newValue);
- }
- };
-
- resource.delegate = new TestBaseResourceDelegate(resource, provider);
- try {
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- try {
- resource.put(new StringEntity("Thank you for flying Hawk"));
- } catch (UnsupportedEncodingException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
- });
- fail("Expected assertion after 401 response.");
- } catch (WaitHelper.InnerError e) {
- assertTrue(e.innerError instanceof AssertionError);
- assertEquals("expected:<200> but was:<401>", ((AssertionError) e.innerError).getMessage());
- }
- }
-
- protected final class TestBaseResourceDelegate extends BaseResourceDelegate {
- protected final HawkAuthHeaderProvider provider;
-
- protected TestBaseResourceDelegate(Resource resource, HawkAuthHeaderProvider provider) throws UnsupportedEncodingException {
- super(resource);
- this.provider = provider;
- }
-
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return provider;
- }
-
- @Override
- public int connectionTimeout() {
- return 1000;
- }
-
- @Override
- public int socketTimeout() {
- return 1000;
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- SyncResponse res = new SyncResponse(response);
- try {
- Assert.assertEquals(200, res.getStatusCode());
- WaitHelper.getTestWaiter().performNotify();
- } catch (Throwable e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
-
- @Override
- public void handleHttpProtocolException(ClientProtocolException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
-
- @Override
- public String getUserAgent() {
- return null;
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestUserAgentHeaders.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestUserAgentHeaders.java
deleted file mode 100644
index 30b8a38ec..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/net/test/TestUserAgentHeaders.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.net.test;
-
-import ch.boye.httpclientandroidlib.protocol.HTTP;
-import junit.framework.Assert;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.fxa.FxAccountClient20;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.RequestDelegate;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.RecoveryEmailStatusResponse;
-import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
-import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.util.concurrent.Executors;
-
-@RunWith(TestRunner.class)
-public class TestUserAgentHeaders {
- private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private static final String TEST_SERVER = "http://localhost:" + TEST_PORT;
-
- protected final HTTPServerTestHelper data = new HTTPServerTestHelper();
-
- protected class UserAgentServer extends MockServer {
- public String lastUserAgent = null;
-
- @Override
- public void handle(Request request, Response response) {
- lastUserAgent = request.getValue(HTTP.USER_AGENT);
- super.handle(request, response);
- }
- }
-
- protected final UserAgentServer userAgentServer = new UserAgentServer();
-
- @Before
- public void setUp() {
- BaseResource.rewriteLocalhost = false;
- data.startHTTPServer(userAgentServer);
- }
-
- @After
- public void tearDown() {
- data.stopHTTPServer();
- }
-
- @Test
- public void testSyncUserAgent() throws Exception {
- final SyncStorageRecordRequest request = new SyncStorageRecordRequest(TEST_SERVER);
- request.delegate = new SyncStorageRequestDelegate() {
- @Override
- public String ifUnmodifiedSince() {
- return null;
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse response) {
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return null;
- }
- };
-
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- request.get();
- }
- });
-
- // Verify that we're getting the value from the correct place.
- Assert.assertEquals(SyncConstants.USER_AGENT, userAgentServer.lastUserAgent);
- }
-
- @Test
- public void testFxAccountClientUserAgent() throws Exception {
- final FxAccountClient20 client = new FxAccountClient20(TEST_SERVER, Executors.newSingleThreadExecutor());
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- client.recoveryEmailStatus(new byte[] { 0 }, new RequestDelegate<RecoveryEmailStatusResponse>() {
- @Override
- public void handleSuccess(RecoveryEmailStatusResponse result) {
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void handleFailure(FxAccountClientRemoteException e) {
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void handleError(Exception e) {
- WaitHelper.getTestWaiter().performNotify();
- }
- });
- }
- });
-
- // Verify that we're getting the value from the correct place.
- Assert.assertEquals(FxAccountConstants.USER_AGENT, userAgentServer.lastUserAgent);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/BrowserContractHelpersTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/BrowserContractHelpersTest.java
deleted file mode 100644
index eecfa8dc2..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/BrowserContractHelpersTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.android;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class BrowserContractHelpersTest {
- @Test
- public void testBookmarkCodes() {
- final String[] strings = {
- // Observe omissions: "microsummary", "item".
- "folder", "bookmark", "separator", "livemark", "query"
- };
- for (int i = 0; i < strings.length; ++i) {
- assertEquals(strings[i], BrowserContractHelpers.typeStringForCode(i));
- assertEquals(i, BrowserContractHelpers.typeCodeForString(strings[i]));
- }
- assertEquals(null, BrowserContractHelpers.typeStringForCode(-1));
- assertEquals(null, BrowserContractHelpers.typeStringForCode(100));
-
- assertEquals(-1, BrowserContractHelpers.typeCodeForString(null));
- assertEquals(-1, BrowserContractHelpers.typeCodeForString("folder "));
- assertEquals(-1, BrowserContractHelpers.typeCodeForString("FOLDER"));
- assertEquals(-1, BrowserContractHelpers.typeCodeForString(""));
- assertEquals(-1, BrowserContractHelpers.typeCodeForString("nope"));
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/VisitsHelperTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/VisitsHelperTest.java
deleted file mode 100644
index 67bbca089..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/VisitsHelperTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.android;
-
-import android.content.ContentProviderClient;
-import android.content.ContentValues;
-import android.net.Uri;
-
-import junit.framework.Assert;
-
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.db.DelegatingTestContentProvider;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserProvider;
-import org.robolectric.shadows.ShadowContentResolver;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class VisitsHelperTest {
- @Test
- public void testBulkInsertRemoteVisits() throws Exception {
- JSONArray toInsert = new JSONArray();
- Assert.assertEquals(0, VisitsHelper.getVisitsContentValues("testGUID", toInsert).length);
-
- JSONObject visit = new JSONObject();
- Long date = Long.valueOf(123432552344l);
- visit.put("date", date);
- visit.put("type", 2l);
- toInsert.add(visit);
-
- JSONObject visit2 = new JSONObject();
- visit2.put("date", date + 1000);
- visit2.put("type", 5l);
- toInsert.add(visit2);
-
- ContentValues[] cvs = VisitsHelper.getVisitsContentValues("testGUID", toInsert);
- Assert.assertEquals(2, cvs.length);
- ContentValues cv1 = cvs[0];
- ContentValues cv2 = cvs[1];
- Assert.assertEquals(Integer.valueOf(2), cv1.getAsInteger(BrowserContract.Visits.VISIT_TYPE));
- Assert.assertEquals(Integer.valueOf(5), cv2.getAsInteger(BrowserContract.Visits.VISIT_TYPE));
-
- Assert.assertEquals(date, cv1.getAsLong("date"));
- Assert.assertEquals(Long.valueOf(date + 1000), cv2.getAsLong(BrowserContract.Visits.DATE_VISITED));
- }
-
- @Test
- public void testGetRecentHistoryVisitsForGUID() throws Exception {
- Uri historyTestUri = testUri(BrowserContract.History.CONTENT_URI);
- Uri visitsTestUri = testUri(BrowserContract.Visits.CONTENT_URI);
-
- BrowserProvider provider = new BrowserProvider();
- try {
- provider.onCreate();
- ShadowContentResolver.registerProvider(BrowserContract.AUTHORITY, new DelegatingTestContentProvider(provider));
-
- final ShadowContentResolver cr = new ShadowContentResolver();
- ContentProviderClient historyClient = cr.acquireContentProviderClient(BrowserContractHelpers.HISTORY_CONTENT_URI);
- ContentProviderClient visitsClient = cr.acquireContentProviderClient(BrowserContractHelpers.VISITS_CONTENT_URI);
-
- ContentValues historyItem = new ContentValues();
- historyItem.put(BrowserContract.History.URL, "https://www.mozilla.org");
- historyItem.put(BrowserContract.History.GUID, "testGUID");
- historyClient.insert(historyTestUri, historyItem);
-
- Long baseDate = System.currentTimeMillis();
- for (int i = 0; i < 30; i++) {
- ContentValues visitItem = new ContentValues();
- visitItem.put(BrowserContract.Visits.HISTORY_GUID, "testGUID");
- visitItem.put(BrowserContract.Visits.DATE_VISITED, baseDate - i * 100);
- visitItem.put(BrowserContract.Visits.VISIT_TYPE, 1);
- visitItem.put(BrowserContract.Visits.IS_LOCAL, 1);
- visitsClient.insert(visitsTestUri, visitItem);
- }
-
- // test that limit worked, that sorting is correct, and that both date and type are present
- JSONArray recentVisits = VisitsHelper.getRecentHistoryVisitsForGUID(visitsClient, "testGUID", 10);
- Assert.assertEquals(10, recentVisits.size());
- for (int i = 0; i < recentVisits.size(); i++) {
- JSONObject v = (JSONObject) recentVisits.get(i);
- Long date = (Long) v.get("date");
- Long type = (Long) v.get("type");
- Assert.assertEquals(Long.valueOf(baseDate - i * 100), date);
- Assert.assertEquals(Long.valueOf(1), type);
- }
- } finally {
- provider.shutdown();
- }
- }
-
- @Test
- public void testGetVisitContentValues() throws Exception {
- JSONObject visit = new JSONObject();
- Long date = Long.valueOf(123432552344l);
- visit.put("date", date);
- visit.put("type", Long.valueOf(2));
-
- ContentValues cv = VisitsHelper.getVisitContentValues("testGUID", visit, true);
- assertTrue(cv.containsKey(BrowserContract.Visits.VISIT_TYPE));
- assertTrue(cv.containsKey(BrowserContract.Visits.DATE_VISITED));
- assertTrue(cv.containsKey(BrowserContract.Visits.HISTORY_GUID));
- assertTrue(cv.containsKey(BrowserContract.Visits.IS_LOCAL));
- assertEquals(4, cv.size());
-
- assertEquals(date, cv.getAsLong(BrowserContract.Visits.DATE_VISITED));
- assertEquals(Long.valueOf(2), cv.getAsLong(BrowserContract.Visits.VISIT_TYPE));
- assertEquals("testGUID", cv.getAsString(BrowserContract.Visits.HISTORY_GUID));
- assertEquals(Integer.valueOf(1), cv.getAsInteger(BrowserContract.Visits.IS_LOCAL));
-
- cv = VisitsHelper.getVisitContentValues("testGUID", visit, false);
- assertEquals(Integer.valueOf(0), cv.getAsInteger(BrowserContract.Visits.IS_LOCAL));
-
- try {
- JSONObject visit2 = new JSONObject();
- visit.put("date", date);
- VisitsHelper.getVisitContentValues("testGUID", visit2, false);
- assertTrue("Must check that visit type key is present", false);
- } catch (IllegalArgumentException e) {}
-
- try {
- JSONObject visit3 = new JSONObject();
- visit.put("type", Long.valueOf(2));
- VisitsHelper.getVisitContentValues("testGUID", visit3, false);
- assertTrue("Must check that visit date key is present", false);
- } catch (IllegalArgumentException e) {}
-
- try {
- JSONObject visit4 = new JSONObject();
- VisitsHelper.getVisitContentValues("testGUID", visit4, false);
- assertTrue("Must check that visit type and date keys are present", false);
- } catch (IllegalArgumentException e) {}
- }
-
- private Uri testUri(Uri baseUri) {
- return baseUri.buildUpon().appendQueryParameter(BrowserContract.PARAM_IS_TEST, "1").build();
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/test/TestBookmarksInsertionManager.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/test/TestBookmarksInsertionManager.java
deleted file mode 100644
index cbf5c37d3..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/test/TestBookmarksInsertionManager.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.android.test;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.android.BookmarksInsertionManager;
-import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestBookmarksInsertionManager {
- public BookmarksInsertionManager manager;
- public ArrayList<String[]> insertions;
-
- @Before
- public void setUp() {
- insertions = new ArrayList<String[]>();
- Set<String> writtenFolders = new HashSet<String>();
- writtenFolders.add("mobile");
-
- BookmarksInsertionManager.BookmarkInserter inserter = new BookmarksInsertionManager.BookmarkInserter() {
- @Override
- public boolean insertFolder(BookmarkRecord record) {
- if (record.guid == "fail") {
- return false;
- }
- Logger.debug(BookmarksInsertionManager.LOG_TAG, "Inserted folder (" + record.guid + ").");
- insertions.add(new String[] { record.guid });
- return true;
- }
-
- @Override
- public void bulkInsertNonFolders(Collection<BookmarkRecord> records) {
- ArrayList<String> guids = new ArrayList<String>();
- for (BookmarkRecord record : records) {
- guids.add(record.guid);
- }
- String[] guidList = guids.toArray(new String[guids.size()]);
- insertions.add(guidList);
- Logger.debug(BookmarksInsertionManager.LOG_TAG, "Inserted non-folders (" + Utils.toCommaSeparatedString(guids) + ").");
- }
- };
- manager = new BookmarksInsertionManager(3, writtenFolders, inserter);
- BookmarksInsertionManager.DEBUG = true;
- }
-
- protected static BookmarkRecord bookmark(String guid, String parent) {
- BookmarkRecord bookmark = new BookmarkRecord(guid);
- bookmark.type = "bookmark";
- bookmark.parentID = parent;
- return bookmark;
- }
-
- protected static BookmarkRecord folder(String guid, String parent) {
- BookmarkRecord bookmark = new BookmarkRecord(guid);
- bookmark.type = "folder";
- bookmark.parentID = parent;
- return bookmark;
- }
-
- @Test
- public void testChildrenBeforeFolder() {
- BookmarkRecord folder = folder("folder", "mobile");
- BookmarkRecord child1 = bookmark("child1", "folder");
- BookmarkRecord child2 = bookmark("child2", "folder");
-
- manager.enqueueRecord(child1);
- assertTrue(insertions.isEmpty());
- manager.enqueueRecord(child2);
- assertTrue(insertions.isEmpty());
- manager.enqueueRecord(folder);
- assertEquals(1, insertions.size());
- manager.finishUp();
- assertTrue(manager.isClear());
- assertEquals(2, insertions.size());
- assertArrayEquals(new String[] { "folder" }, insertions.get(0));
- assertArrayEquals(new String[] { "child1", "child2" }, insertions.get(1));
- }
-
- @Test
- public void testChildAfterFolder() {
- BookmarkRecord folder = folder("folder", "mobile");
- BookmarkRecord child1 = bookmark("child1", "folder");
- BookmarkRecord child2 = bookmark("child2", "folder");
-
- manager.enqueueRecord(child1);
- assertTrue(insertions.isEmpty());
- manager.enqueueRecord(folder);
- assertEquals(1, insertions.size());
- manager.enqueueRecord(child2);
- assertEquals(1, insertions.size());
- manager.finishUp();
- assertTrue(manager.isClear());
- assertEquals(2, insertions.size());
- assertArrayEquals(new String[] { "folder" }, insertions.get(0));
- assertArrayEquals(new String[] { "child1", "child2" }, insertions.get(1));
- }
-
- @Test
- public void testFolderAfterFolder() {
- manager.enqueueRecord(bookmark("child1", "folder1"));
- assertEquals(0, insertions.size());
- manager.enqueueRecord(folder("folder1", "mobile"));
- assertEquals(1, insertions.size());
- manager.enqueueRecord(bookmark("child2", "folder2"));
- assertEquals(1, insertions.size());
- manager.enqueueRecord(folder("folder2", "folder1"));
- assertEquals(2, insertions.size());
- manager.enqueueRecord(bookmark("child3", "folder1"));
- manager.enqueueRecord(bookmark("child4", "folder2"));
- assertEquals(3, insertions.size());
-
- manager.finishUp();
- assertTrue(manager.isClear());
- assertEquals(4, insertions.size());
- assertArrayEquals(new String[] { "folder1" }, insertions.get(0));
- assertArrayEquals(new String[] { "folder2" }, insertions.get(1));
- assertArrayEquals(new String[] { "child1", "child2", "child3" }, insertions.get(2));
- assertArrayEquals(new String[] { "child4" }, insertions.get(3));
- }
-
- @Test
- public void testFolderRecursion() {
- manager.enqueueRecord(folder("1", "mobile"));
- manager.enqueueRecord(folder("2", "1"));
- assertEquals(2, insertions.size());
- manager.enqueueRecord(bookmark("3a", "3"));
- manager.enqueueRecord(bookmark("3b", "3"));
- manager.enqueueRecord(bookmark("3c", "3"));
- manager.enqueueRecord(bookmark("4a", "4"));
- manager.enqueueRecord(bookmark("4b", "4"));
- manager.enqueueRecord(bookmark("4c", "4"));
- assertEquals(2, insertions.size());
- manager.enqueueRecord(folder("3", "2"));
- assertEquals(4, insertions.size());
- manager.enqueueRecord(folder("4", "2"));
- assertEquals(6, insertions.size());
-
- assertTrue(manager.isClear());
- manager.finishUp();
- assertTrue(manager.isClear());
- // Folders in order.
- assertArrayEquals(new String[] { "1" }, insertions.get(0));
- assertArrayEquals(new String[] { "2" }, insertions.get(1));
- assertArrayEquals(new String[] { "3" }, insertions.get(2));
- // Then children in batches of 3.
- assertArrayEquals(new String[] { "3a", "3b", "3c" }, insertions.get(3));
- // Then last folder.
- assertArrayEquals(new String[] { "4" }, insertions.get(4));
- assertArrayEquals(new String[] { "4a", "4b", "4c" }, insertions.get(5));
- }
-
- @Test
- public void testFailedFolderInsertion() {
- manager.enqueueRecord(bookmark("failA", "fail"));
- manager.enqueueRecord(bookmark("failB", "fail"));
- assertEquals(0, insertions.size());
- manager.enqueueRecord(folder("fail", "mobile"));
- assertEquals(0, insertions.size());
- manager.enqueueRecord(bookmark("failC", "fail"));
- assertEquals(0, insertions.size());
- manager.finishUp(); // Children inserted at the end; they will be treated as orphans.
- assertTrue(manager.isClear());
- assertEquals(1, insertions.size());
- assertArrayEquals(new String[] { "failA", "failB", "failC" }, insertions.get(0));
- }
-
- @Test
- public void testIncrementalFlush() {
- manager.enqueueRecord(bookmark("a", "1"));
- manager.enqueueRecord(bookmark("b", "1"));
- manager.enqueueRecord(folder("1", "mobile"));
- assertEquals(1, insertions.size());
- manager.enqueueRecord(bookmark("c", "1"));
- assertEquals(2, insertions.size());
- manager.enqueueRecord(bookmark("d", "1"));
- manager.enqueueRecord(bookmark("e", "1"));
- manager.enqueueRecord(bookmark("f", "1"));
- assertEquals(3, insertions.size());
- manager.enqueueRecord(bookmark("g", "1")); // Start of new batch.
- assertEquals(3, insertions.size());
- manager.finishUp(); // Children inserted at the end; they will be treated as orphans.
- assertTrue(manager.isClear());
- assertEquals(4, insertions.size());
- assertArrayEquals(new String[] { "1" }, insertions.get(0));
- assertArrayEquals(new String[] { "a", "b", "c"}, insertions.get(1));
- assertArrayEquals(new String[] { "d", "e", "f"}, insertions.get(2));
- assertArrayEquals(new String[] { "g" }, insertions.get(3));
- }
-
- @Test
- public void testFinishUp() {
- manager.enqueueRecord(bookmark("a", "1"));
- manager.enqueueRecord(bookmark("b", "1"));
- manager.enqueueRecord(folder("2", "1"));
- manager.enqueueRecord(bookmark("c", "1"));
- manager.enqueueRecord(bookmark("d", "1"));
- manager.enqueueRecord(folder("3", "1"));
- assertEquals(0, insertions.size());
- manager.finishUp(); // Children inserted at the end; they will be treated as orphans.
- assertTrue(manager.isClear());
- assertEquals(3, insertions.size());
- assertArrayEquals(new String[] { "2" }, insertions.get(0));
- assertArrayEquals(new String[] { "3" }, insertions.get(1));
- assertArrayEquals(new String[] { "a", "b", "c", "d" }, insertions.get(2)); // Last insertion could be big.
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/domain/TestClientRecord.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/domain/TestClientRecord.java
deleted file mode 100644
index 790d47620..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/domain/TestClientRecord.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.domain;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.Utils;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestClientRecord {
-
- @Test
- public void testEnsureDefaults() {
- // Ensure defaults.
- ClientRecord record = new ClientRecord();
- assertEquals(ClientRecord.COLLECTION_NAME, record.collection);
- assertEquals(0, record.lastModified);
- assertEquals(false, record.deleted);
- assertEquals("Default Name", record.name);
- assertEquals(ClientRecord.CLIENT_TYPE, record.type);
- assertTrue(null == record.os);
- assertTrue(null == record.device);
- assertTrue(null == record.application);
- assertTrue(null == record.appPackage);
- assertTrue(null == record.formfactor);
- }
-
- @Test
- public void testGetPayload() {
- // Test ClientRecord.getPayload().
- ClientRecord record = new ClientRecord();
- CryptoRecord cryptoRecord = record.getEnvelope();
- assertEquals(record.guid, cryptoRecord.payload.get("id"));
- assertEquals(null, cryptoRecord.payload.get("collection"));
- assertEquals(null, cryptoRecord.payload.get("lastModified"));
- assertEquals(null, cryptoRecord.payload.get("deleted"));
- assertEquals(null, cryptoRecord.payload.get("version"));
- assertEquals(record.name, cryptoRecord.payload.get("name"));
- assertEquals(record.type, cryptoRecord.payload.get("type"));
- }
-
- @Test
- public void testInitFromPayload() {
- // Test ClientRecord.initFromPayload() in ClientRecordFactory.
- ClientRecord record1 = new ClientRecord();
- CryptoRecord cryptoRecord = record1.getEnvelope();
- ClientRecordFactory factory = new ClientRecordFactory();
- ClientRecord record2 = (ClientRecord) factory.createRecord(cryptoRecord);
- assertEquals(cryptoRecord.payload.get("id"), record2.guid);
- assertEquals(ClientRecord.COLLECTION_NAME, record2.collection);
- assertEquals(0, record2.lastModified);
- assertEquals(false, record2.deleted);
- assertEquals(cryptoRecord.payload.get("name"), record2.name);
- assertEquals(cryptoRecord.payload.get("type"), record2.type);
- }
-
- @Test
- public void testCopyWithIDs() {
- // Test ClientRecord.copyWithIDs.
- ClientRecord record1 = new ClientRecord();
- record1.version = "20";
- String newGUID = Utils.generateGuid();
- ClientRecord record2 = (ClientRecord) record1.copyWithIDs(newGUID, 0);
- assertEquals(newGUID, record2.guid);
- assertEquals(0, record2.androidID);
- assertEquals(record1.collection, record2.collection);
- assertEquals(record1.lastModified, record2.lastModified);
- assertEquals(record1.deleted, record2.deleted);
- assertEquals(record1.name, record2.name);
- assertEquals(record1.type, record2.type);
- assertEquals(record1.version, record2.version);
- }
-
- @Test
- public void testEquals() {
- // Test ClientRecord.equals().
- ClientRecord record1 = new ClientRecord();
- ClientRecord record2 = new ClientRecord();
- record2.guid = record1.guid;
- record2.version = "20";
- record1.version = null;
-
- ClientRecord record3 = new ClientRecord(Utils.generateGuid());
- record3.name = "New Name";
-
- ClientRecord record4 = new ClientRecord(Utils.generateGuid());
- record4.name = ClientRecord.DEFAULT_CLIENT_NAME;
- record4.type = "desktop";
-
- assertTrue(record2.equals(record1));
- assertFalse(record3.equals(record1));
- assertFalse(record3.equals(record2));
- assertFalse(record4.equals(record1));
- assertFalse(record4.equals(record2));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/domain/test/TestFormHistoryRecord.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/domain/test/TestFormHistoryRecord.java
deleted file mode 100644
index c0682e90e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/domain/test/TestFormHistoryRecord.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.domain.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.domain.FormHistoryRecord;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestFormHistoryRecord {
- public static FormHistoryRecord withIdFieldNameAndValue(long id, String fieldName, String value) {
- FormHistoryRecord fr = new FormHistoryRecord();
- fr.androidID = id;
- fr.fieldName = fieldName;
- fr.fieldValue = value;
-
- return fr;
- }
-
- @Test
- public void testCollection() {
- FormHistoryRecord fr = new FormHistoryRecord();
- assertEquals("forms", fr.collection);
- }
-
- @Test
- public void testGetPayload() {
- FormHistoryRecord fr = withIdFieldNameAndValue(0, "username", "aUsername");
- CryptoRecord rec = fr.getEnvelope();
- assertEquals("username", rec.payload.get("name"));
- assertEquals("aUsername", rec.payload.get("value"));
- }
-
- @Test
- public void testCopyWithIDs() {
- FormHistoryRecord fr = withIdFieldNameAndValue(0, "username", "aUsername");
- String guid = Utils.generateGuid();
- FormHistoryRecord fr2 = (FormHistoryRecord)fr.copyWithIDs(guid, 9999);
- assertEquals(guid, fr2.guid);
- assertEquals(9999, fr2.androidID);
- assertEquals(fr.fieldName, fr2.fieldName);
- assertEquals(fr.fieldValue, fr2.fieldValue);
- }
-
- @Test
- public void testEquals() {
- FormHistoryRecord fr1a = withIdFieldNameAndValue(0, "username1", "Alice");
- FormHistoryRecord fr1b = withIdFieldNameAndValue(0, "username1", "Bob");
- FormHistoryRecord fr2a = withIdFieldNameAndValue(0, "username2", "Alice");
- FormHistoryRecord fr2b = withIdFieldNameAndValue(0, "username2", "Bob");
-
- assertFalse(fr1a.equals(fr1b));
- assertFalse(fr1a.equals(fr2a));
- assertFalse(fr1a.equals(fr2b));
- assertFalse(fr1b.equals(fr2a));
- assertFalse(fr1b.equals(fr2b));
- assertFalse(fr2a.equals(fr2b));
-
- assertFalse(fr1a.equals(withIdFieldNameAndValue(fr1a.androidID, fr1a.fieldName, fr1b.fieldValue)));
- assertFalse(fr1a.equals(fr1a.copyWithIDs(fr2a.guid, 9999)));
- assertTrue(fr1a.equals(fr1a));
- }
-
- @Test
- public void testEqualsForDeleted() {
- FormHistoryRecord fr1 = withIdFieldNameAndValue(0, "username1", "Alice");
- FormHistoryRecord fr2 = (FormHistoryRecord)fr1.copyWithIDs(fr1.guid, fr1.androidID);
- assertTrue(fr1.equals(fr2));
- fr1.deleted = true;
- assertFalse(fr1.equals(fr2));
- fr2.deleted = true;
- assertTrue(fr1.equals(fr2));
- FormHistoryRecord fr3 = (FormHistoryRecord)fr2.copyWithIDs(Utils.generateGuid(), 9999);
- assertFalse(fr2.equals(fr3));
- }
-
- @Test
- public void testTTL() {
- FormHistoryRecord fr = withIdFieldNameAndValue(0, "username", "aUsername");
- assertEquals(FormHistoryRecord.FORMS_TTL, fr.ttl);
- CryptoRecord rec = fr.getEnvelope();
- assertEquals(FormHistoryRecord.FORMS_TTL, rec.ttl);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/downloaders/BatchingDownloaderDelegateTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/downloaders/BatchingDownloaderDelegateTest.java
deleted file mode 100644
index da2bbac18..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/downloaders/BatchingDownloaderDelegateTest.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.repositories.downloaders;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.HTTPFailureException;
-import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.InfoConfiguration;
-import org.mozilla.gecko.sync.net.SyncResponse;
-import org.mozilla.gecko.sync.net.SyncStorageCollectionRequest;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.mozilla.gecko.sync.repositories.Server11Repository;
-import org.mozilla.gecko.sync.repositories.Server11RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import java.net.URI;
-import java.util.concurrent.ExecutorService;
-
-import ch.boye.httpclientandroidlib.ProtocolVersion;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-import ch.boye.httpclientandroidlib.message.BasicHttpResponse;
-import ch.boye.httpclientandroidlib.message.BasicStatusLine;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class BatchingDownloaderDelegateTest {
- private Server11Repository server11Repository;
- private Server11RepositorySession repositorySession;
- private MockDownloader mockDownloader;
- private String DEFAULT_COLLECTION_URL = "http://dummy.url/";
-
- class MockDownloader extends BatchingDownloader {
- public boolean isSuccess = false;
- public boolean isFetched = false;
- public boolean isFailure = false;
- public Exception ex;
-
- public MockDownloader(Server11Repository repository, Server11RepositorySession repositorySession) {
- super(repository, repositorySession);
- }
-
- @Override
- public void onFetchCompleted(SyncStorageResponse response,
- final RepositorySessionFetchRecordsDelegate fetchRecordsDelegate,
- final SyncStorageCollectionRequest request,
- long l, long newerTimestamp, boolean full, String sort, String ids) {
- this.isSuccess = true;
- }
-
- @Override
- public void onFetchFailed(final Exception ex,
- final RepositorySessionFetchRecordsDelegate fetchRecordsDelegate,
- final SyncStorageCollectionRequest request) {
- this.isFailure = true;
- this.ex = ex;
- }
-
- @Override
- public void onFetchedRecord(CryptoRecord record,
- RepositorySessionFetchRecordsDelegate fetchRecordsDelegate) {
- this.isFetched = true;
- }
- }
-
- class SimpleSessionFetchRecordsDelegate implements RepositorySessionFetchRecordsDelegate {
- @Override
- public void onFetchFailed(Exception ex, Record record) {
-
- }
-
- @Override
- public void onFetchedRecord(Record record) {
-
- }
-
- @Override
- public void onFetchCompleted(long fetchEnd) {
-
- }
-
- @Override
- public RepositorySessionFetchRecordsDelegate deferredFetchDelegate(ExecutorService executor) {
- return null;
- }
- }
-
- @Before
- public void setUp() throws Exception {
- server11Repository = new Server11Repository(
- "dummyCollection",
- DEFAULT_COLLECTION_URL,
- null,
- new InfoCollections(),
- new InfoConfiguration());
- repositorySession = new Server11RepositorySession(server11Repository);
- mockDownloader = new MockDownloader(server11Repository, repositorySession);
- }
-
- @Test
- public void testIfUnmodifiedSince() throws Exception {
- BatchingDownloader downloader = new BatchingDownloader(server11Repository, repositorySession);
- RepositorySessionFetchRecordsDelegate delegate = new SimpleSessionFetchRecordsDelegate();
- BatchingDownloaderDelegate downloaderDelegate = new BatchingDownloaderDelegate(downloader, delegate,
- new SyncStorageCollectionRequest(new URI(DEFAULT_COLLECTION_URL)), 0, 0, true, null, null);
- String lastModified = "12345678";
- SyncStorageResponse response = makeSyncStorageResponse(200, lastModified);
- downloaderDelegate.handleRequestSuccess(response);
- assertEquals(lastModified, downloaderDelegate.ifUnmodifiedSince());
- }
-
- @Test
- public void testSuccess() throws Exception {
- BatchingDownloaderDelegate downloaderDelegate = new BatchingDownloaderDelegate(mockDownloader, null,
- new SyncStorageCollectionRequest(new URI(DEFAULT_COLLECTION_URL)), 0, 0, true, null, null);
- SyncStorageResponse response = makeSyncStorageResponse(200, "12345678");
- downloaderDelegate.handleRequestSuccess(response);
- assertTrue(mockDownloader.isSuccess);
- assertFalse(mockDownloader.isFailure);
- assertFalse(mockDownloader.isFetched);
- }
-
- @Test
- public void testFailureMissingLMHeader() throws Exception {
- BatchingDownloaderDelegate downloaderDelegate = new BatchingDownloaderDelegate(mockDownloader, null,
- new SyncStorageCollectionRequest(new URI(DEFAULT_COLLECTION_URL)), 0, 0, true, null, null);
- SyncStorageResponse response = makeSyncStorageResponse(200, null);
- downloaderDelegate.handleRequestSuccess(response);
- assertTrue(mockDownloader.isFailure);
- assertEquals(IllegalStateException.class, mockDownloader.ex.getClass());
- assertFalse(mockDownloader.isSuccess);
- assertFalse(mockDownloader.isFetched);
- }
-
- @Test
- public void testFailureHTTPException() throws Exception {
- BatchingDownloaderDelegate downloaderDelegate = new BatchingDownloaderDelegate(mockDownloader, null,
- new SyncStorageCollectionRequest(new URI(DEFAULT_COLLECTION_URL)), 0, 0, true, null, null);
- SyncStorageResponse response = makeSyncStorageResponse(400, null);
- downloaderDelegate.handleRequestFailure(response);
- assertTrue(mockDownloader.isFailure);
- assertEquals(HTTPFailureException.class, mockDownloader.ex.getClass());
- assertFalse(mockDownloader.isSuccess);
- assertFalse(mockDownloader.isFetched);
- }
-
- @Test
- public void testFailureRequestError() throws Exception {
- BatchingDownloaderDelegate downloaderDelegate = new BatchingDownloaderDelegate(mockDownloader, null,
- new SyncStorageCollectionRequest(new URI(DEFAULT_COLLECTION_URL)), 0, 0, true, null, null);
- downloaderDelegate.handleRequestError(new ClientProtocolException());
- assertTrue(mockDownloader.isFailure);
- assertEquals(ClientProtocolException.class, mockDownloader.ex.getClass());
- assertFalse(mockDownloader.isSuccess);
- assertFalse(mockDownloader.isFetched);
- }
-
- @Test
- public void testFetchRecord() throws Exception {
- BatchingDownloaderDelegate downloaderDelegate = new BatchingDownloaderDelegate(mockDownloader, null,
- new SyncStorageCollectionRequest(new URI(DEFAULT_COLLECTION_URL)), 0, 0, true, null, null);
- CryptoRecord record = new CryptoRecord();
- downloaderDelegate.handleWBO(record);
- assertTrue(mockDownloader.isFetched);
- assertFalse(mockDownloader.isSuccess);
- assertFalse(mockDownloader.isFailure);
- }
-
- private SyncStorageResponse makeSyncStorageResponse(int code, String lastModified) {
- BasicHttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), code, null));
-
- if (lastModified != null) {
- response.addHeader(SyncResponse.X_LAST_MODIFIED, lastModified);
- }
-
- return new SyncStorageResponse(response);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/downloaders/BatchingDownloaderTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/downloaders/BatchingDownloaderTest.java
deleted file mode 100644
index fbbd9cae9..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/downloaders/BatchingDownloaderTest.java
+++ /dev/null
@@ -1,543 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.repositories.downloaders;
-
-import android.support.annotation.NonNull;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.InfoConfiguration;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.SyncResponse;
-import org.mozilla.gecko.sync.net.SyncStorageCollectionRequest;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.mozilla.gecko.sync.repositories.Repository;
-import org.mozilla.gecko.sync.repositories.Server11Repository;
-import org.mozilla.gecko.sync.repositories.Server11RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
-import org.mozilla.gecko.sync.repositories.domain.Record;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.concurrent.ExecutorService;
-
-import ch.boye.httpclientandroidlib.ProtocolVersion;
-import ch.boye.httpclientandroidlib.message.BasicHttpResponse;
-import ch.boye.httpclientandroidlib.message.BasicStatusLine;
-
-import static org.junit.Assert.*;
-import static org.junit.Assert.assertEquals;
-
-@RunWith(TestRunner.class)
-public class BatchingDownloaderTest {
- private MockSever11Repository serverRepository;
- private Server11RepositorySession repositorySession;
- private MockSessionFetchRecordsDelegate sessionFetchRecordsDelegate;
- private MockDownloader mockDownloader;
- private String DEFAULT_COLLECTION_NAME = "dummyCollection";
- private String DEFAULT_COLLECTION_URL = "http://dummy.url/";
- private long DEFAULT_NEWER = 1;
- private String DEFAULT_SORT = "index";
- private String DEFAULT_IDS = "1";
- private String DEFAULT_LMHEADER = "12345678";
-
- class MockSessionFetchRecordsDelegate implements RepositorySessionFetchRecordsDelegate {
- public boolean isFailure;
- public boolean isFetched;
- public boolean isSuccess;
- public Exception ex;
- public Record record;
-
- @Override
- public void onFetchFailed(Exception ex, Record record) {
- this.isFailure = true;
- this.ex = ex;
- this.record = record;
- }
-
- @Override
- public void onFetchedRecord(Record record) {
- this.isFetched = true;
- this.record = record;
- }
-
- @Override
- public void onFetchCompleted(long fetchEnd) {
- this.isSuccess = true;
- }
-
- @Override
- public RepositorySessionFetchRecordsDelegate deferredFetchDelegate(ExecutorService executor) {
- return null;
- }
- }
-
- class MockRequest extends SyncStorageCollectionRequest {
-
- public MockRequest(URI uri) {
- super(uri);
- }
-
- @Override
- public void get() {
-
- }
- }
-
- class MockDownloader extends BatchingDownloader {
- public long newer;
- public long limit;
- public boolean full;
- public String sort;
- public String ids;
- public String offset;
- public boolean abort;
-
- public MockDownloader(Server11Repository repository, Server11RepositorySession repositorySession) {
- super(repository, repositorySession);
- }
-
- @Override
- public void fetchWithParameters(long newer,
- long batchLimit,
- boolean full,
- String sort,
- String ids,
- SyncStorageCollectionRequest request,
- RepositorySessionFetchRecordsDelegate fetchRecordsDelegate)
- throws UnsupportedEncodingException, URISyntaxException {
- this.newer = newer;
- this.limit = batchLimit;
- this.full = full;
- this.sort = sort;
- this.ids = ids;
- MockRequest mockRequest = new MockRequest(new URI(DEFAULT_COLLECTION_URL));
- super.fetchWithParameters(newer, batchLimit, full, sort, ids, mockRequest, fetchRecordsDelegate);
- }
-
- @Override
- public void abortRequests() {
- this.abort = true;
- }
-
- @Override
- public SyncStorageCollectionRequest makeSyncStorageCollectionRequest(long newer,
- long batchLimit,
- boolean full,
- String sort,
- String ids,
- String offset)
- throws URISyntaxException, UnsupportedEncodingException {
- this.offset = offset;
- return super.makeSyncStorageCollectionRequest(newer, batchLimit, full, sort, ids, offset);
- }
- }
-
- class MockSever11Repository extends Server11Repository {
- public MockSever11Repository(@NonNull String collection, @NonNull String storageURL,
- AuthHeaderProvider authHeaderProvider, @NonNull InfoCollections infoCollections,
- @NonNull InfoConfiguration infoConfiguration) throws URISyntaxException {
- super(collection, storageURL, authHeaderProvider, infoCollections, infoConfiguration);
- }
-
- @Override
- public long getDefaultTotalLimit() {
- return 200;
- }
- }
-
- class MockRepositorySession extends Server11RepositorySession {
- public boolean abort;
-
- public MockRepositorySession(Repository repository) {
- super(repository);
- }
-
- @Override
- public void abort() {
- this.abort = true;
- }
- }
-
- @Before
- public void setUp() throws Exception {
- sessionFetchRecordsDelegate = new MockSessionFetchRecordsDelegate();
-
- serverRepository = new MockSever11Repository(DEFAULT_COLLECTION_NAME, DEFAULT_COLLECTION_URL, null,
- new InfoCollections(), new InfoConfiguration());
- repositorySession = new Server11RepositorySession(serverRepository);
- mockDownloader = new MockDownloader(serverRepository, repositorySession);
- }
-
- @Test
- public void testFlattenId() {
- String[] emptyGuid = new String[]{};
- String flatten = BatchingDownloader.flattenIDs(emptyGuid);
- assertEquals("", flatten);
-
- String guid0 = "123456789abc";
- String[] singleGuid = new String[1];
- singleGuid[0] = guid0;
- flatten = BatchingDownloader.flattenIDs(singleGuid);
- assertEquals("123456789abc", flatten);
-
- String guid1 = "456789abc";
- String guid2 = "789abc";
- String[] multiGuid = new String[3];
- multiGuid[0] = guid0;
- multiGuid[1] = guid1;
- multiGuid[2] = guid2;
- flatten = BatchingDownloader.flattenIDs(multiGuid);
- assertEquals("123456789abc,456789abc,789abc", flatten);
- }
-
- @Test
- public void testEncodeParam() throws Exception {
- String param = "123&123";
- String encodedParam = mockDownloader.encodeParam(param);
- assertEquals("123%26123", encodedParam);
- }
-
- @Test(expected=IllegalArgumentException.class)
- public void testOverTotalLimit() throws Exception {
- // Per-batch limits exceed total.
- Server11Repository repository = new Server11Repository(DEFAULT_COLLECTION_NAME, DEFAULT_COLLECTION_URL,
- null, new InfoCollections(), new InfoConfiguration()) {
- @Override
- public long getDefaultTotalLimit() {
- return 100;
- }
- @Override
- public long getDefaultBatchLimit() {
- return 200;
- }
- };
- MockDownloader mockDownloader = new MockDownloader(repository, repositorySession);
-
- assertNull(mockDownloader.getLastModified());
- mockDownloader.fetchSince(DEFAULT_NEWER, sessionFetchRecordsDelegate);
- }
-
- @Test
- public void testTotalLimit() throws Exception {
- // Total and per-batch limits are the same.
- Server11Repository repository = new Server11Repository(DEFAULT_COLLECTION_NAME, DEFAULT_COLLECTION_URL,
- null, new InfoCollections(), new InfoConfiguration()) {
- @Override
- public long getDefaultTotalLimit() {
- return 100;
- }
- @Override
- public long getDefaultBatchLimit() {
- return 100;
- }
- };
- MockDownloader mockDownloader = new MockDownloader(repository, repositorySession);
-
- assertNull(mockDownloader.getLastModified());
- mockDownloader.fetchSince(DEFAULT_NEWER, sessionFetchRecordsDelegate);
-
- SyncStorageResponse response = makeSyncStorageResponse(200, DEFAULT_LMHEADER, "100", "100");
- SyncStorageCollectionRequest request = new SyncStorageCollectionRequest(new URI(DEFAULT_COLLECTION_URL));
- long limit = repository.getDefaultBatchLimit();
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request,
- DEFAULT_NEWER, limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertEquals(DEFAULT_LMHEADER, mockDownloader.getLastModified());
- assertTrue(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
- }
-
- @Test
- public void testOverHalfOfTotalLimit() throws Exception {
- // Per-batch limit is just a bit lower than total.
- Server11Repository repository = new Server11Repository(DEFAULT_COLLECTION_NAME, DEFAULT_COLLECTION_URL,
- null, new InfoCollections(), new InfoConfiguration()) {
- @Override
- public long getDefaultTotalLimit() {
- return 100;
- }
- @Override
- public long getDefaultBatchLimit() {
- return 75;
- }
- };
- MockDownloader mockDownloader = new MockDownloader(repository, repositorySession);
-
- assertNull(mockDownloader.getLastModified());
- mockDownloader.fetchSince(DEFAULT_NEWER, sessionFetchRecordsDelegate);
-
- String offsetHeader = "75";
- String recordsHeader = "75";
- SyncStorageResponse response = makeSyncStorageResponse(200, DEFAULT_LMHEADER, offsetHeader, recordsHeader);
- SyncStorageCollectionRequest request = new SyncStorageCollectionRequest(new URI(DEFAULT_COLLECTION_URL));
- long limit = repository.getDefaultBatchLimit();
-
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertEquals(DEFAULT_LMHEADER, mockDownloader.getLastModified());
- // Verify the same parameters are used in the next fetch.
- assertSameParameters(mockDownloader, limit);
- assertEquals(offsetHeader, mockDownloader.offset);
- assertFalse(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
-
- // The next batch, we still have an offset token but we complete our fetch since we have reached the total limit.
- offsetHeader = "150";
- response = makeSyncStorageResponse(200, DEFAULT_LMHEADER, offsetHeader, recordsHeader);
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertEquals(DEFAULT_LMHEADER, mockDownloader.getLastModified());
- assertTrue(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
- }
-
- @Test
- public void testHalfOfTotalLimit() throws Exception {
- // Per-batch limit is half of total.
- Server11Repository repository = new Server11Repository(DEFAULT_COLLECTION_NAME, DEFAULT_COLLECTION_URL,
- null, new InfoCollections(), new InfoConfiguration()) {
- @Override
- public long getDefaultTotalLimit() {
- return 100;
- }
- @Override
- public long getDefaultBatchLimit() {
- return 50;
- }
- };
- mockDownloader = new MockDownloader(repository, repositorySession);
-
- assertNull(mockDownloader.getLastModified());
- mockDownloader.fetchSince(DEFAULT_NEWER, sessionFetchRecordsDelegate);
-
- String offsetHeader = "50";
- String recordsHeader = "50";
- SyncStorageResponse response = makeSyncStorageResponse(200, DEFAULT_LMHEADER, offsetHeader, recordsHeader);
- SyncStorageCollectionRequest request = new SyncStorageCollectionRequest(new URI(DEFAULT_COLLECTION_URL));
- long limit = repository.getDefaultBatchLimit();
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertEquals(DEFAULT_LMHEADER, mockDownloader.getLastModified());
- // Verify the same parameters are used in the next fetch.
- assertSameParameters(mockDownloader, limit);
- assertEquals(offsetHeader, mockDownloader.offset);
- assertFalse(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
-
- // The next batch, we still have an offset token but we complete our fetch since we have reached the total limit.
- offsetHeader = "100";
- response = makeSyncStorageResponse(200, DEFAULT_LMHEADER, offsetHeader, recordsHeader);
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertEquals(DEFAULT_LMHEADER, mockDownloader.getLastModified());
- assertTrue(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
- }
-
- @Test
- public void testFractionOfTotalLimit() throws Exception {
- // Per-batch limit is a small fraction of the total.
- Server11Repository repository = new Server11Repository(DEFAULT_COLLECTION_NAME, DEFAULT_COLLECTION_URL,
- null, new InfoCollections(), new InfoConfiguration()) {
- @Override
- public long getDefaultTotalLimit() {
- return 100;
- }
- @Override
- public long getDefaultBatchLimit() {
- return 25;
- }
- };
- mockDownloader = new MockDownloader(repository, repositorySession);
-
- assertNull(mockDownloader.getLastModified());
- mockDownloader.fetchSince(DEFAULT_NEWER, sessionFetchRecordsDelegate);
-
- String offsetHeader = "25";
- String recordsHeader = "25";
- SyncStorageResponse response = makeSyncStorageResponse(200, DEFAULT_LMHEADER, offsetHeader, recordsHeader);
- SyncStorageCollectionRequest request = new SyncStorageCollectionRequest(new URI(DEFAULT_COLLECTION_URL));
- long limit = repository.getDefaultBatchLimit();
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertEquals(DEFAULT_LMHEADER, mockDownloader.getLastModified());
- // Verify the same parameters are used in the next fetch.
- assertSameParameters(mockDownloader, limit);
- assertEquals(offsetHeader, mockDownloader.offset);
- assertFalse(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
-
- // The next batch, we still have an offset token and has not exceed the total limit.
- offsetHeader = "50";
- response = makeSyncStorageResponse(200, DEFAULT_LMHEADER, offsetHeader, recordsHeader);
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertEquals(DEFAULT_LMHEADER, mockDownloader.getLastModified());
- // Verify the same parameters are used in the next fetch.
- assertSameParameters(mockDownloader, limit);
- assertEquals(offsetHeader, mockDownloader.offset);
- assertFalse(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
-
- // The next batch, we still have an offset token and has not exceed the total limit.
- offsetHeader = "75";
- response = makeSyncStorageResponse(200, DEFAULT_LMHEADER, offsetHeader, recordsHeader);
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertEquals(DEFAULT_LMHEADER, mockDownloader.getLastModified());
- // Verify the same parameters are used in the next fetch.
- assertSameParameters(mockDownloader, limit);
- assertEquals(offsetHeader, mockDownloader.offset);
- assertFalse(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
-
- // The next batch, we still have an offset token but we complete our fetch since we have reached the total limit.
- offsetHeader = "100";
- response = makeSyncStorageResponse(200, DEFAULT_LMHEADER, offsetHeader, recordsHeader);
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertEquals(DEFAULT_LMHEADER, mockDownloader.getLastModified());
- assertTrue(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
- }
-
- @Test
- public void testFailureLMChangedMultiBatch() throws Exception {
- assertNull(mockDownloader.getLastModified());
-
- String lmHeader = "12345678";
- String offsetHeader = "100";
- SyncStorageResponse response = makeSyncStorageResponse(200, lmHeader, offsetHeader, null);
- SyncStorageCollectionRequest request = new SyncStorageCollectionRequest(new URI("http://dummy.url"));
- long limit = 1;
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertEquals(lmHeader, mockDownloader.getLastModified());
- // Verify the same parameters are used in the next fetch.
- assertEquals(DEFAULT_NEWER, mockDownloader.newer);
- assertEquals(limit, mockDownloader.limit);
- assertTrue(mockDownloader.full);
- assertEquals(DEFAULT_SORT, mockDownloader.sort);
- assertEquals(DEFAULT_IDS, mockDownloader.ids);
- assertEquals(offsetHeader, mockDownloader.offset);
- assertFalse(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
-
- // Last modified header somehow changed.
- lmHeader = "10000000";
- response = makeSyncStorageResponse(200, lmHeader, offsetHeader, null);
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- limit, true, DEFAULT_SORT, DEFAULT_IDS);
-
- assertNotEquals(lmHeader, mockDownloader.getLastModified());
- assertTrue(mockDownloader.abort);
- assertFalse(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertTrue(sessionFetchRecordsDelegate.isFailure);
- }
-
- @Test
- public void testFailureMissingLMMultiBatch() throws Exception {
- assertNull(mockDownloader.getLastModified());
-
- String offsetHeader = "100";
- SyncStorageResponse response = makeSyncStorageResponse(200, null, offsetHeader, null);
- SyncStorageCollectionRequest request = new SyncStorageCollectionRequest(new URI("http://dummy.url"));
- mockDownloader.onFetchCompleted(response, sessionFetchRecordsDelegate, request, DEFAULT_NEWER,
- 1, true, DEFAULT_SORT, DEFAULT_IDS);
-
- // Last modified header somehow missing from response.
- assertNull(null, mockDownloader.getLastModified());
- assertTrue(mockDownloader.abort);
- assertFalse(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertTrue(sessionFetchRecordsDelegate.isFailure);
- }
-
- @Test
- public void testFailureException() throws Exception {
- Exception ex = new IllegalStateException();
- SyncStorageCollectionRequest request = new SyncStorageCollectionRequest(new URI("http://dummy.url"));
- mockDownloader.onFetchFailed(ex, sessionFetchRecordsDelegate, request);
-
- assertFalse(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFetched);
- assertTrue(sessionFetchRecordsDelegate.isFailure);
- assertEquals(ex.getClass(), sessionFetchRecordsDelegate.ex.getClass());
- assertNull(sessionFetchRecordsDelegate.record);
- }
-
- @Test
- public void testFetchRecord() {
- CryptoRecord record = new CryptoRecord();
- mockDownloader.onFetchedRecord(record, sessionFetchRecordsDelegate);
-
- assertTrue(sessionFetchRecordsDelegate.isFetched);
- assertFalse(sessionFetchRecordsDelegate.isSuccess);
- assertFalse(sessionFetchRecordsDelegate.isFailure);
- assertEquals(record, sessionFetchRecordsDelegate.record);
- }
-
- @Test
- public void testAbortRequests() {
- MockRepositorySession mockRepositorySession = new MockRepositorySession(serverRepository);
- BatchingDownloader downloader = new BatchingDownloader(serverRepository, mockRepositorySession);
- assertFalse(mockRepositorySession.abort);
- downloader.abortRequests();
- assertTrue(mockRepositorySession.abort);
- }
-
- private void assertSameParameters(MockDownloader mockDownloader, long limit) {
- assertEquals(DEFAULT_NEWER, mockDownloader.newer);
- assertEquals(limit, mockDownloader.limit);
- assertTrue(mockDownloader.full);
- assertEquals(DEFAULT_SORT, mockDownloader.sort);
- assertEquals(DEFAULT_IDS, mockDownloader.ids);
- }
-
- private SyncStorageResponse makeSyncStorageResponse(int code, String lastModified, String offset, String records) {
- BasicHttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), code, null));
-
- if (lastModified != null) {
- response.addHeader(SyncResponse.X_LAST_MODIFIED, lastModified);
- }
-
- if (offset != null) {
- response.addHeader(SyncResponse.X_WEAVE_NEXT_OFFSET, offset);
- }
-
- if (records != null) {
- response.addHeader(SyncResponse.X_WEAVE_RECORDS, records);
- }
-
- return new SyncStorageResponse(response);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/test/TestRepositorySessionBundle.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/test/TestRepositorySessionBundle.java
deleted file mode 100644
index e81d13640..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/test/TestRepositorySessionBundle.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-@RunWith(TestRunner.class)
-public class TestRepositorySessionBundle {
- @Test
- public void testSetGetTimestamp() {
- RepositorySessionBundle bundle = new RepositorySessionBundle(-1);
- assertEquals(-1, bundle.getTimestamp());
-
- bundle.setTimestamp(10);
- assertEquals(10, bundle.getTimestamp());
- }
-
- @Test
- public void testBumpTimestamp() {
- RepositorySessionBundle bundle = new RepositorySessionBundle(50);
- assertEquals(50, bundle.getTimestamp());
-
- bundle.bumpTimestamp(20);
- assertEquals(50, bundle.getTimestamp());
-
- bundle.bumpTimestamp(80);
- assertEquals(80, bundle.getTimestamp());
- }
-
- @Test
- public void testSerialize() throws Exception {
- RepositorySessionBundle bundle = new RepositorySessionBundle(50);
-
- String json = bundle.toJSONString();
- assertNotNull(json);
-
- RepositorySessionBundle read = new RepositorySessionBundle(json);
- assertEquals(50, read.getTimestamp());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/test/TestSafeConstrainedServer11Repository.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/test/TestSafeConstrainedServer11Repository.java
deleted file mode 100644
index 249a7831a..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/test/TestSafeConstrainedServer11Repository.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.test;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.InfoConfiguration;
-import org.mozilla.gecko.sync.JSONRecordFetcher;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.repositories.RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
-import org.mozilla.gecko.sync.stage.SafeConstrainedServer11Repository;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.net.URISyntaxException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-@RunWith(TestRunner.class)
-public class TestSafeConstrainedServer11Repository {
- private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private static final String TEST_SERVER = "http://localhost:" + TEST_PORT + "/";
- private static final String TEST_USERNAME = "c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd";
- private static final String TEST_BASE_PATH = "/1.1/" + TEST_USERNAME + "/";
-
- public AuthHeaderProvider getAuthHeaderProvider() {
- return null;
- }
-
- protected final InfoCollections infoCollections = new InfoCollections();
- protected final InfoConfiguration infoConfiguration = new InfoConfiguration();
-
- private class CountsMockServer extends MockServer {
- public final AtomicInteger count = new AtomicInteger(0);
- public final AtomicBoolean error = new AtomicBoolean(false);
-
- @Override
- public void handle(Request request, Response response) {
- final String path = request.getPath().getPath();
- if (error.get()) {
- super.handle(request, response, 503, "Unavailable.");
- return;
- }
-
- if (!path.startsWith(TEST_BASE_PATH)) {
- super.handle(request, response, 404, "Not Found");
- return;
- }
-
- if (path.endsWith("info/collections")) {
- super.handle(request, response, 200, "{\"rotary\": 123456789}");
- return;
- }
-
- if (path.endsWith("info/collection_counts")) {
- super.handle(request, response, 200, "{\"rotary\": " + count.get() + "}");
- return;
- }
-
- super.handle(request, response);
- }
- }
-
- /**
- * Ensure that a {@link SafeConstrainedServer11Repository} will advise
- * skipping if the reported collection counts are higher than its limit.
- */
- @Test
- public void testShouldSkip() throws URISyntaxException {
- final HTTPServerTestHelper data = new HTTPServerTestHelper();
- final CountsMockServer server = new CountsMockServer();
- data.startHTTPServer(server);
-
- try {
- String countsURL = TEST_SERVER + TEST_BASE_PATH + "info/collection_counts";
- JSONRecordFetcher countFetcher = new JSONRecordFetcher(countsURL, getAuthHeaderProvider());
- String sort = "sortindex";
- String collection = "rotary";
-
- final int TEST_LIMIT = 1000;
- final SafeConstrainedServer11Repository repo = new SafeConstrainedServer11Repository(
- collection, getCollectionURL(collection), null, infoCollections, infoConfiguration,
- TEST_LIMIT, TEST_LIMIT, sort, countFetcher);
-
- final AtomicBoolean shouldSkipLots = new AtomicBoolean(false);
- final AtomicBoolean shouldSkipFew = new AtomicBoolean(true);
- final AtomicBoolean shouldSkip503 = new AtomicBoolean (false);
-
- WaitHelper.getTestWaiter().performWait(2000, new Runnable() {
- @Override
- public void run() {
- repo.createSession(new RepositorySessionCreationDelegate() {
- @Override
- public void onSessionCreated(RepositorySession session) {
- // Try with too many items.
- server.count.set(TEST_LIMIT + 1);
- shouldSkipLots.set(session.shouldSkip());
-
- // … and few enough that we should sync.
- server.count.set(TEST_LIMIT - 1);
- shouldSkipFew.set(session.shouldSkip());
-
- // Now try with an error response. We advise skipping if we can't
- // fetch counts, because we'll try again later.
- server.error.set(true);
- shouldSkip503.set(session.shouldSkip());
-
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void onSessionCreateFailed(Exception ex) {
- WaitHelper.getTestWaiter().performNotify(ex);
- }
-
- @Override
- public RepositorySessionCreationDelegate deferredCreationDelegate() {
- return this;
- }
- }, null);
- }
- });
-
- Assert.assertTrue(shouldSkipLots.get());
- Assert.assertFalse(shouldSkipFew.get());
- Assert.assertTrue(shouldSkip503.get());
-
- } finally {
- data.stopHTTPServer();
- }
- }
-
- protected String getCollectionURL(String collection) {
- return TEST_BASE_PATH + "/storage/" + collection;
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/BatchMetaTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/BatchMetaTest.java
deleted file mode 100644
index 2e136c117..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/BatchMetaTest.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.uploaders;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class BatchMetaTest {
- private BatchMeta batchMeta;
- private long byteLimit = 1024;
- private long recordLimit = 5;
- private Object lock = new Object();
- private Long collectionLastModified = 123L;
-
- @Before
- public void setUp() throws Exception {
- batchMeta = new BatchMeta(lock, byteLimit, recordLimit, collectionLastModified);
- }
-
- @Test
- public void testConstructor() {
- assertEquals(batchMeta.collectionLastModified, collectionLastModified);
-
- BatchMeta otherBatchMeta = new BatchMeta(lock, byteLimit, recordLimit, null);
- assertNull(otherBatchMeta.collectionLastModified);
- }
-
- @Test
- public void testGetLastModified() {
- // Defaults to collection L-M
- assertEquals(batchMeta.getLastModified(), Long.valueOf(123L));
-
- try {
- batchMeta.setLastModified(333L, true);
- } catch (BatchingUploader.LastModifiedChangedUnexpectedly e) {
- } catch (BatchingUploader.LastModifiedDidNotChange e) {}
-
- assertEquals(batchMeta.getLastModified(), Long.valueOf(333L));
- }
-
- @Test
- public void testSetLastModified() {
- assertEquals(batchMeta.getLastModified(), collectionLastModified);
-
- try {
- batchMeta.setLastModified(123L, true);
- assertEquals(batchMeta.getLastModified(), Long.valueOf(123L));
- } catch (BatchingUploader.LastModifiedChangedUnexpectedly e) {
- fail("Should not check for modifications on first L-M set");
- } catch (BatchingUploader.LastModifiedDidNotChange e) {
- fail("Should not check for modifications on first L-M set");
- }
-
- // Now the same, but passing in 'false' for "expecting to change".
- batchMeta.reset();
- assertEquals(batchMeta.getLastModified(), collectionLastModified);
-
- try {
- batchMeta.setLastModified(123L, false);
- assertEquals(batchMeta.getLastModified(), Long.valueOf(123L));
- } catch (BatchingUploader.LastModifiedChangedUnexpectedly e) {
- fail("Should not check for modifications on first L-M set");
- } catch (BatchingUploader.LastModifiedDidNotChange e) {
- fail("Should not check for modifications on first L-M set");
- }
-
- // Test that we can't modify L-M when we're not expecting to
- try {
- batchMeta.setLastModified(333L, false);
- } catch (BatchingUploader.LastModifiedChangedUnexpectedly e) {
- assertTrue("Must throw when L-M changes unexpectedly", true);
- } catch (BatchingUploader.LastModifiedDidNotChange e) {
- fail("Not expecting did-not-change throw");
- }
- assertEquals(batchMeta.getLastModified(), Long.valueOf(123L));
-
- // Test that we can modify L-M when we're expecting to
- try {
- batchMeta.setLastModified(333L, true);
- } catch (BatchingUploader.LastModifiedChangedUnexpectedly e) {
- fail("Not expecting changed-unexpectedly throw");
- } catch (BatchingUploader.LastModifiedDidNotChange e) {
- fail("Not expecting did-not-change throw");
- }
- assertEquals(batchMeta.getLastModified(), Long.valueOf(333L));
-
- // Test that we catch L-M modifications that expect to change but actually don't
- try {
- batchMeta.setLastModified(333L, true);
- } catch (BatchingUploader.LastModifiedChangedUnexpectedly e) {
- fail("Not expecting changed-unexpectedly throw");
- } catch (BatchingUploader.LastModifiedDidNotChange e) {
- assertTrue("Expected-to-change-but-did-not-change didn't throw", true);
- }
- assertEquals(batchMeta.getLastModified(), Long.valueOf(333));
- }
-
- @Test
- public void testSetToken() {
- assertNull(batchMeta.getToken());
-
- try {
- batchMeta.setToken("MTIzNA", false);
- } catch (BatchingUploader.TokenModifiedException e) {
- fail("Should be able to set token for the first time");
- }
- assertEquals("MTIzNA", batchMeta.getToken());
-
- try {
- batchMeta.setToken("XYCvNA", false);
- } catch (BatchingUploader.TokenModifiedException e) {
- assertTrue("Should not be able to modify a token", true);
- }
- assertEquals("MTIzNA", batchMeta.getToken());
-
- try {
- batchMeta.setToken("XYCvNA", true);
- } catch (BatchingUploader.TokenModifiedException e) {
- assertTrue("Should catch non-null tokens during onCommit sets", true);
- }
- assertEquals("MTIzNA", batchMeta.getToken());
-
- try {
- batchMeta.setToken(null, true);
- } catch (BatchingUploader.TokenModifiedException e) {
- fail("Should be able to set token to null during onCommit set");
- }
- assertNull(batchMeta.getToken());
- }
-
- @Test
- public void testRecordSucceeded() {
- assertTrue(batchMeta.getSuccessRecordGuids().isEmpty());
-
- batchMeta.recordSucceeded("guid1");
-
- assertTrue(batchMeta.getSuccessRecordGuids().size() == 1);
- assertTrue(batchMeta.getSuccessRecordGuids().contains("guid1"));
-
- try {
- batchMeta.recordSucceeded(null);
- fail();
- } catch (IllegalStateException e) {
- assertTrue("Should not be able to 'succeed' a null guid", true);
- }
- }
-
- @Test
- public void testByteLimits() {
- assertTrue(batchMeta.canFit(0));
-
- // Should just fit
- assertTrue(batchMeta.canFit(byteLimit - BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT));
-
- // Can't fit a record due to payload overhead.
- assertFalse(batchMeta.canFit(byteLimit));
-
- assertFalse(batchMeta.canFit(byteLimit + BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT));
- assertFalse(batchMeta.canFit(byteLimit * 1000));
-
- long recordDelta = byteLimit / 2;
- assertFalse(batchMeta.addAndEstimateIfFull(recordDelta));
-
- // Record delta shouldn't fit due to payload overhead.
- assertFalse(batchMeta.canFit(recordDelta));
- }
-
- @Test
- public void testCountLimits() {
- // Our record limit is 5, let's add 4.
- assertFalse(batchMeta.addAndEstimateIfFull(1));
- assertFalse(batchMeta.addAndEstimateIfFull(1));
- assertFalse(batchMeta.addAndEstimateIfFull(1));
- assertFalse(batchMeta.addAndEstimateIfFull(1));
-
- // 5th record still fits in
- assertTrue(batchMeta.canFit(1));
-
- // Add the 5th record
- assertTrue(batchMeta.addAndEstimateIfFull(1));
-
- // 6th record won't fit
- assertFalse(batchMeta.canFit(1));
- }
-
- @Test
- public void testNeedCommit() {
- assertFalse(batchMeta.needToCommit());
-
- assertFalse(batchMeta.addAndEstimateIfFull(1));
-
- assertTrue(batchMeta.needToCommit());
-
- assertFalse(batchMeta.addAndEstimateIfFull(1));
- assertFalse(batchMeta.addAndEstimateIfFull(1));
- assertFalse(batchMeta.addAndEstimateIfFull(1));
-
- assertTrue(batchMeta.needToCommit());
-
- batchMeta.reset();
-
- assertFalse(batchMeta.needToCommit());
- }
-
- @Test
- public void testAdd() {
- // Ensure we account for payload overhead twice when the batch is empty.
- // Payload overhead is either RECORDS_START or RECORDS_END, and for an empty payload
- // we need both.
- assertTrue(batchMeta.getByteCount() == 2 * BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT);
- assertTrue(batchMeta.getRecordCount() == 0);
-
- assertFalse(batchMeta.addAndEstimateIfFull(1));
-
- assertTrue(batchMeta.getByteCount() == (1 + BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT));
- assertTrue(batchMeta.getRecordCount() == 1);
-
- assertFalse(batchMeta.addAndEstimateIfFull(1));
- assertFalse(batchMeta.addAndEstimateIfFull(1));
- assertFalse(batchMeta.addAndEstimateIfFull(1));
-
- assertTrue(batchMeta.getByteCount() == (4 + BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT));
- assertTrue(batchMeta.getRecordCount() == 4);
-
- assertTrue(batchMeta.addAndEstimateIfFull(1));
-
- try {
- assertTrue(batchMeta.addAndEstimateIfFull(1));
- fail("BatchMeta should not let us insert records that won't fit");
- } catch (IllegalStateException e) {
- assertTrue(true);
- }
- }
-
- @Test
- public void testReset() {
- assertTrue(batchMeta.getByteCount() == 2 * BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT);
- assertTrue(batchMeta.getRecordCount() == 0);
- assertTrue(batchMeta.getSuccessRecordGuids().isEmpty());
-
- // Shouldn't throw even if already empty
- batchMeta.reset();
- assertTrue(batchMeta.getByteCount() == 2 * BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT);
- assertTrue(batchMeta.getRecordCount() == 0);
- assertTrue(batchMeta.getSuccessRecordGuids().isEmpty());
-
- assertFalse(batchMeta.addAndEstimateIfFull(1));
- batchMeta.recordSucceeded("guid1");
- try {
- batchMeta.setToken("MTIzNA", false);
- } catch (BatchingUploader.TokenModifiedException e) {}
- try {
- batchMeta.setLastModified(333L, true);
- } catch (BatchingUploader.LastModifiedChangedUnexpectedly e) {
- } catch (BatchingUploader.LastModifiedDidNotChange e) {}
- assertEquals(Long.valueOf(333L), batchMeta.getLastModified());
- assertEquals("MTIzNA", batchMeta.getToken());
- assertTrue(batchMeta.getSuccessRecordGuids().size() == 1);
-
- batchMeta.reset();
-
- // Counts must be reset
- assertTrue(batchMeta.getByteCount() == 2 * BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT);
- assertTrue(batchMeta.getRecordCount() == 0);
- assertTrue(batchMeta.getSuccessRecordGuids().isEmpty());
-
- // Collection L-M shouldn't change
- assertEquals(batchMeta.collectionLastModified, collectionLastModified);
-
- // Token must be reset
- assertNull(batchMeta.getToken());
-
- // L-M must be reverted to collection L-M
- assertEquals(batchMeta.getLastModified(), collectionLastModified);
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/BatchingUploaderTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/BatchingUploaderTest.java
deleted file mode 100644
index 5ce94b222..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/BatchingUploaderTest.java
+++ /dev/null
@@ -1,441 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.uploaders;
-
-import android.support.annotation.NonNull;
-
-import static org.junit.Assert.*;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.MockRecord;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.InfoConfiguration;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.Server11Repository;
-import org.mozilla.gecko.sync.repositories.Server11RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
-
-import java.net.URISyntaxException;
-import java.util.Random;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-
-@RunWith(TestRunner.class)
-public class BatchingUploaderTest {
- class MockExecutorService implements Executor {
- public int totalPayloads = 0;
- public int commitPayloads = 0;
-
- @Override
- public void execute(@NonNull Runnable command) {
- ++totalPayloads;
- if (((RecordUploadRunnable) command).isCommit) {
- ++commitPayloads;
- }
- }
- }
-
- class MockStoreDelegate implements RepositorySessionStoreDelegate {
- public int storeFailed = 0;
- public int storeSucceeded = 0;
- public int storeCompleted = 0;
-
- @Override
- public void onRecordStoreFailed(Exception ex, String recordGuid) {
- ++storeFailed;
- }
-
- @Override
- public void onRecordStoreSucceeded(String guid) {
- ++storeSucceeded;
- }
-
- @Override
- public void onStoreCompleted(long storeEnd) {
- ++storeCompleted;
- }
-
- @Override
- public RepositorySessionStoreDelegate deferredStoreDelegate(ExecutorService executor) {
- return null;
- }
- }
-
- private Executor workQueue;
- private RepositorySessionStoreDelegate storeDelegate;
-
- @Before
- public void setUp() throws Exception {
- workQueue = new MockExecutorService();
- storeDelegate = new MockStoreDelegate();
- }
-
- @Test
- public void testProcessEvenPayloadBatch() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- MockRecord record = new MockRecord(Utils.generateGuid(), null, 0, false);
- // 1st
- uploader.process(record);
- assertEquals(0, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- // 2nd -> payload full
- uploader.process(record);
- assertEquals(1, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- // 3rd
- uploader.process(record);
- assertEquals(1, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- // 4th -> batch & payload full
- uploader.process(record);
- assertEquals(2, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- // 5th
- uploader.process(record);
- assertEquals(2, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- // 6th -> payload full
- uploader.process(record);
- assertEquals(3, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- // 7th
- uploader.process(record);
- assertEquals(3, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- // 8th -> batch & payload full
- uploader.process(record);
- assertEquals(4, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(2, ((MockExecutorService) workQueue).commitPayloads);
- // 9th
- uploader.process(record);
- assertEquals(4, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(2, ((MockExecutorService) workQueue).commitPayloads);
- // 10th -> payload full
- uploader.process(record);
- assertEquals(5, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(2, ((MockExecutorService) workQueue).commitPayloads);
- // 11th
- uploader.process(record);
- assertEquals(5, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(2, ((MockExecutorService) workQueue).commitPayloads);
- // 12th -> batch & payload full
- uploader.process(record);
- assertEquals(6, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(3, ((MockExecutorService) workQueue).commitPayloads);
- // 13th
- uploader.process(record);
- assertEquals(6, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(3, ((MockExecutorService) workQueue).commitPayloads);
- }
-
- @Test
- public void testProcessUnevenPayloadBatch() {
- BatchingUploader uploader = makeConstrainedUploader(2, 5);
-
- MockRecord record = new MockRecord(Utils.generateGuid(), null, 0, false);
- // 1st
- uploader.process(record);
- assertEquals(0, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- // 2nd -> payload full
- uploader.process(record);
- assertEquals(1, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- // 3rd
- uploader.process(record);
- assertEquals(1, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- // 4th -> payload full
- uploader.process(record);
- assertEquals(2, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- // 5th -> batch full
- uploader.process(record);
- assertEquals(3, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- // 6th -> starts new batch
- uploader.process(record);
- assertEquals(3, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- // 7th -> payload full
- uploader.process(record);
- assertEquals(4, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- // 8th
- uploader.process(record);
- assertEquals(4, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- // 9th -> payload full
- uploader.process(record);
- assertEquals(5, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- // 10th -> batch full
- uploader.process(record);
- assertEquals(6, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(2, ((MockExecutorService) workQueue).commitPayloads);
- // 11th -> starts new batch
- uploader.process(record);
- assertEquals(6, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(2, ((MockExecutorService) workQueue).commitPayloads);
- }
-
- @Test
- public void testNonBatchingOptimization() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- MockRecord record = new MockRecord(Utils.generateGuid(), null, 0, false);
- // 1st
- uploader.process(record);
- assertEquals(0, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- // 2nd
- uploader.process(record);
- assertEquals(1, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- // 3rd
- uploader.process(record);
- assertEquals(1, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- // 4th
- uploader.process(record);
- assertEquals(2, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
-
- // 5th
- uploader.process(record);
- assertEquals(2, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
-
- // And now we tell uploader that batching isn't supported.
- // It shouldn't bother with batches from now on, just payloads.
- uploader.setInBatchingMode(false);
-
- // 6th
- uploader.process(record);
- assertEquals(3, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
-
- // 7th
- uploader.process(record);
- assertEquals(3, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
-
- // 8th
- uploader.process(record);
- assertEquals(4, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
-
- // 9th
- uploader.process(record);
- assertEquals(4, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
-
- // 10th
- uploader.process(record);
- assertEquals(5, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- }
-
- @Test
- public void testPreemtiveUploadByteCounts() {
- // While processing a record, if we know for sure that another one won't fit,
- // we upload the payload.
- BatchingUploader uploader = makeConstrainedUploader(3, 6);
-
- // Payload byte max: 1024; batch byte max: 4096
- MockRecord record = new MockRecord(Utils.generateGuid(), null, 0, false, 400);
-
- uploader.process(record);
- assertEquals(0, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
-
- // After 2nd record, byte count is at 800+overhead. Our payload max is 1024, so it's unlikely
- // we can fit another record at this pace. Expect payload to be uploaded.
- uploader.process(record);
- assertEquals(1, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
-
- // After this record, we'll have less than 124 bytes of room left in the payload. Expect upload.
- record = new MockRecord(Utils.generateGuid(), null, 0, false, 970);
- uploader.process(record);
- assertEquals(2, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
-
- uploader.process(record);
- assertEquals(3, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
-
- // At this point our byte count for the batch is at 3600+overhead;
- // since we have just 496 bytes left in the batch, it's unlikely we'll fit another record.
- // Expect a batch commit
- uploader.process(record);
- assertEquals(4, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- }
-
- @Test
- public void testRandomPayloadSizesBatching() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- final Random random = new Random();
- for (int i = 0; i < 15000; i++) {
- uploader.process(new MockRecord(Utils.generateGuid(), null, 0, false, random.nextInt(15000)));
- }
- }
-
- @Test
- public void testRandomPayloadSizesNonBatching() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- final Random random = new Random();
- uploader.setInBatchingMode(false);
- for (int i = 0; i < 15000; i++) {
- uploader.process(new MockRecord(Utils.generateGuid(), null, 0, false, random.nextInt(15000)));
- }
- }
-
- @Test
- public void testRandomPayloadSizesNonBatchingDelayed() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- final Random random = new Random();
- // Delay telling uploader that batching isn't supported.
- // Randomize how many records we wait for.
- final int delay = random.nextInt(20);
- for (int i = 0; i < 15000; i++) {
- if (delay == i) {
- uploader.setInBatchingMode(false);
- }
- uploader.process(new MockRecord(Utils.generateGuid(), null, 0, false, random.nextInt(15000)));
- }
- }
-
- @Test
- public void testNoMoreRecordsAfterPayloadPost() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- // Process two records (payload limit is also two, batch is four),
- // and ensure that 'no more records' commits.
- MockRecord record = new MockRecord(Utils.generateGuid(), null, 0, false);
- uploader.process(record);
- uploader.process(record);
- uploader.setInBatchingMode(true);
- uploader.commitIfNecessaryAfterLastPayload();
- // One will be a payload post, the other one is batch commit (empty payload)
- assertEquals(2, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- }
-
- @Test
- public void testNoMoreRecordsAfterPayloadPostWithOneRecordLeft() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- // Process two records (payload limit is also two, batch is four),
- // and ensure that 'no more records' commits.
- MockRecord record = new MockRecord(Utils.generateGuid(), null, 0, false);
- uploader.process(record);
- uploader.process(record);
- uploader.process(record);
- uploader.commitIfNecessaryAfterLastPayload();
- // One will be a payload post, the other one is batch commit (one record payload)
- assertEquals(2, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- }
-
- @Test
- public void testNoMoreRecordsNoOp() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- uploader.commitIfNecessaryAfterLastPayload();
- assertEquals(0, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- }
-
- @Test
- public void testNoMoreRecordsNoOpAfterCommit() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- MockRecord record = new MockRecord(Utils.generateGuid(), null, 0, false);
- uploader.process(record);
- uploader.process(record);
- uploader.process(record);
- uploader.process(record);
- assertEquals(2, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
-
- uploader.commitIfNecessaryAfterLastPayload();
- assertEquals(2, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- }
-
- @Test
- public void testNoMoreRecordsEvenNonBatching() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- // Process two records (payload limit is also two, batch is four),
- // set non-batching mode, and ensure that 'no more records' doesn't commit.
- MockRecord record = new MockRecord(Utils.generateGuid(), null, 0, false);
- uploader.process(record);
- uploader.process(record);
- uploader.setInBatchingMode(false);
- uploader.commitIfNecessaryAfterLastPayload();
- // One will be a payload post, the other one is batch commit (one record payload)
- assertEquals(1, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(0, ((MockExecutorService) workQueue).commitPayloads);
- }
-
- @Test
- public void testNoMoreRecordsIncompletePayload() {
- BatchingUploader uploader = makeConstrainedUploader(2, 4);
-
- // We have one record (payload limit is 2), and "no-more-records" signal should commit it.
- MockRecord record = new MockRecord(Utils.generateGuid(), null, 0, false);
- uploader.process(record);
-
- uploader.commitIfNecessaryAfterLastPayload();
- assertEquals(1, ((MockExecutorService) workQueue).totalPayloads);
- assertEquals(1, ((MockExecutorService) workQueue).commitPayloads);
- }
-
- private BatchingUploader makeConstrainedUploader(long maxPostRecords, long maxTotalRecords) {
- Server11RepositorySession server11RepositorySession = new Server11RepositorySession(
- makeCountConstrainedRepository(maxPostRecords, maxTotalRecords)
- );
- server11RepositorySession.setStoreDelegate(storeDelegate);
- return new BatchingUploader(server11RepositorySession, workQueue, storeDelegate);
- }
-
- private Server11Repository makeCountConstrainedRepository(long maxPostRecords, long maxTotalRecords) {
- return makeConstrainedRepository(1024, 1024, maxPostRecords, 4096, maxTotalRecords);
- }
-
- private Server11Repository makeConstrainedRepository(long maxRequestBytes, long maxPostBytes, long maxPostRecords, long maxTotalBytes, long maxTotalRecords) {
- ExtendedJSONObject infoConfigurationJSON = new ExtendedJSONObject();
- infoConfigurationJSON.put(InfoConfiguration.MAX_TOTAL_BYTES, maxTotalBytes);
- infoConfigurationJSON.put(InfoConfiguration.MAX_TOTAL_RECORDS, maxTotalRecords);
- infoConfigurationJSON.put(InfoConfiguration.MAX_POST_RECORDS, maxPostRecords);
- infoConfigurationJSON.put(InfoConfiguration.MAX_POST_BYTES, maxPostBytes);
- infoConfigurationJSON.put(InfoConfiguration.MAX_REQUEST_BYTES, maxRequestBytes);
-
- InfoConfiguration infoConfiguration = new InfoConfiguration(infoConfigurationJSON);
-
- try {
- return new Server11Repository(
- "dummyCollection",
- "http://dummy.url/",
- null,
- new InfoCollections(),
- infoConfiguration
- );
- } catch (URISyntaxException e) {
- // Won't throw, and this won't happen.
- return null;
- }
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/PayloadTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/PayloadTest.java
deleted file mode 100644
index b1d6dd9d0..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/PayloadTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.uploaders;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class PayloadTest {
- private Payload payload;
- private long byteLimit = 1024;
- private long recordLimit = 5;
- private Object lock = new Object();
-
- @Before
- public void setUp() throws Exception {
- payload = new Payload(lock, byteLimit, recordLimit);
- }
-
- @Test
- public void testByteLimits() {
- assertTrue(payload.canFit(0));
-
- // Should just fit
- assertTrue(payload.canFit(byteLimit - BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT));
-
- // Can't fit a record due to payload overhead.
- assertFalse(payload.canFit(byteLimit));
-
- assertFalse(payload.canFit(byteLimit + BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT));
- assertFalse(payload.canFit(byteLimit * 1000));
-
- long recordDelta = byteLimit / 2;
- assertFalse(payload.addAndEstimateIfFull(recordDelta, new byte[0], null));
-
- // Record delta shouldn't fit due to payload overhead.
- assertFalse(payload.canFit(recordDelta));
- }
-
- @Test
- public void testCountLimits() {
- byte[] bytes = new byte[0];
-
- // Our record limit is 5, let's add 4.
- assertFalse(payload.addAndEstimateIfFull(1, bytes, null));
- assertFalse(payload.addAndEstimateIfFull(1, bytes, null));
- assertFalse(payload.addAndEstimateIfFull(1, bytes, null));
- assertFalse(payload.addAndEstimateIfFull(1, bytes, null));
-
- // 5th record still fits in
- assertTrue(payload.canFit(1));
-
- // Add the 5th record
- assertTrue(payload.addAndEstimateIfFull(1, bytes, null));
-
- // 6th record won't fit
- assertFalse(payload.canFit(1));
- }
-
- @Test
- public void testAdd() {
- assertTrue(payload.getByteCount() == 2 * BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT);
- assertTrue(payload.getRecordCount() == 0);
- assertTrue(payload.isEmpty());
- assertTrue(payload.getRecordsBuffer().isEmpty());
- assertTrue(payload.getRecordGuidsBuffer().isEmpty());
-
- try {
- payload.addAndEstimateIfFull(1024);
- fail("Simple add is not supported");
- } catch (UnsupportedOperationException e) {
- assertTrue(true);
- }
-
- byte[] recordBytes1 = new byte[100];
- assertFalse(payload.addAndEstimateIfFull(1, recordBytes1, "guid1"));
-
- assertTrue(payload.getRecordsBuffer().size() == 1);
- assertTrue(payload.getRecordGuidsBuffer().size() == 1);
- assertTrue(payload.getRecordGuidsBuffer().contains("guid1"));
- assertTrue(payload.getRecordsBuffer().contains(recordBytes1));
-
- assertTrue(payload.getByteCount() == (1 + BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT));
- assertTrue(payload.getRecordCount() == 1);
-
- assertFalse(payload.isEmpty());
-
- assertFalse(payload.addAndEstimateIfFull(1, recordBytes1, "guid2"));
- assertFalse(payload.addAndEstimateIfFull(1, recordBytes1, "guid3"));
- assertFalse(payload.addAndEstimateIfFull(1, recordBytes1, "guid4"));
-
- assertTrue(payload.getByteCount() == (4 + BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT));
- assertTrue(payload.getRecordCount() == 4);
-
- assertTrue(payload.addAndEstimateIfFull(1, recordBytes1, "guid5"));
-
- try {
- assertTrue(payload.addAndEstimateIfFull(1, recordBytes1, "guid6"));
- fail("Payload should not let us insert records that won't fit");
- } catch (IllegalStateException e) {
- assertTrue(true);
- }
- }
-
- @Test
- public void testReset() {
- assertTrue(payload.getByteCount() == 2 * BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT);
- assertTrue(payload.getRecordCount() == 0);
- assertTrue(payload.getRecordsBuffer().isEmpty());
- assertTrue(payload.getRecordGuidsBuffer().isEmpty());
- assertTrue(payload.isEmpty());
-
- // Shouldn't throw even if already empty
- payload.reset();
- assertTrue(payload.getByteCount() == 2 * BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT);
- assertTrue(payload.getRecordCount() == 0);
- assertTrue(payload.getRecordsBuffer().isEmpty());
- assertTrue(payload.getRecordGuidsBuffer().isEmpty());
- assertTrue(payload.isEmpty());
-
- byte[] recordBytes1 = new byte[100];
- assertFalse(payload.addAndEstimateIfFull(1, recordBytes1, "guid1"));
- assertFalse(payload.isEmpty());
- payload.reset();
-
- assertTrue(payload.getByteCount() == 2 * BatchingUploader.PER_PAYLOAD_OVERHEAD_BYTE_COUNT);
- assertTrue(payload.getRecordCount() == 0);
- assertTrue(payload.getRecordsBuffer().isEmpty());
- assertTrue(payload.getRecordGuidsBuffer().isEmpty());
- assertTrue(payload.isEmpty());
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/PayloadUploadDelegateTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/PayloadUploadDelegateTest.java
deleted file mode 100644
index fc43c2f5e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/PayloadUploadDelegateTest.java
+++ /dev/null
@@ -1,404 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.uploaders;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.HTTPFailureException;
-import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.InfoConfiguration;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.net.SyncResponse;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.mozilla.gecko.sync.repositories.Server11Repository;
-import org.mozilla.gecko.sync.repositories.Server11RepositorySession;
-import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
-
-import java.io.ByteArrayInputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.concurrent.Executor;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.ProtocolVersion;
-import ch.boye.httpclientandroidlib.entity.BasicHttpEntity;
-import ch.boye.httpclientandroidlib.message.BasicHttpResponse;
-import ch.boye.httpclientandroidlib.message.BasicStatusLine;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class PayloadUploadDelegateTest {
- private BatchingUploader batchingUploader;
-
- class MockUploader extends BatchingUploader {
- public final ArrayList<String> successRecords = new ArrayList<>();
- public final HashMap<String, Exception> failedRecords = new HashMap<>();
- public boolean didLastPayloadFail = false;
-
- public ArrayList<SyncStorageResponse> successResponses = new ArrayList<>();
- public int commitPayloadsSucceeded = 0;
- public int lastPayloadsSucceeded = 0;
-
- public MockUploader(final Server11RepositorySession repositorySession, final Executor workQueue, final RepositorySessionStoreDelegate sessionStoreDelegate) {
- super(repositorySession, workQueue, sessionStoreDelegate);
- }
-
- @Override
- public void payloadSucceeded(final SyncStorageResponse response, final boolean isCommit, final boolean isLastPayload) {
- successResponses.add(response);
- if (isCommit) {
- ++commitPayloadsSucceeded;
- }
- if (isLastPayload) {
- ++lastPayloadsSucceeded;
- }
- }
-
- @Override
- public void recordSucceeded(final String recordGuid) {
- successRecords.add(recordGuid);
- }
-
- @Override
- public void recordFailed(final String recordGuid) {
- recordFailed(new Exception(), recordGuid);
- }
-
- @Override
- public void recordFailed(final Exception e, final String recordGuid) {
- failedRecords.put(recordGuid, e);
- }
-
- @Override
- public void lastPayloadFailed() {
- didLastPayloadFail = true;
- }
- }
-
- @Before
- public void setUp() throws Exception {
- Server11Repository server11Repository = new Server11Repository(
- "dummyCollection",
- "http://dummy.url/",
- null,
- new InfoCollections(),
- new InfoConfiguration()
- );
- batchingUploader = new MockUploader(
- new Server11RepositorySession(server11Repository),
- null,
- null
- );
- }
-
- @Test
- public void testHandleRequestSuccessNonSuccess() {
- ArrayList<String> postedGuids = new ArrayList<>(2);
- postedGuids.add("testGuid1");
- postedGuids.add("testGuid2");
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, false);
-
- // Test that non-2* responses aren't processed
- payloadUploadDelegate.handleRequestSuccess(makeSyncStorageResponse(404, null, null));
- assertEquals(2, ((MockUploader) batchingUploader).failedRecords.size());
- assertFalse(((MockUploader) batchingUploader).didLastPayloadFail);
- assertEquals(IllegalStateException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid1").getClass());
- assertEquals(IllegalStateException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid2").getClass());
- }
-
- @Test
- public void testHandleRequestSuccessNoHeaders() {
- ArrayList<String> postedGuids = new ArrayList<>(2);
- postedGuids.add("testGuid1");
- postedGuids.add("testGuid2");
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, false);
-
- // Test that responses without X-Last-Modified header aren't processed
- payloadUploadDelegate.handleRequestSuccess(makeSyncStorageResponse(200, null, null));
- assertEquals(2, ((MockUploader) batchingUploader).failedRecords.size());
- assertFalse(((MockUploader) batchingUploader).didLastPayloadFail);
- assertEquals(IllegalStateException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid1").getClass());
- assertEquals(IllegalStateException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid2").getClass());
- }
-
- @Test
- public void testHandleRequestSuccessBadBody() {
- ArrayList<String> postedGuids = new ArrayList<>(2);
- postedGuids.add("testGuid1");
- postedGuids.add("testGuid2");
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, true);
-
- // Test that we catch json processing errors
- payloadUploadDelegate.handleRequestSuccess(makeSyncStorageResponse(200, "non json body", "123"));
- assertEquals(2, ((MockUploader) batchingUploader).failedRecords.size());
- assertTrue(((MockUploader) batchingUploader).didLastPayloadFail);
- assertEquals(NonObjectJSONException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid1").getClass());
- assertEquals(NonObjectJSONException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid2").getClass());
- }
-
- @Test
- public void testHandleRequestSuccess202NoToken() {
- ArrayList<String> postedGuids = new ArrayList<>(1);
- postedGuids.add("testGuid1");
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, true);
-
- // Test that we catch absent tokens in 202 responses
- payloadUploadDelegate.handleRequestSuccess(makeSyncStorageResponse(202, "{\"success\": []}", "123"));
- assertEquals(1, ((MockUploader) batchingUploader).failedRecords.size());
- assertEquals(IllegalStateException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid1").getClass());
- }
-
- @Test
- public void testHandleRequestSuccessBad200() {
- ArrayList<String> postedGuids = new ArrayList<>(1);
- postedGuids.add("testGuid1");
-
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, false);
-
- // Test that if in batching mode and saw the token, 200 must be a response to a commit
- try {
- batchingUploader.getCurrentBatch().setToken("MTIzNA", true);
- } catch (BatchingUploader.BatchingUploaderException e) {}
- batchingUploader.setInBatchingMode(true);
-
- // not a commit, so should fail
- payloadUploadDelegate.handleRequestSuccess(makeSyncStorageResponse(200, "{\"success\": []}", "123"));
- assertEquals(1, ((MockUploader) batchingUploader).failedRecords.size());
- assertEquals(IllegalStateException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid1").getClass());
- }
-
- @Test
- public void testHandleRequestSuccessNonBatchingFailedLM() {
- ArrayList<String> postedGuids = new ArrayList<>(1);
- postedGuids.add("guid1");
- postedGuids.add("guid2");
- postedGuids.add("guid3");
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, false);
-
- payloadUploadDelegate.handleRequestSuccess(
- makeSyncStorageResponse(200, "{\"success\": [\"guid1\", \"guid2\", \"guid3\"]}", "123"));
- assertEquals(0, ((MockUploader) batchingUploader).failedRecords.size());
- assertEquals(3, ((MockUploader) batchingUploader).successRecords.size());
- assertFalse(((MockUploader) batchingUploader).didLastPayloadFail);
- assertEquals(1, ((MockUploader) batchingUploader).successResponses.size());
- assertEquals(0, ((MockUploader) batchingUploader).commitPayloadsSucceeded);
- assertEquals(0, ((MockUploader) batchingUploader).lastPayloadsSucceeded);
-
- // These should fail, because we're returning a non-changed L-M in a non-batching mode
- postedGuids.add("guid4");
- postedGuids.add("guid6");
- payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, false);
- payloadUploadDelegate.handleRequestSuccess(
- makeSyncStorageResponse(200, "{\"success\": [\"guid4\", 5, \"guid6\"]}", "123"));
- assertEquals(5, ((MockUploader) batchingUploader).failedRecords.size());
- assertEquals(3, ((MockUploader) batchingUploader).successRecords.size());
- assertFalse(((MockUploader) batchingUploader).didLastPayloadFail);
- assertEquals(1, ((MockUploader) batchingUploader).successResponses.size());
- assertEquals(0, ((MockUploader) batchingUploader).commitPayloadsSucceeded);
- assertEquals(0, ((MockUploader) batchingUploader).lastPayloadsSucceeded);
- assertEquals(BatchingUploader.LastModifiedDidNotChange.class,
- ((MockUploader) batchingUploader).failedRecords.get("guid4").getClass());
- }
-
- @Test
- public void testHandleRequestSuccessNonBatching() {
- ArrayList<String> postedGuids = new ArrayList<>();
- postedGuids.add("guid1");
- postedGuids.add("guid2");
- postedGuids.add("guid3");
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, false);
- payloadUploadDelegate.handleRequestSuccess(
- makeSyncStorageResponse(200, "{\"success\": [\"guid1\", \"guid2\", \"guid3\"], \"failed\": {}}", "123"));
-
- postedGuids = new ArrayList<>();
- postedGuids.add("guid4");
- postedGuids.add("guid5");
- payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, false);
- payloadUploadDelegate.handleRequestSuccess(
- makeSyncStorageResponse(200, "{\"success\": [\"guid4\", \"guid5\"], \"failed\": {}}", "333"));
-
- postedGuids = new ArrayList<>();
- postedGuids.add("guid6");
- payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, true);
- payloadUploadDelegate.handleRequestSuccess(
- makeSyncStorageResponse(200, "{\"success\": [\"guid6\"], \"failed\": {}}", "444"));
-
- assertEquals(0, ((MockUploader) batchingUploader).failedRecords.size());
- assertEquals(6, ((MockUploader) batchingUploader).successRecords.size());
- assertFalse(((MockUploader) batchingUploader).didLastPayloadFail);
- assertEquals(3, ((MockUploader) batchingUploader).successResponses.size());
- assertEquals(0, ((MockUploader) batchingUploader).commitPayloadsSucceeded);
- assertEquals(1, ((MockUploader) batchingUploader).lastPayloadsSucceeded);
- assertFalse(batchingUploader.getInBatchingMode());
-
- postedGuids = new ArrayList<>();
- postedGuids.add("guid7");
- postedGuids.add("guid8");
- payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, true);
- payloadUploadDelegate.handleRequestSuccess(
- makeSyncStorageResponse(200, "{\"success\": [\"guid8\"], \"failed\": {\"guid7\": \"reason\"}}", "555"));
- assertEquals(1, ((MockUploader) batchingUploader).failedRecords.size());
- assertTrue(((MockUploader) batchingUploader).failedRecords.containsKey("guid7"));
- assertEquals(7, ((MockUploader) batchingUploader).successRecords.size());
- assertFalse(((MockUploader) batchingUploader).didLastPayloadFail);
- assertEquals(4, ((MockUploader) batchingUploader).successResponses.size());
- assertEquals(0, ((MockUploader) batchingUploader).commitPayloadsSucceeded);
- assertEquals(2, ((MockUploader) batchingUploader).lastPayloadsSucceeded);
- assertFalse(batchingUploader.getInBatchingMode());
- }
-
- @Test
- public void testHandleRequestSuccessBatching() {
- ArrayList<String> postedGuids = new ArrayList<>();
- postedGuids.add("guid1");
- postedGuids.add("guid2");
- postedGuids.add("guid3");
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, false);
- payloadUploadDelegate.handleRequestSuccess(
- makeSyncStorageResponse(202, "{\"batch\": \"MTIzNA\", \"success\": [\"guid1\", \"guid2\", \"guid3\"], \"failed\": {}}", "123"));
-
- assertTrue(batchingUploader.getInBatchingMode());
- assertEquals("MTIzNA", batchingUploader.getCurrentBatch().getToken());
-
- postedGuids = new ArrayList<>();
- postedGuids.add("guid4");
- postedGuids.add("guid5");
- postedGuids.add("guid6");
- payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, false, false);
- payloadUploadDelegate.handleRequestSuccess(
- makeSyncStorageResponse(202, "{\"batch\": \"MTIzNA\", \"success\": [\"guid4\", \"guid5\", \"guid6\"], \"failed\": {}}", "123"));
-
- assertTrue(batchingUploader.getInBatchingMode());
- assertEquals("MTIzNA", batchingUploader.getCurrentBatch().getToken());
-
- postedGuids = new ArrayList<>();
- postedGuids.add("guid7");
- payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, true, false);
- payloadUploadDelegate.handleRequestSuccess(
- makeSyncStorageResponse(200, "{\"success\": [\"guid6\"], \"failed\": {}}", "222"));
-
- // Even though everything indicates we're not in a batching, we were, so test that
- // we don't reset the flag.
- assertTrue(batchingUploader.getInBatchingMode());
- assertNull(batchingUploader.getCurrentBatch().getToken());
-
- postedGuids = new ArrayList<>();
- postedGuids.add("guid8");
- payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, postedGuids, true, true);
- payloadUploadDelegate.handleRequestSuccess(
- makeSyncStorageResponse(200, "{\"success\": [\"guid7\"], \"failed\": {}}", "333"));
-
- assertEquals(0, ((MockUploader) batchingUploader).failedRecords.size());
- assertEquals(8, ((MockUploader) batchingUploader).successRecords.size());
- assertFalse(((MockUploader) batchingUploader).didLastPayloadFail);
- assertEquals(4, ((MockUploader) batchingUploader).successResponses.size());
- assertEquals(2, ((MockUploader) batchingUploader).commitPayloadsSucceeded);
- assertEquals(1, ((MockUploader) batchingUploader).lastPayloadsSucceeded);
- assertTrue(batchingUploader.getInBatchingMode());
- }
-
- @Test
- public void testHandleRequestError() {
- ArrayList<String> postedGuids = new ArrayList<>(3);
- postedGuids.add("testGuid1");
- postedGuids.add("testGuid2");
- postedGuids.add("testGuid3");
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(batchingUploader, postedGuids, false, false);
-
- IllegalStateException e = new IllegalStateException();
- payloadUploadDelegate.handleRequestError(e);
-
- assertEquals(3, ((MockUploader) batchingUploader).failedRecords.size());
- assertEquals(e, ((MockUploader) batchingUploader).failedRecords.get("testGuid1"));
- assertEquals(e, ((MockUploader) batchingUploader).failedRecords.get("testGuid2"));
- assertEquals(e, ((MockUploader) batchingUploader).failedRecords.get("testGuid3"));
- assertFalse(((MockUploader) batchingUploader).didLastPayloadFail);
-
- payloadUploadDelegate = new PayloadUploadDelegate(batchingUploader, postedGuids, false, true);
- payloadUploadDelegate.handleRequestError(e);
- assertEquals(3, ((MockUploader) batchingUploader).failedRecords.size());
- assertTrue(((MockUploader) batchingUploader).didLastPayloadFail);
- }
-
- @Test
- public void testHandleRequestFailure() {
- ArrayList<String> postedGuids = new ArrayList<>(3);
- postedGuids.add("testGuid1");
- postedGuids.add("testGuid2");
- postedGuids.add("testGuid3");
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(batchingUploader, postedGuids, false, false);
-
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
- payloadUploadDelegate.handleRequestFailure(new SyncStorageResponse(response));
- assertEquals(3, ((MockUploader) batchingUploader).failedRecords.size());
- assertEquals(HTTPFailureException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid1").getClass());
- assertEquals(HTTPFailureException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid2").getClass());
- assertEquals(HTTPFailureException.class,
- ((MockUploader) batchingUploader).failedRecords.get("testGuid3").getClass());
-
- payloadUploadDelegate = new PayloadUploadDelegate(batchingUploader, postedGuids, false, true);
- payloadUploadDelegate.handleRequestFailure(new SyncStorageResponse(response));
- assertEquals(3, ((MockUploader) batchingUploader).failedRecords.size());
- assertTrue(((MockUploader) batchingUploader).didLastPayloadFail);
- }
-
- @Test
- public void testIfUnmodifiedSince() {
- PayloadUploadDelegate payloadUploadDelegate = new PayloadUploadDelegate(
- batchingUploader, new ArrayList<String>(), false, false);
-
- assertNull(payloadUploadDelegate.ifUnmodifiedSince());
-
- try {
- batchingUploader.getCurrentBatch().setLastModified(1471645412480L, true);
- } catch (BatchingUploader.BatchingUploaderException e) {}
-
- assertEquals("1471645412.480", payloadUploadDelegate.ifUnmodifiedSince());
- }
-
- private SyncStorageResponse makeSyncStorageResponse(int code, String body, String lastModified) {
- BasicHttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), code, null));
-
- if (body != null) {
- BasicHttpEntity entity = new BasicHttpEntity();
- entity.setContent(new ByteArrayInputStream(body.getBytes()));
- response.setEntity(entity);
- }
-
- if (lastModified != null) {
- response.addHeader(SyncResponse.X_LAST_MODIFIED, lastModified);
- }
- return new SyncStorageResponse(response);
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/RecordUploadRunnableTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/RecordUploadRunnableTest.java
deleted file mode 100644
index 269c25362..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/uploaders/RecordUploadRunnableTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.uploaders;
-
-import android.net.Uri;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import java.net.URI;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class RecordUploadRunnableTest {
- @Test
- public void testBuildPostURI() throws Exception {
- BatchMeta batchMeta = new BatchMeta(new Object(), 1, 1, null);
- URI postURI = RecordUploadRunnable.buildPostURI(
- false, batchMeta, Uri.parse("http://example.com/"));
- assertEquals("http://example.com/?batch=true", postURI.toString());
-
- postURI = RecordUploadRunnable.buildPostURI(
- true, batchMeta, Uri.parse("http://example.com/"));
- assertEquals("http://example.com/?batch=true&commit=true", postURI.toString());
-
- batchMeta.setToken("MTIzNA", false);
- postURI = RecordUploadRunnable.buildPostURI(
- false, batchMeta, Uri.parse("http://example.com/"));
- assertEquals("http://example.com/?batch=MTIzNA", postURI.toString());
-
- postURI = RecordUploadRunnable.buildPostURI(
- true, batchMeta, Uri.parse("http://example.com/"));
- assertEquals("http://example.com/?batch=MTIzNA&commit=true", postURI.toString());
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestEnsureCrypto5KeysStage.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestEnsureCrypto5KeysStage.java
deleted file mode 100644
index cb74b427b..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestEnsureCrypto5KeysStage.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.stage.test;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockGlobalSessionCallback;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.testhelpers.MockGlobalSession;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.AlreadySyncingException;
-import org.mozilla.gecko.sync.CollectionKeys;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.stage.EnsureCrypto5KeysStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collection;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestEnsureCrypto5KeysStage {
- private int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private final String TEST_CLUSTER_URL = "http://localhost:" + TEST_PORT;
- private final String TEST_USERNAME = "johndoe";
- private final String TEST_PASSWORD = "password";
- private final String TEST_SYNC_KEY = "abcdeabcdeabcdeabcdeabcdea";
-
- private final String TEST_JSON_NO_CRYPTO =
- "{\"history\":1.3319567131E9}";
- private final String TEST_JSON_OLD_CRYPTO =
- "{\"history\":1.3319567131E9,\"crypto\":1.1E9}";
- private final String TEST_JSON_NEW_CRYPTO =
- "{\"history\":1.3319567131E9,\"crypto\":3.1E9}";
-
- private HTTPServerTestHelper data = new HTTPServerTestHelper();
-
- private KeyBundle syncKeyBundle;
- private MockGlobalSessionCallback callback;
- private GlobalSession session;
-
- private boolean calledResetStages;
- private Collection<String> stagesReset;
-
- @Before
- public void setUp() throws Exception {
- syncKeyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY);
- callback = new MockGlobalSessionCallback();
- session = new MockGlobalSession(TEST_USERNAME, TEST_PASSWORD,
- syncKeyBundle, callback) {
- @Override
- protected void prepareStages() {
- super.prepareStages();
- withStage(Stage.ensureKeysStage, new EnsureCrypto5KeysStage());
- }
-
- @Override
- public void resetStagesByEnum(Collection<Stage> stages) {
- calledResetStages = true;
- stagesReset = new ArrayList<String>();
- for (Stage stage : stages) {
- stagesReset.add(stage.name());
- }
- }
-
- @Override
- public void resetStagesByName(Collection<String> names) {
- calledResetStages = true;
- stagesReset = names;
- }
- };
- session.config.setClusterURL(new URI(TEST_CLUSTER_URL));
-
- // Set info collections to not have crypto.
- final ExtendedJSONObject noCrypto = new ExtendedJSONObject(TEST_JSON_NO_CRYPTO);
- session.config.infoCollections = new InfoCollections(noCrypto);
- calledResetStages = false;
- stagesReset = null;
- }
-
- public void doSession(MockServer server) {
- data.startHTTPServer(server);
- try {
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- try {
- session.start();
- } catch (AlreadySyncingException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
- });
- } finally {
- data.stopHTTPServer();
- }
- }
-
- @Test
- public void testDownloadUsesPersisted() throws Exception {
- session.config.infoCollections = new InfoCollections(new ExtendedJSONObject
- (TEST_JSON_OLD_CRYPTO));
- session.config.persistedCryptoKeys().persistLastModified(System.currentTimeMillis());
-
- assertNull(session.config.collectionKeys);
- final CollectionKeys keys = CollectionKeys.generateCollectionKeys();
- keys.setDefaultKeyBundle(syncKeyBundle);
- session.config.persistedCryptoKeys().persistKeys(keys);
-
- MockServer server = new MockServer() {
- public void handle(Request request, Response response) {
- this.handle(request, response, 404, "should not be called!");
- }
- };
-
- doSession(server);
-
- assertTrue(callback.calledSuccess);
- assertNotNull(session.config.collectionKeys);
- assertTrue(CollectionKeys.differences(session.config.collectionKeys, keys).isEmpty());
- }
-
- @Test
- public void testDownloadFetchesNew() throws Exception {
- session.config.infoCollections = new InfoCollections(new ExtendedJSONObject(TEST_JSON_NEW_CRYPTO));
- session.config.persistedCryptoKeys().persistLastModified(System.currentTimeMillis());
-
- assertNull(session.config.collectionKeys);
- final CollectionKeys keys = CollectionKeys.generateCollectionKeys();
- keys.setDefaultKeyBundle(syncKeyBundle);
- session.config.persistedCryptoKeys().persistKeys(keys);
-
- MockServer server = new MockServer() {
- public void handle(Request request, Response response) {
- try {
- CryptoRecord rec = keys.asCryptoRecord();
- rec.keyBundle = syncKeyBundle;
- rec.encrypt();
- this.handle(request, response, 200, rec.toJSONString());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- };
-
- doSession(server);
-
- assertTrue(callback.calledSuccess);
- assertNotNull(session.config.collectionKeys);
- assertTrue(session.config.collectionKeys.equals(keys));
- }
-
- /**
- * Change the default key but keep one collection key the same. Should reset
- * all but that one collection.
- */
- @Test
- public void testDownloadResetsOnDifferentDefaultKey() throws Exception {
- String TEST_COLLECTION = "bookmarks";
-
- session.config.infoCollections = new InfoCollections(new ExtendedJSONObject(TEST_JSON_NEW_CRYPTO));
- session.config.persistedCryptoKeys().persistLastModified(System.currentTimeMillis());
-
- KeyBundle keyBundle = KeyBundle.withRandomKeys();
- assertNull(session.config.collectionKeys);
- final CollectionKeys keys = CollectionKeys.generateCollectionKeys();
- keys.setKeyBundleForCollection(TEST_COLLECTION, keyBundle);
- session.config.persistedCryptoKeys().persistKeys(keys);
- keys.setDefaultKeyBundle(syncKeyBundle); // Change the default key bundle, but keep "bookmarks" the same.
-
- MockServer server = new MockServer() {
- public void handle(Request request, Response response) {
- try {
- CryptoRecord rec = keys.asCryptoRecord();
- rec.keyBundle = syncKeyBundle;
- rec.encrypt();
- this.handle(request, response, 200, rec.toJSONString());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- };
-
- doSession(server);
-
- assertTrue(calledResetStages);
- Collection<String> allButCollection = new ArrayList<String>();
- for (Stage stage : Stage.getNamedStages()) {
- allButCollection.add(stage.getRepositoryName());
- }
- allButCollection.remove(TEST_COLLECTION);
- assertTrue(stagesReset.containsAll(allButCollection));
- assertTrue(allButCollection.containsAll(stagesReset));
- assertTrue(callback.calledError);
- }
-
- @Test
- public void testDownloadResetsEngineOnDifferentKey() throws Exception {
- final String TEST_COLLECTION = "history";
-
- session.config.infoCollections = new InfoCollections(new ExtendedJSONObject(TEST_JSON_NEW_CRYPTO));
- session.config.persistedCryptoKeys().persistLastModified(System.currentTimeMillis());
-
- assertNull(session.config.collectionKeys);
- final CollectionKeys keys = CollectionKeys.generateCollectionKeys();
- session.config.persistedCryptoKeys().persistKeys(keys);
- keys.setKeyBundleForCollection(TEST_COLLECTION, syncKeyBundle); // Change one key bundle.
-
- CryptoRecord rec = keys.asCryptoRecord();
- rec.keyBundle = syncKeyBundle;
- rec.encrypt();
- MockServer server = new MockServer(200, rec.toJSONString());
-
- doSession(server);
-
- assertTrue(calledResetStages);
- assertNotNull(stagesReset);
- assertEquals(1, stagesReset.size());
- assertTrue(stagesReset.contains(TEST_COLLECTION));
- assertTrue(callback.calledError);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestFetchMetaGlobalStage.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestFetchMetaGlobalStage.java
deleted file mode 100644
index f7ed7a559..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestFetchMetaGlobalStage.java
+++ /dev/null
@@ -1,391 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.stage.test;
-
-import org.json.simple.JSONArray;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.net.test.TestMetaGlobal;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockGlobalSessionCallback;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.testhelpers.MockGlobalSession;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.AlreadySyncingException;
-import org.mozilla.gecko.sync.CollectionKeys;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.MetaGlobal;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.FreshStartDelegate;
-import org.mozilla.gecko.sync.delegates.KeyUploadDelegate;
-import org.mozilla.gecko.sync.delegates.WipeServerDelegate;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.stage.FetchMetaGlobalStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestFetchMetaGlobalStage {
- @SuppressWarnings("unused")
- private static final String LOG_TAG = "TestMetaGlobalStage";
-
- private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private static final String TEST_SERVER = "http://localhost:" + TEST_PORT + "/";
- private static final String TEST_CLUSTER_URL = TEST_SERVER + "cluster/";
- private HTTPServerTestHelper data = new HTTPServerTestHelper();
-
- private final String TEST_USERNAME = "johndoe";
- private final String TEST_PASSWORD = "password";
- private final String TEST_SYNC_KEY = "abcdeabcdeabcdeabcdeabcdea";
-
- private final String TEST_INFO_COLLECTIONS_JSON = "{}";
-
- private static final String TEST_SYNC_ID = "testSyncID";
- private static final long TEST_STORAGE_VERSION = GlobalSession.STORAGE_VERSION;
-
- private InfoCollections infoCollections;
- private KeyBundle syncKeyBundle;
- private MockGlobalSessionCallback callback;
- private GlobalSession session;
-
- private boolean calledRequiresUpgrade = false;
- private boolean calledProcessMissingMetaGlobal = false;
- private boolean calledFreshStart = false;
- private boolean calledWipeServer = false;
- private boolean calledUploadKeys = false;
- private boolean calledResetAllStages = false;
-
- private static void assertSameContents(JSONArray expected, Set<String> actual) {
- assertEquals(expected.size(), actual.size());
- for (Object o : expected) {
- assertTrue(actual.contains(o));
- }
- }
-
- @Before
- public void setUp() throws Exception {
- calledRequiresUpgrade = false;
- calledProcessMissingMetaGlobal = false;
- calledFreshStart = false;
- calledWipeServer = false;
- calledUploadKeys = false;
- calledResetAllStages = false;
-
- // Set info collections to not have crypto.
- infoCollections = new InfoCollections(new ExtendedJSONObject(TEST_INFO_COLLECTIONS_JSON));
-
- syncKeyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY);
- callback = new MockGlobalSessionCallback();
- session = new MockGlobalSession(TEST_USERNAME, TEST_PASSWORD,
- syncKeyBundle, callback) {
- @Override
- protected void prepareStages() {
- super.prepareStages();
- withStage(Stage.fetchMetaGlobal, new FetchMetaGlobalStage());
- }
-
- @Override
- public void requiresUpgrade() {
- calledRequiresUpgrade = true;
- this.abort(null, "Requires upgrade");
- }
-
- @Override
- public void processMissingMetaGlobal(MetaGlobal mg) {
- calledProcessMissingMetaGlobal = true;
- this.abort(null, "Missing meta/global");
- }
-
- // Don't really uploadKeys.
- @Override
- public void uploadKeys(CollectionKeys keys, KeyUploadDelegate keyUploadDelegate) {
- calledUploadKeys = true;
- keyUploadDelegate.onKeysUploaded();
- }
-
- // On fresh start completed, just stop.
- @Override
- public void freshStart() {
- calledFreshStart = true;
- freshStart(this, new FreshStartDelegate() {
- @Override
- public void onFreshStartFailed(Exception e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
-
- @Override
- public void onFreshStart() {
- WaitHelper.getTestWaiter().performNotify();
- }
- });
- }
-
- // Don't really wipeServer.
- @Override
- protected void wipeServer(final AuthHeaderProvider authHeaderProvider, final WipeServerDelegate wipeDelegate) {
- calledWipeServer = true;
- wipeDelegate.onWiped(System.currentTimeMillis());
- }
-
- // Don't really resetAllStages.
- @Override
- public void resetAllStages() {
- calledResetAllStages = true;
- }
- };
- session.config.setClusterURL(new URI(TEST_CLUSTER_URL));
- session.config.infoCollections = infoCollections;
- }
-
- protected void doSession(MockServer server) {
- data.startHTTPServer(server);
- WaitHelper.getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- try {
- session.start();
- } catch (AlreadySyncingException e) {
- WaitHelper.getTestWaiter().performNotify(e);
- }
- }
- }));
- data.stopHTTPServer();
- }
-
- @Test
- public void testFetchRequiresUpgrade() throws Exception {
- MetaGlobal mg = new MetaGlobal(null, null);
- mg.setSyncID(TEST_SYNC_ID);
- mg.setStorageVersion(Long.valueOf(TEST_STORAGE_VERSION + 1));
-
- MockServer server = new MockServer(200, mg.asCryptoRecord().toJSONString());
- doSession(server);
-
- assertEquals(true, callback.calledError);
- assertTrue(calledRequiresUpgrade);
- }
-
- @SuppressWarnings("unchecked")
- private JSONArray makeTestDeclinedArray() {
- final JSONArray declined = new JSONArray();
- declined.add("foobar");
- return declined;
- }
-
- /**
- * Verify that a fetched meta/global with remote syncID == local syncID does
- * not reset.
- *
- * @throws Exception
- */
- @Test
- public void testFetchSuccessWithSameSyncID() throws Exception {
- session.config.syncID = TEST_SYNC_ID;
-
- MetaGlobal mg = new MetaGlobal(null, null);
- mg.setSyncID(TEST_SYNC_ID);
- mg.setStorageVersion(Long.valueOf(TEST_STORAGE_VERSION));
-
- // Set declined engines in the server object.
- final JSONArray testingDeclinedEngines = makeTestDeclinedArray();
- mg.setDeclinedEngineNames(testingDeclinedEngines);
-
- MockServer server = new MockServer(200, mg.asCryptoRecord().toJSONString());
- doSession(server);
-
- assertTrue(callback.calledSuccess);
- assertFalse(calledProcessMissingMetaGlobal);
- assertFalse(calledResetAllStages);
- assertEquals(TEST_SYNC_ID, session.config.metaGlobal.getSyncID());
- assertEquals(TEST_STORAGE_VERSION, session.config.metaGlobal.getStorageVersion().longValue());
- assertEquals(TEST_SYNC_ID, session.config.syncID);
-
- // Declined engines propagate from the server meta/global.
- final Set<String> actual = session.config.metaGlobal.getDeclinedEngineNames();
- assertSameContents(testingDeclinedEngines, actual);
- }
-
- /**
- * Verify that a fetched meta/global with remote syncID != local syncID resets
- * local and retains remote syncID.
- *
- * @throws Exception
- */
- @Test
- public void testFetchSuccessWithDifferentSyncID() throws Exception {
- session.config.syncID = "NOT TEST SYNC ID";
-
- MetaGlobal mg = new MetaGlobal(null, null);
- mg.setSyncID(TEST_SYNC_ID);
- mg.setStorageVersion(Long.valueOf(TEST_STORAGE_VERSION));
-
- // Set declined engines in the server object.
- final JSONArray testingDeclinedEngines = makeTestDeclinedArray();
- mg.setDeclinedEngineNames(testingDeclinedEngines);
-
- MockServer server = new MockServer(200, mg.asCryptoRecord().toJSONString());
- doSession(server);
-
- assertEquals(true, callback.calledSuccess);
- assertFalse(calledProcessMissingMetaGlobal);
- assertTrue(calledResetAllStages);
- assertEquals(TEST_SYNC_ID, session.config.metaGlobal.getSyncID());
- assertEquals(TEST_STORAGE_VERSION, session.config.metaGlobal.getStorageVersion().longValue());
- assertEquals(TEST_SYNC_ID, session.config.syncID);
-
- // Declined engines propagate from the server meta/global.
- final Set<String> actual = session.config.metaGlobal.getDeclinedEngineNames();
- assertSameContents(testingDeclinedEngines, actual);
- }
-
- /**
- * Verify that a fetched meta/global does not merge declined engines.
- * TODO: eventually it should!
- */
- @SuppressWarnings("unchecked")
- @Test
- public void testFetchSuccessWithDifferentSyncIDMergesDeclined() throws Exception {
- session.config.syncID = "NOT TEST SYNC ID";
-
- // Fake the local declined engine names.
- session.config.declinedEngineNames = new HashSet<String>();
- session.config.declinedEngineNames.add("baznoo");
-
- MetaGlobal mg = new MetaGlobal(null, null);
- mg.setSyncID(TEST_SYNC_ID);
- mg.setStorageVersion(Long.valueOf(TEST_STORAGE_VERSION));
-
- // Set declined engines in the server object.
- final JSONArray testingDeclinedEngines = makeTestDeclinedArray();
- mg.setDeclinedEngineNames(testingDeclinedEngines);
-
- MockServer server = new MockServer(200, mg.asCryptoRecord().toJSONString());
- doSession(server);
-
- // Declined engines propagate from the server meta/global, and are NOT merged.
- final Set<String> expected = new HashSet<String>(testingDeclinedEngines);
- // expected.add("baznoo"); // Not until we merge. Local is lost.
-
- final Set<String> newDeclined = session.config.metaGlobal.getDeclinedEngineNames();
- assertEquals(expected, newDeclined);
- }
-
- @Test
- public void testFetchMissing() throws Exception {
- MockServer server = new MockServer(404, "missing");
- doSession(server);
-
- assertEquals(true, callback.calledError);
- assertTrue(calledProcessMissingMetaGlobal);
- }
-
- /**
- * Empty payload object has no syncID or storageVersion and should call freshStart.
- * @throws Exception
- */
- @Test
- public void testFetchEmptyPayload() throws Exception {
- MockServer server = new MockServer(200, TestMetaGlobal.TEST_META_GLOBAL_EMPTY_PAYLOAD_RESPONSE);
- doSession(server);
-
- assertTrue(calledFreshStart);
- }
-
- /**
- * No payload means no syncID or storageVersion and therefore we should call freshStart.
- * @throws Exception
- */
- @Test
- public void testFetchNoPayload() throws Exception {
- MockServer server = new MockServer(200, TestMetaGlobal.TEST_META_GLOBAL_NO_PAYLOAD_RESPONSE);
- doSession(server);
-
- assertTrue(calledFreshStart);
- }
-
- /**
- * Malformed payload is a server response issue, not a meta/global record
- * issue. This should error out of the sync.
- * @throws Exception
- */
- @Test
- public void testFetchMalformedPayload() throws Exception {
- MockServer server = new MockServer(200, TestMetaGlobal.TEST_META_GLOBAL_MALFORMED_PAYLOAD_RESPONSE);
- doSession(server);
-
- assertEquals(true, callback.calledError);
- assertEquals(NonObjectJSONException.class, callback.calledErrorException.getClass());
- }
-
- protected void doFreshStart(MockServer server) {
- data.startHTTPServer(server);
- WaitHelper.getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
- @Override
- public void run() {
- session.freshStart();
- }
- }));
- data.stopHTTPServer();
- }
-
- @Test
- public void testFreshStart() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, CryptoException {
- final AtomicBoolean mgUploaded = new AtomicBoolean(false);
- final AtomicBoolean mgDownloaded = new AtomicBoolean(false);
- final MetaGlobal uploadedMg = new MetaGlobal(null, null);
-
- MockServer server = new MockServer() {
- @Override
- public void handle(Request request, Response response) {
- if (request.getMethod().equals("PUT")) {
- try {
- ExtendedJSONObject body = new ExtendedJSONObject(request.getContent());
- assertTrue(body.containsKey("payload"));
- assertFalse(body.containsKey("default"));
-
- CryptoRecord rec = CryptoRecord.fromJSONRecord(body);
- uploadedMg.setFromRecord(rec);
- mgUploaded.set(true);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- this.handle(request, response, 200, "success");
- return;
- }
- if (mgUploaded.get()) {
- // We shouldn't be trying to download anything after uploading meta/global.
- mgDownloaded.set(true);
- }
- this.handle(request, response, 404, "missing");
- }
- };
- doFreshStart(server);
-
- assertTrue(this.calledFreshStart);
- assertTrue(this.calledWipeServer);
- assertTrue(this.calledUploadKeys);
- assertTrue(mgUploaded.get());
- assertFalse(mgDownloaded.get());
- assertEquals(GlobalSession.STORAGE_VERSION, uploadedMg.getStorageVersion().longValue());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestStageLookup.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestStageLookup.java
deleted file mode 100644
index 86829844f..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestStageLookup.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.stage.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-
-@RunWith(TestRunner.class)
-public class TestStageLookup {
-
- @Test
- public void testStageLookupByName() {
- Set<Stage> namedStages = new HashSet<Stage>(Stage.getNamedStages());
- Set<Stage> expected = new HashSet<Stage>();
- expected.add(Stage.syncClientsEngine);
- expected.add(Stage.syncBookmarks);
- expected.add(Stage.syncTabs);
- expected.add(Stage.syncFormHistory);
- expected.add(Stage.syncHistory);
- expected.add(Stage.syncPasswords);
-
- assertEquals(expected, namedStages);
- assertEquals(Stage.syncClientsEngine, Stage.byName("clients"));
- assertEquals(Stage.syncTabs, Stage.byName("tabs"));
- assertEquals(Stage.syncBookmarks, Stage.byName("bookmarks"));
- assertEquals(Stage.syncFormHistory, Stage.byName("forms"));
- assertEquals(Stage.syncHistory, Stage.byName("history"));
- assertEquals(Stage.syncPasswords, Stage.byName("passwords"));
-
- assertEquals(null, Stage.byName("foobar"));
- assertEquals(null, Stage.byName(null));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java
deleted file mode 100644
index cff9287df..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.test;
-
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.NonArrayJSONException;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.UnexpectedJSONException.BadRequiredFieldJSONException;
-
-import java.io.IOException;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestExtendedJSONObject {
- public static String exampleJSON = "{\"modified\":1233702554.25,\"success\":[\"{GXS58IDC}12\",\"{GXS58IDC}13\",\"{GXS58IDC}15\",\"{GXS58IDC}16\",\"{GXS58IDC}18\",\"{GXS58IDC}19\"],\"failed\":{\"{GXS58IDC}11\":[\"invalid parentid\"],\"{GXS58IDC}14\":[\"invalid parentid\"],\"{GXS58IDC}17\":[\"invalid parentid\"],\"{GXS58IDC}20\":[\"invalid parentid\"]}}";
- public static String exampleIntegral = "{\"modified\":1233702554,}";
-
- @Test
- public void testFractional() throws IOException, NonObjectJSONException {
- ExtendedJSONObject o = new ExtendedJSONObject(exampleJSON);
- assertTrue(o.containsKey("modified"));
- assertTrue(o.containsKey("success"));
- assertTrue(o.containsKey("failed"));
- assertFalse(o.containsKey(" "));
- assertFalse(o.containsKey(""));
- assertFalse(o.containsKey("foo"));
- assertTrue(o.get("modified") instanceof Number);
- assertTrue(o.get("modified").equals(Double.parseDouble("1233702554.25")));
- assertEquals(Long.valueOf(1233702554250L), o.getTimestamp("modified"));
- assertEquals(null, o.getTimestamp("foo"));
- }
-
- @Test
- public void testIntegral() throws IOException, NonObjectJSONException {
- ExtendedJSONObject o = new ExtendedJSONObject(exampleIntegral);
- assertTrue(o.containsKey("modified"));
- assertFalse(o.containsKey("success"));
- assertTrue(o.get("modified") instanceof Number);
- assertTrue(o.get("modified").equals(Long.parseLong("1233702554")));
- assertEquals(Long.valueOf(1233702554000L), o.getTimestamp("modified"));
- assertEquals(null, o.getTimestamp("foo"));
- }
-
- @Test
- public void testSafeInteger() {
- ExtendedJSONObject o = new ExtendedJSONObject();
- o.put("integer", Integer.valueOf(5));
- o.put("string", "66");
- o.put("object", new ExtendedJSONObject());
- o.put("null", (JSONArray) null);
-
- assertEquals(Integer.valueOf(5), o.getIntegerSafely("integer"));
- assertEquals(Integer.valueOf(66), o.getIntegerSafely("string"));
- assertNull(o.getIntegerSafely(null));
- }
-
- @Test
- public void testParseJSONArray() throws Exception {
- JSONArray result = ExtendedJSONObject.parseJSONArray("[0, 1, {\"test\": 2}]");
- assertNotNull(result);
-
- assertThat((Long) result.get(0), is(equalTo(0L)));
- assertThat((Long) result.get(1), is(equalTo(1L)));
- assertThat((Long) ((JSONObject) result.get(2)).get("test"), is(equalTo(2L)));
- }
-
- @Test
- public void testBadParseJSONArray() throws Exception {
- try {
- ExtendedJSONObject.parseJSONArray("[0, ");
- fail();
- } catch (NonArrayJSONException e) {
- // Do nothing.
- }
-
- try {
- ExtendedJSONObject.parseJSONArray("{}");
- fail();
- } catch (NonArrayJSONException e) {
- // Do nothing.
- }
- }
-
- @Test
- public void testParseUTF8AsJSONObject() throws Exception {
- String TEST = "{\"key\":\"value\"}";
-
- ExtendedJSONObject o = ExtendedJSONObject.parseUTF8AsJSONObject(TEST.getBytes("UTF-8"));
- assertNotNull(o);
- assertEquals("value", o.getString("key"));
- }
-
- @Test
- public void testBadParseUTF8AsJSONObject() throws Exception {
- try {
- ExtendedJSONObject.parseUTF8AsJSONObject("{}".getBytes("UTF-16"));
- fail();
- } catch (NonObjectJSONException e) {
- // Do nothing.
- }
-
- try {
- ExtendedJSONObject.parseUTF8AsJSONObject("{".getBytes("UTF-8"));
- fail();
- } catch (NonObjectJSONException e) {
- // Do nothing.
- }
- }
-
- @Test
- public void testHashCode() throws Exception {
- ExtendedJSONObject o = new ExtendedJSONObject(exampleJSON);
- assertEquals(o.hashCode(), o.hashCode());
- ExtendedJSONObject p = new ExtendedJSONObject(exampleJSON);
- assertEquals(o.hashCode(), p.hashCode());
-
- ExtendedJSONObject q = new ExtendedJSONObject(exampleJSON);
- q.put("modified", 0);
- assertNotSame(o.hashCode(), q.hashCode());
- }
-
- @Test
- public void testEquals() throws Exception {
- ExtendedJSONObject o = new ExtendedJSONObject(exampleJSON);
- ExtendedJSONObject p = new ExtendedJSONObject(exampleJSON);
- assertEquals(o, p);
-
- ExtendedJSONObject q = new ExtendedJSONObject(exampleJSON);
- q.put("modified", 0);
- assertNotSame(o, q);
- assertNotEquals(o, q);
- }
-
- @Test
- public void testGetBoolean() throws Exception {
- ExtendedJSONObject o = new ExtendedJSONObject("{\"truekey\":true, \"falsekey\":false, \"stringkey\":\"string\"}");
- assertEquals(true, o.getBoolean("truekey"));
- assertEquals(false, o.getBoolean("falsekey"));
- try {
- o.getBoolean("stringkey");
- fail();
- } catch (Exception e) {
- assertTrue(e instanceof ClassCastException);
- }
- assertEquals(null, o.getBoolean("missingkey"));
- }
-
- @Test
- public void testNullLong() throws Exception {
- ExtendedJSONObject o = new ExtendedJSONObject("{\"x\": null}");
- Long x = o.getLong("x");
- assertNull(x);
-
- long y = o.getLong("x", 5L);
- assertEquals(5L, y);
- }
-
- protected void assertException(ExtendedJSONObject o, String[] requiredFields, Class<?> requiredFieldClass) {
- try {
- o.throwIfFieldsMissingOrMisTyped(requiredFields, requiredFieldClass);
- fail();
- } catch (Exception e) {
- assertTrue(e instanceof BadRequiredFieldJSONException);
- }
- }
-
- @Test
- public void testThrow() throws Exception {
- ExtendedJSONObject o = new ExtendedJSONObject("{\"true\":true, \"false\":false, \"string\":\"string\", \"long\":40000000000, \"int\":40, \"nested\":{\"inner\":10}}");
- o.throwIfFieldsMissingOrMisTyped(new String[] { "true", "false" }, Boolean.class);
- o.throwIfFieldsMissingOrMisTyped(new String[] { "string" }, String.class);
- o.throwIfFieldsMissingOrMisTyped(new String[] { "long" }, Long.class);
- o.throwIfFieldsMissingOrMisTyped(new String[] { "int" }, Long.class);
- o.throwIfFieldsMissingOrMisTyped(new String[] { "int" }, null);
-
- // Perhaps a bit unexpected, but we'll document it here.
- o.throwIfFieldsMissingOrMisTyped(new String[] { "nested" }, JSONObject.class);
-
- // Should fail.
- assertException(o, new String[] { "int" }, Integer.class); // Irritating, but...
- assertException(o, new String[] { "long" }, Integer.class); // Ditto.
- assertException(o, new String[] { "missing" }, String.class);
- assertException(o, new String[] { "missing" }, null);
- assertException(o, new String[] { "string", "int" }, String.class); // Irritating, but...
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestInfoCollections.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestInfoCollections.java
deleted file mode 100644
index d850ccc56..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestInfoCollections.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.test;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.InfoCounts;
-import org.mozilla.gecko.sync.Utils;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Test both info/collections and info/collection_counts.
- */
-@RunWith(TestRunner.class)
-public class TestInfoCollections {
- public static final String TEST_COLLECTIONS_JSON =
- "{\"history\":1.3319567131E9, " +
- " \"bookmarks\":1.33195669592E9, " +
- " \"prefs\":1.33115408641E9, " +
- " \"crypto\":1.32046063664E9, " +
- " \"meta\":1.321E9, " +
- " \"forms\":1.33136685374E9, " +
- " \"clients\":1.3313667619E9, " +
- " \"tabs\":1.35E9" +
- "}";
-
-
- public static final String TEST_COUNTS_JSON =
- "{\"passwords\": 390, " +
- " \"clients\": 2, " +
- " \"crypto\": 1, " +
- " \"forms\": 1019, " +
- " \"bookmarks\": 766, " +
- " \"prefs\": 1, " +
- " \"history\": 9278" +
- "}";
-
- @SuppressWarnings("static-method")
- @Test
- public void testSetCountsFromRecord() throws Exception {
- InfoCounts infoCountsEmpty = new InfoCounts(new ExtendedJSONObject("{}"));
- assertEquals(null, infoCountsEmpty.getCount("bookmarks"));
-
- ExtendedJSONObject record = new ExtendedJSONObject(TEST_COUNTS_JSON);
- InfoCounts infoCountsFull = new InfoCounts(record);
- assertEquals(Integer.valueOf(766), infoCountsFull.getCount("bookmarks"));
- assertEquals(null, infoCountsFull.getCount("notpresent"));
- }
-
-
- @SuppressWarnings("static-method")
- @Test
- public void testSetCollectionsFromRecord() throws Exception {
- ExtendedJSONObject record = new ExtendedJSONObject(TEST_COLLECTIONS_JSON);
- InfoCollections infoCollections = new InfoCollections(record);
-
- assertEquals(Utils.decimalSecondsToMilliseconds(1.3319567131E9), infoCollections.getTimestamp("history").longValue());
- assertEquals(Utils.decimalSecondsToMilliseconds(1.321E9), infoCollections.getTimestamp("meta").longValue());
- assertEquals(Utils.decimalSecondsToMilliseconds(1.35E9), infoCollections.getTimestamp("tabs").longValue());
- assertNull(infoCollections.getTimestamp("missing"));
- }
-
- @SuppressWarnings("static-method")
- @Test
- public void testUpdateNeeded() throws Exception {
- ExtendedJSONObject record = new ExtendedJSONObject(TEST_COLLECTIONS_JSON);
- InfoCollections infoCollections = new InfoCollections(record);
-
- long none = -1;
- long past = Utils.decimalSecondsToMilliseconds(1.3E9);
- long same = Utils.decimalSecondsToMilliseconds(1.35E9);
- long future = Utils.decimalSecondsToMilliseconds(1.4E9);
-
-
- // Test with no local timestamp set.
- assertTrue(infoCollections.updateNeeded("tabs", none));
-
- // Test with local timestamp set in the past.
- assertTrue(infoCollections.updateNeeded("tabs", past));
-
- // Test with same timestamp.
- assertFalse(infoCollections.updateNeeded("tabs", same));
-
- // Test with local timestamp set in the future.
- assertFalse(infoCollections.updateNeeded("tabs", future));
-
- // Test with no collection.
- assertTrue(infoCollections.updateNeeded("missing", none));
- assertTrue(infoCollections.updateNeeded("missing", past));
- assertTrue(infoCollections.updateNeeded("missing", same));
- assertTrue(infoCollections.updateNeeded("missing", future));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestPersistedMetaGlobal.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestPersistedMetaGlobal.java
deleted file mode 100644
index d1b6cadef..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/test/TestPersistedMetaGlobal.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.test;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.MockSharedPreferences;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.MetaGlobal;
-import org.mozilla.gecko.sync.NoCollectionKeysSetException;
-import org.mozilla.gecko.sync.PersistedMetaGlobal;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestPersistedMetaGlobal {
- MockSharedPreferences prefs = null;
- private final String TEST_META_URL = "metaURL";
- private final String TEST_CREDENTIALS = "credentials";
-
- @Before
- public void setUp() {
- prefs = new MockSharedPreferences();
- }
-
- @Test
- public void testPersistLastModified() throws CryptoException, NoCollectionKeysSetException {
- long LAST_MODIFIED = System.currentTimeMillis();
- PersistedMetaGlobal persisted = new PersistedMetaGlobal(prefs);
-
- // Test fresh start.
- assertEquals(-1, persisted.lastModified());
-
- // Test persisting.
- persisted.persistLastModified(LAST_MODIFIED);
- assertEquals(LAST_MODIFIED, persisted.lastModified());
-
- // Test clearing.
- persisted.persistLastModified(0);
- assertEquals(-1, persisted.lastModified());
- }
-
- @Test
- public void testPersistMetaGlobal() throws Exception {
- PersistedMetaGlobal persisted = new PersistedMetaGlobal(prefs);
- AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(TEST_CREDENTIALS);
-
- // Test fresh start.
- assertNull(persisted.metaGlobal(TEST_META_URL, authHeaderProvider));
-
- // Test persisting.
- String body = "{\"id\":\"global\",\"payload\":\"{\\\"syncID\\\":\\\"zPSQTm7WBVWB\\\",\\\"storageVersion\\\":5,\\\"engines\\\":{\\\"clients\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"fDg0MS5bDtV7\\\"},\\\"bookmarks\\\":{\\\"version\\\":2,\\\"syncID\\\":\\\"NNaQr6_F-9dm\\\"},\\\"forms\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"GXF29AFprnvc\\\"},\\\"history\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"av75g4vm-_rp\\\"},\\\"passwords\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"LT_ACGpuKZ6a\\\"},\\\"prefs\\\":{\\\"version\\\":2,\\\"syncID\\\":\\\"-3nsksP9wSAs\\\"},\\\"tabs\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"W4H5lOMChkYA\\\"}}}\",\"username\":\"5817483\",\"modified\":1.32046073744E9}";
- MetaGlobal mg = new MetaGlobal(TEST_META_URL, authHeaderProvider);
- mg.setFromRecord(CryptoRecord.fromJSONRecord(body));
- persisted.persistMetaGlobal(mg);
-
- MetaGlobal persistedGlobal = persisted.metaGlobal(TEST_META_URL, authHeaderProvider);
- assertNotNull(persistedGlobal);
- assertEquals("zPSQTm7WBVWB", persistedGlobal.getSyncID());
- assertTrue(persistedGlobal.getEngines() instanceof ExtendedJSONObject);
- assertEquals(Long.valueOf(5), persistedGlobal.getStorageVersion());
-
- // Test clearing.
- persisted.persistMetaGlobal(null);
- assertNull(persisted.metaGlobal(null, null));
- }
-
- @Test
- public void testPersistDeclinedEngines() throws Exception {
- PersistedMetaGlobal persisted = new PersistedMetaGlobal(prefs);
- AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(TEST_CREDENTIALS);
-
- // Test fresh start.
- assertNull(persisted.metaGlobal(TEST_META_URL, authHeaderProvider));
-
- // Test persisting.
- String body = "{\"id\":\"global\",\"payload\":\"{\\\"declined\\\":[\\\"bookmarks\\\",\\\"addons\\\"],\\\"syncID\\\":\\\"zPSQTm7WBVWB\\\",\\\"storageVersion\\\":5,\\\"engines\\\":{\\\"clients\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"fDg0MS5bDtV7\\\"},,\\\"forms\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"GXF29AFprnvc\\\"},\\\"history\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"av75g4vm-_rp\\\"},\\\"passwords\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"LT_ACGpuKZ6a\\\"},\\\"prefs\\\":{\\\"version\\\":2,\\\"syncID\\\":\\\"-3nsksP9wSAs\\\"},\\\"tabs\\\":{\\\"version\\\":1,\\\"syncID\\\":\\\"W4H5lOMChkYA\\\"}}}\",\"username\":\"5817483\",\"modified\":1.32046073744E9}";
- MetaGlobal mg = new MetaGlobal(TEST_META_URL, authHeaderProvider);
- mg.setFromRecord(CryptoRecord.fromJSONRecord(body));
- persisted.persistMetaGlobal(mg);
-
- MetaGlobal persistedGlobal = persisted.metaGlobal(TEST_META_URL, authHeaderProvider);
- assertNotNull(persistedGlobal);
- Set<String> declined = persistedGlobal.getDeclinedEngineNames();
- assertEquals(2, declined.size());
- assertTrue(declined.contains("bookmarks"));
- assertTrue(declined.contains("addons"));
-
- // Test clearing.
- persisted.persistMetaGlobal(null);
- assertNull(persisted.metaGlobal(null, null));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/measurements/TestSearchCountMeasurements.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/measurements/TestSearchCountMeasurements.java
deleted file mode 100644
index 058461f8e..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/measurements/TestSearchCountMeasurements.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.telemetry.measurements;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-
-import static org.junit.Assert.*;
-
-/**
- * Tests for the class that stores search count measurements.
- */
-@RunWith(TestRunner.class)
-public class TestSearchCountMeasurements {
-
- private SharedPreferences sharedPrefs;
-
- @Before
- public void setUp() throws Exception {
- sharedPrefs = RuntimeEnvironment.application.getSharedPreferences(
- TestSearchCountMeasurements.class.getSimpleName(), Context.MODE_PRIVATE);
- }
-
- private void assertNewValueInsertedNoIncrementedValues(final int expectedKeyCount) {
- assertEquals("Shared prefs key count has incremented", expectedKeyCount, sharedPrefs.getAll().size());
- assertTrue("Shared prefs still contains non-incremented initial value", sharedPrefs.getAll().containsValue(1));
- assertFalse("Shared prefs has not incremented any values", sharedPrefs.getAll().containsValue(2));
- }
-
- @Test
- public void testIncrementSearchCanRecreateEngineAndWhere() throws Exception {
- final String expectedIdentifier = "google";
- final String expectedWhere = "suggestbar";
-
- SearchCountMeasurements.incrementSearch(sharedPrefs, expectedIdentifier, expectedWhere);
- assertFalse("Shared prefs has some values", sharedPrefs.getAll().isEmpty());
- assertTrue("Shared prefs contains initial value", sharedPrefs.getAll().containsValue(1));
-
- boolean foundEngine = false;
- for (final String key : sharedPrefs.getAll().keySet()) {
- // We could try to match the exact key, but that's more fragile.
- if (key.contains(expectedIdentifier) && key.contains(expectedWhere)) {
- foundEngine = true;
- }
- }
- assertTrue("SharedPrefs keyset contains enough info to recreate engine & where", foundEngine);
- }
-
- @Test
- public void testIncrementSearchCalledMultipleTimesSameEngine() throws Exception {
- final String engineIdentifier = "whatever";
- final String where = "wherever";
-
- SearchCountMeasurements.incrementSearch(sharedPrefs, engineIdentifier, where);
- assertFalse("Shared prefs has some values", sharedPrefs.getAll().isEmpty());
- assertTrue("Shared prefs contains initial value", sharedPrefs.getAll().containsValue(1));
-
- // The initial key count storage saves metadata so we can't verify the number of keys is only 1. However,
- // we assume subsequent calls won't add additional metadata and use it to verify the key count.
- final int keyCountAfterFirst = sharedPrefs.getAll().size();
- for (int i = 2; i <= 3; ++i) {
- SearchCountMeasurements.incrementSearch(sharedPrefs, engineIdentifier, where);
- assertEquals("Shared prefs key count has not changed", keyCountAfterFirst, sharedPrefs.getAll().size());
- assertTrue("Shared prefs incremented", sharedPrefs.getAll().containsValue(i));
- }
- }
-
- @Test
- public void testIncrementSearchCalledMultipleTimesSameEngineDifferentWhere() throws Exception {
- final String engineIdenfitier = "whatever";
-
- SearchCountMeasurements.incrementSearch(sharedPrefs, engineIdenfitier, "one place");
- assertFalse("Shared prefs has some values", sharedPrefs.getAll().isEmpty());
- assertTrue("Shared prefs contains initial value", sharedPrefs.getAll().containsValue(1));
-
- // The initial key count storage saves metadata so we can't verify the number of keys is only 1. However,
- // we assume subsequent calls won't add additional metadata and use it to verify the key count.
- final int keyCountAfterFirst = sharedPrefs.getAll().size();
- for (int i = 1; i <= 2; ++i) {
- SearchCountMeasurements.incrementSearch(sharedPrefs, engineIdenfitier, "another place " + i);
- assertNewValueInsertedNoIncrementedValues(keyCountAfterFirst + i);
- }
- }
-
- @Test
- public void testIncrementSearchCalledMultipleTimesDifferentEngines() throws Exception {
- final String where = "wherever";
-
- SearchCountMeasurements.incrementSearch(sharedPrefs, "steam engine", where);
- assertFalse("Shared prefs has some values", sharedPrefs.getAll().isEmpty());
- assertTrue("Shared prefs contains initial value", sharedPrefs.getAll().containsValue(1));
-
- // The initial key count storage saves metadata so we can't verify the number of keys is only 1. However,
- // we assume subsequent calls won't add additional metadata and use it to verify the key count.
- final int keyCountAfterFirst = sharedPrefs.getAll().size();
- for (int i = 1; i <= 2; ++i) {
- SearchCountMeasurements.incrementSearch(sharedPrefs, "combustion engine" + i, where);
- assertNewValueInsertedNoIncrementedValues(keyCountAfterFirst + i);
- }
- }
-
- @Test // assumes the format saved in SharedPrefs to store test data
- public void testGetAndZeroSearchDeletesPrefs() throws Exception {
- assertTrue("Shared prefs is empty", sharedPrefs.getAll().isEmpty());
-
- final SharedPreferences.Editor editor = sharedPrefs.edit();
- final Set<String> engineKeys = new HashSet<>(Arrays.asList("whatever.yeah", "lol.what"));
- editor.putStringSet(SearchCountMeasurements.PREF_SEARCH_KEYSET, engineKeys);
- for (final String key : engineKeys) {
- editor.putInt(getEngineSearchCountKey(key), 1);
- }
- editor.apply();
- assertFalse("Shared prefs is not empty after test data inserted", sharedPrefs.getAll().isEmpty());
-
- SearchCountMeasurements.getAndZeroSearch(sharedPrefs);
- assertTrue("Shared prefs is empty after zero", sharedPrefs.getAll().isEmpty());
- }
-
- @Test // assumes the format saved in SharedPrefs to store test data
- public void testGetAndZeroSearchVerifyReturnedData() throws Exception {
- final HashMap<String, Integer> expected = new HashMap<>();
- expected.put("steamengine.here", 1337);
- expected.put("combustionengine.there", 10);
-
- final SharedPreferences.Editor editor = sharedPrefs.edit();
- editor.putStringSet(SearchCountMeasurements.PREF_SEARCH_KEYSET, expected.keySet());
- for (final String key : expected.keySet()) {
- editor.putInt(SearchCountMeasurements.getEngineSearchCountKey(key), expected.get(key));
- }
- editor.apply();
- assertFalse("Shared prefs is not empty after test data inserted", sharedPrefs.getAll().isEmpty());
-
- final ExtendedJSONObject actual = SearchCountMeasurements.getAndZeroSearch(sharedPrefs);
- assertEquals("Returned JSON contains number of items inserted", expected.size(), actual.size());
- for (final String key : expected.keySet()) {
- assertEquals("Returned JSON contains inserted value", expected.get(key), (Integer) actual.getIntegerSafely(key));
- }
- }
-
- @Test
- public void testGetAndZeroSearchNoData() throws Exception {
- final ExtendedJSONObject actual = SearchCountMeasurements.getAndZeroSearch(sharedPrefs);
- assertEquals("Returned json is empty", 0, actual.size());
- }
-
- private String getEngineSearchCountKey(final String engineWhereStr) {
- return SearchCountMeasurements.getEngineSearchCountKey(engineWhereStr);
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/measurements/TestSessionMeasurements.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/measurements/TestSessionMeasurements.java
deleted file mode 100644
index a5d3ce551..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/measurements/TestSessionMeasurements.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.telemetry.measurements;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.telemetry.measurements.SessionMeasurements.SessionMeasurementsContainer;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.concurrent.TimeUnit;
-
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
-
-/**
- * Tests the session measurements class.
- */
-@RunWith(TestRunner.class)
-public class TestSessionMeasurements {
-
- private SessionMeasurements testMeasurements;
- private SharedPreferences sharedPrefs;
- private Context context;
-
- @Before
- public void setUp() throws Exception {
- testMeasurements = spy(SessionMeasurements.class);
- sharedPrefs = RuntimeEnvironment.application.getSharedPreferences(
- TestSessionMeasurements.class.getSimpleName(), Context.MODE_PRIVATE);
- doReturn(sharedPrefs).when(testMeasurements).getSharedPreferences(any(Context.class));
-
- context = RuntimeEnvironment.application;
- }
-
- private void assertSessionCount(final String postfix, final int expectedSessionCount) {
- final int actual = sharedPrefs.getInt(SessionMeasurements.PREF_SESSION_COUNT, -1);
- assertEquals("Expected number of sessions occurred " + postfix, expectedSessionCount, actual);
- }
-
- private void assertSessionDuration(final String postfix, final long expectedSessionDuration) {
- final long actual = sharedPrefs.getLong(SessionMeasurements.PREF_SESSION_DURATION, -1);
- assertEquals("Expected session duration received " + postfix, expectedSessionDuration, actual);
- }
-
- private void mockGetSystemTimeNanosToReturn(final long value) {
- doReturn(value).when(testMeasurements).getSystemTimeNano();
- }
-
- @Test
- public void testRecordSessionStartAndEndCalledOnce() throws Exception {
- final long expectedElapsedSeconds = 4;
- mockGetSystemTimeNanosToReturn(0);
- testMeasurements.recordSessionStart();
- mockGetSystemTimeNanosToReturn(TimeUnit.SECONDS.toNanos(expectedElapsedSeconds));
- testMeasurements.recordSessionEnd(context);
-
- final String postfix = "after recordSessionStart/End called once";
- assertSessionCount(postfix, 1);
- assertSessionDuration(postfix, expectedElapsedSeconds);
- }
-
- @Test
- public void testRecordSessionStartAndEndCalledTwice() throws Exception {
- final long expectedElapsedSeconds = 100;
- mockGetSystemTimeNanosToReturn(0L);
- for (int i = 1; i <= 2; ++i) {
- testMeasurements.recordSessionStart();
- mockGetSystemTimeNanosToReturn(TimeUnit.SECONDS.toNanos((expectedElapsedSeconds / 2) * i));
- testMeasurements.recordSessionEnd(context);
- }
-
- final String postfix = "after recordSessionStart/End called twice";
- assertSessionCount(postfix, 2);
- assertSessionDuration(postfix, expectedElapsedSeconds);
- }
-
- @Test(expected = IllegalStateException.class)
- public void testRecordSessionStartThrowsIfSessionAlreadyStarted() throws Exception {
- // First call will start the session, next expected to throw.
- for (int i = 0; i < 2; ++i) {
- testMeasurements.recordSessionStart();
- }
- }
-
- @Test(expected = IllegalStateException.class)
- public void testRecordSessionEndThrowsIfCalledBeforeSessionStarted() {
- testMeasurements.recordSessionEnd(context);
- }
-
- @Test // assumes the underlying format in SessionMeasurements
- public void testGetAndResetSessionMeasurementsReturnsSetData() throws Exception {
- final int expectedSessionCount = 42;
- final long expectedSessionDuration = 1234567890;
- sharedPrefs.edit()
- .putInt(SessionMeasurements.PREF_SESSION_COUNT, expectedSessionCount)
- .putLong(SessionMeasurements.PREF_SESSION_DURATION, expectedSessionDuration)
- .apply();
-
- final SessionMeasurementsContainer actual = testMeasurements.getAndResetSessionMeasurements(context);
- assertEquals("Returned session count matches expected", expectedSessionCount, actual.sessionCount);
- assertEquals("Returned session duration matches expected", expectedSessionDuration, actual.elapsedSeconds);
- }
-
- @Test
- public void testGetAndResetSessionMeasurementsResetsData() throws Exception {
- sharedPrefs.edit()
- .putInt(SessionMeasurements.PREF_SESSION_COUNT, 10)
- .putLong(SessionMeasurements.PREF_SESSION_DURATION, 10)
- .apply();
-
- testMeasurements.getAndResetSessionMeasurements(context);
- final String postfix = "is reset after retrieval";
- assertSessionCount(postfix, 0);
- assertSessionDuration(postfix, 0);
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/pingbuilders/TestTelemetryPingBuilder.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/pingbuilders/TestTelemetryPingBuilder.java
deleted file mode 100644
index ca0124121..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/pingbuilders/TestTelemetryPingBuilder.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.telemetry.pingbuilders;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import static org.junit.Assert.*;
-
-/**
- * Unit test methods of the {@link TelemetryPingBuilder} class.
- */
-@RunWith(TestRunner.class)
-public class TestTelemetryPingBuilder {
- @Test
- public void testMandatoryFieldsNone() {
- final NoMandatoryFieldsBuilder builder = new NoMandatoryFieldsBuilder();
- builder.setNonMandatoryField();
- assertNotNull("Builder does not throw and returns a non-null value", builder.build());
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testMandatoryFieldsMissing() {
- final MandatoryFieldsBuilder builder = new MandatoryFieldsBuilder();
- builder.setNonMandatoryField()
- .build(); // should throw
- }
-
- @Test
- public void testMandatoryFieldsIncluded() {
- final MandatoryFieldsBuilder builder = new MandatoryFieldsBuilder();
- builder.setNonMandatoryField()
- .setMandatoryField();
- assertNotNull("Builder does not throw and returns non-null value", builder.build());
- }
-
- private static class NoMandatoryFieldsBuilder extends TelemetryPingBuilder {
- @Override
- public String getDocType() {
- return "";
- }
-
- @Override
- public String[] getMandatoryFields() {
- return new String[0];
- }
-
- public NoMandatoryFieldsBuilder setNonMandatoryField() {
- payload.put("non-mandatory", true);
- return this;
- }
- }
-
- private static class MandatoryFieldsBuilder extends TelemetryPingBuilder {
- private static final String MANDATORY_FIELD = "mandatory-field";
-
- @Override
- public String getDocType() {
- return "";
- }
-
- @Override
- public String[] getMandatoryFields() {
- return new String[] {
- MANDATORY_FIELD,
- };
- }
-
- public MandatoryFieldsBuilder setNonMandatoryField() {
- payload.put("non-mandatory", true);
- return this;
- }
-
- public MandatoryFieldsBuilder setMandatoryField() {
- payload.put(MANDATORY_FIELD, true);
- return this;
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/schedulers/TestTelemetryUploadAllPingsImmediatelyScheduler.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/schedulers/TestTelemetryUploadAllPingsImmediatelyScheduler.java
deleted file mode 100644
index 8093040ee..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/schedulers/TestTelemetryUploadAllPingsImmediatelyScheduler.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.telemetry.schedulers;
-
-import android.content.Context;
-import android.content.Intent;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.telemetry.TelemetryUploadService;
-import org.mozilla.gecko.telemetry.stores.TelemetryPingStore;
-
-import static junit.framework.Assert.*;
-import static org.mockito.Mockito.*;
-
-/**
- * Unit tests for the upload immediately scheduler.
- *
- * When we add more schedulers, we'll likely change the interface
- * (e.g. pass in current time) and these tests will be more useful.
- */
-@RunWith(TestRunner.class)
-public class TestTelemetryUploadAllPingsImmediatelyScheduler {
-
- private TelemetryUploadAllPingsImmediatelyScheduler testScheduler;
- private TelemetryPingStore testStore;
-
- @Before
- public void setUp() {
- testScheduler = new TelemetryUploadAllPingsImmediatelyScheduler();
- testStore = mock(TelemetryPingStore.class);
- }
-
- @Test
- public void testReadyToUpload() {
- assertTrue("Scheduler is always ready to upload", testScheduler.isReadyToUpload(testStore));
- }
-
- @Test
- public void testScheduleUpload() {
- final Context context = mock(Context.class);
-
- testScheduler.scheduleUpload(context, testStore);
-
- final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(context).startService(intentCaptor.capture());
- final Intent actualIntent = intentCaptor.getValue();
- assertEquals("Intent action is upload", TelemetryUploadService.ACTION_UPLOAD, actualIntent.getAction());
- assertTrue("Intent contains store", actualIntent.hasExtra(TelemetryUploadService.EXTRA_STORE));
- assertEquals("Intent class target is upload service",
- TelemetryUploadService.class.getName(), actualIntent.getComponent().getClassName());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/stores/TestTelemetryJSONFilePingStore.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/stores/TestTelemetryJSONFilePingStore.java
deleted file mode 100644
index a95a8b292..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/telemetry/stores/TestTelemetryJSONFilePingStore.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.telemetry.stores;
-
-import org.json.JSONObject;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.telemetry.TelemetryPing;
-import org.mozilla.gecko.util.FileUtils;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FilenameFilter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-
-import static org.junit.Assert.*;
-
-/**
- * Unit test methods of the {@link TelemetryJSONFilePingStore} class.
- */
-@RunWith(TestRunner.class)
-public class TestTelemetryJSONFilePingStore {
-
- @Rule
- public TemporaryFolder tempDir = new TemporaryFolder();
- private File testDir;
- private TelemetryJSONFilePingStore testStore;
-
- @Before
- public void setUp() throws Exception {
- testDir = tempDir.newFolder();
- testStore = new TelemetryJSONFilePingStore(testDir, "");
- }
-
- private ExtendedJSONObject generateTelemetryPayload() {
- final ExtendedJSONObject out = new ExtendedJSONObject();
- out.put("str", "a String");
- out.put("int", 42);
- out.put("null", (ExtendedJSONObject) null);
- return out;
- }
-
- private void assertIsGeneratedPayload(final ExtendedJSONObject actual) throws Exception {
- assertNull("Null field is null", actual.getObject("null"));
- assertEquals("int field is correct", 42, (int) actual.getIntegerSafely("int"));
- assertEquals("str field is correct", "a String", actual.getString("str"));
- }
-
- private void assertStoreFileCount(final int expectedCount) {
- assertEquals("Store contains " + expectedCount + " item(s)", expectedCount, testDir.list().length);
- }
-
- @Test
- public void testConstructorOnlyWritesToGivenDir() throws Exception {
- // Constructor is called in @Before method
- assertTrue("Store dir exists", testDir.exists());
- assertEquals("Temp dir contains one dir (the store dir)", 1, tempDir.getRoot().list().length);
- }
-
- @Test(expected = IllegalStateException.class)
- public void testConstructorStoreAlreadyExistsAsNonDirectory() throws Exception {
- final File file = tempDir.newFile();
- new TelemetryJSONFilePingStore(file, "profileName"); // expected to throw.
- }
-
- @Test(expected = IllegalStateException.class)
- public void testConstructorDirIsNotReadable() throws Exception {
- final File dir = tempDir.newFolder();
- dir.setReadable(false);
- new TelemetryJSONFilePingStore(dir, "profileName"); // expected to throw.
- }
-
- @Test(expected = IllegalStateException.class)
- public void testConstructorDirIsNotWritable() throws Exception {
- final File dir = tempDir.newFolder();
- dir.setWritable(false);
- new TelemetryJSONFilePingStore(dir, "profileName"); // expected to throw.
- }
-
- @Test(expected = IllegalStateException.class)
- public void testConstructorDirIsNotExecutable() throws Exception {
- final File dir = tempDir.newFolder();
- dir.setExecutable(false);
- new TelemetryJSONFilePingStore(dir, "profileName"); // expected to throw.
- }
-
- @Test
- public void testStorePingStoresCorrectData() throws Exception {
- assertStoreFileCount(0);
-
- final String expectedID = getDocID();
- final TelemetryPing expectedPing = new TelemetryPing("a/server/url", generateTelemetryPayload(), expectedID);
- testStore.storePing(expectedPing);
-
- assertStoreFileCount(1);
- final String filename = testDir.list()[0];
- assertTrue("Filename contains expected ID", filename.equals(expectedID));
- final JSONObject actual = FileUtils.readJSONObjectFromFile(new File(testDir, filename));
- assertEquals("Ping url paths are equal", expectedPing.getURLPath(), actual.getString(TelemetryJSONFilePingStore.KEY_URL_PATH));
- assertIsGeneratedPayload(new ExtendedJSONObject(actual.getString(TelemetryJSONFilePingStore.KEY_PAYLOAD)));
- }
-
- @Test
- public void testStorePingMultiplePingsStoreSeparateFiles() throws Exception {
- assertStoreFileCount(0);
- for (int i = 1; i < 10; ++i) {
- testStore.storePing(new TelemetryPing("server", generateTelemetryPayload(), getDocID()));
- assertStoreFileCount(i);
- }
- }
-
- @Test
- public void testStorePingReleasesFileLock() throws Exception {
- assertStoreFileCount(0);
- testStore.storePing(new TelemetryPing("server", generateTelemetryPayload(), getDocID()));
- assertStoreFileCount(1);
- final File file = new File(testDir, testDir.list()[0]);
- final FileOutputStream stream = new FileOutputStream(file);
- try {
- assertNotNull("File lock is released after store write", stream.getChannel().tryLock());
- } finally {
- stream.close(); // releases lock
- }
- }
-
- @Test
- public void testGetAllPingsSavesData() throws Exception {
- final String urlPrefix = "url";
- writeTestPingsToStore(3, urlPrefix);
-
- final ArrayList<TelemetryPing> pings = testStore.getAllPings();
- for (final TelemetryPing ping : pings) {
- assertEquals("Expected url path value received", urlPrefix + ping.getDocID(), ping.getURLPath());
- assertIsGeneratedPayload(ping.getPayload());
- }
- }
-
- @Test
- public void testGetAllPingsIsSorted() throws Exception {
- final List<String> storedDocIDs = writeTestPingsToStore(3, "urlPrefix");
-
- final ArrayList<TelemetryPing> pings = testStore.getAllPings();
- for (int i = 0; i < pings.size(); ++i) {
- final String expectedDocID = storedDocIDs.get(i);
- final TelemetryPing ping = pings.get(i);
-
- assertEquals("Stored ping " + i + " retrieved in order", expectedDocID, ping.getDocID());
- }
- }
-
- @Test // regression test: bug 1272817
- public void testGetAllPingsHandlesEmptyFiles() throws Exception {
- final int expectedPingCount = 3;
- writeTestPingsToStore(expectedPingCount, "whatever");
- assertTrue("Empty file is created", testStore.getPingFile(getDocID()).createNewFile());
- assertEquals("Returned pings only contains valid files", expectedPingCount, testStore.getAllPings().size());
- }
-
- @Test
- public void testMaybePrunePingsDoesNothingIfAtMax() throws Exception {
- final int pingCount = TelemetryJSONFilePingStore.MAX_PING_COUNT;
- writeTestPingsToStore(pingCount, "whatever");
- assertStoreFileCount(pingCount);
- testStore.maybePrunePings();
- assertStoreFileCount(pingCount);
- }
-
- @Test
- public void testMaybePrunePingsPrunesIfAboveMax() throws Exception {
- final int pingCount = TelemetryJSONFilePingStore.MAX_PING_COUNT + 1;
- final List<String> expectedDocIDs = writeTestPingsToStore(pingCount, "whatever");
- assertStoreFileCount(pingCount);
- testStore.maybePrunePings();
- assertStoreFileCount(TelemetryJSONFilePingStore.MAX_PING_COUNT);
-
- final HashSet<String> existingIDs = new HashSet<>(Arrays.asList(testDir.list()));
- assertFalse("Oldest ping was removed", existingIDs.contains(expectedDocIDs.get(0)));
- }
-
- @Test
- public void testOnUploadAttemptCompleted() throws Exception {
- final List<String> savedDocIDs = writeTestPingsToStore(10, "url");
- final int halfSize = savedDocIDs.size() / 2;
- final Set<String> unuploadedPingIDs = new HashSet<>(savedDocIDs.subList(0, halfSize));
- final Set<String> removedPingIDs = new HashSet<>(savedDocIDs.subList(halfSize, savedDocIDs.size()));
- testStore.onUploadAttemptComplete(removedPingIDs);
-
- for (final String unuploadedDocID : testDir.list()) {
- assertFalse("Unuploaded ID is not in removed ping IDs", removedPingIDs.contains(unuploadedDocID));
- assertTrue("Unuploaded ID is in unuploaded ping IDs", unuploadedPingIDs.contains(unuploadedDocID));
- unuploadedPingIDs.remove(unuploadedDocID);
- }
- assertTrue("All non-successful-upload ping IDs were matched", unuploadedPingIDs.isEmpty());
- }
-
- @Test
- public void testGetPingFileIsDocID() throws Exception {
- final String docID = getDocID();
- final File file = testStore.getPingFile(docID);
- assertTrue("Ping filename contains ID", file.getName().equals(docID));
- }
-
- /**
- * Writes pings to store without using store API with:
- * server = urlPrefix + docID
- * payload = generated payload
- *
- * The docID is stored as the filename.
- *
- * Note: assumes {@link TelemetryJSONFilePingStore#getPingFile(String)} works.
- *
- * @return a list of doc IDs saved to disk in ascending order of last modified date
- */
- private List<String> writeTestPingsToStore(final int count, final String urlPrefix) throws Exception {
- final List<String> savedDocIDs = new ArrayList<>(count);
- final long now = System.currentTimeMillis();
- for (int i = 1; i <= count; ++i) {
- final String docID = getDocID();
- final JSONObject obj = new JSONObject()
- .put(TelemetryJSONFilePingStore.KEY_URL_PATH, urlPrefix + docID)
- .put(TelemetryJSONFilePingStore.KEY_PAYLOAD, generateTelemetryPayload());
- final File pingFile = testStore.getPingFile(docID);
- FileUtils.writeJSONObjectToFile(pingFile, obj);
-
- // If we don't set an explicit time, the modified times are all equal.
- // Also, last modified times are rounded by second.
- assertTrue("Able to set last modified time", pingFile.setLastModified(now - (count * 10_000) + i * 10_000));
- savedDocIDs.add(docID);
- }
- return savedDocIDs;
- }
-
- private String getDocID() {
- return UUID.randomUUID().toString();
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/tokenserver/test/TestTokenServerClient.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/tokenserver/test/TestTokenServerClient.java
deleted file mode 100644
index 03fe67794..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/tokenserver/test/TestTokenServerClient.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.tokenserver.test;
-
-import ch.boye.httpclientandroidlib.Header;
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.ProtocolVersion;
-import ch.boye.httpclientandroidlib.client.methods.HttpGet;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.entity.StringEntity;
-import ch.boye.httpclientandroidlib.message.BasicHeader;
-import ch.boye.httpclientandroidlib.message.BasicHttpResponse;
-import ch.boye.httpclientandroidlib.message.BasicStatusLine;
-import junit.framework.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.common.log.writers.StringLogWriter;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncResponse;
-import org.mozilla.gecko.tokenserver.TokenServerClient;
-import org.mozilla.gecko.tokenserver.TokenServerClient.TokenFetchResourceDelegate;
-import org.mozilla.gecko.tokenserver.TokenServerClientDelegate;
-import org.mozilla.gecko.tokenserver.TokenServerException;
-import org.mozilla.gecko.tokenserver.TokenServerException.TokenServerConditionsRequiredException;
-import org.mozilla.gecko.tokenserver.TokenServerException.TokenServerInvalidCredentialsException;
-import org.mozilla.gecko.tokenserver.TokenServerException.TokenServerMalformedRequestException;
-import org.mozilla.gecko.tokenserver.TokenServerException.TokenServerMalformedResponseException;
-import org.mozilla.gecko.tokenserver.TokenServerException.TokenServerUnknownServiceException;
-import org.mozilla.gecko.tokenserver.TokenServerToken;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestTokenServerClient {
- public static final String JSON = "application/json";
- public static final String TEXT = "text/plain";
-
- public static final String TEST_TOKEN_RESPONSE = "{\"api_endpoint\": \"https://stage-aitc1.services.mozilla.com/1.0/1659259\"," +
- "\"duration\": 300," +
- "\"id\": \"eySHORTENED\"," +
- "\"key\": \"-plSHORTENED\"," +
- "\"uid\": 1659259}";
-
- public static final String TEST_CONDITIONS_RESPONSE = "{\"errors\":[{" +
- "\"location\":\"header\"," +
- "\"description\":\"Need to accept conditions\"," +
- "\"condition_urls\":{\"tos\":\"http://url-to-tos.com\"}," +
- "\"name\":\"X-Conditions-Accepted\"}]," +
- "\"status\":\"error\"}";
-
- public static final String TEST_ERROR_RESPONSE = "{\"status\": \"error\"," +
- "\"errors\": [{\"location\": \"body\", \"name\": \"\", \"description\": \"Unauthorized EXTENDED\"}]}";
-
- public static final String TEST_INVALID_TIMESTAMP_RESPONSE = "{\"status\": \"invalid-timestamp\", " +
- "\"errors\": [{\"location\": \"body\", \"name\": \"\", \"description\": \"Unauthorized\"}]}";
-
- protected TokenServerClient client;
-
- @Before
- public void setUp() throws Exception {
- this.client = new TokenServerClient(new URI("http://unused.com"), Executors.newSingleThreadExecutor());
- }
-
- protected TokenServerToken doProcessResponse(int statusCode, String contentType, Object token)
- throws UnsupportedEncodingException, TokenServerException {
- final HttpResponse response = new BasicHttpResponse(
- new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), statusCode, "OK"));
-
- StringEntity stringEntity = new StringEntity(token.toString());
- stringEntity.setContentType(contentType);
- response.setEntity(stringEntity);
-
- return client.processResponse(new SyncResponse(response));
- }
-
- @SuppressWarnings("rawtypes")
- protected TokenServerException expectProcessResponseFailure(int statusCode, String contentType, Object token, Class klass)
- throws TokenServerException, UnsupportedEncodingException {
- try {
- doProcessResponse(statusCode, contentType, token.toString());
- fail("Expected exception of type " + klass + ".");
-
- return null;
- } catch (TokenServerException e) {
- assertEquals(klass, e.getClass());
-
- return e;
- }
- }
-
- @SuppressWarnings("rawtypes")
- protected TokenServerException expectProcessResponseFailure(Object token, Class klass)
- throws UnsupportedEncodingException, TokenServerException {
- return expectProcessResponseFailure(200, "application/json", token, klass);
- }
-
- @Test
- public void testProcessResponseSuccess() throws Exception {
- TokenServerToken token = doProcessResponse(200, "application/json", TEST_TOKEN_RESPONSE);
-
- assertEquals("eySHORTENED", token.id);
- assertEquals("-plSHORTENED", token.key);
- assertEquals("1659259", token.uid);
- assertEquals("https://stage-aitc1.services.mozilla.com/1.0/1659259", token.endpoint);
- }
-
- @Test
- public void testProcessResponseFailure() throws Exception {
- // Wrong Content-Type.
- expectProcessResponseFailure(200, TEXT, new ExtendedJSONObject(), TokenServerMalformedResponseException.class);
-
- // Not valid JSON.
- expectProcessResponseFailure("#!", TokenServerMalformedResponseException.class);
-
- // Status code 400.
- expectProcessResponseFailure(400, JSON, new ExtendedJSONObject(), TokenServerMalformedRequestException.class);
-
- // Status code 401.
- expectProcessResponseFailure(401, JSON, new ExtendedJSONObject(), TokenServerInvalidCredentialsException.class);
- expectProcessResponseFailure(401, JSON, TEST_INVALID_TIMESTAMP_RESPONSE, TokenServerInvalidCredentialsException.class);
-
- // Status code 404.
- expectProcessResponseFailure(404, JSON, new ExtendedJSONObject(), TokenServerUnknownServiceException.class);
-
- // Status code 406, which is not specially handled, but with errors. We take
- // care that errors are actually printed because we're going to want this to
- // work when things go wrong.
- StringLogWriter logWriter = new StringLogWriter();
-
- Logger.startLoggingTo(logWriter);
- try {
- expectProcessResponseFailure(406, JSON, TEST_ERROR_RESPONSE, TokenServerException.class);
-
- assertTrue(logWriter.toString().contains("Unauthorized EXTENDED"));
- } finally {
- Logger.stopLoggingTo(logWriter);
- }
-
- // Status code 503.
- expectProcessResponseFailure(503, JSON, new ExtendedJSONObject(), TokenServerException.class);
- }
-
- @Test
- public void testProcessResponseConditionsRequired() throws Exception {
-
- // Status code 403: conditions need to be accepted, but malformed (no urls).
- expectProcessResponseFailure(403, JSON, new ExtendedJSONObject(), TokenServerMalformedResponseException.class);
-
- // Status code 403, with urls.
- TokenServerConditionsRequiredException e = (TokenServerConditionsRequiredException)
- expectProcessResponseFailure(403, JSON, TEST_CONDITIONS_RESPONSE, TokenServerConditionsRequiredException.class);
-
- ExtendedJSONObject expectedUrls = new ExtendedJSONObject();
- expectedUrls.put("tos", "http://url-to-tos.com");
- assertEquals(expectedUrls.toString(), e.conditionUrls.toString());
- }
-
- @Test
- public void testProcessResponseMalformedToken() throws Exception {
- ExtendedJSONObject token;
-
- // Missing key.
- token = new ExtendedJSONObject(TEST_TOKEN_RESPONSE);
- token.remove("api_endpoint");
- expectProcessResponseFailure(token, TokenServerMalformedResponseException.class);
-
- // Key has wrong type; expected String.
- token = new ExtendedJSONObject(TEST_TOKEN_RESPONSE);
- token.put("api_endpoint", new ExtendedJSONObject());
- expectProcessResponseFailure(token, TokenServerMalformedResponseException.class);
-
- // Key has wrong type; expected number.
- token = new ExtendedJSONObject(TEST_TOKEN_RESPONSE);
- token.put("uid", "NON NUMERIC");
- expectProcessResponseFailure(token, TokenServerMalformedResponseException.class);
- }
-
- private class MockBaseResource extends BaseResource {
- public MockBaseResource(String uri) throws URISyntaxException {
- super(uri);
- this.request = new HttpGet(this.uri);
- }
-
- public HttpRequestBase prepareHeadersAndReturn() throws Exception {
- super.prepareClient();
- return request;
- }
- }
-
- @Test
- public void testClientStateHeader() throws Exception {
- String assertion = "assertion";
- String clientState = "abcdef";
- MockBaseResource resource = new MockBaseResource("http://unused.local/");
-
- TokenServerClientDelegate delegate = new TokenServerClientDelegate() {
- @Override
- public void handleSuccess(TokenServerToken token) {
- }
-
- @Override
- public void handleFailure(TokenServerException e) {
- }
-
- @Override
- public void handleError(Exception e) {
- }
-
- @Override
- public void handleBackoff(int backoffSeconds) {
- }
-
- @Override
- public String getUserAgent() {
- return null;
- }
- };
-
- resource.delegate = new TokenServerClient.TokenFetchResourceDelegate(client, resource, delegate, assertion, clientState , true) {
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return null;
- }
- };
-
- HttpRequestBase request = resource.prepareHeadersAndReturn();
- Assert.assertEquals("abcdef", request.getFirstHeader("X-Client-State").getValue());
- Assert.assertEquals("1", request.getFirstHeader("X-Conditions-Accepted").getValue());
- }
-
- public static class MockTokenServerClient extends TokenServerClient {
- public MockTokenServerClient(URI uri, Executor executor) {
- super(uri, executor);
- }
- }
-
- public static final class MockTokenServerClientDelegate implements
- TokenServerClientDelegate {
- public volatile boolean backoffCalled;
- public volatile boolean succeeded;
- public volatile int backoff;
-
- @Override
- public String getUserAgent() {
- return null;
- }
-
- @Override
- public void handleSuccess(TokenServerToken token) {
- succeeded = true;
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void handleFailure(TokenServerException e) {
- succeeded = false;
- WaitHelper.getTestWaiter().performNotify();
- }
-
- @Override
- public void handleError(Exception e) {
- succeeded = false;
- WaitHelper.getTestWaiter().performNotify(e);
- }
-
- @Override
- public void handleBackoff(int backoffSeconds) {
- backoffCalled = true;
- backoff = backoffSeconds;
- }
- }
-
- private void expectDelegateCalls(URI uri, MockTokenServerClient client, int code, Header header, String body, boolean succeeded, long backoff, boolean expectBackoff) throws UnsupportedEncodingException {
- final BaseResource resource = new BaseResource(uri);
- final String assertion = "someassertion";
- final String clientState = "abcdefabcdefabcdefabcdefabcdefab";
- final boolean conditionsAccepted = true;
-
- MockTokenServerClientDelegate delegate = new MockTokenServerClientDelegate();
-
- final TokenFetchResourceDelegate tokenFetchResourceDelegate = new TokenServerClient.TokenFetchResourceDelegate(client, resource, delegate, assertion, clientState, conditionsAccepted);
-
- final BasicStatusLine statusline = new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), code, "Whatever");
- final HttpResponse response = new BasicHttpResponse(statusline);
- response.setHeader(header);
- if (body != null) {
- final StringEntity entity = new StringEntity(body);
- entity.setContentType("application/json");
- response.setEntity(entity);
- }
-
- WaitHelper.getTestWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- tokenFetchResourceDelegate.handleHttpResponse(response);
- }
- });
-
- assertEquals(expectBackoff, delegate.backoffCalled);
- assertEquals(backoff, delegate.backoff);
- assertEquals(succeeded, delegate.succeeded);
- }
-
- @Test
- public void testBackoffHandling() throws URISyntaxException, UnsupportedEncodingException {
- final URI uri = new URI("http://unused.com");
- final MockTokenServerClient client = new MockTokenServerClient(uri, Executors.newSingleThreadExecutor());
-
- // Even the 200 code here is false because the body is malformed.
- expectDelegateCalls(uri, client, 200, new BasicHeader("x-backoff", "13"), "baaaa", false, 13, true);
- expectDelegateCalls(uri, client, 400, new BasicHeader("X-Weave-Backoff", "15"), null, false, 15, true);
- expectDelegateCalls(uri, client, 503, new BasicHeader("retry-after", "3"), null, false, 3, true);
-
- // Retry-After is only processed on 503.
- expectDelegateCalls(uri, client, 200, new BasicHeader("retry-after", "13"), null, false, 0, false);
-
- // Now let's try one with a valid body.
- expectDelegateCalls(uri, client, 200, new BasicHeader("X-Backoff", "1234"), TEST_TOKEN_RESPONSE, true, 1234, true);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/NetworkUtilsTest.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/NetworkUtilsTest.java
deleted file mode 100644
index fb2cffc92..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/NetworkUtilsTest.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.util;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.telephony.TelephonyManager;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.util.NetworkUtils.*;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.internal.ShadowExtractor;
-import org.robolectric.shadows.ShadowConnectivityManager;
-import org.robolectric.shadows.ShadowNetworkInfo;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class NetworkUtilsTest {
- private ConnectivityManager connectivityManager;
- private ShadowConnectivityManager shadowConnectivityManager;
-
- @Before
- public void setUp() {
- connectivityManager = (ConnectivityManager) RuntimeEnvironment.application.getSystemService(Context.CONNECTIVITY_SERVICE);
-
- // Not using Shadows.shadowOf(connectivityManager) because of Robolectric bug when using API23+
- // See: https://github.com/robolectric/robolectric/issues/1862
- shadowConnectivityManager = (ShadowConnectivityManager) ShadowExtractor.extract(connectivityManager);
- }
-
- @Test
- public void testIsConnected() throws Exception {
- assertFalse(NetworkUtils.isConnected((ConnectivityManager) null));
-
- shadowConnectivityManager.setActiveNetworkInfo(null);
- assertFalse(NetworkUtils.isConnected(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_WIFI, 0, true, true)
- );
- assertTrue(NetworkUtils.isConnected(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.DISCONNECTED, ConnectivityManager.TYPE_WIFI, 0, true, false)
- );
- assertFalse(NetworkUtils.isConnected(connectivityManager));
- }
-
- @Test
- public void testGetConnectionSubType() throws Exception {
- assertEquals(ConnectionSubType.UNKNOWN, NetworkUtils.getConnectionSubType(null));
-
- shadowConnectivityManager.setActiveNetworkInfo(null);
- assertEquals(ConnectionSubType.UNKNOWN, NetworkUtils.getConnectionSubType(connectivityManager));
-
- // We don't seem to care about figuring out all connection types. So...
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_VPN, 0, true, true)
- );
- assertEquals(ConnectionSubType.UNKNOWN, NetworkUtils.getConnectionSubType(connectivityManager));
-
- // But anything below we should recognize.
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_ETHERNET, 0, true, true)
- );
- assertEquals(ConnectionSubType.ETHERNET, NetworkUtils.getConnectionSubType(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_WIFI, 0, true, true)
- );
- assertEquals(ConnectionSubType.WIFI, NetworkUtils.getConnectionSubType(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_WIMAX, 0, true, true)
- );
- assertEquals(ConnectionSubType.WIMAX, NetworkUtils.getConnectionSubType(connectivityManager));
-
- // Unknown mobile
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, true, true)
- );
- assertEquals(ConnectionSubType.UNKNOWN, NetworkUtils.getConnectionSubType(connectivityManager));
-
- // 2G mobile types
- int[] cell2gTypes = new int[] {
- TelephonyManager.NETWORK_TYPE_GPRS,
- TelephonyManager.NETWORK_TYPE_EDGE,
- TelephonyManager.NETWORK_TYPE_CDMA,
- TelephonyManager.NETWORK_TYPE_1xRTT,
- TelephonyManager.NETWORK_TYPE_IDEN
- };
- for (int i = 0; i < cell2gTypes.length; i++) {
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_MOBILE, cell2gTypes[i], true, true)
- );
- assertEquals(ConnectionSubType.CELL_2G, NetworkUtils.getConnectionSubType(connectivityManager));
- }
-
- // 3G mobile types
- int[] cell3gTypes = new int[] {
- TelephonyManager.NETWORK_TYPE_UMTS,
- TelephonyManager.NETWORK_TYPE_EVDO_0,
- TelephonyManager.NETWORK_TYPE_EVDO_A,
- TelephonyManager.NETWORK_TYPE_HSDPA,
- TelephonyManager.NETWORK_TYPE_HSUPA,
- TelephonyManager.NETWORK_TYPE_HSPA,
- TelephonyManager.NETWORK_TYPE_EVDO_B,
- TelephonyManager.NETWORK_TYPE_EHRPD,
- TelephonyManager.NETWORK_TYPE_HSPAP
- };
- for (int i = 0; i < cell3gTypes.length; i++) {
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_MOBILE, cell3gTypes[i], true, true)
- );
- assertEquals(ConnectionSubType.CELL_3G, NetworkUtils.getConnectionSubType(connectivityManager));
- }
-
- // 4G mobile type
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE, true, true)
- );
- assertEquals(ConnectionSubType.CELL_4G, NetworkUtils.getConnectionSubType(connectivityManager));
- }
-
- @Test
- public void testGetConnectionType() {
- shadowConnectivityManager.setActiveNetworkInfo(null);
- assertEquals(ConnectionType.NONE, NetworkUtils.getConnectionType(connectivityManager));
- assertEquals(ConnectionType.NONE, NetworkUtils.getConnectionType(null));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_VPN, 0, true, true)
- );
- assertEquals(ConnectionType.OTHER, NetworkUtils.getConnectionType(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_WIFI, 0, true, true)
- );
- assertEquals(ConnectionType.WIFI, NetworkUtils.getConnectionType(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_MOBILE, 0, true, true)
- );
- assertEquals(ConnectionType.CELLULAR, NetworkUtils.getConnectionType(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_ETHERNET, 0, true, true)
- );
- assertEquals(ConnectionType.ETHERNET, NetworkUtils.getConnectionType(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_BLUETOOTH, 0, true, true)
- );
- assertEquals(ConnectionType.BLUETOOTH, NetworkUtils.getConnectionType(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_WIMAX, 0, true, true)
- );
- assertEquals(ConnectionType.CELLULAR, NetworkUtils.getConnectionType(connectivityManager));
- }
-
- @Test
- public void testGetNetworkStatus() {
- assertEquals(NetworkStatus.UNKNOWN, NetworkUtils.getNetworkStatus(null));
-
- shadowConnectivityManager.setActiveNetworkInfo(null);
- assertEquals(NetworkStatus.DOWN, NetworkUtils.getNetworkStatus(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTING, ConnectivityManager.TYPE_MOBILE, 0, true, false)
- );
- assertEquals(NetworkStatus.DOWN, NetworkUtils.getNetworkStatus(connectivityManager));
-
- shadowConnectivityManager.setActiveNetworkInfo(
- ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_MOBILE, 0, true, true)
- );
- assertEquals(NetworkStatus.UP, NetworkUtils.getNetworkStatus(connectivityManager));
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestContextUtils.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestContextUtils.java
deleted file mode 100644
index 56b69b684..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestContextUtils.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.util;
-
-import android.content.Context;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import static org.junit.Assert.*;
-
-/**
- * Unit test methods of the ContextUtils class.
- */
-@RunWith(TestRunner.class)
-public class TestContextUtils {
-
- private Context context;
-
- @Before
- public void setUp() {
- context = RuntimeEnvironment.application;
- }
-
- @Test
- public void testGetPackageInstallTimeReturnsReasonableValue() throws Exception {
- // At the time of writing, Robolectric's value is 0, which is reasonable.
- final long installTime = ContextUtils.getCurrentPackageInfo(context).firstInstallTime;
- assertTrue("Package install time is positive", installTime >= 0);
- assertTrue("Package install time is less than current time", installTime < System.currentTimeMillis());
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestDateUtil.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestDateUtil.java
deleted file mode 100644
index a93c81ef0..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestDateUtil.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.util;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for date utilities.
- */
-@RunWith(TestRunner.class)
-public class TestDateUtil {
- @Test
- public void testGetDateInHTTPFormatGMT() {
- final TimeZone gmt = TimeZone.getTimeZone("GMT");
- final GregorianCalendar calendar = new GregorianCalendar(gmt, Locale.US);
- calendar.set(2011, Calendar.FEBRUARY, 1, 14, 0, 0);
- final String expectedDate = "Tue, 01 Feb 2011 14:00:00 GMT";
-
- final String actualDate = DateUtil.getDateInHTTPFormat(calendar.getTime());
- assertEquals("Returned date is expected", expectedDate, actualDate);
- }
-
- @Test
- public void testGetDateInHTTPFormatNonGMT() {
- final TimeZone kst = TimeZone.getTimeZone("Asia/Seoul"); // no daylight savings time.
- final GregorianCalendar calendar = new GregorianCalendar(kst, Locale.US);
- calendar.set(2011, Calendar.FEBRUARY, 1, 14, 0, 0);
- final String expectedDate = "Tue, 01 Feb 2011 05:00:00 GMT";
-
- final String actualDate = DateUtil.getDateInHTTPFormat(calendar.getTime());
- assertEquals("Returned date is expected", expectedDate, actualDate);
- }
-
- @Test
- public void testGetTimezoneOffsetInMinutes() {
- assertEquals("GMT has no offset", 0, DateUtil.getTimezoneOffsetInMinutes(TimeZone.getTimeZone("GMT")));
-
- // We use custom timezones because they don't have daylight savings time.
- assertEquals("Offset for GMT-8 is correct",
- -480, DateUtil.getTimezoneOffsetInMinutes(TimeZone.getTimeZone("GMT-8")));
- assertEquals("Offset for GMT+12:45 is correct",
- 765, DateUtil.getTimezoneOffsetInMinutes(TimeZone.getTimeZone("GMT+12:45")));
-
- // We use a non-custom timezone without DST.
- assertEquals("Offset for KST is correct",
- 540, DateUtil.getTimezoneOffsetInMinutes(TimeZone.getTimeZone("Asia/Seoul")));
- }
-
- @Test
- public void testGetTimezoneOffsetInMinutesForGivenDateNoDaylightSavingsTime() {
- final TimeZone kst = TimeZone.getTimeZone("Asia/Seoul");
- final Calendar[] calendars =
- new Calendar[] { getCalendarForMonth(Calendar.DECEMBER), getCalendarForMonth(Calendar.AUGUST) };
- for (final Calendar cal : calendars) {
- cal.setTimeZone(kst);
- assertEquals("Offset for KST does not change with daylight savings time",
- 540, DateUtil.getTimezoneOffsetInMinutesForGivenDate(cal));
- }
- }
-
- @Test
- public void testGetTimezoneOffsetInMinutesForGivenDateDaylightSavingsTime() {
- final TimeZone pacificTimeZone = TimeZone.getTimeZone("America/Los_Angeles");
- final Calendar pstCalendar = getCalendarForMonth(Calendar.DECEMBER);
- final Calendar pdtCalendar = getCalendarForMonth(Calendar.AUGUST);
- pstCalendar.setTimeZone(pacificTimeZone);
- pdtCalendar.setTimeZone(pacificTimeZone);
- assertEquals("Offset for PST is correct", -480, DateUtil.getTimezoneOffsetInMinutesForGivenDate(pstCalendar));
- assertEquals("Offset for PDT is correct", -420, DateUtil.getTimezoneOffsetInMinutesForGivenDate(pdtCalendar));
-
- }
-
- private Calendar getCalendarForMonth(final int month) {
- return new GregorianCalendar(2000, month, 1);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestFileUtils.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestFileUtils.java
deleted file mode 100644
index 88fa7307d..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestFileUtils.java
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.util;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.util.FileUtils.FileLastModifiedComparator;
-import org.mozilla.gecko.util.FileUtils.FilenameRegexFilter;
-import org.mozilla.gecko.util.FileUtils.FilenameWhitelistFilter;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import static junit.framework.Assert.*;
-import static org.mockito.Mockito.*;
-
-/**
- * Tests the utilities in {@link FileUtils}.
- */
-@RunWith(TestRunner.class)
-public class TestFileUtils {
-
- private static final Charset CHARSET = Charset.forName("UTF-8");
-
- @Rule
- public TemporaryFolder tempDir = new TemporaryFolder();
- public File testFile;
- public File nonExistentFile;
-
- @Before
- public void setUp() throws Exception {
- testFile = tempDir.newFile();
- nonExistentFile = new File(tempDir.getRoot(), "non-existent-file");
- }
-
- @Test
- public void testReadJSONObjectFromFile() throws Exception {
- final JSONObject expected = new JSONObject("{\"str\": \"some str\"}");
- writeStringToFile(testFile, expected.toString());
-
- final JSONObject actual = FileUtils.readJSONObjectFromFile(testFile);
- assertEquals("JSON contains expected str", expected.getString("str"), actual.getString("str"));
- }
-
- @Test(expected=IOException.class)
- public void testReadJSONObjectFromFileEmptyFile() throws Exception {
- assertEquals("Test file is empty", 0, testFile.length());
- FileUtils.readJSONObjectFromFile(testFile); // expected to throw
- }
-
- @Test(expected=JSONException.class)
- public void testReadJSONObjectFromFileInvalidJSON() throws Exception {
- writeStringToFile(testFile, "not a json str");
- FileUtils.readJSONObjectFromFile(testFile); // expected to throw
- }
-
- @Test
- public void testReadStringFromFileReadsData() throws Exception {
- final String expected = "String to write contains hard characters: !\n \\s..\"'\u00f1";
- writeStringToFile(testFile, expected);
-
- final String actual = FileUtils.readStringFromFile(testFile);
- assertEquals("Read content matches written content", expected, actual);
- }
-
- @Test
- public void testReadStringFromFileEmptyFile() throws Exception {
- assertEquals("Test file is empty", 0, testFile.length());
-
- final String actual = FileUtils.readStringFromFile(testFile);
- assertEquals("Read content is empty", "", actual);
- }
-
- @Test(expected=FileNotFoundException.class)
- public void testReadStringFromNonExistentFile() throws Exception {
- assertFalse("File does not exist", nonExistentFile.exists());
- FileUtils.readStringFromFile(nonExistentFile);
- }
-
- @Test
- public void testReadStringFromInputStreamAndCloseStreamBufferLenIsFileLen() throws Exception {
- final String expected = "String to write contains hard characters: !\n \\s..\"'\u00f1";
- writeStringToFile(testFile, expected);
-
- final FileInputStream stream = new FileInputStream(testFile);
- final String actual = FileUtils.readStringFromInputStreamAndCloseStream(stream, expected.length());
- assertEquals("Read content matches written content", expected, actual);
- }
-
- @Test
- public void testReadStringFromInputStreamAndCloseStreamBufferLenIsBiggerThanFile() throws Exception {
- final String expected = "aoeuhtns";
- writeStringToFile(testFile, expected);
-
- final FileInputStream stream = new FileInputStream(testFile);
- final String actual = FileUtils.readStringFromInputStreamAndCloseStream(stream, expected.length() + 1024);
- assertEquals("Read content matches written content", expected, actual);
- }
-
- @Test
- public void testReadStringFromInputStreamAndCloseStreamBufferLenIsSmallerThanFile() throws Exception {
- final String expected = "aoeuhtns aoeusth aoeusth aoeusnth aoeusth aoeusnth aoesuth";
- writeStringToFile(testFile, expected);
-
- final FileInputStream stream = new FileInputStream(testFile);
- final String actual = FileUtils.readStringFromInputStreamAndCloseStream(stream, 8);
- assertEquals("Read content matches written content", expected, actual);
- }
-
- @Test(expected=IllegalArgumentException.class)
- public void testReadStringFromInputStreamAndCloseStreamBufferLenIsZero() throws Exception {
- final String expected = "aoeuhtns aoeusth aoeusth aoeusnth aoeusth aoeusnth aoesuth";
- writeStringToFile(testFile, expected);
-
- final FileInputStream stream = new FileInputStream(testFile);
- FileUtils.readStringFromInputStreamAndCloseStream(stream, 0); // expected to throw.
- }
-
- @Test
- public void testReadStringFromInputStreamAndCloseStreamIsEmptyStream() throws Exception {
- assertTrue("Test file exists", testFile.exists());
- assertEquals("Test file is empty", 0, testFile.length());
-
- final FileInputStream stream = new FileInputStream(testFile);
- final String actual = FileUtils.readStringFromInputStreamAndCloseStream(stream, 8);
- assertEquals("Read content from stream is empty", "", actual);
- }
-
- @Test(expected=IOException.class)
- public void testReadStringFromInputStreamAndCloseStreamClosesStream() throws Exception {
- final String expected = "String to write contains hard characters: !\n \\s..\"'\u00f1";
- writeStringToFile(testFile, expected);
-
- final FileInputStream stream = new FileInputStream(testFile);
- try {
- stream.read(); // should not throw because stream is open.
- FileUtils.readStringFromInputStreamAndCloseStream(stream, expected.length());
- } catch (final IOException e) {
- fail("Did not expect method to throw when writing file: " + e);
- }
-
- stream.read(); // expected to throw because stream is closed.
- }
-
- @Test
- public void testWriteStringToOutputStreamAndCloseStreamWritesData() throws Exception {
- final String expected = "A string with some data in it! \u00f1 \n";
- final FileOutputStream fos = new FileOutputStream(testFile, false);
- FileUtils.writeStringToOutputStreamAndCloseStream(fos, expected);
-
- assertTrue("Written file exists", testFile.exists());
- assertEquals("Read data equals written data", expected, readStringFromFile(testFile, expected.length()));
- }
-
- @Test(expected=IOException.class)
- public void testWriteStringToOutputStreamAndCloseStreamClosesStream() throws Exception {
- final FileOutputStream fos = new FileOutputStream(testFile, false);
- try {
- fos.write('c'); // should not throw because stream is open.
- FileUtils.writeStringToOutputStreamAndCloseStream(fos, "some string with data");
- } catch (final IOException e) {
- fail("Did not expect method to throw when writing file: " + e);
- }
-
- fos.write('c'); // expected to throw because stream is closed.
- }
-
- /**
- * The Writer we wrap our stream in can throw in .close(), preventing the underlying stream from closing.
- * I added code to prevent ensure we close if the writer .close() throws.
- *
- * I wrote this test to test that code, however, we'd have to mock the writer [1] and that isn't straight-forward.
- * I left this test around because it's a good test of other code.
- *
- * [1]: We thought we could mock FileOutputStream.flush but it's only flushed if the Writer thinks it should be
- * flushed. We can write directly to the Stream, but that doesn't change the Writer state and doesn't affect whether
- * it thinks it should be flushed.
- */
- @Test(expected=IOException.class)
- public void testWriteStringToOutputStreamAndCloseStreamClosesStreamIfWriterThrows() throws Exception {
- final FileOutputStream fos = mock(FileOutputStream.class);
- doThrow(IOException.class).when(fos).write(any(byte[].class), anyInt(), anyInt());
- doThrow(IOException.class).when(fos).write(anyInt());
- doThrow(IOException.class).when(fos).write(any(byte[].class));
-
- boolean exceptionCaught = false;
- try {
- FileUtils.writeStringToOutputStreamAndCloseStream(fos, "some string with data");
- } catch (final IOException e) {
- exceptionCaught = true;
- }
- assertTrue("Exception caught during tested method", exceptionCaught); // not strictly necessary but documents assumptions
-
- fos.write('c'); // expected to throw because stream is closed.
- }
-
- @Test
- public void testWriteStringToFile() throws Exception {
- final String expected = "String to write contains hard characters: !\n \\s..\"'\u00f1";
- FileUtils.writeStringToFile(testFile, expected);
-
- assertTrue("Written file exists", testFile.exists());
- assertEquals("Read data equals written data", expected, readStringFromFile(testFile, expected.length()));
- }
-
- @Test
- public void testWriteStringToFileEmptyString() throws Exception {
- final String expected = "";
- FileUtils.writeStringToFile(testFile, expected);
-
- assertTrue("Written file exists", testFile.exists());
- assertEquals("Written file is empty", 0, testFile.length());
- assertEquals("Read data equals written (empty) data", expected, readStringFromFile(testFile, expected.length()));
- }
-
- @Test
- public void testWriteStringToFileCreatesNewFile() throws Exception {
- final String expected = "some str to write";
- assertFalse("Non existent file does not exist", nonExistentFile.exists());
- FileUtils.writeStringToFile(nonExistentFile, expected); // expected to create file
-
- assertTrue("Written file was created", nonExistentFile.exists());
- assertEquals("Read data equals written data", expected, readStringFromFile(nonExistentFile, (int) nonExistentFile.length()));
- }
-
- @Test
- public void testWriteStringToFileOverwritesFile() throws Exception {
- writeStringToFile(testFile, "data");
-
- final String expected = "some str to write";
- FileUtils.writeStringToFile(testFile, expected);
-
- assertTrue("Written file was created", testFile.exists());
- assertEquals("Read data equals written data", expected, readStringFromFile(testFile, (int) testFile.length()));
- }
-
- @Test
- public void testWriteJSONObjectToFile() throws Exception {
- final JSONObject expected = new JSONObject()
- .put("int", 1)
- .put("str", "1")
- .put("bool", true)
- .put("null", JSONObject.NULL)
- .put("raw null", null);
- FileUtils.writeJSONObjectToFile(testFile, expected);
-
- assertTrue("Written file exists", testFile.exists());
-
- // JSONObject.equals compares references so we have to assert each key individually. >:(
- final JSONObject actual = new JSONObject(readStringFromFile(testFile, (int) testFile.length()));
- assertEquals(1, actual.getInt("int"));
- assertEquals("1", actual.getString("str"));
- assertEquals(true, actual.getBoolean("bool"));
- assertEquals(JSONObject.NULL, actual.get("null"));
- assertFalse(actual.has("raw null"));
- }
-
- // Since the read methods may not be tested yet.
- private static String readStringFromFile(final File file, final int bufferLen) throws IOException {
- final char[] buffer = new char[bufferLen];
- try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"))) {
- reader.read(buffer, 0, buffer.length);
- }
- return new String(buffer);
- }
-
- // Since the write methods may not be tested yet.
- private static void writeStringToFile(final File file, final String str) throws IOException {
- try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file, false), CHARSET)) {
- writer.write(str);
- }
- assertTrue("Written file from helper method exists", file.exists());
- }
-
- @Test
- public void testFilenameWhitelistFilter() {
- final String[] expectedToAccept = new String[] { "one", "two", "three" };
- final Set<String> whitelist = new HashSet<>(Arrays.asList(expectedToAccept));
- final FilenameWhitelistFilter testFilter = new FilenameWhitelistFilter(whitelist);
- for (final String str : expectedToAccept) {
- assertTrue("Filename, " + str + ", in whitelist is accepted", testFilter.accept(testFile, str));
- }
-
- final String[] notExpectedToAccept = new String[] { "not-in-whitelist", "meh", "whatever" };
- for (final String str : notExpectedToAccept) {
- assertFalse("Filename, " + str + ", not in whitelist is not accepted", testFilter.accept(testFile, str));
- }
- }
-
- @Test
- public void testFilenameRegexFilter() {
- final Pattern pattern = Pattern.compile("[a-z]{1,6}");
- final FilenameRegexFilter testFilter = new FilenameRegexFilter(pattern);
- final String[] expectedToAccept = new String[] { "duckie", "goes", "quack" };
- for (final String str : expectedToAccept) {
- assertTrue("Filename, " + str + ", matching regex expected to accept", testFilter.accept(testFile, str));
- }
-
- final String[] notExpectedToAccept = new String[] { "DUCKIE", "1337", "2fast" };
- for (final String str : notExpectedToAccept) {
- assertFalse("Filename, " + str + ", not matching regex not expected to accept", testFilter.accept(testFile, str));
- }
- }
-
- @Test
- public void testFileLastModifiedComparator() {
- final FileLastModifiedComparator testComparator = new FileLastModifiedComparator();
- final File oldFile = mock(File.class);
- final File newFile = mock(File.class);
- final File equallyNewFile = mock(File.class);
- when(oldFile.lastModified()).thenReturn(10L);
- when(newFile.lastModified()).thenReturn(100L);
- when(equallyNewFile.lastModified()).thenReturn(100L);
-
- assertTrue("Old file is less than new file", testComparator.compare(oldFile, newFile) < 0);
- assertTrue("New file is greater than old file", testComparator.compare(newFile, oldFile) > 0);
- assertTrue("New files are equal", testComparator.compare(newFile, equallyNewFile) == 0);
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestIntentUtils.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestIntentUtils.java
deleted file mode 100644
index 186821451..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestIntentUtils.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.util;
-
-import android.content.Intent;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.mozglue.SafeIntent;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.*;
-
-/**
- * Tests for the Intent utilities.
- */
-@RunWith(TestRunner.class)
-public class TestIntentUtils {
-
- private static final Map<String, String> TEST_ENV_VAR_MAP;
- static {
- final HashMap<String, String> tempMap = new HashMap<>();
- tempMap.put("ZERO", "0");
- tempMap.put("ONE", "1");
- tempMap.put("STRING", "TEXT");
- tempMap.put("L_WHITESPACE", " LEFT");
- tempMap.put("R_WHITESPACE", "RIGHT ");
- tempMap.put("ALL_WHITESPACE", " ALL ");
- tempMap.put("WHITESPACE_IN_VALUE", "IN THE MIDDLE");
- tempMap.put("WHITESPACE IN KEY", "IS_PROBABLY_NOT_VALID_ANYWAY");
- tempMap.put("BLANK_VAL", "");
- TEST_ENV_VAR_MAP = Collections.unmodifiableMap(tempMap);
- }
-
- private Intent testIntent;
-
- @Before
- public void setUp() throws Exception {
- testIntent = getIntentWithTestData();
- }
-
- private static Intent getIntentWithTestData() {
- final Intent out = new Intent(Intent.ACTION_VIEW);
- int i = 0;
- for (final String key : TEST_ENV_VAR_MAP.keySet()) {
- final String value = key + "=" + TEST_ENV_VAR_MAP.get(key);
- out.putExtra("env" + i, value);
- i += 1;
- }
- return out;
- }
-
- @Test
- public void testGetEnvVarMap() throws Exception {
- final HashMap<String, String> actual = IntentUtils.getEnvVarMap(new SafeIntent(testIntent));
- for (final String actualEnvVarName : actual.keySet()) {
- assertTrue("Actual key exists in test data: " + actualEnvVarName,
- TEST_ENV_VAR_MAP.containsKey(actualEnvVarName));
-
- final String expectedValue = TEST_ENV_VAR_MAP.get(actualEnvVarName);
- final String actualValue = actual.get(actualEnvVarName);
- assertEquals("Actual env var value matches test data", expectedValue, actualValue);
- }
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestStringUtils.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestStringUtils.java
deleted file mode 100644
index ee0a705c7..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestStringUtils.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.util;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestStringUtils {
- @Test
- public void testIsHttpOrHttps() {
- // No value
- assertFalse(StringUtils.isHttpOrHttps(null));
- assertFalse(StringUtils.isHttpOrHttps(""));
-
- // Garbage
- assertFalse(StringUtils.isHttpOrHttps("lksdjflasuf"));
-
- // URLs with http/https
- assertTrue(StringUtils.isHttpOrHttps("https://www.google.com"));
- assertTrue(StringUtils.isHttpOrHttps("http://www.facebook.com"));
- assertTrue(StringUtils.isHttpOrHttps("https://mozilla.org/en-US/firefox/products/"));
-
- // IP addresses
- assertTrue(StringUtils.isHttpOrHttps("https://192.168.0.1"));
- assertTrue(StringUtils.isHttpOrHttps("http://63.245.215.20/en-US/firefox/products"));
-
- // Other protocols
- assertFalse(StringUtils.isHttpOrHttps("ftp://people.mozilla.org"));
- assertFalse(StringUtils.isHttpOrHttps("javascript:window.google.com"));
- assertFalse(StringUtils.isHttpOrHttps("tel://1234567890"));
-
- // No scheme
- assertFalse(StringUtils.isHttpOrHttps("google.com"));
- assertFalse(StringUtils.isHttpOrHttps("git@github.com:mozilla/gecko-dev.git"));
- }
-
- @Test
- public void testStripRef() {
- assertEquals(StringUtils.stripRef(null), null);
- assertEquals(StringUtils.stripRef(""), "");
-
- assertEquals(StringUtils.stripRef("??AAABBBCCC"), "??AAABBBCCC");
- assertEquals(StringUtils.stripRef("https://mozilla.org"), "https://mozilla.org");
- assertEquals(StringUtils.stripRef("https://mozilla.org#BBBB"), "https://mozilla.org");
- assertEquals(StringUtils.stripRef("https://mozilla.org/#BBBB"), "https://mozilla.org/");
- }
-
- @Test
- public void testStripScheme() {
- assertEquals("mozilla.org", StringUtils.stripScheme("http://mozilla.org"));
- assertEquals("mozilla.org", StringUtils.stripScheme("http://mozilla.org/"));
- assertEquals("https://mozilla.org", StringUtils.stripScheme("https://mozilla.org"));
- assertEquals("https://mozilla.org", StringUtils.stripScheme("https://mozilla.org/"));
- assertEquals("mozilla.org", StringUtils.stripScheme("https://mozilla.org/", StringUtils.UrlFlags.STRIP_HTTPS));
- assertEquals("mozilla.org", StringUtils.stripScheme("https://mozilla.org", StringUtils.UrlFlags.STRIP_HTTPS));
- assertEquals("", StringUtils.stripScheme("http://"));
- assertEquals("", StringUtils.stripScheme("https://", StringUtils.UrlFlags.STRIP_HTTPS));
- // This edge case is not handled properly yet
-// assertEquals(StringUtils.stripScheme("https://"), "");
- assertEquals(null, StringUtils.stripScheme(null));
- }
-
- @Test
- public void testIsRTL() {
- assertFalse(StringUtils.isRTL("mozilla.org"));
- assertFalse(StringUtils.isRTL("something.عربي"));
-
- assertTrue(StringUtils.isRTL("عربي"));
- assertTrue(StringUtils.isRTL("عربي.org"));
-
- // Text with LTR mark
- assertFalse(StringUtils.isRTL("\u200EHello"));
- assertFalse(StringUtils.isRTL("\u200Eعربي"));
- }
-
- @Test
- public void testForceLTR() {
- assertFalse(StringUtils.isRTL(StringUtils.forceLTR("عربي")));
- assertFalse(StringUtils.isRTL(StringUtils.forceLTR("عربي.org")));
-
- // Strings that are already LTR are not modified
- final String someLtrString = "HelloWorld";
- assertEquals(someLtrString, StringUtils.forceLTR(someLtrString));
-
- // We add the LTR mark only once
- final String someRtlString = "عربي";
- assertEquals(4, someRtlString.length());
- final String forcedLtrString = StringUtils.forceLTR(someRtlString);
- assertEquals(5, forcedLtrString.length());
- final String forcedAgainLtrString = StringUtils.forceLTR(forcedLtrString);
- assertEquals(5, forcedAgainLtrString.length());
- }
-
- @Test
- public void testJoin() {
- assertEquals("", StringUtils.join("", Collections.<String>emptyList()));
- assertEquals("", StringUtils.join("-", Collections.<String>emptyList()));
- assertEquals("", StringUtils.join("", Collections.singletonList("")));
- assertEquals("", StringUtils.join(".", Collections.singletonList("")));
-
- assertEquals("192.168.0.1", StringUtils.join(".", Arrays.asList("192", "168", "0", "1")));
- assertEquals("www.mozilla.org", StringUtils.join(".", Arrays.asList("www", "mozilla", "org")));
-
- assertEquals("hello", StringUtils.join("", Collections.singletonList("hello")));
- assertEquals("helloworld", StringUtils.join("", Arrays.asList("hello", "world")));
- assertEquals("hello world", StringUtils.join(" ", Arrays.asList("hello", "world")));
-
- assertEquals("m::o::z::i::l::l::a", StringUtils.join("::", Arrays.asList("m", "o", "z", "i", "l", "l", "a")));
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestUUIDUtil.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestUUIDUtil.java
deleted file mode 100644
index 732dd21b9..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestUUIDUtil.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package org.mozilla.gecko.util;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import static org.junit.Assert.*;
-
-/**
- * Tests for uuid utils.
- */
-@RunWith(TestRunner.class)
-public class TestUUIDUtil {
- private static final String[] validUUIDs = {
- "904cd9f8-af63-4525-8ce0-b9127e5364fa",
- "8d584bd2-00ea-4043-a617-ed4ce7018ed0",
- "3abad327-2669-4f68-b9ef-7ace8c5314d6",
- };
-
- private static final String[] invalidUUIDs = {
- "its-not-a-uuid-mate",
- "904cd9f8-af63-4525-8ce0-b9127e5364falol",
- "904cd9f8-af63-4525-8ce0-b9127e5364f",
- };
-
- @Test
- public void testUUIDRegex() {
- for (final String uuid : validUUIDs) {
- assertTrue("Valid UUID matches UUID-regex", uuid.matches(UUIDUtil.UUID_REGEX));
- }
- for (final String uuid : invalidUUIDs) {
- assertFalse("Invalid UUID does not match UUID-regex", uuid.matches(UUIDUtil.UUID_REGEX));
- }
- }
-
- @Test
- public void testUUIDPattern() {
- for (final String uuid : validUUIDs) {
- assertTrue("Valid UUID matches UUID-regex", UUIDUtil.UUID_PATTERN.matcher(uuid).matches());
- }
- for (final String uuid : invalidUUIDs) {
- assertFalse("Invalid UUID does not match UUID-regex", UUIDUtil.UUID_PATTERN.matcher(uuid).matches());
- }
- }
-}
diff --git a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/publicsuffix/TestPublicSuffix.java b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/publicsuffix/TestPublicSuffix.java
deleted file mode 100644
index e47d361c0..000000000
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/publicsuffix/TestPublicSuffix.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.mozilla.gecko.util.publicsuffix;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(TestRunner.class)
-public class TestPublicSuffix {
- @Test
- public void testStripPublicSuffix() {
- // Test empty value
- Assert.assertEquals("",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, ""));
-
- // Test domains with public suffix
- Assert.assertEquals("www.mozilla",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "www.mozilla.org"));
- Assert.assertEquals("www.google",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "www.google.com"));
- Assert.assertEquals("foobar",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "foobar.blogspot.com"));
- Assert.assertEquals("independent",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "independent.co.uk"));
- Assert.assertEquals("biz",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "biz.com.ua"));
- Assert.assertEquals("example",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "example.org"));
- Assert.assertEquals("example",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "example.pvt.k12.ma.us"));
-
- // Test domain without public suffix
- Assert.assertEquals("localhost",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "localhost"));
- Assert.assertEquals("firefox.mozilla",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "firefox.mozilla"));
-
- // IDN domains
- Assert.assertEquals("ουτοπία.δπθ",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "ουτοπία.δπθ.gr"));
- Assert.assertEquals("a网络A",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "a网络A.网络.Cn"));
-
- // Other non-domain values
- Assert.assertEquals("192.168.0.1",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "192.168.0.1"));
- Assert.assertEquals("asdflkj9uahsd",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "asdflkj9uahsd"));
-
- // Other trailing and other types of dots
- Assert.assertEquals("www.mozilla。home.example",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "www.mozilla。home.example。org"));
- Assert.assertEquals("example",
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, "example.org"));
- }
-
- @Test(expected = NullPointerException.class)
- public void testStripPublicSuffixThrowsException() {
- PublicSuffix.stripPublicSuffix(RuntimeEnvironment.application, null);
- }
-}
diff --git a/mobile/android/tests/background/moz.build b/mobile/android/tests/background/moz.build
deleted file mode 100644
index 891477f32..000000000
--- a/mobile/android/tests/background/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-TEST_DIRS += [
- 'junit3',
-]
diff --git a/mobile/android/tests/browser/chrome/basic_article.html b/mobile/android/tests/browser/chrome/basic_article.html
deleted file mode 100644
index f34cbece4..000000000
--- a/mobile/android/tests/browser/chrome/basic_article.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Article title</title>
-<meta name="description" content="This is the article description." />
-</head>
-<body>
-<header>Site header</header>
-<div>
-<h1>Article title</h1>
-<h2 class="author">by Jane Doe</h2>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p>
-<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
-</div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/basic_article_mobile.html b/mobile/android/tests/browser/chrome/basic_article_mobile.html
deleted file mode 100644
index d89ff248d..000000000
--- a/mobile/android/tests/browser/chrome/basic_article_mobile.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Article title</title>
-<meta name="description" content="This is the article description." />
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-</head>
-<body>
-<header>Site header</header>
-<div>
-<h1>Article title</h1>
-<h2 class="author">by Jane Doe</h2>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p>
-<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p>
-<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
-</div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/chrome.ini b/mobile/android/tests/browser/chrome/chrome.ini
deleted file mode 100644
index f190d6199..000000000
--- a/mobile/android/tests/browser/chrome/chrome.ini
+++ /dev/null
@@ -1,49 +0,0 @@
-[DEFAULT]
-skip-if = os != 'android'
-support-files =
- basic_article.html
- basic_article_mobile.html
- desktopmode_user_agent.sjs
- devicesearch.xml
- head.js
- head_search.js
- session_formdata_sample.html
- simpleservice.xml
- video_controls.html
- video_discovery.html
- video_discovery.sjs
- web_channel.html
- tp5/**
-
-[test_about_logins.html]
-[test_accounts.html]
-[test_android_log.html]
-[test_app_constants.html]
-[test_awsy_lite.html]
-# historically, we only run awsy on opt; gc times out on debug
-skip-if = debug
-[test_debugger_server.html]
-[test_desktop_useragent.html]
-[test_device_search_engine.html]
-[test_get_last_visited.html]
-[test_home_provider.html]
-[test_hidden_select_option.html]
-[test_identity_mode.html]
-[test_java_addons.html]
-[test_jni.html]
-[test_migrate_ui.html]
-[test_network_manager.html]
-[test_offline_page.html]
-skip-if = true # Bug 1241478
-[test_reader_view.html]
-[test_resource_substitutions.html]
-[test_restricted_profiles.html]
-[test_select_disabled.html]
-[test_selectoraddtab.html]
-[test_session_form_data.html]
-[test_session_scroll_position.html]
-[test_session_zombification.html]
-[test_shared_preferences.html]
-[test_simple_discovery.html]
-[test_video_discovery.html]
-[test_web_channel.html]
diff --git a/mobile/android/tests/browser/chrome/desktopmode_user_agent.sjs b/mobile/android/tests/browser/chrome/desktopmode_user_agent.sjs
deleted file mode 100644
index 88cfb8f7e..000000000
--- a/mobile/android/tests/browser/chrome/desktopmode_user_agent.sjs
+++ /dev/null
@@ -1,11 +0,0 @@
-function handleRequest(request, response)
-{
- // avoid confusing cache behaviors
- response.setHeader("Cache-Control", "no-cache", false);
- response.setHeader("Content-Type", "text/plain", false);
- response.setHeader("Access-Control-Allow-Origin", "*", false);
-
- // used by mobile/desktop user agent tests
- response.write(request.getHeader("User-Agent"));
-}
-
diff --git a/mobile/android/tests/browser/chrome/devicesearch.xml b/mobile/android/tests/browser/chrome/devicesearch.xml
deleted file mode 100644
index 5b472acf5..000000000
--- a/mobile/android/tests/browser/chrome/devicesearch.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
-<ShortName>Test search engine</ShortName>
-<Description>A test search engine (based on Google search)</Description>
-<InputEncoding>UTF-8</InputEncoding>
-<Image width="16" height="16">data:image/png;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image>
-<Url type="text/html" method="GET" template="http://example.com/search">
- <Param name="q" value="{searchTerms}"/>
-</Url>
-<Url type="application/x-moz-tabletsearch" method="GET" template="http://example.com/search/tablet">
- <Param name="q" value="{searchTerms}"/>
-</Url>
-<Url type="application/x-moz-phonesearch" method="GET" template="http://example.com/search/phone">
- <Param name="q" value="{searchTerms}"/>
-</Url>
-<SearchForm>http://example.com/</SearchForm>
-</SearchPlugin>
diff --git a/mobile/android/tests/browser/chrome/head.js b/mobile/android/tests/browser/chrome/head.js
deleted file mode 100644
index 0ac8ed010..000000000
--- a/mobile/android/tests/browser/chrome/head.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-function fuzzyEquals(a, b) {
- return (Math.abs(a - b) < 1e-6);
-}
-
-function promiseBrowserEvent(browser, eventType) {
- return new Promise((resolve) => {
- function handle(event) {
- // Since we'll be redirecting, don't make assumptions about the given URL and the loaded URL
- if (event.target != browser.contentDocument || event.target.location.href == "about:blank") {
- info("Skipping spurious '" + eventType + "' event" + " for " + event.target.location.href);
- return;
- }
- info("Received event " + eventType + " from browser");
- browser.removeEventListener(eventType, handle, true);
- resolve(event);
- }
-
- browser.addEventListener(eventType, handle, true);
- info("Now waiting for " + eventType + " event from browser");
- });
-}
-
-function promiseTabEvent(container, eventType) {
- return new Promise((resolve) => {
- function handle(event) {
- info("Received event " + eventType + " from container");
- container.removeEventListener(eventType, handle, true);
- resolve(event);
- }
-
- container.addEventListener(eventType, handle, true);
- info("Now waiting for " + eventType + " event from container");
- });
-}
-
-function promiseNotification(topic) {
- Cu.import("resource://gre/modules/Services.jsm");
-
- return new Promise((resolve, reject) => {
- function observe(subject, topic, data) {
- info("Received " + topic + " notification from Gecko");
- Services.obs.removeObserver(observe, topic);
- resolve();
- }
- Services.obs.addObserver(observe, topic, false);
- info("Now waiting for " + topic + " notification from Gecko");
- });
-}
-
-function promiseLinkVisit(url) {
- Cu.import("resource://gre/modules/Services.jsm");
-
- var topic = "link-visited";
- return new Promise((resolve, reject) => {
- function observe(subject, topic, data) {
- info("Received " + topic + " notification from Gecko");
- var uri = subject.QueryInterface(Ci.nsIURI);
- if (uri.spec != url) {
- info("Visited URL " + uri.spec + " is not desired URL " + url + "; ignoring.");
- return;
- }
- info("Visited URL " + uri.spec + " is desired URL " + url);
- Services.obs.removeObserver(observe, topic);
- resolve();
- };
- Services.obs.addObserver(observe, topic, false);
- info("Now waiting for " + topic + " notification from Gecko with URL " + url);
- });
-}
diff --git a/mobile/android/tests/browser/chrome/head_search.js b/mobile/android/tests/browser/chrome/head_search.js
deleted file mode 100644
index b6fb94449..000000000
--- a/mobile/android/tests/browser/chrome/head_search.js
+++ /dev/null
@@ -1,46 +0,0 @@
-// Bits and pieces copied from toolkit/components/search/tests/xpcshell/head_search.js
-
-var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-
-/**
- * Adds test engines and returns a promise resolved when they are installed.
- *
- * The engines are added in the given order.
- *
- * @param aItems
- * Array of objects with the following properties:
- * {
- * name: Engine name, used to wait for it to be loaded.
- * details: Array containing the parameters of addEngineWithDetails,
- * except for the engine name. Alternative to xmlFileName.
- * }
- */
-var addTestEngines = Task.async(function* (aItems) {
- let engines = [];
-
- for (let item of aItems) {
- yield new Promise((resolve, reject) => {
- Services.obs.addObserver(function obs(subject, topic, data) {
- try {
- let engine = subject.QueryInterface(Ci.nsISearchEngine);
- if (data != "engine-added" || engine.name != item.name) {
- return;
- }
-
- Services.obs.removeObserver(obs, "browser-search-engine-modified");
- engines.push(engine);
- resolve();
- } catch (ex) {
- reject(ex);
- }
- }, "browser-search-engine-modified", false);
-
- Services.search.addEngineWithDetails(item.name, ...item.details);
- });
- }
-
- return engines;
-});
diff --git a/mobile/android/tests/browser/chrome/memory_page_1.html b/mobile/android/tests/browser/chrome/memory_page_1.html
deleted file mode 100644
index f34cbece4..000000000
--- a/mobile/android/tests/browser/chrome/memory_page_1.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Article title</title>
-<meta name="description" content="This is the article description." />
-</head>
-<body>
-<header>Site header</header>
-<div>
-<h1>Article title</h1>
-<h2 class="author">by Jane Doe</h2>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p>
-<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
-</div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/memory_page_2.html b/mobile/android/tests/browser/chrome/memory_page_2.html
deleted file mode 100644
index f34cbece4..000000000
--- a/mobile/android/tests/browser/chrome/memory_page_2.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Article title</title>
-<meta name="description" content="This is the article description." />
-</head>
-<body>
-<header>Site header</header>
-<div>
-<h1>Article title</h1>
-<h2 class="author">by Jane Doe</h2>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p>
-<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
-</div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/memory_page_3.html b/mobile/android/tests/browser/chrome/memory_page_3.html
deleted file mode 100644
index f34cbece4..000000000
--- a/mobile/android/tests/browser/chrome/memory_page_3.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Article title</title>
-<meta name="description" content="This is the article description." />
-</head>
-<body>
-<header>Site header</header>
-<div>
-<h1>Article title</h1>
-<h2 class="author">by Jane Doe</h2>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p>
-<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
-</div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/memory_page_4.html b/mobile/android/tests/browser/chrome/memory_page_4.html
deleted file mode 100644
index f34cbece4..000000000
--- a/mobile/android/tests/browser/chrome/memory_page_4.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Article title</title>
-<meta name="description" content="This is the article description." />
-</head>
-<body>
-<header>Site header</header>
-<div>
-<h1>Article title</h1>
-<h2 class="author">by Jane Doe</h2>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p>
-<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
-</div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/session_formdata_sample.html b/mobile/android/tests/browser/chrome/session_formdata_sample.html
deleted file mode 100644
index f88e8668f..000000000
--- a/mobile/android/tests/browser/chrome/session_formdata_sample.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <meta charset="utf-8">
- <title>session_formdata_sample.html</title>
- </head>
- <body>
- <input id="txt" />
-
- <script type="text/javascript;version=1.8">
- let isOuter = window == window.top;
-
- if (isOuter) {
- let iframe = document.createElement("iframe");
- iframe.setAttribute("src", "https://example.com" + location.pathname);
- document.body.appendChild(iframe);
- }
- </script>
- </body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/simpleservice.xml b/mobile/android/tests/browser/chrome/simpleservice.xml
deleted file mode 100644
index f20becf1c..000000000
--- a/mobile/android/tests/browser/chrome/simpleservice.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0"?>
-<root xmlns="urn:schemas-upnp-org:device-1-0">
- <specVersion>
- <major>1</major>
- <minor>0</minor>
- </specVersion>
- <URLBase>http://example.com</URLBase>
- <device>
- <deviceType>urn:dial-multiscreen-org:device:dial:1</deviceType>
- <friendlyName>Pretend Device</friendlyName>
- <manufacturer>Copy Cat Inc.</manufacturer>
- <modelName>Eureka Dongle</modelName>
- <UDN>uuid:5ec9ff92-e8b2-4a94-a72c-76b34e6dabb1</UDN>
- </device>
-</root>
diff --git a/mobile/android/tests/browser/chrome/test_about_logins.html b/mobile/android/tests/browser/chrome/test_about_logins.html
deleted file mode 100644
index 8e7b404fd..000000000
--- a/mobile/android/tests/browser/chrome/test_about_logins.html
+++ /dev/null
@@ -1,106 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1136477
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1136477</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.8" src="head.js"></script>
- <script type="application/javascript;version=1.8">
-
- "use strict";
-
- const { interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/AppConstants.jsm");
- Cu.import("resource://gre/modules/Services.jsm");
-
- const LOGIN_FIELDS = {
- hostname: "http://example.org/tests/robocop/robocop_blank_01.html",
- formSubmitUrl: "",
- realmAny: null,
- username: "username1",
- password: "password1",
- usernameField: "",
- passwordField: ""
- };
-
- const LoginInfo = Components.Constructor("@mozilla.org/login-manager/loginInfo;1", "nsILoginInfo", "init");
-
- function add_login(login) {
- let newLogin = new LoginInfo(login.hostname,
- login.formSubmitUrl,
- login.realmAny,
- login.username,
- login.password,
- login.usernameField,
- login.passwordField);
-
- Services.logins.addLogin(newLogin);
- }
-
- add_task(function* test_passwords_list() {
- add_login(LOGIN_FIELDS);
-
- // Load about:logins.
- let BrowserApp = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp;
- let browser = BrowserApp.addTab("about:logins", { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
-
- yield promiseBrowserEvent(browser, "load");
-
- let logins_list_parent = browser.contentDocument.getElementById("logins-list").parentNode;
-
- let waitForLoginToBeAdded = new Promise((resolve) => {
- let observer = new MutationObserver((mutations) => {
- for (let mutation of mutations) {
- for (let node of mutation.addedNodes) {
- if (node.id == 'logins-list') {
- info("Received mutation replacing 'logins-list'");
- resolve();
- return;
- }
- }
- }
- info("Skipping spurious mutation not replacing 'logins-list'");
- });
- observer.observe(logins_list_parent, {
- childList: true,
- });
- info("Now waiting for mutation to replace 'logins-list'");
- });
-
- yield waitForLoginToBeAdded;
-
- let logins_list = browser.contentDocument.getElementById("logins-list");
-
- // Test that the (single) entry added in setup is correct.
- let hostname = logins_list.querySelector(".hostname");
- is(hostname.textContent, LOGIN_FIELDS.hostname, "hostname is correct");
-
- let username = logins_list.querySelector(".username");
- is(username.textContent, LOGIN_FIELDS.username, "username is correct");
-
- // Cleanup: close about:logins, opened in password_setup()
- BrowserApp.closeTab(BrowserApp.selectedTab);
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1136477">Mozilla Bug 1136477</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testAboutLogins</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_accounts.html b/mobile/android/tests/browser/chrome/test_accounts.html
deleted file mode 100644
index 1f7b4469a..000000000
--- a/mobile/android/tests/browser/chrome/test_accounts.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=917942
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 917942</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- Components.utils.import("resource://gre/modules/Accounts.jsm");
-
- add_task(function* () {
- let syncExists = yield Accounts.syncAccountsExist();
- info("Sync account exists? " + syncExists + "\n");
- let firefoxExists = yield Accounts.firefoxAccountsExist();
- info("Firefox account exists? " + firefoxExists + "\n");
- let anyExists = yield Accounts.anySyncAccountsExist();
- info("Any accounts exist? " + anyExists + "\n");
-
- // Only one account should exist.
- ok(!syncExists || !firefoxExists, "at least one account does not exist");
- is(anyExists, firefoxExists || syncExists, "sync/firefox account existence consistent with any existence");
-
- // TODO: How can this be cleaned up?
- //info("Launching setup.\n");
- //Accounts.launchSetup();
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=917942">Mozilla Bug 917942</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testAccounts</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_android_log.html b/mobile/android/tests/browser/chrome/test_android_log.html
deleted file mode 100644
index 6048b3eb1..000000000
--- a/mobile/android/tests/browser/chrome/test_android_log.html
+++ /dev/null
@@ -1,95 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1004825
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1004825</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- /*globals AndroidLog */
-
- const TAG = "AndroidLogTest";
-
- const VERBOSE_MESSAGE = "This is a verbose message.";
- const DEBUG_MESSAGE = "This is a debug message.";
- const INFO_MESSAGE = "This is an info message.";
- const WARNING_MESSAGE = "This is a warning message.";
- const ERROR_MESSAGE = "This is an error message.";
-
- // Number of bytes we expect to log. This isn't equivalent to the number
- // of characters, although the difference is consistent, so we can calculate it
- // from the lengths of the messages and tag. We include the length of "Gecko"
- // because the module prepends it to the tag.
- const VERBOSE_BYTES = "Gecko".length + TAG.length + VERBOSE_MESSAGE.length + 3;
- const DEBUG_BYTES = "Gecko".length + TAG.length + DEBUG_MESSAGE.length + 3;
- const INFO_BYTES = "Gecko".length + TAG.length + INFO_MESSAGE.length + 3;
- const WARNING_BYTES = "Gecko".length + TAG.length + WARNING_MESSAGE.length + 3;
- const ERROR_BYTES = "Gecko".length + TAG.length + ERROR_MESSAGE.length + 3;
-
- Components.utils.import("resource://gre/modules/AndroidLog.jsm");
-
- ok(!!AndroidLog, "AndroidLog is defined");
-
- ok("v" in AndroidLog && typeof AndroidLog.v == "function", "v function found");
- ok("d" in AndroidLog && typeof AndroidLog.d == "function", "d function found");
- ok("i" in AndroidLog && typeof AndroidLog.i == "function", "i function found");
- ok("w" in AndroidLog && typeof AndroidLog.w == "function", "w function found");
- ok("e" in AndroidLog && typeof AndroidLog.e == "function", "e function found");
-
- // Ensure that the functions don't cause the test process to crash
- // (because of some change to the native object being accessed via ctypes)
- // and return the right values (the number of bytes logged).
- // XXX Ensure that these messages actually make it to the log (bug 1046096).
- is(VERBOSE_BYTES, AndroidLog.v(TAG, VERBOSE_MESSAGE), "verbose bytes correct");
- is(DEBUG_BYTES, AndroidLog.d(TAG, DEBUG_MESSAGE), "debug bytes correct");
- is(INFO_BYTES, AndroidLog.i(TAG, INFO_MESSAGE), "info bytes correct");
- is(WARNING_BYTES, AndroidLog.w(TAG, WARNING_MESSAGE), "warning bytes correct");
- is(ERROR_BYTES, AndroidLog.e(TAG, ERROR_MESSAGE), "error bytes correct");
-
- // Ensure the functions work when bound with null value for thisArg parameter.
- is(VERBOSE_BYTES, AndroidLog.v.bind(null, TAG)(VERBOSE_MESSAGE), "verbose bytes correct with bind");
- is(DEBUG_BYTES, AndroidLog.d.bind(null, TAG)(DEBUG_MESSAGE), "debug bytes correct with bind");
- is(INFO_BYTES, AndroidLog.i.bind(null, TAG)(INFO_MESSAGE), "info bytes correct with bind");
- is(WARNING_BYTES, AndroidLog.w.bind(null, TAG)(WARNING_MESSAGE), "warning bytes correct with bind");
- is(ERROR_BYTES, AndroidLog.e.bind(null, TAG)(ERROR_MESSAGE), "error bytes correct with bind");
-
- // Ensure the functions work when the module object is "bound" to a tag.
- let Log = AndroidLog.bind(TAG);
- is(VERBOSE_BYTES, Log.v(VERBOSE_MESSAGE), "verbose bytes correct after bind");
- is(DEBUG_BYTES, Log.d(DEBUG_MESSAGE), "debug bytes correct after bind");
- is(INFO_BYTES, Log.i(INFO_MESSAGE), "info bytes correct after bind");
- is(WARNING_BYTES, Log.w(WARNING_MESSAGE), "warning bytes correct after bind");
- is(ERROR_BYTES, Log.e(ERROR_MESSAGE), "error bytes correct after bind");
-
- // Ensure the functions work when the tag length is greater than the maximum
- // tag length.
- let tag = "X".repeat(AndroidLog.MAX_TAG_LENGTH + 1);
- is(AndroidLog.MAX_TAG_LENGTH + 54, AndroidLog.v(tag, "This is a verbose message with a too-long tag."), "verbose message with too-long tag");
- is(AndroidLog.MAX_TAG_LENGTH + 52, AndroidLog.d(tag, "This is a debug message with a too-long tag."), "debug message with too-long tag");
- is(AndroidLog.MAX_TAG_LENGTH + 52, AndroidLog.i(tag, "This is an info message with a too-long tag."), "info message with too-long tag");
- is(AndroidLog.MAX_TAG_LENGTH + 54, AndroidLog.w(tag, "This is a warning message with a too-long tag."), "warning message with too-long tag");
- is(AndroidLog.MAX_TAG_LENGTH + 53, AndroidLog.e(tag, "This is an error message with a too-long tag."), "error message with too-long tag");
-
- // We should also ensure that the module is accessible from a ChromeWorker,
- // but there doesn't seem to be a way to load a ChromeWorker from this test.
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1004825">Mozilla Bug 1004825</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testAndroidLog</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_app_constants.html b/mobile/android/tests/browser/chrome/test_app_constants.html
deleted file mode 100644
index 7989ca1b6..000000000
--- a/mobile/android/tests/browser/chrome/test_app_constants.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1130872
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1130872</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript">
-
- Components.utils.import("resource://gre/modules/AppConstants.jsm");
-
- var packageName = AppConstants.ANDROID_PACKAGE_NAME;
-
- ok(packageName != "@ANDROID_PACKAGE_NAME@", "package name is not placeholder");
- ok(packageName.length > 0, "package name is not empty");
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1130872">Mozilla Bug 1130872</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testAppConstants</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_awsy_lite.html b/mobile/android/tests/browser/chrome/test_awsy_lite.html
deleted file mode 100644
index 066aaf2ea..000000000
--- a/mobile/android/tests/browser/chrome/test_awsy_lite.html
+++ /dev/null
@@ -1,258 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
- This test reports Firefox memory use to Perfherder.
-
- Inspired by https://areweslimyet.com/mobile
-
- https://bugzilla.mozilla.org/show_bug.cgi?id=1233220
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1233220</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/MemoryStats.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.8" src="head.js"></script>
- <script type="application/javascript;version=1.8">
-
- "use strict";
-
- const { interfaces: Ci, utils: Cu, classes: Cc } = Components;
-
- var kUrls = [
- "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/s@wd=mozilla.html",
- "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/tp5/twitter.com/twitter.com/ICHCheezburger.html",
- "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/tp5/msn.com/www.msn.com/index.html",
- "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/tp5/163.com/www.163.com/index.html",
- "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/news/index.html"
- ];
-
- var gTabsOpened = 0;
- var gWindow = null;
- var gLastTab = null;
- var gResults = [];
-
- Cu.import("resource://gre/modules/Services.jsm");
-
- var BrowserApp = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp;
- SimpleTest.waitForExplicitFinish();
- SimpleTest.requestLongerTimeout(3); // several long waits and GCs make for a long-running test
- SimpleTest.requestCompleteLog(); // so that "PERFHERDER_DATA" can be scraped from the log
-
- function checkpoint(aName) {
- var mrm = Cc["@mozilla.org/memory-reporter-manager;1"].getService(Ci.nsIMemoryReporterManager);
- gResults.push( { name: aName, resident: mrm.resident } );
- info(`${aName} | Resident Memory: ${mrm.resident}`);
- }
-
- var browserListener = {
- onOpenWindow: function(aWindow) {
- var win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
- win.addEventListener("UIReady", function listener(aEvent) {
- win.removeEventListener("UIReady", listener, false);
- attachTo(win);
- }, false);
- },
-
- onCloseWindow: function(aWindow) {
- detachFrom(aWindow);
- },
-
- onWindowTitleChange: function(aWindow, aTitle) {
- }
- };
-
- function doFullGc(aCallback, aIterations) {
- var threadMan = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
- var domWindowUtils = gWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils);
-
- function runSoon(f) {
- threadMan.mainThread.dispatch({ run: f }, Ci.nsIThread.DISPATCH_NORMAL);
- }
-
- function cc() {
- if (domWindowUtils.cycleCollect) {
- domWindowUtils.cycleCollect();
- }
- Services.obs.notifyObservers(null, "child-cc-request", null);
- }
-
- function minimizeInner() {
- // In order of preference: schedulePreciseShrinkingGC, schedulePreciseGC
- // garbageCollect
- if (++j <= aIterations) {
- var schedGC = Cu.schedulePreciseShrinkingGC;
- if (!schedGC) {
- schedGC = Cu.schedulePreciseGC;
- }
-
- Services.obs.notifyObservers(null, "child-gc-request", null);
-
- if (schedGC) {
- schedGC.call(Cu, { callback: function () {
- runSoon(function () { cc(); runSoon(minimizeInner); });
- } });
- } else {
- if (domWindowUtils.garbageCollect) {
- domWindowUtils.garbageCollect();
- }
- runSoon(function () { cc(); runSoon(minimizeInner); });
- }
- } else {
- runSoon(aCallback);
- }
- }
-
- var j = 0;
- minimizeInner();
- }
-
- function attachTo(aWindow) {
- if (gWindow != null) {
- info("attempting to attach to a second window [" + aWindow + "] while already attached to one window [" + gWindow + "]");
- return;
- }
- gWindow = aWindow;
- setTimeout(startTest, 0);
- }
-
- function detachFrom(aWindow) {
- if (gWindow == aWindow) {
- gWindow = null;
- }
- }
-
- function startup() {
- var enumerator = Services.wm.getEnumerator("navigator:browser");
- while (enumerator.hasMoreElements()) {
- // potential race condition here - the window may not be ready yet at
- // this point, so ideally we would test for that. but i can't find a
- // property that reflects whether or not UIReady has been fired, so
- // for now just assume the window is ready
- attachTo(enumerator.getNext().QueryInterface(Ci.nsIDOMWindow));
- }
- Services.wm.addListener(browserListener);
- }
-
- function startTest() {
- checkpoint("Fresh start");
- setTimeout(settle, 30000);
- }
-
- function settle() {
- checkpoint("Fresh start [+30s]");
- openTab();
- }
-
- function openTab() {
- var urlIndex = gTabsOpened++;
- if (urlIndex >= kUrls.length) {
- checkpoint("After tabs");
- setTimeout(postOpening, 30000);
- return;
- }
-
- info("opening tab with url [" + kUrls[urlIndex] + "]");
- gLastTab = BrowserApp.addTab(kUrls[urlIndex], { selected: true });
- setTimeout(waitForTab, 10000);
- }
-
- function waitForTab() {
- if (gLastTab.browser.contentDocument.readyState === "complete") {
- gLastTab = null;
- openTab();
- } else {
- setTimeout(waitForTab, 10000);
- }
- }
-
- function postOpening() {
- checkpoint("After tabs [+30s]");
- doFullGc(() => closeTabs());
- }
-
- function closeTabs() {
- checkpoint("After tabs [+30s, forced GC]");
- var tabCount = BrowserApp.tabs.length;
- for (var i = 1; i < tabCount; i++) {
- BrowserApp.closeTab(BrowserApp.tabs[i]);
- }
-
- var closeListener = {
- observe: function(aSubject, aTopic, aData) {
- tabCount--;
- dump("tab count dropped to [" + tabCount + "]");
- if (tabCount == 1) {
- Services.obs.removeObserver(this, "Tab:Closed", false);
- setTimeout(tabsClosed, 0);
- }
- }
- };
- Services.obs.addObserver(closeListener, "Tab:Closed", false);
- }
-
- function tabsClosed() {
- checkpoint("Tabs closed");
- setTimeout(postClosing, 30000);
- }
-
- function postClosing() {
- checkpoint("Tabs closed [+30s]");
- doFullGc(() => {
- checkpoint("Tabs closed [+30s, forced GC]");
- finalReport();
- ok(true, "memory logging complete -- view results in Perfherder");
- SimpleTest.finish();
- });
- }
-
- function geomean(aProperty) {
- // https://en.wikipedia.org/wiki/Geometric_mean#Relationship_with_arithmetic_mean_of_logarithms
- var logsum = 0;
- var i;
- for (i = 0; i < gResults.length; i++) {
- var result = gResults[i];
- logsum += Math.log(result[aProperty]);
- }
- return Math.round(Math.exp(logsum/gResults.length));
- }
-
- function finalReport() {
- var i;
- var perfherder = "PERFHERDER_DATA: ";
- perfherder += "{\"framework\": {\"name\": \"awsy\"}, ";
- perfherder += "\"suites\": [";
- perfherder += "{\"name\": \"Resident Memory\", ";
- perfherder += "\"subtests\": [";
- for (i = 0; i < gResults.length; i++) {
- var result = gResults[i];
- if (i > 0) {
- perfherder += ", ";
- }
- perfherder += `{\"name\": \"${result.name}\", \"value\": ${result.resident}}`;
- }
- perfherder += "], "; // end subtests
- perfherder += "\"value\": "+geomean("resident");
- perfherder += "}"; // end Resident Memory suite
- perfherder += "]"; // end suites
- perfherder += "}"; // end PERFHERDER_DATA
- info(perfherder);
- }
-
- startup();
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1233220">Mozilla Bug 1233220</a>
-<br>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_debugger_server.html b/mobile/android/tests/browser/chrome/test_debugger_server.html
deleted file mode 100644
index a7b49ede6..000000000
--- a/mobile/android/tests/browser/chrome/test_debugger_server.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1010750
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1010750</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- "use strict";
-
- const { utils: Cu } = Components;
-
- const DEBUGGER_USB_ENABLED = "devtools.remote.usb.enabled";
-
- Cu.import("resource://gre/modules/Services.jsm");
- const { require } =
- Cu.import("resource://devtools/shared/Loader.jsm", {});
- const { DebuggerServer } = require("devtools/server/main");
-
- let win = Services.wm.getMostRecentWindow("navigator:browser");
-
- win.RemoteDebugger.init();
-
- SimpleTest.registerCleanupFunction(function() {
- Services.prefs.clearUserPref(DEBUGGER_USB_ENABLED);
- });
-
- // Enable the debugger via the pref it listens for
- Services.prefs.setBoolPref(DEBUGGER_USB_ENABLED, true);
-
- ok(DebuggerServer.initialized, "initialized");
- is(DebuggerServer.listeningSockets, 1, "1 listening socket");
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1010750">Mozilla Bug 1010750</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testDebuggerServer</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_desktop_useragent.html b/mobile/android/tests/browser/chrome/test_desktop_useragent.html
deleted file mode 100644
index cfa82659a..000000000
--- a/mobile/android/tests/browser/chrome/test_desktop_useragent.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1157319
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1157319</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript;version=1.7">
-
- "use strict";
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/Services.jsm");
-
- // Load a custom sjs script that echos our "User-Agent" header back at us
- const TestURI = Services.io.newURI("http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/desktopmode_user_agent.sjs", null, null);
-
- add_task(function* test_desktopmode() {
- let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- // Add a new 'desktop mode' tab with our test page
- let desktopTab = BrowserApp.addTab(TestURI.spec, { selected: true, parentId: BrowserApp.selectedTab.id, desktopMode: true });
- let desktopBrowser = desktopTab.browser;
- yield promiseBrowserEvent(desktopBrowser, "load");
-
- // Some debugging
- info("desktop: " + desktopBrowser.contentWindow.navigator.userAgent);
- info("desktop: " + desktopBrowser.contentDocument.body.innerHTML);
-
- // Check the server UA and the navigator UA for 'desktop'
- ok(desktopBrowser.contentWindow.navigator.userAgent.indexOf("Linux x86_64") != -1, "window.navigator.userAgent has 'Linux' in it");
- ok(desktopBrowser.contentDocument.body.innerHTML.indexOf("Linux x86_64") != -1, "HTTP header 'User-Agent' has 'Linux' in it");
-
- BrowserApp.closeTab(desktopTab);
-
- // Add a new 'mobile mode' tab with our test page
- let mobileTab = BrowserApp.addTab(TestURI.spec, { selected: true, parentId: BrowserApp.selectedTab.id });
- let mobileBrowser = mobileTab.browser;
- yield promiseBrowserEvent(mobileBrowser, "load");
-
- // Some debugging
- info("mobile: " + mobileBrowser.contentWindow.navigator.userAgent);
- info("mobile: " + mobileBrowser.contentDocument.body.innerHTML);
-
- // Check the server UA and the navigator UA for 'mobile'
- // We only check for 'Android' because we don't know the version or if it's phone or tablet
- ok(mobileBrowser.contentWindow.navigator.userAgent.indexOf("Android") != -1, "window.navigator.userAgent has 'Android' in it");
- ok(mobileBrowser.contentDocument.body.innerHTML.indexOf("Android") != -1, "HTTP header 'User-Agent' has 'Android' in it");
-
- BrowserApp.closeTab(mobileTab);
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1157319">Mozilla Bug 1157319</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testDesktopUseragent</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_device_search_engine.html b/mobile/android/tests/browser/chrome/test_device_search_engine.html
deleted file mode 100644
index bb67548cd..000000000
--- a/mobile/android/tests/browser/chrome/test_device_search_engine.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=861164
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 861164</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- var Cc = Components.classes;
- var Ci = Components.interfaces;
-
- SimpleTest.waitForExplicitFinish();
-
- function search_observer(aSubject, aTopic, aData) {
- let engine = aSubject.QueryInterface(Ci.nsISearchEngine);
- info("Observer: " + aData + " for " + engine.name);
-
- if (aData != "engine-added")
- return;
-
- if (engine.name != "Test search engine")
- return;
-
- function check_submission(aExpected, aSearchTerm, aType) {
- is(engine.getSubmission(aSearchTerm, aType).uri.spec, "http://example.com/search" + aExpected, "submission matches");
- }
-
- // Force the type and check for the expected URL
- check_submission("?q=foo", "foo", "text/html");
- check_submission("/tablet?q=foo", "foo", "application/x-moz-tabletsearch");
- check_submission("/phone?q=foo", "foo", "application/x-moz-phonesearch");
-
- // Let the service pick the appropriate type based on the device
- // and check for expected URL
- let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
- if (sysInfo.get("tablet")) {
- info("Device: tablet");
- check_submission("/tablet?q=foo", "foo", null);
- } else {
- info("Device: phone");
- check_submission("/phone?q=foo", "foo", null);
- }
-
- SimpleTest.finish();
- };
-
- SimpleTest.registerCleanupFunction(function() {
- Services.obs.removeObserver(search_observer, "browser-search-engine-modified");
- });
- Services.obs.addObserver(search_observer, "browser-search-engine-modified", false);
- info("Loading search engine");
- Services.search.addEngine("http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/devicesearch.xml", Ci.nsISearchEngine.DATA_XML, null, false);
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=861164">Mozilla Bug 861164</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testDeviceSearchEngine</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_get_last_visited.html b/mobile/android/tests/browser/chrome/test_get_last_visited.html
deleted file mode 100644
index da8a0fbfb..000000000
--- a/mobile/android/tests/browser/chrome/test_get_last_visited.html
+++ /dev/null
@@ -1,106 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1214366
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1214366</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript;version=1.7">
-
- "use strict";
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/Services.jsm");
- Cu.import("resource://gre/modules/Messaging.jsm");
- Cu.import("resource://gre/modules/Task.jsm");
-
- let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- function get_last_visited(prePath) {
- return Messaging.sendRequestForResult({
- type: "History:GetPrePathLastVisitedTimeMilliseconds",
- prePath: prePath,
- });
- };
-
- var browser = BrowserApp.addTab("about:blank").browser;
-
- // It's useful to see *all* "link-visited" events in the face of intermittent failures.
- let observe = function(subject, topic, data) {
- var uri = subject.QueryInterface(Ci.nsIURI);
- info("Witnessed " + topic + " notification from Gecko with URI " + uri.spec);
- }
- Services.obs.addObserver(observe, "link-visited", false);
-
- SimpleTest.registerCleanupFunction(function cleanup() {
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
- Services.obs.removeObserver(observe, "link-visited");
- });
-
- // N.b.: the write to the Fennec DB happens before the Gecko notification
- // is fired. This is delicate.
- function add_history_visit(url) {
- browser.loadURI(url, null, null);
- return promiseLinkVisit(url);
- };
-
- // Be aware that some paths under mochi.test and example.org redirect. The
- // blank robocop pages appear to not. Redirects can impact this test, since
- // they can write to the history database.
-
- // The apparent mis-ordering here just uses simpler pages (01 and 03) for the
- // real test, and a more complex page (02) for a final delay. See comment below.
- const url1 = "http://example.org/tests/robocop/robocop_blank_01.html";
- const url2 = "http://example.org/tests/robocop/robocop_blank_03.html";
- const url3 = "http://example.org/tests/robocop/robocop_blank_02.html";
-
- add_task(function* test_get_last_visited() {
- var v = yield get_last_visited("https://random.com/");
- is(v, 0, `Last visited timestamp is 0 for unknown prePath: ${v}`);
-
- let prePath = Services.io.newURI(url1, null, null).prePath + "/";
- is(prePath, Services.io.newURI(url2, null, null).prePath + "/", "url1 and url2 have the same prePath");
-
- let t0 = Date.now();
- yield add_history_visit(url1);
- v = yield get_last_visited(prePath);
- let t1 = Date.now();
- ok(t0 <= v, `Last visited timestamp is after visit: ${t0} <= ${v}.`);
- ok(v <= t1, `Last visited timestamp is before present ${v} <= ${t1}.`);
-
- let t2 = Date.now();
- yield add_history_visit(url1);
- v = yield get_last_visited(prePath);
- ok(t2 <= v, `Last visited timestamp is updated after visit: ${t2} <= ${v}`);
-
- let t3 = Date.now();
- yield add_history_visit(url2);
- v = yield get_last_visited(prePath);
- ok(t3 <= v, `Last visited timestamp is updated after visit to URL with same prePath: ${t3} <= ${v}`);
-
- // This whole system is flaky, so we wait for an unrelated visit, so that we
- // can witness "link-visited" events a little after the test completes
- // while debugging.
- yield add_history_visit(url3);
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1214366">Mozilla Bug 1214366</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_hidden_select_option.html b/mobile/android/tests/browser/chrome/test_hidden_select_option.html
deleted file mode 100644
index ecdfe710e..000000000
--- a/mobile/android/tests/browser/chrome/test_hidden_select_option.html
+++ /dev/null
@@ -1,103 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1178722
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1178722</title>
- <style>
- .hideme {display:none}
- </style>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript;version=1.7">
- "use strict";
-
- const VISIBLE_OPTION_COUNT = 5;
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
- Cu.import("resource://gre/modules/Services.jsm");
- let win = Services.wm.getMostRecentWindow("navigator:browser");
- let SelectHelper = win.SelectHelper;
-
- // Returns whether an element should be visible according to its text content.
- function shouldBeVisible(e){
- return e.label.indexOf("visible") > 0;
- }
-
- // Returns an object for the callback method that would normally be created by Prompt.java's
- // addListResult(..) method.
- function createCallBackDummyData(select){
- var dummyList = new Array();
- let listElements = SelectHelper.getListForElement(select);
- for (var i = 0; i < listElements.length; i++) {
- dummyList.push(i);
- }
- return {list:dummyList};
- }
-
- // Wait until the page has loaded so that we can access the DOM.
- SimpleTest.waitForExplicitFinish();
- window.onload = function () {
- let select = document.getElementById("sample-select");
-
- // ##############################################
- // ### Testing SelectHelper.getListForElement ###
- // ##############################################
-
- // Check that SelectHelper.getListForElement only includes visible options...
- let listElements = SelectHelper.getListForElement(select);
- for (var i = 0; i < listElements.length; i++) {
- ok(shouldBeVisible(listElements[i]), "Element should be visible: " + listElements[i]);
- }
-
- // Check SelectHelper.getListForElement does not include additional options...
- is(listElements.length, VISIBLE_OPTION_COUNT, "Correct number of elements were returned.");
-
- // ############################################
- // ### Testing SelectHelper._promptCallBack ###
- // ############################################
-
- // We will simulate "selecting" (ie choosing via the prompt) all the visible options...
- is(select.selectedOptions.length, 0, "No options selected yet.");
- let dummyData = createCallBackDummyData(select);
- SelectHelper._promptCallBack(dummyData,select);
-
- // Check that only the visible options had the "selected" attribute set...
- let selectedOptions = select.selectedOptions;
- for (var i = 0; i < selectedOptions.length; i++) {
- ok(shouldBeVisible(selectedOptions[i]), "Element should be visible.");
- }
-
- // Check that no additional options had the "selected" attribute set...
- is(selectedOptions.length, VISIBLE_OPTION_COUNT, "Correct number of options were selected.");
-
- SimpleTest.finish();
- }
- </script>
-</head>
-<body>
-
-<p id="display">
- <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1178722">Mozilla Bug 1178722</a>
- <select multiple id="sample-select">
- <option value="1">1 - visible</option> 0
- <option value="2" style="display: none">2 - hidden</option> 1
- <option value="3">3 - visible</option> 2
- <option value="4" style="display: nOnE">4 - hidden </option> 3
- <option value="5">5 - visible</option> 4
- <option value="6" class="hideme">6 - hidden</option> 5
- <option value="7">7 - visible</option> 6
- <option value="8" hiddEn>8 - hidden</option> 7
- <option value="9">9 - visible</option> 8
- </select>
-</p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-</pre>
-</body>
-</html> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/test_home_provider.html b/mobile/android/tests/browser/chrome/test_home_provider.html
deleted file mode 100644
index 542cd82c0..000000000
--- a/mobile/android/tests/browser/chrome/test_home_provider.html
+++ /dev/null
@@ -1,165 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=942288
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 942288</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- const { utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/HomeProvider.jsm");
- Cu.import("resource://gre/modules/osfile.jsm");
- Cu.import("resource://gre/modules/Services.jsm");
- Cu.import("resource://gre/modules/Sqlite.jsm");
- Cu.import("resource://gre/modules/Task.jsm");
-
- const TEST_DATASET_ID = "test-dataset-id";
- const TEST_URL = "http://test.com";
- const TEST_TITLE = "Test";
- const TEST_BACKGROUND_URL = "http://example.com/background";
- const TEST_BACKGROUND_COLOR = "#FF9500";
-
- const PREF_SYNC_CHECK_INTERVAL_SECS = "home.sync.checkIntervalSecs";
- const TEST_INTERVAL_SECS = 1;
-
- const DB_PATH = OS.Path.join(OS.Constants.Path.profileDir, "home.sqlite");
-
- test_request_sync();
- test_periodic_sync();
-
- function test_request_sync() {
- // The current implementation of requestSync is synchronous.
- let success = HomeProvider.requestSync(TEST_DATASET_ID, function callback(datasetId) {
- is(datasetId, TEST_DATASET_ID, "expected dataset ID");
- });
-
- ok(success, "requestSync success");
- }
-
- function test_periodic_sync() {
- SimpleTest.registerCleanupFunction(function() {
- Services.prefs.clearUserPref(PREF_SYNC_CHECK_INTERVAL_SECS);
- HomeProvider.removePeriodicSync(TEST_DATASET_ID);
- });
-
- // Lower the check interval for testing purposes.
- Services.prefs.setIntPref(PREF_SYNC_CHECK_INTERVAL_SECS, TEST_INTERVAL_SECS);
-
- HomeProvider.addPeriodicSync(TEST_DATASET_ID, TEST_INTERVAL_SECS, function callback(datasetId) {
- is(datasetId, TEST_DATASET_ID, "expected dataset ID");
- });
- }
-
- add_task(function* test_save_and_delete() {
- // Use the HomeProvider API to save some data.
- let storage = HomeProvider.getStorage(TEST_DATASET_ID);
- yield storage.save([{
- title: TEST_TITLE,
- url: TEST_URL,
- background_url: TEST_BACKGROUND_URL,
- background_color: TEST_BACKGROUND_COLOR
- }]);
-
- // Peek in the DB to make sure we have the right data.
- let db = yield Sqlite.openConnection({ path: DB_PATH });
-
- // Make sure the items table was created.
- ok((yield db.tableExists("items")), "items table exists");
-
- // Make sure the correct values for the item ended up in there.
- let result = yield db.execute("SELECT * FROM items", null, function onRow(row){
- is(row.getResultByName("dataset_id"), TEST_DATASET_ID, "expected dataset ID");
- is(row.getResultByName("url"), TEST_URL, "expected test url");
- is(row.getResultByName("background_url"), TEST_BACKGROUND_URL, "expected background url");
- is(row.getResultByName("background_color"), TEST_BACKGROUND_COLOR, "expected background color");
- });
-
- // Use the HomeProvider API to delete the data.
- yield storage.deleteAll();
-
- // Make sure the data was deleted.
- result = yield db.execute("SELECT * FROM items");
- is(result.length, 0, "length is 0");
-
- db.close();
- });
-
- add_task(function* test_row_validation() {
- // Use the HomeProvider API to save some data.
- let storage = HomeProvider.getStorage(TEST_DATASET_ID);
-
- let invalidRows = [
- { url: "url" },
- { title: "title" },
- { description: "description" },
- { image_url: "image_url" }
- ];
-
- // None of these save calls should save anything
- for (let row of invalidRows) {
- try {
- yield storage.save([row]);
- } catch (e if e instanceof HomeProvider.ValidationError) {
- // Just catch and ignore validation errors
- }
- }
-
- // Peek in the DB to make sure we have the right data.
- let db = yield Sqlite.openConnection({ path: DB_PATH });
-
- // Make sure no data has been saved.
- let result = yield db.execute("SELECT * FROM items");
- is(result.length, 0, "length is 0");
-
- db.close();
- });
-
- add_task(function* test_save_transaction() {
- // Use the HomeProvider API to save some data.
- let storage = HomeProvider.getStorage(TEST_DATASET_ID);
-
- // One valid, one invalid
- let rows = [
- { title: TEST_TITLE, url: TEST_URL },
- { image_url: "image_url" }
- ];
-
- // Try to save all the rows at once
- try {
- yield storage.save(rows);
- } catch (e if e instanceof HomeProvider.ValidationError) {
- // Just catch and ignore validation errors
- }
-
- // Peek in the DB to make sure we have the right data.
- let db = yield Sqlite.openConnection({ path: DB_PATH });
-
- // Make sure no data has been saved.
- let result = yield db.execute("SELECT * FROM items");
- is(result.length, 0, "length is 0");
-
- db.close();
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=942288">Mozilla Bug 942288</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testHomeProvider</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_identity_mode.html b/mobile/android/tests/browser/chrome/test_identity_mode.html
deleted file mode 100644
index 5c41489a4..000000000
--- a/mobile/android/tests/browser/chrome/test_identity_mode.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1099088
--->
-<head>
- <meta charset="utf-8">
- <title>Test for getIdentityMode</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript;version=1.7">
-
- "use strict";
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/Services.jsm");
-
- let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let IdentityHandler = chromeWin.IdentityHandler;
-
- ok(IdentityHandler.getIdentityMode(0, Services.io.newURI("about:", null, null)) == IdentityHandler.IDENTITY_MODE_CHROMEUI,
- "'about:' is a verified internal page");
- ok(IdentityHandler.getIdentityMode(0, Services.io.newURI("about:config", null, null)) == IdentityHandler.IDENTITY_MODE_CHROMEUI,
- "'about:config' is a verified internal page");
- ok(IdentityHandler.getIdentityMode(0, Services.io.newURI("about:accounts", null, null)) == IdentityHandler.IDENTITY_MODE_CHROMEUI,
- "'about:accounts is a verified internal page");
- ok(IdentityHandler.getIdentityMode(0, Services.io.newURI("about:addonss", null, null)) == IdentityHandler.IDENTITY_MODE_UNKNOWN,
- "'about:addonss is not a verified internal page");
- ok(IdentityHandler.getIdentityMode(0, Services.io.newURI("about:accountss", null, null)) == IdentityHandler.IDENTITY_MODE_UNKNOWN,
- "'about:accountss is not a verified internal page");
- ok(IdentityHandler.getIdentityMode(0, Services.io.newURI("about:accounts?action=signup", null, null)) == IdentityHandler.IDENTITY_MODE_CHROMEUI,
- "'about:accounts?action=signup is a verified internal page");
- ok(IdentityHandler.getIdentityMode(0, Services.io.newURI("about:evil_extension_page", null, null)) == IdentityHandler.IDENTITY_MODE_UNKNOWN,
- "'about:evil_extension_page' is not a verified internal page");
-
- ok(IdentityHandler.getIdentityMode(0, Services.io.newURI("http://mozilla.com", null, null)) == IdentityHandler.IDENTITY_MODE_UNKNOWN,
- "http://mozilla.com is an unknown page");
- ok(IdentityHandler.getIdentityMode(0, Services.io.newURI("https://mozilla.com", null, null)) == IdentityHandler.IDENTITY_MODE_UNKNOWN,
- "https://mozilla.com over an insecure connection is an unknown page");
- ok(IdentityHandler.getIdentityMode(Ci.nsIWebProgressListener.STATE_IS_SECURE, Services.io.newURI("https://mozilla.com", null, null)) == IdentityHandler.IDENTITY_MODE_IDENTIFIED,
- "https://mozilla.com over a secure connection is a verified page");
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1099088">Mozilla Bug 1099088</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_java_addons.html b/mobile/android/tests/browser/chrome/test_java_addons.html
deleted file mode 100644
index 7a656671a..000000000
--- a/mobile/android/tests/browser/chrome/test_java_addons.html
+++ /dev/null
@@ -1,118 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1168407
-Migrated from Robocop https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1168407</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/JavaAddonManager.jsm"); /*global JavaAddonManager */
- Cu.import("resource://gre/modules/Promise.jsm"); /*global Promise */
- Cu.import("resource://gre/modules/Task.jsm"); /*global Task */
-
- const DEX_FILE = "chrome://roboextender/content/javaaddons-test.apk";
- const CLASS = "org.mozilla.javaaddons.test.JavaAddonV1";
-
- const MESSAGE = "JavaAddon:V1";
-
- add_task(function* testFailureCases() {
- info("Loading Java Addon from non-existent class.");
- let gotError1 = yield JavaAddonManager.classInstanceFromFile(CLASS + "GARBAGE", DEX_FILE)
- .then((result) => false)
- .catch((error) => true);
- is(gotError1, true, "got expected error for non-existent class");
-
- info("Loading Java Addon from non-existent DEX file.");
- let gotError2 = yield JavaAddonManager.classInstanceFromFile(CLASS, DEX_FILE + "GARBAGE")
- .then((result) => false)
- .catch((error) => true);
- is(gotError2, true, "got expected error for non-existent DEX file");
- });
-
- // Make a request to a dynamically loaded Java Addon; wait for a response.
- // Then expect the add-on to make a request; respond.
- // Then expect the add-on to make a second request; use it to verify the response to the first request.
- add_task(function* testJavaAddonV1() {
- info("Loading Java Addon from: " + DEX_FILE);
-
- let javaAddon = yield JavaAddonManager.classInstanceFromFile(CLASS, DEX_FILE);
- isnot(javaAddon, null, "addon is not null");
- isnot(javaAddon._guid, null, "guid is not null");
- is(javaAddon._classname, CLASS, "got expected class");
- is(javaAddon._loaded, true, "addon is loaded");
-
- let messagePromise = Promise.defer();
- var count = 0;
- function listener(data) {
- info("Got request initiated from Java Addon: " + data + ", " + typeof(data) + ", " + JSON.stringify(data));
- count += 1;
- messagePromise.resolve(); // It's okay to resolve before returning: we'll wait on the verification promise no matter what.
- return {
- outputStringKey: "inputStringKey=" + data.inputStringKey,
- outputIntKey: data.inputIntKey - 1
- };
- }
- javaAddon.addListener(listener, "JavaAddon:V1:Request");
-
- let verifierPromise = Promise.defer();
- function verifier(data) {
- info("Got verification request initiated from Java Addon: " + data + ", " + typeof(data) + ", " + JSON.stringify(data));
- // These values are from the test Java Addon, after being processed by the :Request listener above.
- is(data.outputStringKey, "inputStringKey=raw", "got expected outputStringKey");
- is(data.outputIntKey, 2, "got expected outputIntKey");
- verifierPromise.resolve();
- return {};
- }
- javaAddon.addListener(verifier, "JavaAddon:V1:VerificationRequest");
-
- let message = {type: MESSAGE, inputStringKey: "test", inputIntKey: 5};
- info("Sending request to Java Addon: " + JSON.stringify(message));
- let output = yield javaAddon.sendRequestForResult(message);
-
- info("Got response from Java Addon: " + output + ", " + typeof(output) + ", " + JSON.stringify(output));
- is(output.outputStringKey, "inputStringKey=test", "got expected outputStringKey");
- is(output.outputIntKey, 6, "got expected outputIntKey");
-
- // We don't worry about timing out: the harness will (very much later)
- // kill us if we don't see the expected messages.
-
- info("Waiting for request initiated from Java Addon.");
- yield messagePromise.promise;
- is(count, 1, "count is 1");
-
- info("Send request for result 2 for request initiated from Java Addon.");
-
- // The JavaAddon should have removed its listener, so we shouldn't get a response and count should stay the same.
- let gotError = yield javaAddon.sendRequestForResult(message)
- .then((result) => false)
- .catch((error) => true);
- is(gotError, true, "got expected error");
- is(count, 1, "count is still 1");
-
- info("Waiting for verification request initiated from Java Addon.");
- yield verifierPromise.promise;
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1168407">Mozilla Bug 1168407</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testJavaAddons</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_jni.html b/mobile/android/tests/browser/chrome/test_jni.html
deleted file mode 100644
index 5e0d045dc..000000000
--- a/mobile/android/tests/browser/chrome/test_jni.html
+++ /dev/null
@@ -1,82 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=873569
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 873569</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- Components.utils.import("resource://gre/modules/ctypes.jsm");
- Components.utils.import("resource://gre/modules/JNI.jsm");
-
- function test_JNI() {
- var jenv = null;
- try {
- jenv = JNI.GetForThread();
-
- // Test a simple static method.
- var geckoAppShell = JNI.LoadClass(jenv, "org.mozilla.gecko.GeckoAppShell", {
- static_methods: [
- { name: "getPreferredIconSize", sig: "()I" },
- { name: "getContext", sig: "()Landroid/content/Context;" },
- ],
- });
-
- let iconSize = -1;
- iconSize = geckoAppShell.getPreferredIconSize();
- isnot(iconSize, -1, "icon size is valid");
-
- // Test GeckoNetworkManager methods that are accessed by PaymentsUI.js.
- // The return values can vary, so we can't test for equivalence, but we
- // can ensure that the method calls return values of the correct type.
- let jGeckoNetworkManager = JNI.LoadClass(jenv, "org/mozilla/gecko/GeckoNetworkManager", {
- static_methods: [
- { name: "getMNC", sig: "()I" },
- { name: "getMCC", sig: "()I" },
- ],
- });
- is(typeof jGeckoNetworkManager.getMNC(), "number", "typeof getMNC is number");
- is(typeof jGeckoNetworkManager.getMCC(), "number", "typeof getMCC is number");
-
- // Test retrieving the context's class's name, which tests dynamic method
- // invocation as well as converting a Java string to JavaScript.
- JNI.LoadClass(jenv, "android.content.Context", {
- methods: [
- { name: "getClass", sig: "()Ljava/lang/Class;" },
- ],
- });
- JNI.LoadClass(jenv, "java.lang.Class", {
- methods: [
- { name: "getName", sig: "()Ljava/lang/String;" },
- ],
- });
- is("org.mozilla.gecko.BrowserApp", JNI.ReadString(jenv, geckoAppShell.getContext().getClass().getName()), "class name is correct");
- } finally {
- if (jenv) {
- JNI.UnloadClasses(jenv);
- }
- }
- }
-
- test_JNI();
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=873569">Mozilla Bug 873569</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testJNI</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_migrate_ui.html b/mobile/android/tests/browser/chrome/test_migrate_ui.html
deleted file mode 100644
index 124b4b4f4..000000000
--- a/mobile/android/tests/browser/chrome/test_migrate_ui.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1154504
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1154504</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head_search.js"></script>
- <script type="application/javascript;version=1.7">
-
- Services.prefs.clearUserPref("browser.migration.version");
- Services.prefs.setBoolPref("nglayout.debug.paint_flashing", true);
-
- addTestEngines([
- { name: "bacon", details: ["", "bacon", "Search Bacon", "GET",
- "http://www.bacon.moz/?search={searchTerms}"] },
- ]).then(engines => {
- Services.prefs.setCharPref("browser.search.defaultenginename", engines[0].name);
-
- let BrowserApp = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp;
-
- // This performs the serach migration asynchronously, but the search service is already initialized
- // by `addTestEngines`, so we don't need to worry about waiting before checking the new engine.
- BrowserApp._migrateUI();
-
- // Check that migration version increased.
- is(Services.prefs.getIntPref("browser.migration.version"), 3, "found expected version");
-
- // Check that user pref value was reset.
- is(Services.prefs.prefHasUserValue("nglayout.debug.paint_flashing"), false, "found expected user value");
-
- function searchObserver(s, t, d) {
- Services.obs.removeObserver(searchObserver, "default-search-engine-migrated");
- is(Services.search.defaultEngine.name, engines[0].name, "found expected default search engine");
- }
- Services.obs.addObserver(searchObserver, "default-search-engine-migrated", false);
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1154504">Mozilla Bug 1154504</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testMigrateUI</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_network_manager.html b/mobile/android/tests/browser/chrome/test_network_manager.html
deleted file mode 100644
index f21c68e72..000000000
--- a/mobile/android/tests/browser/chrome/test_network_manager.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=895775
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 895775</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- "use strict";
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
- Cu.import("resource://gre/modules/Services.jsm");
-
- // Let's exercise the interface. Even if the network is not up, we can make sure nothing blows up.
- let network = Cc["@mozilla.org/network/network-link-service;1"].getService(Ci.nsINetworkLinkService);
- if (network.isLinkUp) {
- ok(network.linkType != Ci.nsINetworkLinkService.LINK_TYPE_UNKNOWN, "LinkType is not UNKNOWN");
- } else {
- ok(network.linkType == Ci.nsINetworkLinkService.LINK_TYPE_UNKNOWN, "LinkType is UNKNOWN");
- }
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=895775">Mozilla Bug 895775</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testNetworkManager</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_offline_page.html b/mobile/android/tests/browser/chrome/test_offline_page.html
deleted file mode 100644
index e1b723266..000000000
--- a/mobile/android/tests/browser/chrome/test_offline_page.html
+++ /dev/null
@@ -1,111 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1089190
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1089190</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript;version=1.7">
-
- "use strict";
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/Services.jsm");
- Cu.import("resource://gre/modules/Messaging.jsm");
- Cu.import("resource://gre/modules/Task.jsm");
-
- // Provide a helper to yield until we are sure the offline state has changed
- function promiseOffline(isOffline) {
- return new Promise((resolve, reject) => {
- function observe(subject, topic, data) {
- info("Received topic: " + topic);
- Services.obs.removeObserver(observe, "network:offline-status-changed");
- resolve();
- }
- Services.obs.addObserver(observe, "network:offline-status-changed", false);
- Services.io.offline = isOffline;
- });
- }
-
- // The chrome window
- let chromeWin;
-
- // Track the <browser> where the tests are happening
- let browser;
-
- // The proxy setting
- let proxyPrefValue;
-
- const kUniqueURI = Services.io.newURI("http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/video_controls.html", null, null);
-
- add_task(function* test_offline() {
- // Tests always connect to localhost, and per bug 87717, localhost is now
- // reachable in offline mode. To avoid this, disable any proxy.
- proxyPrefValue = Services.prefs.getIntPref("network.proxy.type");
- Services.prefs.setIntPref("network.proxy.type", 0);
-
- // Clear network cache.
- Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService).clear();
-
- chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- // Add a new tab with a blank page so we can better control the real page load and the offline state
- browser = BrowserApp.addTab("about:blank", { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
-
- SimpleTest.registerCleanupFunction(function() {
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
- Services.prefs.setIntPref("network.proxy.type", proxyPrefValue);
- Services.io.offline = false;
- });
-
- // Go offline, expecting the error page.
- yield promiseOffline(true);
-
- // Load our test web page
- browser.loadURI(kUniqueURI.spec, null, null)
- yield promiseBrowserEvent(browser, "DOMContentLoaded");
-
- // This is an error page.
- is(browser.contentDocument.documentURI.substring(0, 27), "about:neterror?e=netOffline", "Document URI is the error page.");
-
- // But location bar should show the original request.
- is(browser.contentWindow.location.href, kUniqueURI.spec, "Docshell URI is the original URI.");
-
- Services.prefs.setIntPref("network.proxy.type", proxyPrefValue);
-
- // Go online and try to load the page again
- yield promiseOffline(false);
-
- ok(browser.contentDocument.getElementById("errorTryAgain"), "The error page has got a #errorTryAgain element");
-
- // Click "Try Again" button to start the page load
- browser.contentDocument.getElementById("errorTryAgain").click();
- yield promiseBrowserEvent(browser, "DOMContentLoaded");
-
- // This is not an error page.
- is(browser.contentDocument.documentURI, kUniqueURI.spec, "Document URI is not the offline-error page, but the original URI.");
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1089190">Mozilla Bug 1089190</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testOfflinePage</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_reader_view.html b/mobile/android/tests/browser/chrome/test_reader_view.html
deleted file mode 100644
index 05b74e164..000000000
--- a/mobile/android/tests/browser/chrome/test_reader_view.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1158885
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1158885</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript;version=1.7">
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/Services.jsm");
-
- add_task(function* test_reader_view_visibility() {
- let gWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = gWin.BrowserApp;
-
- let url = "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/basic_article.html";
- let browser = BrowserApp.addTab("about:reader?url=" + url).browser;
-
- SimpleTest.registerCleanupFunction(function() {
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
- });
-
- yield promiseBrowserEvent(browser, "load");
-
- let doc = browser.contentDocument;
- let title = doc.getElementById("reader-title");
-
- // We need to wait for reader content to appear because AboutReader.jsm
- // asynchronously fetches the content after about:reader loads.
- yield promiseNotification("AboutReader:Ready");
- is(title.textContent, "Article title", "found expected content");
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1158885">Mozilla Bug 1158885</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testReaderView</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_resource_substitutions.html b/mobile/android/tests/browser/chrome/test_resource_substitutions.html
deleted file mode 100644
index 709ac112e..000000000
--- a/mobile/android/tests/browser/chrome/test_resource_substitutions.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=948465
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 948465</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/Promise.jsm"); /*global Promise */
- Cu.import("resource://gre/modules/Services.jsm"); /*global Services */
- Cu.import("resource://gre/modules/NetUtil.jsm"); /*global NetUtil */
-
- function readChannel(url) {
- let deferred = Promise.defer();
-
- let channel = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
-
- channel.contentType = "text/plain";
-
- NetUtil.asyncFetch(channel, function(inputStream, status) {
- if (!Components.isSuccessCode(status)) {
- deferred.reject();
- return;
- }
-
- let content = NetUtil.readInputStreamToString(inputStream, inputStream.available());
- deferred.resolve(content);
- });
-
- return deferred.promise;
- }
-
- add_task(function* () {
- let protocolHandler = Services.io
- .getProtocolHandler("resource")
- .QueryInterface(Ci.nsIResProtocolHandler);
-
- ok(protocolHandler.hasSubstitution("android"));
-
- // This can be any file that we know exists in the root of every APK.
- let packageName = yield readChannel("resource://android/package-name.txt");
- info(packageName);
-
- // It's difficult to fish ANDROID_PACKAGE_NAME from JavaScript, so we test the
- // following weaker condition.
- let expectedPrefix = "org.mozilla.";
- is(packageName.substring(0, expectedPrefix.length), expectedPrefix);
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=948465">Mozilla Bug 948465</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testResourceSubstitutions</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_restricted_profiles.html b/mobile/android/tests/browser/chrome/test_restricted_profiles.html
deleted file mode 100644
index d699176b5..000000000
--- a/mobile/android/tests/browser/chrome/test_restricted_profiles.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1042715
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1042715</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/ctypes.jsm");
- Cu.import("resource://gre/modules/JNI.jsm");
- Cu.import("resource://gre/modules/Task.jsm");
-
- function test_isUserRestricted() {
- // Make sure the parental controls service is available
- ok("@mozilla.org/parental-controls-service;1" in Cc);
-
- let pc = Cc["@mozilla.org/parental-controls-service;1"].createInstance(Ci.nsIParentalControlsService);
-
- // In an admin profile, like the tests: enabled = false
- // In a restricted profile: enabled = true
- ok(!pc.parentalControlsEnabled);
- ok(!pc.blockFileDownloadsEnabled);
-
- ok(pc.isAllowed(Ci.nsIParentalControlsService.DOWNLOAD));
- ok(pc.isAllowed(Ci.nsIParentalControlsService.INSTALL_EXTENSION));
- ok(pc.isAllowed(Ci.nsIParentalControlsService.INSTALL_APP));
- ok(pc.isAllowed(Ci.nsIParentalControlsService.BROWSE));
- ok(pc.isAllowed(Ci.nsIParentalControlsService.SHARE));
- ok(pc.isAllowed(Ci.nsIParentalControlsService.BOOKMARK));
- ok(pc.isAllowed(Ci.nsIParentalControlsService.INSTALL_EXTENSION));
- ok(pc.isAllowed(Ci.nsIParentalControlsService.MODIFY_ACCOUNTS));
- }
-
- test_isUserRestricted();
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1042715">Mozilla Bug 1042715</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testRestrictedProfiles</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_select_disabled.html b/mobile/android/tests/browser/chrome/test_select_disabled.html
deleted file mode 100644
index d241f60ae..000000000
--- a/mobile/android/tests/browser/chrome/test_select_disabled.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1263589
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1263589</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript;version=1.7">
- "use strict";
-
- const VISIBLE_OPTION_COUNT = 5;
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
- Cu.import("resource://gre/modules/Services.jsm");
- let win = Services.wm.getMostRecentWindow("navigator:browser");
- let SelectHelper = win.SelectHelper;
-
- // Wait until the page has loaded so that we can access the DOM.
- SimpleTest.waitForExplicitFinish();
- window.onload = function () {
- // test options are not incorrectly disabled...
- let isEnabled1 = document.getElementById("is_enabled_1");
- let isEnabled2 = document.getElementById("is_enabled_2");
- ok(!SelectHelper._isDisabledElement(isEnabled1),"input with name=\"disabled\" should not disable options (bug 1263589)");
- ok(!SelectHelper._isDisabledElement(isEnabled2),"<form disabled> is not valid and will have no effect.");
-
- // test options are disabled when expected...
- let isNotEnabled1 = document.getElementById("is_not_enabled_1");
- let isNotEnabled2 = document.getElementById("is_not_enabled_2");
- let isNotEnabled3 = document.getElementById("is_not_enabled_2");
- ok(SelectHelper._isDisabledElement(isNotEnabled1),"<option disabled> is disabled.");
- ok(SelectHelper._isDisabledElement(isNotEnabled2),"<optelement disabled> will have disabled children.");
- ok(SelectHelper._isDisabledElement(isNotEnabled3),"<fieldset disabled> will have disabled children.");
-
- SimpleTest.finish();
- }
-
- </script>
-</head>
-<body>
-
-<p id="display">
-
-<form>
- <!-- This input field is to confused SelectHelper._isDisabledElement(e). See bug 1263589 for details.-->
- <input type="text" id="disabled" name="disabled" value="disabled" disabled="disabled">
-
- <select>
- <option id="is_enabled_1">A</option>
- <option disabled id="is_not_enabled_1">C</option>
- <optgroup disabled>
- <option id="is_not_enabled_2">B</option>
- <option>C</option>
- </optgroup>
- </select>
-
- <fieldset disabled>
- <select>
- <option>F</option>
- <option id="is_not_enabled_3">G</option>
- </select>
- </fieldset>
-</form>
-
-
-<form disabled>
- <!-- "Disabled" is not a valid attribute for <form> and so fields should not be disabled -->
- <select>
- <option id="is_enabled_2">D</option>
- <option>E</option>
- </select>
-</form>
-
-
-</p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-</pre>
-</body>
-</html> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/test_selectoraddtab.html b/mobile/android/tests/browser/chrome/test_selectoraddtab.html
deleted file mode 100644
index b2c4ececa..000000000
--- a/mobile/android/tests/browser/chrome/test_selectoraddtab.html
+++ /dev/null
@@ -1,92 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1216047
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1216047</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript;version=1.7">
-
- "use strict";
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/Services.jsm");
- Cu.import("resource://gre/modules/Messaging.jsm");
- Cu.import("resource://gre/modules/Task.jsm");
-
- // The chrome window
- let chromeWin;
-
- // Track the <browser>s where the tests are happening
- let browserBlank;
- let browserTest;
-
- const kTestPage = "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/basic_article.html";
-
- add_task(function* test_selectOrAdd() {
- chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- SimpleTest.registerCleanupFunction(function() {
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browserBlank));
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browserTest));
- });
-
- // Add a new tab with a blank page
- browserBlank = BrowserApp.addTab("about:blank", { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
-
- // Now, let's force the target browser to be added
- browserTest = BrowserApp.selectOrAddTab(kTestPage, { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
- yield promiseBrowserEvent(browserTest, "DOMContentLoaded");
-
- // Check that basic_article is now selected
- is(BrowserApp.selectedBrowser, browserTest, "Target browser is selected after being added.");
-
- // Switch back to about:blank
- BrowserApp.selectTab(BrowserApp.getTabForBrowser(browserBlank));
- yield promiseTabEvent(BrowserApp.deck, "TabSelect");
-
- // Check that about:blank is selected
- is(BrowserApp.selectedBrowser, browserBlank, "about:blank is selected.");
-
- // Use selectOrAddTab to select the existing tab
- BrowserApp.selectOrAddTab(kTestPage, { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
- yield promiseTabEvent(BrowserApp.deck, "TabSelect");
-
- // Check that basic_article is now selected
- is(BrowserApp.selectedBrowser, browserTest, "Target browser is selected.");
-
- // Switch back to about:blank
- BrowserApp.selectTab(BrowserApp.getTabForBrowser(browserBlank));
- yield promiseTabEvent(BrowserApp.deck, "TabSelect");
-
- // Check that about:blank is selected
- is(BrowserApp.selectedBrowser, browserBlank, "about:blank is selected.");
-
- // Use selectOrAddTab to select the existing tab using the startsWith flag
- BrowserApp.selectOrAddTab(kTestPage, { selected: true, parentId: BrowserApp.selectedTab.id }, { startsWith: kTestPage }).browser;
- yield promiseTabEvent(BrowserApp.deck, "TabSelect");
-
- // Check that basic_article is now selected
- is(BrowserApp.selectedBrowser, browserTest, "Target browser is selected.");
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1216047">Mozilla Bug 1216047</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_session_form_data.html b/mobile/android/tests/browser/chrome/test_session_form_data.html
deleted file mode 100644
index cf09350c7..000000000
--- a/mobile/android/tests/browser/chrome/test_session_form_data.html
+++ /dev/null
@@ -1,274 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=671993
-https://bugzilla.mozilla.org/show_bug.cgi?id=1261225
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bugs 671993, 1261225</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript;version=1.7">
-
-"use strict";
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-
-let gChromeWin;
-let gBrowserApp;
-
-// Waiting for a tab to load or restore can be slow on the emulator.
-SimpleTest.requestLongerTimeout(2);
-
-setup_browser();
-
-function queryElement(contentWindow, data) {
- let frame = contentWindow;
- if (data.hasOwnProperty("frame")) {
- frame = contentWindow.frames[data.frame];
- }
-
- let doc = frame.document;
-
- if (data.hasOwnProperty("id")) {
- return doc.getElementById(data.id);
- }
-
- if (data.hasOwnProperty("selector")) {
- return doc.querySelector(data.selector);
- }
-
- if (data.hasOwnProperty("xpath")) {
- let xptype = Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE;
- return doc.evaluate(data.xpath, doc, null, xptype, null).singleNodeValue;
- }
-
- throw new Error("couldn't query element");
-}
-
-function dispatchUIEvent(input, type) {
- let event = input.ownerDocument.createEvent("UIEvents");
- event.initUIEvent(type, true, true, input.ownerDocument.defaultView, 0);
- input.dispatchEvent(event);
-}
-
-function setInputValue(browser, data) {
- let input = queryElement(browser.contentWindow, data);
- input.value = data.value;
- dispatchUIEvent(input, "input");
-}
-
-function getInputValue(browser, data) {
- let input = queryElement(browser.contentWindow, data);
- return input.value;
-}
-
-let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
-
-function setup_browser() {
- gChromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- gBrowserApp = gChromeWin.BrowserApp;
-}
-
-/**
- * This test ensures that form data collection respects the privacy level as
- * set by the user.
- */
-add_task(function* test_formdata() {
- const URL = "http://example.org/chrome/mobile/android/tests/browser/chrome/session_formdata_sample.html";
-
- const OUTER_VALUE = "browser_formdata_" + Math.random();
- const INNER_VALUE = "browser_formdata_" + Math.random();
-
- // Creates a tab, loads a page with some form fields,
- // modifies their values and closes the tab.
- function createAndRemoveTab() {
- return Task.spawn(function () {
- // Create a new tab.
- let tab = gBrowserApp.addTab(URL);
- let browser = tab.browser;
- yield promiseBrowserEvent(browser, "load");
-
- // Modify form data.
- setInputValue(browser, {id: "txt", value: OUTER_VALUE});
- setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0});
-
- // Remove the tab.
- gBrowserApp.closeTab(tab);
- yield promiseTabEvent(browser, "SSTabCloseProcessed");
- });
- }
-
- yield createAndRemoveTab();
- let state = ss.getClosedTabs(gChromeWin);
- let [{formdata}] = state;
- is(formdata.id.txt, OUTER_VALUE, "outer value is correct");
- is(formdata.children[0].id.txt, INNER_VALUE, "inner value is correct");
-
- // Disable saving data for encrypted sites.
- Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1);
-
- yield createAndRemoveTab();
- state = ss.getClosedTabs(gChromeWin);
- [{formdata}] = state;
- is(formdata.id.txt, OUTER_VALUE, "outer value is correct");
- ok(!formdata.children, "inner value was *not* stored");
-
- // Disable saving data for any site.
- Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2);
-
- yield createAndRemoveTab();
- state = ss.getClosedTabs(gChromeWin);
- [{formdata}] = state;
- ok(!formdata, "form data has *not* been stored");
-
- // Restore the default privacy level.
- Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
-});
-
-/**
- * This test ensures that form data collection restores correctly.
- */
-add_task(function* test_formdata2() {
- const URL = "http://example.org/chrome/mobile/android/tests/browser/chrome/session_formdata_sample.html";
-
- const OUTER_VALUE = "browser_formdata_" + Math.random();
- const INNER_VALUE = "browser_formdata_" + Math.random();
-
- // Creates a tab, loads a page with some form fields,
- // modifies their values and closes the tab.
- function createAndRemoveTab() {
- return Task.spawn(function () {
- // Create a new tab.
- let tab = gBrowserApp.addTab(URL);
- let browser = tab.browser;
- yield promiseBrowserEvent(browser, "load");
-
- // Modify form data.
- setInputValue(browser, {id: "txt", value: OUTER_VALUE});
- setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0});
-
- // Remove the tab.
- gBrowserApp.closeTab(tab);
- yield promiseTabEvent(browser, "SSTabCloseProcessed");
- });
- }
-
- yield createAndRemoveTab();
- let state = ss.getClosedTabs(gChromeWin);
- let [{formdata}] = state;
- is(formdata.id.txt, OUTER_VALUE, "outer value is correct");
- is(formdata.children[0].id.txt, INNER_VALUE, "inner value is correct");
-
- // Restore the closed tab.
- let closedTabData = ss.getClosedTabs(gChromeWin)[0];
- let browser = ss.undoCloseTab(gChromeWin, closedTabData);
- yield promiseBrowserEvent(browser, "load");
-
- // Check the form data.
- is(getInputValue(browser, {id: "txt"}), OUTER_VALUE, "outer value restored correctly");
- is(getInputValue(browser, {id: "txt", frame: 0}), INNER_VALUE, "inner value restored correctly");
-
- // Remove the tab.
- gBrowserApp.closeTab(gBrowserApp.getTabForBrowser(browser));
-});
-
-/**
- * This test ensures that form data collection restores correctly even after
- * navigating to a different page and then returning via hitting back.
- */
-add_task(function* test_formdata_navigation() {
- const URL = "http://example.org/chrome/mobile/android/tests/browser/chrome/session_formdata_sample.html";
- const otherURL = "http://example.org/chrome/mobile/android/tests/browser/chrome/basic_article.html";
-
- const OUTER_VALUE = "browser_formdata_" + Math.random();
- const INNER_VALUE = "browser_formdata_" + Math.random();
-
- // Make sure the bfcache remains enabled during this test,
- // otherwise the inner value will not be restored correctly.
- Services.prefs.setBoolPref("browser.sessionhistory.bfcacheIgnoreMemoryPressure", true);
- Services.prefs.setIntPref("browser.sessionhistory.max_total_viewers", 1);
-
- SimpleTest.registerCleanupFunction(function() {
- // Turn the bfcache memory pressure protection back off once we're finished.
- Services.prefs.clearUserPref("browser.sessionhistory.bfcacheIgnoreMemoryPressure");
- Services.prefs.clearUserPref("browser.sessionhistory.max_total_viewers");
- });
-
- // Creates a tab, loads a page with some form fields, modifies their values,
- // navigates to a different page and back again and closes the tab.
- function createNavigateAndRemoveTab() {
- return Task.spawn(function () {
- // Create a new tab.
- let tab = gBrowserApp.addTab(URL);
- let browser = tab.browser;
- yield promiseBrowserEvent(browser, "load");
-
- // Modify form data.
- setInputValue(browser, {id: "txt", value: OUTER_VALUE});
- setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0});
-
- // Visit a different page.
- gBrowserApp.loadURI(otherURL, browser);
- yield promiseBrowserEvent(browser, "DOMContentLoaded");
- is(browser.currentURI.spec, otherURL, "navigated to a different page");
-
- // Go back.
- is(browser.canGoBack, true, "can go back");
- browser.goBack();
- yield promiseTabEvent(browser, "SSTabDataUpdated");
- is(browser.currentURI.spec, URL, "navigated back to form data page");
-
- // Make sure form data is still present.
- is(getInputValue(browser, {id: "txt"}), OUTER_VALUE, "outer value present after navigation");
- is(getInputValue(browser, {id: "txt", frame: 0}), INNER_VALUE, "inner value present after navigation");
-
- // Remove the tab.
- gBrowserApp.closeTab(tab);
- yield promiseTabEvent(browser, "SSTabCloseProcessed");
- });
- }
-
- yield createNavigateAndRemoveTab();
- let state = ss.getClosedTabs(gChromeWin);
- let [{formdata}] = state;
- is(formdata.id.txt, OUTER_VALUE, "outer value is correct");
- is(formdata.children[0].id.txt, INNER_VALUE, "inner value is correct");
-
- // Restore the closed tab.
- let closedTabData = ss.getClosedTabs(gChromeWin)[0];
- let browser = ss.undoCloseTab(gChromeWin, closedTabData);
- yield promiseBrowserEvent(browser, "load");
-
- // Check the form data.
- is(getInputValue(browser, {id: "txt"}), OUTER_VALUE, "outer value restored correctly");
- is(getInputValue(browser, {id: "txt", frame: 0}), INNER_VALUE, "inner value restored correctly");
-
- // Remove the tab.
- gBrowserApp.closeTab(gBrowserApp.getTabForBrowser(browser));
-});
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=671993">Mozilla Bug 671993</a>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1261225">Mozilla Bug 1261225</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testSessionFormData</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_session_scroll_position.html b/mobile/android/tests/browser/chrome/test_session_scroll_position.html
deleted file mode 100644
index cfbeb5164..000000000
--- a/mobile/android/tests/browser/chrome/test_session_scroll_position.html
+++ /dev/null
@@ -1,310 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=810981
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 810981</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript;version=1.7">
-
- /** Test for Bug 810981 **/
-
- "use strict";
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/XPCOMUtils.jsm");
- Cu.import("resource://gre/modules/Services.jsm");
- Cu.import("resource://gre/modules/Messaging.jsm");
- Cu.import("resource://gre/modules/Task.jsm");
-
- // The chrome window.
- let chromeWin;
-
- // Track the tabs where the tests are happening.
- let tabScroll;
-
- // Use something with enough content to allow for scrolling.
- const URL = "http://example.org/chrome/mobile/android/tests/browser/chrome/basic_article_mobile.html";
- // Something to test the zoom level scaling on rotation with.
- const URL_desktop = "http://example.org/chrome/mobile/android/tests/browser/chrome/basic_article.html";
- // Reader mode URL
- const URL_reader = "about:reader?url=http%3A%2F%2Fexample.org%2Fchrome%2Fmobile%2Fandroid%2Ftests%2Fbrowser%2Fchrome%2Fbasic_article_mobile.html";
-
- function dispatchUIEvent(browser, type) {
- let event = browser.contentDocument.createEvent("UIEvents");
- event.initUIEvent(type, true, false, browser.contentDocument.defaultView, 0);
- browser.dispatchEvent(event);
- }
-
- function setScrollPosition(browser, x, y) {
- browser.contentWindow.scrollTo(x, y);
- dispatchUIEvent(browser, "scroll");
- }
-
- function setZoomLevel(browser, zoom) {
- browser.contentWindow.QueryInterface(
- Ci.nsIInterfaceRequestor).getInterface(
- Ci.nsIDOMWindowUtils).setResolutionAndScaleTo(zoom);
- }
-
- let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
-
- add_task(function* test_sessionStoreScrollPosition() {
- const SCROLL_X = 0;
- const SCROLL_Y = 38;
-
- chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- // Creates a tab, sets a scroll position and closes the tab.
- function createAndRemoveTab() {
- return Task.spawn(function () {
- // Create a new tab.
- tabScroll = BrowserApp.addTab(URL);
- let browser = tabScroll.browser;
- yield promiseBrowserEvent(browser, "pageshow");
-
- // Modify scroll position.
- setScrollPosition(browser, SCROLL_X, SCROLL_Y);
- yield promiseTabEvent(browser, "SSTabScrollCaptured");
-
- // Check that we've actually scrolled.
- let ifreq = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor);
- let utils = ifreq.getInterface(Ci.nsIDOMWindowUtils);
- let scrollX = {}, scrollY = {};
- utils.getScrollXY(false, scrollX, scrollY);
- is(scrollX.value, SCROLL_X, "scrollX set correctly");
- is(scrollY.value, SCROLL_Y, "scrollY set correctly");
-
- // Remove the tab.
- BrowserApp.closeTab(tabScroll);
- yield promiseTabEvent(browser, "SSTabCloseProcessed");
- });
- }
-
- yield createAndRemoveTab();
- let state = ss.getClosedTabs(chromeWin);
- let [{scrolldata}] = state;
- is(scrolldata.scroll, SCROLL_X + "," + SCROLL_Y, "stored scroll position is correct");
-
- // Restore the closed tab.
- let closedTabData = ss.getClosedTabs(chromeWin)[0];
- let browser = ss.undoCloseTab(chromeWin, closedTabData);
- yield promiseBrowserEvent(browser, "pageshow");
-
- // Check the scroll position.
- let ifreq = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor);
- let utils = ifreq.getInterface(Ci.nsIDOMWindowUtils);
- let scrollX = {}, scrollY = {};
- utils.getScrollXY(false, scrollX, scrollY);
- is(scrollX.value, SCROLL_X, "scrollX restored correctly");
- is(scrollY.value, SCROLL_Y, "scrollY restored correctly");
-
- // Remove the tab.
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
- });
-
- add_task(function* test_sessionStoreScrollPositionReaderMode() {
- const SCROLL_X = 0;
- const SCROLL_Y = 44;
-
- chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- // Creates a tab, sets a scroll position and closes the tab.
- function createAndRemoveReaderTab() {
- return Task.spawn(function () {
- // Create a new tab.
- tabScroll = BrowserApp.addTab(URL_reader);
- let browser = tabScroll.browser;
- yield promiseBrowserEvent(browser, "AboutReaderContentReady");
-
- // Modify scroll position.
- setScrollPosition(browser, SCROLL_X, SCROLL_Y);
- yield promiseTabEvent(browser, "SSTabScrollCaptured");
-
- // Check that we've actually scrolled.
- let ifreq = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor);
- let utils = ifreq.getInterface(Ci.nsIDOMWindowUtils);
- let scrollX = {}, scrollY = {};
- utils.getScrollXY(false, scrollX, scrollY);
- is(scrollX.value, SCROLL_X, "scrollX set correctly");
- is(scrollY.value, SCROLL_Y, "scrollY set correctly");
-
- // Remove the tab.
- BrowserApp.closeTab(tabScroll);
- yield promiseTabEvent(browser, "SSTabCloseProcessed");
- });
- }
-
- yield createAndRemoveReaderTab();
- let state = ss.getClosedTabs(chromeWin);
- let [{scrolldata}] = state;
- is(scrolldata.scroll, SCROLL_X + "," + SCROLL_Y, "stored scroll position is correct");
-
- // Restore the closed tab.
- let closedTabData = ss.getClosedTabs(chromeWin)[0];
- let browser = ss.undoCloseTab(chromeWin, closedTabData);
- yield promiseBrowserEvent(browser, "AboutReaderContentReady");
-
- // Check the scroll position.
- let ifreq = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor);
- let utils = ifreq.getInterface(Ci.nsIDOMWindowUtils);
- let scrollX = {}, scrollY = {};
- utils.getScrollXY(false, scrollX, scrollY);
- is(scrollX.value, SCROLL_X, "scrollX restored correctly");
- is(scrollY.value, SCROLL_Y, "scrollY restored correctly");
-
- // Remove the tab.
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
- });
-
- add_task(function* test_sessionStoreZoomLevel() {
- const ZOOM = 4.2;
- const SCROLL_X = 42;
- const SCROLL_Y = 42;
-
- chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- // Creates a tab, sets a scroll position and zoom level and closes the tab.
- function createAndRemoveTab() {
- return Task.spawn(function () {
- // Create a new tab.
- tabScroll = BrowserApp.addTab(URL);
- let browser = tabScroll.browser;
- yield promiseBrowserEvent(browser, "pageshow");
-
- // Modify scroll position and zoom level.
- setZoomLevel(browser, ZOOM);
- setScrollPosition(browser, SCROLL_X, SCROLL_Y);
- yield promiseTabEvent(browser, "SSTabScrollCaptured");
-
- // Check that we've actually scrolled and zoomed.
- let ifreq = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor);
- let utils = ifreq.getInterface(Ci.nsIDOMWindowUtils);
- let scrollX = {}, scrollY = {}, zoom = {};
- utils.getResolution(zoom);
- utils.getScrollXY(false, scrollX, scrollY);
- ok(fuzzyEquals(zoom.value, ZOOM), "zoom set correctly");
- is(scrollX.value, SCROLL_X, "scrollX set correctly");
- is(scrollY.value, SCROLL_Y, "scrollY set correctly");
-
- // Remove the tab.
- BrowserApp.closeTab(tabScroll);
- yield promiseTabEvent(browser, "SSTabCloseProcessed");
- });
- }
-
- yield createAndRemoveTab();
- let state = ss.getClosedTabs(chromeWin);
- let [{scrolldata}] = state;
- is(scrolldata.scroll, SCROLL_X + "," + SCROLL_Y, "stored scroll position is correct");
- ok(fuzzyEquals(scrolldata.zoom.resolution, ZOOM), "stored zoom level is correct");
-
- // Restore the closed tab.
- let closedTabData = ss.getClosedTabs(chromeWin)[0];
- let browser = ss.undoCloseTab(chromeWin, closedTabData);
- yield promiseBrowserEvent(browser, "pageshow");
-
- // Check the scroll position and zoom level.
- let ifreq = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor);
- let utils = ifreq.getInterface(Ci.nsIDOMWindowUtils);
- let scrollX = {}, scrollY = {}, zoom = {};
- utils.getResolution(zoom);
- utils.getScrollXY(false, scrollX, scrollY);
- ok(fuzzyEquals(zoom.value, ZOOM), "zoom restored correctly");
- is(scrollX.value, SCROLL_X, "scrollX restored correctly");
- is(scrollY.value, SCROLL_Y, "scrollY restored correctly");
-
- // Remove the tab.
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
- });
-
- add_task(function* test_sessionStoreZoomLevelRecalc() {
- const ZOOM = 4.2;
- const SCROLL_X = 42;
- const SCROLL_Y = 42;
-
- chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- // Creates a tab, sets a scroll position and zoom level and closes the tab.
- function createAndRemoveTab() {
- return Task.spawn(function () {
- // Create a new tab.
- tabScroll = BrowserApp.addTab(URL_desktop);
- let browser = tabScroll.browser;
- yield promiseBrowserEvent(browser, "pageshow");
-
- // Modify scroll position and zoom level.
- setZoomLevel(browser, ZOOM);
- setScrollPosition(browser, SCROLL_X, SCROLL_Y);
- yield promiseTabEvent(browser, "SSTabScrollCaptured");
-
- // Check that we've actually scrolled and zoomed.
- let ifreq = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor);
- let utils = ifreq.getInterface(Ci.nsIDOMWindowUtils);
- let scrollX = {}, scrollY = {}, zoom = {};
- utils.getResolution(zoom);
- utils.getScrollXY(false, scrollX, scrollY);
- ok(fuzzyEquals(zoom.value, ZOOM), "zoom set correctly");
- is(scrollX.value, SCROLL_X, "scrollX set correctly");
- is(scrollY.value, SCROLL_Y, "scrollY set correctly");
-
- // Remove the tab.
- BrowserApp.closeTab(tabScroll);
- yield promiseTabEvent(browser, "SSTabCloseProcessed");
- });
- }
-
- yield createAndRemoveTab();
- let state = ss.getClosedTabs(chromeWin);
- let [{scrolldata}] = state;
- is(scrolldata.scroll, SCROLL_X + "," + SCROLL_Y, "stored scroll position is correct");
- ok(fuzzyEquals(scrolldata.zoom.resolution, ZOOM), "stored zoom level is correct");
-
- // Pretend the zoom level was originally saved on a rotated device.
- let closedTabData = ss.getClosedTabs(chromeWin)[0];
- let displayWidth = scrolldata.zoom.displaySize.width;
- let displayHeight = scrolldata.zoom.displaySize.height;
- closedTabData.scrolldata.zoom.displaySize.width = displayHeight;
- closedTabData.scrolldata.zoom.displaySize.height = displayWidth;
-
- // Restore the closed tab.
- let browser = ss.undoCloseTab(chromeWin, closedTabData);
- yield promiseBrowserEvent(browser, "pageshow");
-
- // Check the scroll position and zoom level.
- let ifreq = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor);
- let utils = ifreq.getInterface(Ci.nsIDOMWindowUtils);
- let scrollX = {}, scrollY = {}, zoom = {};
- utils.getResolution(zoom);
- utils.getScrollXY(false, scrollX, scrollY);
- ok(fuzzyEquals(zoom.value, ZOOM * displayWidth / displayHeight), "recalculated zoom restored correctly");
- is(scrollX.value, SCROLL_X, "scrollX restored correctly");
- is(scrollY.value, SCROLL_Y, "scrollY restored correctly");
-
- // Remove the tab.
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=810981">Mozilla Bug 810981</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_session_zombification.html b/mobile/android/tests/browser/chrome/test_session_zombification.html
deleted file mode 100644
index eba255ff6..000000000
--- a/mobile/android/tests/browser/chrome/test_session_zombification.html
+++ /dev/null
@@ -1,185 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1044556
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1044556</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="head.js"></script>
- <script type="application/javascript">
-
- /** Test for Bug 1044556 **/
-
- "use strict";
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/XPCOMUtils.jsm");
- Cu.import("resource://gre/modules/Services.jsm");
- Cu.import("resource://gre/modules/Messaging.jsm");
- Cu.import("resource://gre/modules/Task.jsm");
-
- // Import the MemoryObserver
- Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
- XPCOMUtils.defineLazyGetter(this, "MemoryObserver", function() {
- let sandbox = {};
- Services.scriptloader.loadSubScript("chrome://browser/content/MemoryObserver.js", sandbox);
- return sandbox["MemoryObserver"];
- });
-
- // The chrome window
- let chromeWin;
-
- // Track the tabs where the tests are happening
- let tabBlank;
- let tabTest;
-
- const url1 = "data:text/html;charset=utf-8,It%20was%20a%20dark%20and%20stormy%20night.";
- const url2 = "data:text/html;charset=utf-8,Suddenly%2C%20a%20tab%20was%20zombified.";
-
- add_task(function* test_sessionStoreZombify() {
- chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- SimpleTest.registerCleanupFunction(function() {
- BrowserApp.closeTab(tabBlank);
- BrowserApp.closeTab(tabTest);
- });
-
- // Add a new tab with some content
- tabTest = BrowserApp.addTab(url1 , { selected: true, parentId: BrowserApp.selectedTab.id });
- yield promiseBrowserEvent(tabTest.browser, "DOMContentLoaded");
-
- // Add a new tab with a blank page
- tabBlank = BrowserApp.addTab("about:blank", { selected: true, parentId: BrowserApp.selectedTab.id });
- is(BrowserApp.selectedTab, tabBlank, "Test tab is in background.");
-
- // Zombify the backgrounded test tab
- MemoryObserver.zombify(tabTest);
-
- // Check that the test tab is actually zombified
- ok(tabTest.browser.__SS_restore, "Test tab is set for delay loading.");
-
- // Switch back to the test tab and wait for it to reload
- BrowserApp.selectTab(tabTest);
- yield promiseBrowserEvent(tabTest.browser, "DOMContentLoaded");
-
- // Check that the test tab has loaded the correct url
- is(tabTest.browser.currentURI.spec, url1, "Test tab is showing the first URL.");
-
- // Navigate to some other content
- BrowserApp.loadURI(url2, tabTest.browser);
- yield promiseBrowserEvent(tabTest.browser, "DOMContentLoaded");
- is(tabTest.browser.currentURI.spec, url2, "Test tab is showing the second URL.");
-
- // Switch to the other tab
- BrowserApp.selectTab(tabBlank);
- yield promiseTabEvent(BrowserApp.deck, "TabSelect");
- is(BrowserApp.selectedTab, tabBlank, "Test tab is in background.");
-
- // Zombify the backgrounded test tab again
- MemoryObserver.zombify(tabTest);
-
- // Check that the test tab is actually zombified
- ok(tabTest.browser.__SS_restore, "Test tab is set for delay loading.");
-
- // Switch back to the test tab and wait for it to reload
- BrowserApp.selectTab(tabTest);
- yield promiseBrowserEvent(tabTest.browser, "DOMContentLoaded");
-
- // Check that the test tab has loaded the correct url
- is(tabTest.browser.currentURI.spec, url2, "Test tab is showing the second URL.");
- });
-
- add_task(function* test_sessionStoreKeepAsZombie() {
- chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
- let observerService = Services.obs;
-
- SimpleTest.registerCleanupFunction(function() {
- BrowserApp.closeTab(tabBlank);
- BrowserApp.closeTab(tabTest);
- });
-
- // Add a new tab with some content
- tabTest = BrowserApp.addTab(url1 , { selected: true, parentId: BrowserApp.selectedTab.id });
- yield promiseBrowserEvent(tabTest.browser, "DOMContentLoaded");
-
- // Add a new tab with a blank page
- tabBlank = BrowserApp.addTab("about:blank", { selected: true, parentId: BrowserApp.selectedTab.id });
- yield promiseTabEvent(BrowserApp.deck, "TabSelect");
- is(BrowserApp.selectedTab, tabBlank, "Test tab is in background.");
-
- // Zombify the backgrounded test tab
- MemoryObserver.zombify(tabTest);
-
- // Check that the test tab is actually zombified
- ok(tabTest.browser.__SS_restore, "Test tab is set for delay loading.");
- is(tabTest.browser.currentURI.spec, "about:blank", "Test tab is zombified.");
-
- // Tell the session store that it shouldn't restore that tab on selecting
- observerService.notifyObservers(null, "Tab:KeepZombified", tabTest.id);
-
- // Switch back to the test tab and check that it remains zombified
- BrowserApp.selectTab(tabTest);
- yield promiseTabEvent(BrowserApp.deck, "TabSelect");
- is(BrowserApp.selectedTab, tabTest, "Test tab is selected.");
- ok(tabTest.browser.__SS_restore, "Test tab is still set for delay loading.");
-
- // Switch to the other tab and back again
- BrowserApp.selectTab(tabBlank);
- yield promiseTabEvent(BrowserApp.deck, "TabSelect");
- is(BrowserApp.selectedTab, tabBlank, "Test tab is in background.");
- BrowserApp.selectTab(tabTest);
-
- // "Tab:KeepZombified should be good for one TabSelect only
- yield promiseBrowserEvent(tabTest.browser, "DOMContentLoaded");
- is(BrowserApp.selectedTab, tabTest, "Test tab is selected.");
-
- // Check that the test tab is no longer a zombie and has loaded the correct url
- ok(!tabTest.browser.__SS_restore, "Test tab is no longer set for delay loading.");
- is(tabTest.browser.currentURI.spec, url1, "Test tab is showing the test URL.");
-
- // Zombify the test tab again
- BrowserApp.selectTab(tabBlank);
- yield promiseTabEvent(BrowserApp.deck, "TabSelect");
- is(BrowserApp.selectedTab, tabBlank, "Test tab is in background.");
- MemoryObserver.zombify(tabTest);
- ok(tabTest.browser.__SS_restore, "Test tab is set for delay loading.");
- is(tabTest.browser.currentURI.spec, "about:blank", "Test tab is zombified.");
-
- // Tell the session store that it shouldn't restore that tab on selecting
- observerService.notifyObservers(null, "Tab:KeepZombified", tabTest.id);
-
- // Switch back to the test tab and check that it remains zombified
- BrowserApp.selectTab(tabTest);
- yield promiseTabEvent(BrowserApp.deck, "TabSelect");
- is(BrowserApp.selectedTab, tabTest, "Test tab is selected.");
- ok(tabTest.browser.__SS_restore, "Test tab is still set for delay loading.");
-
- // Fake an "application-foreground" notification
- observerService.notifyObservers(null, "application-foreground", null);
-
- // The test tab should now start reloading
- yield promiseBrowserEvent(tabTest.browser, "DOMContentLoaded");
- ok(!tabTest.browser.__SS_restore, "Test tab is no longer set for delay loading.");
- is(tabTest.browser.currentURI.spec, url1, "Test tab is showing the test URL.");
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1044556">Mozilla Bug 1044556</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_shared_preferences.html b/mobile/android/tests/browser/chrome/test_shared_preferences.html
deleted file mode 100644
index b1ed69e66..000000000
--- a/mobile/android/tests/browser/chrome/test_shared_preferences.html
+++ /dev/null
@@ -1,255 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=866271
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 866271</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- Components.utils.import("resource://gre/modules/SharedPreferences.jsm");
- Components.utils.import("resource://gre/modules/Promise.jsm");
- Components.utils.import("resource://gre/modules/Task.jsm");
-
- let _observerId = 0;
-
- function makeObserver() {
- let deferred = Promise.defer();
-
- let ret = {
- id: _observerId++,
- count: 0,
- promise: deferred.promise,
- observe: function (subject, topic, data) {
- ret.count += 1;
- let msg = { subject: subject,
- topic: topic,
- data: data };
- deferred.resolve(msg);
- },
- };
-
- return ret;
- };
-
- add_task(function* test_get_set() {
- let branch = SharedPreferences.forAndroid("test");
-
- branch.setBoolPref("boolKey", true);
- branch.setCharPref("charKey", "string value");
- branch.setIntPref("intKey", 1000);
-
- is(branch.getBoolPref("boolKey"), true);
- is(branch.getCharPref("charKey"), "string value");
- is(branch.getIntPref("intKey"), 1000);
-
- branch.setBoolPref("boolKey", false);
- branch.setCharPref("charKey", "different string value");
- branch.setIntPref("intKey", -2000);
-
- is(branch.getBoolPref("boolKey"), false);
- is(branch.getCharPref("charKey"), "different string value");
- is(branch.getIntPref("intKey"), -2000);
-
- is(typeof(branch.getBoolPref("boolKey")), "boolean");
- is(typeof(branch.getCharPref("charKey")), "string");
- is(typeof(branch.getIntPref("intKey")), "number");
- });
-
- add_task(function* test_default() {
- let branch = SharedPreferences.forAndroid();
-
- branch.setBoolPref("boolKey", true);
- branch.setCharPref("charKey", "string value");
- branch.setIntPref("intKey", 1000);
-
- is(branch.getBoolPref("boolKey"), true);
- is(branch.getCharPref("charKey"), "string value");
- is(branch.getIntPref("intKey"), 1000);
-
- branch.setBoolPref("boolKey", false);
- branch.setCharPref("charKey", "different string value");
- branch.setIntPref("intKey", -2000);
-
- is(branch.getBoolPref("boolKey"), false);
- is(branch.getCharPref("charKey"), "different string value");
- is(branch.getIntPref("intKey"), -2000);
-
- is(typeof(branch.getBoolPref("boolKey")), "boolean");
- is(typeof(branch.getCharPref("charKey")), "string");
- is(typeof(branch.getIntPref("intKey")), "number");
- });
-
- add_task(function* test_multiple_branches() {
- let branch1 = SharedPreferences.forAndroid("test1");
- let branch2 = SharedPreferences.forAndroid("test2");
-
- branch1.setBoolPref("boolKey", true);
- branch2.setBoolPref("boolKey", false);
-
- is(branch1.getBoolPref("boolKey"), true);
- is(branch2.getBoolPref("boolKey"), false);
-
- branch1.setCharPref("charKey", "a value");
- branch2.setCharPref("charKey", "a different value");
-
- is(branch1.getCharPref("charKey"), "a value");
- is(branch2.getCharPref("charKey"), "a different value");
- });
-
- add_task(function* test_add_remove_observer() {
- let branch = SharedPreferences.forAndroid("test");
-
- branch.setBoolPref("boolKey", false);
- is(branch.getBoolPref("boolKey"), false);
-
- let obs1 = makeObserver();
- branch.addObserver("boolKey", obs1);
-
- try {
- branch.setBoolPref("boolKey", true);
- is(branch.getBoolPref("boolKey"), true);
-
- let value1 = yield obs1.promise;
- is(obs1.count, 1);
-
- is(value1.subject, obs1);
- is(value1.topic, "boolKey");
- is(typeof(value1.data), "boolean");
- is(value1.data, true);
- } finally {
- branch.removeObserver("boolKey", obs1);
- }
-
- // Make sure the original observer is really gone, or as close as
- // we: install a second observer, wait for it to be notified, and
- // then verify the original observer was *not* notified. This
- // depends, of course, on the order that observers are notified, but
- // is better than nothing.
-
- let obs2 = makeObserver();
- branch.addObserver("boolKey", obs2);
-
- try {
- branch.setBoolPref("boolKey", false);
- is(branch.getBoolPref("boolKey"), false);
-
- let value2 = yield obs2.promise;
- is(obs2.count, 1);
-
- is(value2.subject, obs2);
- is(value2.topic, "boolKey");
- is(typeof(value2.data), "boolean");
- is(value2.data, false);
-
- // Original observer count is preserved.
- is(obs1.count, 1);
- } finally {
- branch.removeObserver("boolKey", obs2);
- }
- });
-
- add_task(function* test_observer_ignores() {
- let branch = SharedPreferences.forAndroid("test");
-
- branch.setCharPref("charKey", "first value");
- is(branch.getCharPref("charKey"), "first value");
-
- let obs = makeObserver();
- branch.addObserver("charKey", obs);
-
- try {
- // These should all be ignored.
- branch.setBoolPref("boolKey", true);
- branch.setBoolPref("boolKey", false);
- branch.setIntPref("intKey", -3000);
- branch.setIntPref("intKey", 4000);
-
- branch.setCharPref("charKey", "a value");
- let value = yield obs.promise;
-
- // Observer should have been notified exactly once.
- is(obs.count, 1);
-
- is(value.subject, obs);
- is(value.topic, "charKey");
- is(typeof(value.data), "string");
- is(value.data, "a value");
- } finally {
- branch.removeObserver("charKey", obs);
- }
- });
-
- add_task(function* test_observer_ignores_branches() {
- let branch = SharedPreferences.forAndroid("test");
-
- branch.setCharPref("charKey", "first value");
- is(branch.getCharPref("charKey"), "first value");
-
- let obs = makeObserver();
- branch.addObserver("charKey", obs);
-
- try {
- // These should all be ignored.
- let branch2 = SharedPreferences.forAndroid("test2");
- branch2.setCharPref("charKey", "a wrong value");
- let branch3 = SharedPreferences.forAndroid("test.2");
- branch3.setCharPref("charKey", "a different wrong value");
-
- // This should not be ignored.
- branch.setCharPref("charKey", "a value");
-
- let value = yield obs.promise;
-
- // Observer should have been notified exactly once.
- is(obs.count, 1);
-
- is(value.subject, obs);
- is(value.topic, "charKey");
- is(typeof(value.data), "string");
- is(value.data, "a value");
- } finally {
- branch.removeObserver("charKey", obs);
- }
- });
-
- add_task(function* test_scopes() {
- let forApp = SharedPreferences.forApp();
- let forProfile = SharedPreferences.forProfile();
- let forProfileName = SharedPreferences.forProfileName("testProfile");
- let forAndroidDefault = SharedPreferences.forAndroid();
- let forAndroidBranch = SharedPreferences.forAndroid("testBranch");
-
- forApp.setCharPref("charKey", "forApp");
- forProfile.setCharPref("charKey", "forProfile");
- forProfileName.setCharPref("charKey", "forProfileName");
- forAndroidDefault.setCharPref("charKey", "forAndroidDefault");
- forAndroidBranch.setCharPref("charKey", "forAndroidBranch");
-
- is(forApp.getCharPref("charKey"), "forApp");
- is(forProfile.getCharPref("charKey"), "forProfile");
- is(forProfileName.getCharPref("charKey"), "forProfileName");
- is(forAndroidDefault.getCharPref("charKey"), "forAndroidDefault");
- is(forAndroidBranch.getCharPref("charKey"), "forAndroidBranch");
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=866271">Mozilla Bug 866271</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testSharedPreferences</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_simple_discovery.html b/mobile/android/tests/browser/chrome/test_simple_discovery.html
deleted file mode 100644
index a8d84cfe5..000000000
--- a/mobile/android/tests/browser/chrome/test_simple_discovery.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=938571
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 938571</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- "use strict";
-
- /*globals SimpleServiceDiscovery */
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/Services.jsm");
- Cu.import("resource://gre/modules/SimpleServiceDiscovery.jsm");
-
- function discovery_observer(subject, topic, data) {
- dump("Observer: " + data);
-
- let service = SimpleServiceDiscovery.findServiceForID(data);
- if (!service)
- return;
-
- is(service.friendlyName, "Pretend Device");
- is(service.uuid, "uuid:5ec9ff92-e8b2-4a94-a72c-76b34e6dabb1");
- is(service.manufacturer, "Copy Cat Inc.");
- is(service.modelName, "Eureka Dongle");
-
- SimpleTest.finish();
- };
-
- var testDevice = {
- id: "test:dummy",
- target: "test:service",
- factory: function(service) { /* dummy */ },
- types: ["video/mp4"],
- extensions: ["mp4"]
- };
-
- function test_default() {
- SimpleTest.registerCleanupFunction(function cleanup() {
- SimpleServiceDiscovery.unregisterDevice(testDevice);
- Services.obs.removeObserver(discovery_observer, "ssdp-service-found");
- });
-
- Services.obs.addObserver(discovery_observer, "ssdp-service-found", false);
-
- // We need to register a device or processService will ignore us
- SimpleServiceDiscovery.registerDevice(testDevice);
-
- // Create a pretend service
- let service = {
- location: "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/simpleservice.xml",
- target: "test:service"
- };
-
- dump("Force a detailed ping from a pretend service");
-
- // Poke the service directly to get the discovery to happen
- SimpleServiceDiscovery._processService(service);
- }
-
- SimpleTest.waitForExplicitFinish();
- test_default();
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=938571">Mozilla Bug 938571</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testSimpleDiscovery</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_video_discovery.html b/mobile/android/tests/browser/chrome/test_video_discovery.html
deleted file mode 100644
index f6fb60bbe..000000000
--- a/mobile/android/tests/browser/chrome/test_video_discovery.html
+++ /dev/null
@@ -1,154 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=953381
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 953381</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- "use strict";
-
- /*globals SimpleServiceDiscovery */
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
- Cu.import("resource://gre/modules/Services.jsm");
- Cu.import("resource://gre/modules/SimpleServiceDiscovery.jsm");
-
- // The chrome window
- let chromeWin;
-
- // Track the <browser> where the tests are happening
- let browser;
-
- function middle(element) {
- let rect = element.getBoundingClientRect();
- let x = (rect.right - rect.left) / 2 + rect.left;
- let y = (rect.bottom - rect.top) / 2 + rect.top;
- return [x, y];
- }
-
- // We must register a device and make a "mock" service for the device
- var testDevice = {
- id: "test:dummy",
- target: "test:service",
- factory: function(service) { /* dummy */ },
- types: ["video/mp4", "video/webm"],
- extensions: ["mp4", "webm"]
- };
-
- function setup_browser() {
- chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- SimpleTest.registerCleanupFunction(function cleanup() {
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
- SimpleServiceDiscovery.unregisterDevice(testDevice);
- });
-
- // We need to register a device or processService will ignore us
- SimpleServiceDiscovery.registerDevice(testDevice);
-
- // Create a pretend service
- let service = {
- location: "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/simpleservice.xml",
- target: "test:service"
- };
-
- dump("Force a detailed ping from a pretend service");
-
- // Poke the service directly to get the discovery to happen
- SimpleServiceDiscovery._processService(service);
-
- // Load our test web page with <video> elements
- let url = "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/video_discovery.html";
- browser = BrowserApp.addTab(url, { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
- browser.addEventListener("load", function startTests(event) {
- browser.removeEventListener("load", startTests, true);
- Services.tm.mainThread.dispatch(test_video, Ci.nsIThread.DISPATCH_NORMAL);
- }, true);
- }
-
- let videoDiscoveryTests = [
- { id: "simple-mp4", source: "http://mochi.test:8888/simple.mp4", poster: "http://mochi.test:8888/simple.png", text: "simple video with mp4 src" },
- { id: "simple-fail", pass: false, text: "simple video with no mp4 src" },
- { id: "with-sources-mp4", source: "http://mochi.test:8888/simple.mp4", text: "video with mp4 extension source child" },
- { id: "with-sources-webm", source: "http://mochi.test:8888/simple.webm", text: "video with webm extension source child" },
- { id: "with-sources-fail", pass: false, text: "video with no mp4 extension source child" },
- { id: "with-sources-mimetype-mp4", source: "http://mochi.test:8888/simple-video-mp4", text: "video with mp4 mimetype source child" },
- { id: "with-sources-mimetype-webm", source: "http://mochi.test:8888/simple-video-webm", text: "video with webm mimetype source child" },
- { id: "simple-fetch-pass", source: "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/video_discovery.sjs?type=video/mp4", text: "simple video with mp4 mimetype fetched from server" },
- { id: "simple-fetch-fail", pass: false, text: "simple video with non-video mimetype fetched from server" },
- { id: "video-overlay", source: "http://mochi.test:8888/simple.mp4", text: "div overlay covering a simple video with mp4 src" }
- ];
-
- let expectedTests = videoDiscoveryTests.length;
-
- function execute_video_test(test) {
- let element = browser.contentDocument.getElementById(test.id);
- if (element) {
- let [x, y] = middle(element);
- dump("Starting to getVideo");
- chromeWin.CastingApps.getVideo(element, x, y, (video) => {
- dump("Completed getVideo");
- if (video) {
- dump("video source: " + video.source);
-
- let matchPoster = (test.poster == video.poster);
- let matchSource = (test.source == video.source);
- ok(matchPoster && matchSource && test.pass, test.text);
- } else {
- ok(!test.pass, test.text);
- }
- expectedTests--;
- if (expectedTests == 0) {
- SimpleTest.finish();
- }
- });
- } else {
- ok(false, "test element not found: [" + test.id + "]");
- SimpleTest.finish();
- }
- }
-
- function test_video() {
- let videoTest;
- while ((videoTest = videoDiscoveryTests.shift())) {
- if (!("poster" in videoTest)) {
- videoTest.poster = "";
- }
- if (!("pass" in videoTest)) {
- videoTest.pass = true;
- }
- execute_video_test(videoTest);
- }
- }
-
- SimpleTest.waitForExplicitFinish();
-
- // On debug runs, 10 assertions typically observed; 5 each of:
- // - ASSERTION: cancel with non-failure status code: 'NS_FAILED(status)'
- // - ASSERTION: OnDataAvailable implementation consumed no data: 'Error'
- SimpleTest.expectAssertions(0,10);
- setup_browser();
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=953381">Mozilla Bug 953381</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testVideoDiscovery</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/test_web_channel.html b/mobile/android/tests/browser/chrome/test_web_channel.html
deleted file mode 100644
index 3eeb5b527..000000000
--- a/mobile/android/tests/browser/chrome/test_web_channel.html
+++ /dev/null
@@ -1,121 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1174458
-Migrated from Robocop: https://bugzilla.mozilla.org/show_bug.cgi?id=1184186
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1174458</title>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript;version=1.7">
-
- const { classes: Cc, interfaces: Ci, utils: Cu } = Components; /*global Components */
-
- Cu.import("resource://gre/modules/Promise.jsm"); /*global Promise */
- Cu.import("resource://gre/modules/Services.jsm"); /*global Services */
- Cu.import("resource://gre/modules/XPCOMUtils.jsm"); /*global XPCOMUtils */
- Cu.import("resource://gre/modules/Task.jsm"); /*global Task */
- XPCOMUtils.defineLazyModuleGetter(this, "WebChannel",
- "resource://gre/modules/WebChannel.jsm"); /*global WebChannel */
-
- const HTTP_PATH = "http://mochi.test:8888";
- const HTTP_ENDPOINT = "/chrome/mobile/android/tests/browser/chrome/web_channel.html";
-
- const gChromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = gChromeWin.BrowserApp;
-
- // TODO: consider if we want to run the original test in browser-chrome instead
-
- // Keep this synced with /browser/base/content/test/general/browser_web_channel.js
- // as much as possible. (We only have this since we can't run browser chrome
- // tests on Android. Yet?)
- let gTests = [
- {
- desc: "WebChannel generic message",
- run: function* () {
- return new Promise(function(resolve, reject) {
- let tab;
- let channel = new WebChannel("generic", Services.io.newURI(HTTP_PATH, null, null));
- channel.listen(function (id, message, target) {
- is(id, "generic");
- is(message.something.nested, "hello");
- channel.stopListening();
- BrowserApp.closeTab(tab);
- resolve();
- });
-
- tab = BrowserApp.addTab(HTTP_PATH + HTTP_ENDPOINT + "?generic");
- });
- }
- },
- {
- desc: "WebChannel two way communication",
- run: function* () {
- return new Promise(function(resolve, reject) {
- let tab;
- let channel = new WebChannel("twoway", Services.io.newURI(HTTP_PATH, null, null));
-
- channel.listen(function (id, message, sender) {
- is(id, "twoway");
- ok(message.command);
-
- if (message.command === "one") {
- channel.send({ data: { nested: true } }, sender);
- }
-
- if (message.command === "two") {
- is(message.detail.data.nested, true);
- channel.stopListening();
- BrowserApp.closeTab(tab);
- resolve();
- }
- });
-
- tab = BrowserApp.addTab(HTTP_PATH + HTTP_ENDPOINT + "?twoway");
- });
- }
- },
- {
- desc: "WebChannel multichannel",
- run: function* () {
- return new Promise(function(resolve, reject) {
- let tab;
- let channel = new WebChannel("multichannel", Services.io.newURI(HTTP_PATH, null, null));
-
- channel.listen(function (id, message, sender) {
- is(id, "multichannel");
- BrowserApp.closeTab(tab);
- resolve();
- });
-
- tab = BrowserApp.addTab(HTTP_PATH + HTTP_ENDPOINT + "?multichannel");
- });
- }
- }
- ]; // gTests
-
- add_task(function* test() {
- for (let test of gTests) {
- info("Running: " + test.desc);
- yield test.run();
- }
- });
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1174458">Mozilla Bug 1174458</a>
-<br>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1184186">Migrated from Robocop testWebChannel</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/163.wrating.com/a.gif@a=&c=860010-0503010000 b/mobile/android/tests/browser/chrome/tp5/163.com/163.wrating.com/a.gif@a=&c=860010-0503010000
deleted file mode 100755
index 35d42e808..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/163.wrating.com/a.gif@a=&c=860010-0503010000
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/163.wrating.com/a1.js b/mobile/android/tests/browser/chrome/tp5/163.com/163.wrating.com/a1.js
deleted file mode 100755
index 945926770..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/163.wrating.com/a1.js
+++ /dev/null
@@ -1 +0,0 @@
-var vjAcc="";var wrUrl="httpdisabled://c.wrating.com/";var wrSv=0;function vjTrack(C){var B=vjValidateTrack();if(B===false){return }var A=wrUrl+"a.gif"+vjGetTrackImgUrl(C);void('<div style="display:none"><img src="'+A+'" id="wrTagImage" width="1" height="1"/></div>');vjSurveyCheck()}function vjEventTrack(D){var C=vjValidateTrack();if(C===false){return }var B=wrUrl+"a.gif"+vjGetTrackImgUrl(D);var A=new Image();A.src=B;A.onloaddisabled=function(){}}function vjValidateTrack(){if(document.location.protocol=="file:"){return false}if(vjAcc==""){return false}else{if(wrUrl.substr(wrUrl.length-1,1)!="/"){wrUrl+="/"}}return true}function vjGetTrackImgUrl(S){var M=0;var N="expires=Fri, 1 Jan 2038 00:00:00 GMT;";var T=document.location;var P=document.referrer.toString();var D;var H=vjGetDomainFromUrl(T);var K;var V;var Y="";var L=vjFlash();var G="";var Z="";var J="";var O=navigator.appName+" "+navigator.appVersion;var F=new Date();var X=F.getTimezoneOffset()/-60;var A=0;var U="";var R="";if(typeof (H[1])!="undefined"){V=H[1]}else{if(typeof (H[0])!="undefined"){V=H[0]}}if(P!=""){Y=vjGetKeyword(P)}else{if((O.indexOf("MSIE")>=0)&&(parseInt(O.substr(O.indexOf("MSIE")+5),4)>=5)&&(O.indexOf("Mac")==-1)&&(navigator.userAgent.indexOf("Opera")==-1)){try{document.documentElement.addBehavior("#default#homePage");if(document.documentElement.isHomePage(location.href)){P="ishomepage"}}catch(W){}}}if(navigator.cookieEnabled){M=1}if(self.screen){G=screen.width+"x"+screen.height+"x"+screen.colorDepth}else{if(self.java){var Q=java.awt.Toolkit.getDefaultToolkit().getScreenSize();G=Q.width+"x"+Q.height+"x0"}}if(navigator.language){Z=navigator.language.toLowerCase()}else{if(navigator.browserLanguage){Z=navigator.browserLanguage.toLowerCase()}else{Z="-"}}if(navigator.javaEnabled()){A=1}if(M==1){D=document.cookie;if(D.indexOf("vjuids=")<0){K=vjVisitorID();document.cookie="vjuids="+escape(K)+";"+N+";domain="+V+";path=/;"}else{K=vjGetCookie("vjuids")}if(D.indexOf("vjlast=")<0){U="30";var E=vjGetTimestamp(F.getTime()).toString();R=E+"."+E+".30"}else{var a=vjGetCookie("vjlast");var C=a.split(".");var B="";if(typeof (C[0])!="undefined"){R=C[0].toString()}else{R=vjGetTimestamp(F.getTime()).toString()}if(typeof (C[1])!="undefined"){var I=new Date(parseInt(C[1])*1000);if(I.toDateString()!=F.toDateString()){R+="."+vjGetTimestamp(F.getTime()).toString();if(parseInt(vjGetTimestamp(F.getTime())-parseInt(C[1]))/86400>30){U="2"}else{U="1"}if(typeof (C[2])!="undefined"){U+=C[2].substr(0,1)}else{U+="0"}}else{R+="."+C[1].toString();if(typeof (C[2])!="undefined"){U+=C[2]}else{U="10"}}}else{R+="."+vjGetTimestamp(F.getTime()).toString();if(typeof (C[2])!="undefined"){U+=C[2]}else{U="10"}}R+="."+U}document.cookie="vjlast="+R+";"+N+";domain="+V+";path=/;"}J="?a="+F.getTime().toString(16)+"&t=&i="+escape(K);J+="&b="+escape(T)+"&c="+vjAcc;J+="&s="+G+"&l="+Z;J+="&z="+X+"&j="+A+"&f="+escape(L);if(P!=""){J+="&r="+escape(P)+"&kw="+Y}J+="&ut="+U+"&n=";if(typeof (S)=="undefined"){J+="&js="}else{J+="&js="+escape(S)}J+="&ck="+M;return J}function vjGetTimestamp(A){return Math.round(A/1000)}function vjGetKeyword(C){var A=[["baidu","wd"],["baidu","q1"],["google","q"],["google","as_q"],["yahoo","p"],["msn","q"],["live","q"],["sogou","query"],["youdao","q"],["soso","w"],["zhongsou","w"],["zhongsou","w1"]];var B=vjGetDomainFromUrl(C.toString().toLowerCase());var D=-1;var E="";if(typeof (B[0])=="undefined"){return""}for(i=0;i<A.length;i++){if(B[0].indexOf("."+A[i][0]+".")>=0){D=-1;D=C.indexOf("&"+A[i][1]+"=");if(D<0){D=C.indexOf("?"+A[i][1]+"=")}if(D>=0){E=C.substr(D+A[i][1].length+2,C.length-(D+A[i][1].length+2));D=E.indexOf("&");if(D>=0){E=E.substr(0,D)}if(E==""){return""}else{return A[i][0]+"|"+E}}}}return""}function vjGetDomainFromUrl(E){if(E==""){return false}E=E.toString().toLowerCase();var F=[];var C=E.indexOf("//")+2;var B=E.substr(C,E.length-C);var A=B.indexOf("/");if(A>=0){F[0]=B.substr(0,A)}else{F[0]=B}var D=F[0].match(/[^.]+\.(com.cn|net.cn|gov.cn|cn|com|net|org|gov|cc|biz|info)+$/);if(D){if(typeof (D[0])!="undefined"){F[1]=D[0]}}return F}function vjVisitorID(){var A=vjHash(document.location+document.cookie+document.referrer).toString(16);var B=new Date();return A+"."+B.getTime().toString(16)+"."+Math.random().toString(16)}function vjHash(C){if(!C||C==""){return 0}var B=0;for(var A=C.length-1;A>=0;A--){var D=parseInt(C.charCodeAt(A));B=(B<<5)+B+D}return B}function vjGetCookie(D){var B=D+"=";var F=B.length;var A=document.cookie.length;var E=0;while(E<A){var C=E+F;if(document.cookie.substring(E,C)==B){return vjGetCookieVal(C)}E=document.cookie.indexOf(" ",E)+1;if(E==1){break}}return null}function vjGetCookieVal(B){var A=document.cookie.indexOf(";",B);if(A==-1){A=document.cookie.length}return unescape(document.cookie.substring(B,A))}function vjFlash(){var _flashVer="-";var _navigator=navigator;if(_navigator.plugins&&_navigator.plugins.length){for(var ii=0;ii<_navigator.plugins.length;ii++){if(_navigator.plugins[ii].name.indexOf("Shockwave Flash")!=-1){_flashVer=_navigator.plugins[ii].description.split("Shockwave Flash ")[1];break}}}else{if(window.ActiveXObject){for(var ii=10;ii>=2;ii--){try{var fl=eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash."+ii+"');");if(fl){_flashVer=ii+".0";break}}catch(e){}}}}return _flashVer}function vjSurveyCheck(){if(wrSv<=0){return }var C=new Date();var A=C.getTime();var D=Math.random(A);if(D<=parseFloat(1/wrSv)){var B=document.createElement("script");B.type="text/javascript";B.id="wratingSuevey";B.src="httpdisabled://tongji.wrating.com/survey/check.php?c="+vjAcc;document.getElementsByTagName("head")[0].appendChild(B)}}; \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/adgeo.163.com/ad_cookies b/mobile/android/tests/browser/chrome/tp5/163.com/adgeo.163.com/ad_cookies
deleted file mode 100755
index e69de29bb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/adgeo.163.com/ad_cookies
+++ /dev/null
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/analytics.163.com/ntes.js b/mobile/android/tests/browser/chrome/tp5/163.com/analytics.163.com/ntes.js
deleted file mode 100755
index 2654147af..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/analytics.163.com/ntes.js
+++ /dev/null
@@ -1 +0,0 @@
-var _ntes_nacc,_ntes_nvid="VISITOR_CLIENT_NO_COOKIE_SUPPORT",_ntes_nvtm=0,_ntes_nvfi=0,_ntes_nvsf=0,_ntes_nstm=0,_ntes_nurl="",_ntes_ntit="",_ntes_nref="",_ntes_nres="",_ntes_nlag="",_ntes_nscd="",_ntes_nlmf=0,_ntes_flsh="",_ntes_nssn="",_ntes_surv=0;function _ntes_void(){}var _ntes_domain_array=['163.com','188.com','netease.com','126.com','126.net','nease.net','yeah.net','gz2010.cn','co188.com','warcraftchina.com','youdao.com','leihuo.net','gzapg2010.cn'],_ntes_cdmn=ntes_get_domain(),_ntes_src_addr="//analytics.163.com";function neteaseTracker(){_ntes_nurl=escape(document.location);_ntes_ntit=escape(document.title);_ntes_nref=escape(document.referrer);_ntes_flsh=ntes_get_flashver();var now=(new Date()).getTime();document.cookie="__ntes__test__cookies="+now;var _ntes_cookie_enabled=(ntes_get_cookie("__ntes__test__cookies")==now)?true:false;if(_ntes_nacc=="undefined"||!_ntes_nacc)return;if(_ntes_nurl.indexOf("httpdisabled")!=0)return;var run_flag=0;for(i=0;i<_ntes_domain_array.length;i++){if(_ntes_cdmn=="."+_ntes_domain_array[i]){run_flag=1;break}}if(run_flag==1){var _ck_str=ntes_get_cookie("_ntes_nnid");if(_ck_str==-1){if(_ntes_cookie_enabled){_ntes_nvid=fetch_visitor_hash();_ntes_nvfi=1;ntes_set_cookie_long("_ntes_nnid",_ntes_nvid+",0")}}else{var _id_pos=_ck_str.indexOf(","),_suv_pos=_ck_str.indexOf("|");if(_suv_pos==-1)_suv_pos=_ck_str.length;_ntes_nvid=_ck_str.substr(0,_id_pos);_ntes_surv=_ck_str.substr(_id_pos+1,_suv_pos-_id_pos-1);if(_ntes_surv==''||(_ntes_surv!=0&&(now-_ntes_surv)>365*86400)){_ntes_surv=0}ntes_set_cookie_long("_ntes_nnid",_ntes_nvid+","+_ntes_surv)}_ntes_nssn=ntes_get_cookie("P_INFO");if(_ntes_nssn==-1){_ntes_nssn=""}else{_ntes_nssn=_ntes_nssn.substr(0,_ntes_nssn.indexOf("|"))}ntes_get_navigation_info();var _ntes_q="_nacc="+_ntes_nacc;_ntes_q+="&_nvid="+_ntes_nvid+"&_nvtm="+_ntes_nvtm;_ntes_q+="&_nvsf="+_ntes_nvsf+"&_nvfi="+_ntes_nvfi;_ntes_q+="&_nlag="+_ntes_nlag+"&_nlmf="+_ntes_nlmf;_ntes_q+="&_nres="+_ntes_nres+"&_nscd="+_ntes_nscd;_ntes_q+="&_nstm="+_ntes_nstm;_ntes_q+="&_nurl="+_ntes_nurl+"&_ntit="+_ntes_ntit;_ntes_q+="&_nref="+_ntes_nref+"&_nfla="+_ntes_flsh;_ntes_q+="&_nssn="+_ntes_nssn;_ntes_q+="&_nxkey="+(Number(new Date())+''+Math.random()).substring(6,20)+"&_end1";var _img=new Image();_img.src=_ntes_src_addr+"/ntes?"+_ntes_q;_img.onloaddisabled=function(){_ntes_void()};if(1){if(_ntes_nacc!="analytics"&&_ntes_nacc!="research"&&_ntes_nurl.indexOf("httpdisabledsdisabled")!=0){ntes_survey_popup()}}}}function ntes_survey_popup(){if(_ntes_surv==0){if(typeof(_ntes_nvid)=="undefined"||_ntes_nvid.length!=32||_ntes_nvid.substr(30,2)!="23")return;var _ntes_survey_url="//research.163.com/survey/";_ntes_survey_url=_ntes_survey_url+"?_nacc="+_ntes_nacc+"&_nvid="+_ntes_nvid;void(_ntes_survey_url,'','width=680,height=450,top=100,left=120,scrollbars=yes');ntes_set_cookie_long("_ntes_nnid",_ntes_nvid+","+(new Date).getTime())}}function ntes_get_navigation_info(){_ntes_nres="-";_ntes_nscd="-";_ntes_nlag="-";if(self.screen){_ntes_nres=screen.width+"x"+screen.height;_ntes_nscd=screen.colorDepth+"-bit"}else if(self.java){var j=java.awt.Toolkit.getDefaultToolkit(),s=j.getScreenSize();_ntes_nres=s.width+"x"+s.height}if(navigator.language){_ntes_nlag=navigator.language.toLowerCase()}else if(navigator.browserLanguage){_ntes_nlag=navigator.browserLanguage.toLowerCase()}var d=new Date(document.lastModified);_ntes_nlmf=d.getTime()/1000}function fetch_visitor_hash(){var d=new Date(),xy=document.body.clientWidth+":"+document.body.clientHeight,s=str_to_ent(d.getTime()+Math.random()+document.location+document.referrer+screen.width+screen.height+navigator.userAgent+document.cookie+xy);return ntes_hex_md5(s)}function ntes_get_domain(){var domain_name=document.domain,arr_domain_name=domain_name.split("."),domain_name_length=arr_domain_name.length,pattern=/^\d+$/g;if(pattern.test(arr_domain_name[domain_name_length-1])){return domain_name}if(arr_domain_name.length<3){return "."+domain_name}var domain_suffixes=['com','net','org','gov','co'],i,suffix_found=false;for(i=0;i<domain_suffixes.length;i++){if(arr_domain_name[domain_name_length-2]==domain_suffixes[i]){suffix_found=true}}if(!suffix_found){return "."+arr_domain_name[domain_name_length-2]+"."+arr_domain_name[domain_name_length-1]}else{return "."+arr_domain_name[domain_name_length-3]+"."+arr_domain_name[domain_name_length-2]+"."+arr_domain_name[domain_name_length-1]}}function ntes_set_cookie_long(name,value){var _ntes_epd=new Date();_ntes_epd.setTime(_ntes_epd.getTime()+1000*60*60*24*365*100);document.cookie=name+"="+value+";expires="+_ntes_epd.toGMTString()+";path=/;domain="+_ntes_cdmn}function ntes_set_cookie(name,value){var _ntes_epd=new Date();_ntes_epd.setTime(_ntes_epd.getTime()+0);document.cookie=name+"="+value+";path=/;domain="+_ntes_cdmn}function ntes_set_cookie_new(name,value,expires){if(!expires||expires==""){expires=1000*60*60*24*365*1}var _ntes_epd=new Date();_ntes_epd.setTime(_ntes_epd.getTime()+expires);document.cookie=name+"="+value+";expires="+_ntes_epd.toGMTString()+";path=/;domain="+_ntes_cdmn}function ntes_get_cookie(name){var _ntes_dc=document.cookie,_ntes_cname=name+"=",_ntes_clen=_ntes_dc.length,_ntes_cbegin=0;while(_ntes_cbegin<_ntes_clen){var _ntes_vbegin=_ntes_cbegin+_ntes_cname.length;if(_ntes_dc.substring(_ntes_cbegin,_ntes_vbegin)==_ntes_cname){var _ntes_vend=_ntes_dc.indexOf(";",_ntes_vbegin);if(_ntes_vend==-1)_ntes_vend=_ntes_clen;return unescape(_ntes_dc.substring(_ntes_vbegin,_ntes_vend))}_ntes_cbegin=_ntes_dc.indexOf(" ",_ntes_cbegin)+1;if(_ntes_cbegin==0)break}return-1}function ntes_get_flashver(){var f="",n=navigator;if(n.plugins&&n.plugins.length){for(var ii=0;ii<n.plugins.length;ii++){if(n.plugins[ii].name.indexOf('Shockwave Flash')!=-1){f=n.plugins[ii].description.split('Shockwave Flash')[1];break}}}else if(window.ActiveXObject){for(var ii=10;ii>=2;ii--){try{var fl=eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash."+ii+"');");if(fl){f=ii+'.0';break}}catch(e){}}}return f}var _ntes_hexcase=0,_ntes_chrsz=8;function ntes_hex_md5(s){return binl2hex(ntes_core_md5(str2binl(s),s.length*_ntes_chrsz))}function ntes_core_md5(x,len){x[len>>5]|=0x80<<((len)%32);x[(((len+64)>>>9)<<4)+14]=len;var a=1732584193,b=-271733879,c=-1732584194,d=271733878;for(var i=0;i<x.length;i+=16){var olda=a,oldb=b,oldc=c,oldd=d;a=md5_ff(a,b,c,d,x[i+0],7,-680876936);d=md5_ff(d,a,b,c,x[i+1],12,-389564586);c=md5_ff(c,d,a,b,x[i+2],17,606105819);b=md5_ff(b,c,d,a,x[i+3],22,-1044525330);a=md5_ff(a,b,c,d,x[i+4],7,-176418897);d=md5_ff(d,a,b,c,x[i+5],12,1200080426);c=md5_ff(c,d,a,b,x[i+6],17,-1473231341);b=md5_ff(b,c,d,a,x[i+7],22,-45705983);a=md5_ff(a,b,c,d,x[i+8],7,1770035416);d=md5_ff(d,a,b,c,x[i+9],12,-1958414417);c=md5_ff(c,d,a,b,x[i+10],17,-42063);b=md5_ff(b,c,d,a,x[i+11],22,-1990404162);a=md5_ff(a,b,c,d,x[i+12],7,1804603682);d=md5_ff(d,a,b,c,x[i+13],12,-40341101);c=md5_ff(c,d,a,b,x[i+14],17,-1502002290);b=md5_ff(b,c,d,a,x[i+15],22,1236535329);a=md5_gg(a,b,c,d,x[i+1],5,-165796510);d=md5_gg(d,a,b,c,x[i+6],9,-1069501632);c=md5_gg(c,d,a,b,x[i+11],14,643717713);b=md5_gg(b,c,d,a,x[i+0],20,-373897302);a=md5_gg(a,b,c,d,x[i+5],5,-701558691);d=md5_gg(d,a,b,c,x[i+10],9,38016083);c=md5_gg(c,d,a,b,x[i+15],14,-660478335);b=md5_gg(b,c,d,a,x[i+4],20,-405537848);a=md5_gg(a,b,c,d,x[i+9],5,568446438);d=md5_gg(d,a,b,c,x[i+14],9,-1019803690);c=md5_gg(c,d,a,b,x[i+3],14,-187363961);b=md5_gg(b,c,d,a,x[i+8],20,1163531501);a=md5_gg(a,b,c,d,x[i+13],5,-1444681467);d=md5_gg(d,a,b,c,x[i+2],9,-51403784);c=md5_gg(c,d,a,b,x[i+7],14,1735328473);b=md5_gg(b,c,d,a,x[i+12],20,-1926607734);a=md5_hh(a,b,c,d,x[i+5],4,-378558);d=md5_hh(d,a,b,c,x[i+8],11,-2022574463);c=md5_hh(c,d,a,b,x[i+11],16,1839030562);b=md5_hh(b,c,d,a,x[i+14],23,-35309556);a=md5_hh(a,b,c,d,x[i+1],4,-1530992060);d=md5_hh(d,a,b,c,x[i+4],11,1272893353);c=md5_hh(c,d,a,b,x[i+7],16,-155497632);b=md5_hh(b,c,d,a,x[i+10],23,-1094730640);a=md5_hh(a,b,c,d,x[i+13],4,681279174);d=md5_hh(d,a,b,c,x[i+0],11,-358537222);c=md5_hh(c,d,a,b,x[i+3],16,-722521979);b=md5_hh(b,c,d,a,x[i+6],23,76029189);a=md5_hh(a,b,c,d,x[i+9],4,-640364487);d=md5_hh(d,a,b,c,x[i+12],11,-421815835);c=md5_hh(c,d,a,b,x[i+15],16,530742520);b=md5_hh(b,c,d,a,x[i+2],23,-995338651);a=md5_ii(a,b,c,d,x[i+0],6,-198630844);d=md5_ii(d,a,b,c,x[i+7],10,1126891415);c=md5_ii(c,d,a,b,x[i+14],15,-1416354905);b=md5_ii(b,c,d,a,x[i+5],21,-57434055);a=md5_ii(a,b,c,d,x[i+12],6,1700485571);d=md5_ii(d,a,b,c,x[i+3],10,-1894986606);c=md5_ii(c,d,a,b,x[i+10],15,-1051523);b=md5_ii(b,c,d,a,x[i+1],21,-2054922799);a=md5_ii(a,b,c,d,x[i+8],6,1873313359);d=md5_ii(d,a,b,c,x[i+15],10,-30611744);c=md5_ii(c,d,a,b,x[i+6],15,-1560198380);b=md5_ii(b,c,d,a,x[i+13],21,1309151649);a=md5_ii(a,b,c,d,x[i+4],6,-145523070);d=md5_ii(d,a,b,c,x[i+11],10,-1120210379);c=md5_ii(c,d,a,b,x[i+2],15,718787259);b=md5_ii(b,c,d,a,x[i+9],21,-343485551);a=safe_add(a,olda);b=safe_add(b,oldb);c=safe_add(c,oldc);d=safe_add(d,oldd)}return Array(a,b,c,d)}function md5_cmn(q,a,b,x,s,t){return safe_add(bit_rol(safe_add(safe_add(a,q),safe_add(x,t)),s),b)}function md5_ff(a,b,c,d,x,s,t){return md5_cmn((b&c)|((~b)&d),a,b,x,s,t)}function md5_gg(a,b,c,d,x,s,t){return md5_cmn((b&d)|(c&(~d)),a,b,x,s,t)}function md5_hh(a,b,c,d,x,s,t){return md5_cmn(b^c^d,a,b,x,s,t)}function md5_ii(a,b,c,d,x,s,t){return md5_cmn(c^(b|(~d)),a,b,x,s,t)}function safe_add(x,y){var lsw=(x&0xFFFF)+(y&0xFFFF),msw=(x>>16)+(y>>16)+(lsw>>16);return(msw<<16)|(lsw&0xFFFF)}function bit_rol(num,cnt){return(num<<cnt)|(num>>>(32-cnt))}function str2binl(str){var bin=new Array(),mask=(1<<_ntes_chrsz)-1;for(var i=0;i<str.length*_ntes_chrsz;i+=_ntes_chrsz)bin[i>>5]|=(str.charCodeAt(i/_ntes_chrsz)&mask)<<(i%32);return bin}function binl2hex(binarray){var hex_tab=_ntes_hexcase?"0123456789ABCDEF":"0123456789abcdef",str="";for(var i=0;i<binarray.length*4;i++){str+=hex_tab.charAt((binarray[i>>2]>>((i%4)*8+4))&0xF)+hex_tab.charAt((binarray[i>>2]>>((i%4)*8))&0xF)}return str}function str_to_ent(str){var result='',i;for(i=0;i<str.length;i++){var c=str.charCodeAt(i),tmp='';if(c>255){while(c>=1){tmp="0123456789".charAt(c%10)+tmp;c=c/10}if(tmp==''){tmp="0"}tmp="#"+tmp;tmp="&"+tmp;tmp=tmp+";";result+=tmp}else{result+=str.charAt(i)}}return result}function ntes_page_click_stat(obj){var _ntes_a_h=escape(this.href),_ntes_a_t=escape(this.innerHTML),_ntes_p_url=escape(document.location),_ncw=0,_nmx=0,_nmy=0;if(document.documentElement&&document.documentElement.clientWidth){_ncw=document.documentElement.clientWidth}var evt=obj||window.event;if(evt.clientX&&document.documentElement){_nmx=evt.clientX+document.documentElement.scrollLeft;_nmy=evt.clientY+document.documentElement.scrollTop}var _ntes_p_q="_nacc="+_ntes_nacc+"&_npurl="+_ntes_p_url;_ntes_p_q+="&_nah="+_ntes_a_h+"&_nat="+_ntes_a_t;_ntes_p_q+="&_ncw="+_ncw+"&_nmx="+_nmx+"&_nmy="+_nmy;_ntes_p_q+="&_end";var i=new Image();i.src=_ntes_src_addr+"/ntes_p?"+_ntes_p_q;i.onloaddisabled=function(){_ntes_void()};return true}function neteaseClickStat(){if(typeof(_ntes_nacc)=="undefined"||!_ntes_nacc){return}var _ntes_r=Math.random();_ntes_r=Math.round(_ntes_r*30);if(_ntes_r!=15)return;if(document.all&&navigator.userAgent.match(/msie/gi)){var _ntes_a_tag_array=document.getElementsByTagName('a');for(i in _ntes_a_tag_array){if(_ntes_a_tag_array[i].onclick==null){_ntes_a_tag_array[i].onclick=ntes_page_click_stat}}}}function recordAction(aName,vAddr,vName,p1,p2){var _q="";_q+="s="+_ntes_nacc;_q+="&u="+_ntes_nvid;_q+="&a="+escape(aName);_q+="&v="+escape(vAddr);_q+="&n="+escape(vName);_q+="&p1="+p1;if(p2!=undefined)_q+="&p2="+p2;_q+="&r="+_ntes_nurl;_q+="&_nxkey="+(Number(new Date())+''+Math.random()).substring(6,20)+"&_end1";var _img=new Image();_img.src=_ntes_src_addr+"/ntesv?"+_q;_img.onloaddisabled=function(){_ntes_void()}} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/jr@site=netease&affiliate=homepage&cat=homepage&type=adend&location=1 b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/jr@site=netease&affiliate=homepage&cat=homepage&type=adend&location=1
deleted file mode 100755
index 8b0c6b763..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/jr@site=netease&affiliate=homepage&cat=homepage&type=adend&location=1
+++ /dev/null
@@ -1 +0,0 @@
-var adrichend; \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/jr@site=netease&affiliate=homepage&cat=homepage&type=popup&location=1 b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/jr@site=netease&affiliate=homepage&cat=homepage&type=popup&location=1
deleted file mode 100755
index 166293021..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/jr@site=netease&affiliate=homepage&cat=homepage&type=popup&location=1
+++ /dev/null
@@ -1 +0,0 @@
-a=1; \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=banner360x65&location=1.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=banner360x65&location=1.html
deleted file mode 100755
index b6042af08..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=banner360x65&location=1.html
+++ /dev/null
@@ -1 +0,0 @@
-<a target="_blank" href="httpdisabled://g.163.com/c?AID=30417&FlightID=739&Values=1131919305&Redirect=http://l.163.com/indi/april.html"><img src="../img3.126.net/techpro/shangpin/20110331/36-65.jpg" border=0 height=65 width=360 alt=""></a> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=banner360x65&location=2.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=banner360x65&location=2.html
deleted file mode 100755
index fbcd8872a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=banner360x65&location=2.html
+++ /dev/null
@@ -1 +0,0 @@
-<a target="_blank" href="httpdisabled://g.163.com/c?AID=33940&FlightID=740&Values=2875939796&Redirect=http://t.163.com/zt/2011"><img src="../img2.126.net/xoimages/sales/2011/04/wb/360x65.jpg" border=0 height=65 width=360 alt=""></a> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=1.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=1.html
deleted file mode 100755
index 8425685c3..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=1.html
+++ /dev/null
@@ -1 +0,0 @@
-<a target="_blank" href="httpdisabled://g.163.com/c?AID=34355&FlightID=762&Values=868630560&Redirect=http://hr.163.com/hangzhou/"><img src="../img2.126.net/xoimages/hr/20110216/hz/360x100.jpg" border=0 height=100 width=360 alt=""></a> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=2.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=2.html
deleted file mode 100755
index 26926d408..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=2.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33867&FlightID=747&Values=1741461550&Redirect=http://cps.mbaobao.com/cps/25892";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=360 HEIGHT=100>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008995/mbb360100_110406.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008995/mbb360100_110406.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=360 HEIGHT=100');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33867&FlightID=747&Values=1741461550&Redirect=http://cps.mbaobao.com/cps/25892" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008995/mbb360100_110406.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33867&FlightID=747&Values=1741461550&Redirect=http://cps.mbaobao.com/cps/25892" target="_blank"><IMG SRC="../img1.126.net/channel5/008995/mbb360100_110406.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33867&FlightID=747&Values=1741461550&Redirect=http://cps.mbaobao.com/cps/25892" target="_blank"><IMG SRC="../img1.126.net/channel5/008995/mbb360100_110406.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=3.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=3.html
deleted file mode 100755
index 995a54032..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=3.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33925&FlightID=764&Values=3275702516&Redirect=http://a814.oadz.com/link/C/814/88700/Is4Y9DtmCqUv0pLFAc-xPJ0f8ts_/a/108/http://www.m18.com/market/front.aspx?pno=wan-gm-hp-00zty&url=/im";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=360 HEIGHT=100>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008969/mai360100_110401.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008969/mai360100_110401.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=360 HEIGHT=100');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33925&FlightID=764&Values=3275702516&Redirect=http://a814.oadz.com/link/C/814/88700/Is4Y9DtmCqUv0pLFAc-xPJ0f8ts_/a/108/http://www.m18.com/market/front.aspx?pno=wan-gm-hp-00zty&url=/im" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008969/mai360100_110401.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33925&FlightID=764&Values=3275702516&Redirect=http://a814.oadz.com/link/C/814/88700/Is4Y9DtmCqUv0pLFAc-xPJ0f8ts_/a/108/http://www.m18.com/market/front.aspx?pno=wan-gm-hp-00zty&url=/im" target="_blank"><IMG SRC="../img1.126.net/channel5/008969/mai360100_110401.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33925&FlightID=764&Values=3275702516&Redirect=http://a814.oadz.com/link/C/814/88700/Is4Y9DtmCqUv0pLFAc-xPJ0f8ts_/a/108/http://www.m18.com/market/front.aspx?pno=wan-gm-hp-00zty&url=/im" target="_blank"><IMG SRC="../img1.126.net/channel5/008969/mai360100_110401.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=5.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=5.html
deleted file mode 100755
index e6a047938..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=5.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33914&FlightID=749&Values=1855147922&Redirect=http://a1419.oadz.com/link/C/1419/33/T3dnBK9qi69zlngdBjwKaRYj-ms_/a/2/http://www.topshoes.cn/";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=360 HEIGHT=100>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008995/bl360100_110402.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008995/bl360100_110402.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=360 HEIGHT=100');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33914&FlightID=749&Values=1855147922&Redirect=http://a1419.oadz.com/link/C/1419/33/T3dnBK9qi69zlngdBjwKaRYj-ms_/a/2/http://www.topshoes.cn/" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008995/bl360100_110402.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33914&FlightID=749&Values=1855147922&Redirect=http://a1419.oadz.com/link/C/1419/33/T3dnBK9qi69zlngdBjwKaRYj-ms_/a/2/http://www.topshoes.cn/" target="_blank"><IMG SRC="../img1.126.net/channel5/008995/bl360100_110402.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33914&FlightID=749&Values=1855147922&Redirect=http://a1419.oadz.com/link/C/1419/33/T3dnBK9qi69zlngdBjwKaRYj-ms_/a/2/http://www.topshoes.cn/" target="_blank"><IMG SRC="../img1.126.net/channel5/008995/bl360100_110402.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=6.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=6.html
deleted file mode 100755
index e1723fc0f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=6.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33816&FlightID=766&Values=68259114&Redirect=http://click.moonbasa.com/transfer.aspx?cn=1699&type=0&adsiteid=10000007&url=http://www.moonbasa.com/?oid=4";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=360 HEIGHT=100>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008984/liangxie360100_110402.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008984/liangxie360100_110402.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=360 HEIGHT=100');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33816&FlightID=766&Values=68259114&Redirect=http://click.moonbasa.com/transfer.aspx?cn=1699&type=0&adsiteid=10000007&url=http://www.moonbasa.com/?oid=4" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008984/liangxie360100_110402.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33816&FlightID=766&Values=68259114&Redirect=http://click.moonbasa.com/transfer.aspx?cn=1699&type=0&adsiteid=10000007&url=http://www.moonbasa.com/?oid=4" target="_blank"><IMG SRC="../img1.126.net/channel5/008984/liangxie360100_110402.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33816&FlightID=766&Values=68259114&Redirect=http://click.moonbasa.com/transfer.aspx?cn=1699&type=0&adsiteid=10000007&url=http://www.moonbasa.com/?oid=4" target="_blank"><IMG SRC="../img1.126.net/channel5/008984/liangxie360100_110402.swf" WIDTH=360 HEIGHT=100 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=1.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=1.html
deleted file mode 100755
index adb1ca8dc..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=1.html
+++ /dev/null
@@ -1 +0,0 @@
-<a target="_blank" href="httpdisabled://g.163.com/c?AID=34342&FlightID=761&Values=2612011559&Redirect=http://allyes.nie.163.com/main/adfclick?db=afanie&bid=38403,18618,355&cid=637,4,1&sid=37953&show=ignore&url=http://qn.163.com/yr/"><img src="../img2.126.net/xoimages/game/20110216/ql/x/390x100.jpg" border=0 height=100 width=390 alt=""></a> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=2.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=2.html
deleted file mode 100755
index a49ab1078..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=2.html
+++ /dev/null
@@ -1 +0,0 @@
-<a target="_blank" href="httpdisabled://g.163.com/c?AID=34354&FlightID=744&Values=85863423&Redirect=http://travel.163.com/hellocity/"><img src="../img2.126.net/xoimages/sales/2011/03/ly/390x100.jpg" border=0 height=100 width=390 alt=""></a> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=3.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=3.html
deleted file mode 100755
index 29e09983c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=3.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33814&FlightID=763&Values=3968994465&Redirect=http://click.moonbasa.com/transfer.aspx?cn=1698&type=0&adsiteid=10000007&url=http://www.moonbasa.com/?oid=3";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=390 HEIGHT=100>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008984/xizhuang390100_110402.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008984/xizhuang390100_110402.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=390 HEIGHT=100');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33814&FlightID=763&Values=3968994465&Redirect=http://click.moonbasa.com/transfer.aspx?cn=1698&type=0&adsiteid=10000007&url=http://www.moonbasa.com/?oid=3" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008984/xizhuang390100_110402.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33814&FlightID=763&Values=3968994465&Redirect=http://click.moonbasa.com/transfer.aspx?cn=1698&type=0&adsiteid=10000007&url=http://www.moonbasa.com/?oid=3" target="_blank"><IMG SRC="../img1.126.net/channel5/008984/xizhuang390100_110402.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33814&FlightID=763&Values=3968994465&Redirect=http://click.moonbasa.com/transfer.aspx?cn=1698&type=0&adsiteid=10000007&url=http://www.moonbasa.com/?oid=3" target="_blank"><IMG SRC="../img1.126.net/channel5/008984/xizhuang390100_110402.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=4.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=4.html
deleted file mode 100755
index 898bf062c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=4.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=34196&FlightID=745&Values=3301780629&Redirect=http://a1052.oadz.com/link/C/1052/39/TNCPMVEIYp-TRrZLJ27yq2NMhXs_/p032/6/http://www.olomo.com/position/?u=1894274&ompz=4454";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=390 HEIGHT=100>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008995/ou390100_110408.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008995/ou390100_110408.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=390 HEIGHT=100');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=34196&FlightID=745&Values=3301780629&Redirect=http://a1052.oadz.com/link/C/1052/39/TNCPMVEIYp-TRrZLJ27yq2NMhXs_/p032/6/http://www.olomo.com/position/?u=1894274&ompz=4454" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008995/ou390100_110408.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=34196&FlightID=745&Values=3301780629&Redirect=http://a1052.oadz.com/link/C/1052/39/TNCPMVEIYp-TRrZLJ27yq2NMhXs_/p032/6/http://www.olomo.com/position/?u=1894274&ompz=4454" target="_blank"><IMG SRC="../img1.126.net/channel5/008995/ou390100_110408.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=34196&FlightID=745&Values=3301780629&Redirect=http://a1052.oadz.com/link/C/1052/39/TNCPMVEIYp-TRrZLJ27yq2NMhXs_/p032/6/http://www.olomo.com/position/?u=1894274&ompz=4454" target="_blank"><IMG SRC="../img1.126.net/channel5/008995/ou390100_110408.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=5.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=5.html
deleted file mode 100755
index 5edb8dfa4..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=5.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33871&FlightID=746&Values=478684510&Redirect=http://mso.allyes.com/main/c?db=mso&bid=63394,31657,2624&cid=62875,2992,149&sid=63319&show=ignore&url=http://www.vancl.com/?source=wy230703syzt5";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=390 HEIGHT=100>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008977/5v390100_110406.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008977/5v390100_110406.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=390 HEIGHT=100');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33871&FlightID=746&Values=478684510&Redirect=http://mso.allyes.com/main/c?db=mso&bid=63394,31657,2624&cid=62875,2992,149&sid=63319&show=ignore&url=http://www.vancl.com/?source=wy230703syzt5" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008977/5v390100_110406.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33871&FlightID=746&Values=478684510&Redirect=http://mso.allyes.com/main/c?db=mso&bid=63394,31657,2624&cid=62875,2992,149&sid=63319&show=ignore&url=http://www.vancl.com/?source=wy230703syzt5" target="_blank"><IMG SRC="../img1.126.net/channel5/008977/5v390100_110406.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33871&FlightID=746&Values=478684510&Redirect=http://mso.allyes.com/main/c?db=mso&bid=63394,31657,2624&cid=62875,2992,149&sid=63319&show=ignore&url=http://www.vancl.com/?source=wy230703syzt5" target="_blank"><IMG SRC="../img1.126.net/channel5/008977/5v390100_110406.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=6.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=6.html
deleted file mode 100755
index 44952eaec..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=6.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33888&FlightID=765&Values=2426328330&Redirect=http://a777.oadz.com/link/C/777/2972/Z6nbl6URgyAsEQVVzZ5skDUHOQ0_/a/126/http://www.fuocoo.com";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=390 HEIGHT=100>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008995/fk390100_110331.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008995/fk390100_110331.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=390 HEIGHT=100');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33888&FlightID=765&Values=2426328330&Redirect=http://a777.oadz.com/link/C/777/2972/Z6nbl6URgyAsEQVVzZ5skDUHOQ0_/a/126/http://www.fuocoo.com" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008995/fk390100_110331.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33888&FlightID=765&Values=2426328330&Redirect=http://a777.oadz.com/link/C/777/2972/Z6nbl6URgyAsEQVVzZ5skDUHOQ0_/a/126/http://www.fuocoo.com" target="_blank"><IMG SRC="../img1.126.net/channel5/008995/fk390100_110331.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33888&FlightID=765&Values=2426328330&Redirect=http://a777.oadz.com/link/C/777/2972/Z6nbl6URgyAsEQVVzZ5skDUHOQ0_/a/126/http://www.fuocoo.com" target="_blank"><IMG SRC="../img1.126.net/channel5/008995/fk390100_110331.swf" WIDTH=390 HEIGHT=100 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column600x80&location=1.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column600x80&location=1.html
deleted file mode 100755
index b0e6dcf26..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column600x80&location=1.html
+++ /dev/null
@@ -1 +0,0 @@
-<a target="_blank" href="httpdisabled://g.163.com/c?AID=33904&FlightID=21&Values=1257549911&Redirect=http://allyes.nie.163.com/main/adfclick?db=afanie&bid=38403,18618,355&cid=637,4,1&sid=37953&show=ignore&url=http://qn.163.com/yr/"><img src="../img2.126.net/xoimages/game/20110216/ql/x/600x80.gif" border=0 height=80 width=600 alt=""></a> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x100&location=1.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x100&location=1.html
deleted file mode 100755
index b99570776..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x100&location=1.html
+++ /dev/null
@@ -1 +0,0 @@
-<a target="_blank" href="httpdisabled://g.163.com/c?AID=34413&FlightID=750&Values=4252749124&Redirect=http://media.163.com/11/0407/12/711MA88S00762H91.html"><img src="../img2.126.net/xoimages/sales/2011/04/hy/190x100.jpg" border=0 height=100 width=190 alt=""></a> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x100&location=2.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x100&location=2.html
deleted file mode 100755
index e6f26ed54..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x100&location=2.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33896&FlightID=751&Values=2829007648&Redirect=http://www.k121.com/?from=163w2";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=190 HEIGHT=100>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008981/kyd2_190100_110402.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008981/kyd2_190100_110402.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=190 HEIGHT=100');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33896&FlightID=751&Values=2829007648&Redirect=http://www.k121.com/?from=163w2" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008981/kyd2_190100_110402.swf" WIDTH=190 HEIGHT=100 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33896&FlightID=751&Values=2829007648&Redirect=http://www.k121.com/?from=163w2" target="_blank"><IMG SRC="../img1.126.net/channel5/008981/kyd2_190100_110402.swf" WIDTH=190 HEIGHT=100 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33896&FlightID=751&Values=2829007648&Redirect=http://www.k121.com/?from=163w2" target="_blank"><IMG SRC="../img1.126.net/channel5/008981/kyd2_190100_110402.swf" WIDTH=190 HEIGHT=100 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=1.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=1.html
deleted file mode 100755
index fccb481ca..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=1.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33829&FlightID=752&Values=2077038183&Redirect=http://nimafa7.allyes.com/main/c?db=nimafa7&bid=17117,7729,378&cid=6808,162,1&sid=17997&show=ignore&url=http://minisite.163.com/2011/0214/tries/";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=190 HEIGHT=180>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/009400/caizi190180_110408.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/009400/caizi190180_110408.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=190 HEIGHT=180');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33829&FlightID=752&Values=2077038183&Redirect=http://nimafa7.allyes.com/main/c?db=nimafa7&bid=17117,7729,378&cid=6808,162,1&sid=17997&show=ignore&url=http://minisite.163.com/2011/0214/tries/" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/009400/caizi190180_110408.swf" WIDTH=190 HEIGHT=180 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33829&FlightID=752&Values=2077038183&Redirect=http://nimafa7.allyes.com/main/c?db=nimafa7&bid=17117,7729,378&cid=6808,162,1&sid=17997&show=ignore&url=http://minisite.163.com/2011/0214/tries/" target="_blank"><IMG SRC="../img1.126.net/channel5/009400/caizi190180_110408.swf" WIDTH=190 HEIGHT=180 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33829&FlightID=752&Values=2077038183&Redirect=http://nimafa7.allyes.com/main/c?db=nimafa7&bid=17117,7729,378&cid=6808,162,1&sid=17997&show=ignore&url=http://minisite.163.com/2011/0214/tries/" target="_blank"><IMG SRC="../img1.126.net/channel5/009400/caizi190180_110408.swf" WIDTH=190 HEIGHT=180 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=2.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=2.html
deleted file mode 100755
index 69fcd3866..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=2.html
+++ /dev/null
@@ -1 +0,0 @@
-<a target="_blank" href="httpdisabled://g.163.com/c?AID=34156&FlightID=753&Values=2278629106&Redirect=http://cidian.youdao.com/pingtian/"><img src="../img2.126.net/xoimages/sales/2011/04/yd/190x180.jpg" border=0 height=180 width=190 alt=""></a> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=3.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=3.html
deleted file mode 100755
index 308fbd44a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=3.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33920&FlightID=754&Values=743829921&Redirect=http://www.voidg.com/voidg2/lp/voidg/voidg.php?CID=CN_DIS_121_3_1_700";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=190 HEIGHT=180>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008995/voidg190180_110407.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008995/voidg190180_110407.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=190 HEIGHT=180');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33920&FlightID=754&Values=743829921&Redirect=http://www.voidg.com/voidg2/lp/voidg/voidg.php?CID=CN_DIS_121_3_1_700" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008995/voidg190180_110407.swf" WIDTH=190 HEIGHT=180 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33920&FlightID=754&Values=743829921&Redirect=http://www.voidg.com/voidg2/lp/voidg/voidg.php?CID=CN_DIS_121_3_1_700" target="_blank"><IMG SRC="../img1.126.net/channel5/008995/voidg190180_110407.swf" WIDTH=190 HEIGHT=180 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33920&FlightID=754&Values=743829921&Redirect=http://www.voidg.com/voidg2/lp/voidg/voidg.php?CID=CN_DIS_121_3_1_700" target="_blank"><IMG SRC="../img1.126.net/channel5/008995/voidg190180_110407.swf" WIDTH=190 HEIGHT=180 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=4.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=4.html
deleted file mode 100755
index 0dfc0433b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=4.html
+++ /dev/null
@@ -1 +0,0 @@
-<script type='text/javascript' src='../zjs.ipinyou.com/2011032517331513260_2342_190180.js'></script> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x300&location=1.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x300&location=1.html
deleted file mode 100755
index 7dfda0802..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x300&location=1.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- Sniffer Code for Flash version=80 -->
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<SCRIPT LANGUAGE=JavaScript>
-<!--
-var swf_click = "httpdisabled://g.163.com/c?AID=33876&FlightID=756&Values=3536047884&Redirect=http://a814.oadz.com/link/C/814/88637/UoFr9DZA7GBQz2OagEiruxYJZCc_/a/108/http://www.m18.com/market/front.aspx?pno=wan-hp-s1&url=/im";
-var dcswf_click = escape(swf_click);
-var ShockMode = 0;
-var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
-
-if (plugin && parseInt(plugin.description.substring(plugin.description.indexOf(".")-2)) >= 8)
-{
-ShockMode = 1;
-}
-else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0
-&& navigator.userAgent.indexOf("Opera")<0) {
-void('<SCRIPT LANGUAGE=VBScript\> \n');
-void('on error resume next \n');
-void('ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.8")))\n');
-void('<\/SCRIPT\> \n');
-}
-if ( ShockMode ) {
-void('<objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
-void(' codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"');
-void(' ID=flashad WIDTH=190 HEIGHT=300>');
-void(' <PARAM NAME=movie VALUE="httpdisabled://img1.126.net/channel5/008981/190300a_110406.swf?clickTag='+dcswf_click+'"> ');
-void(' <PARAM NAME=quality VALUE=autohigh> ');
-void(' <PARAM NAME=wmode VALUE=opaque> ');
-void(' <embeddisabled SRC="httpdisabled://img1.126.net/channel5/008981/190300a_110406.swf?clickTag='+dcswf_click+'" QUALITY=autohigh wmode=opaque');
-void(' NAME=flashad swLiveConnect=TRUE WIDTH=190 HEIGHT=300');
-void(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="httpdisabled://www.macromedia.com/shockwave/downloaddisabled/index.cgi?P1_Prod_Version=ShockwaveFlash">');
-void('</EMBED>');
-void('</OBJECT>');
-} else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){
-void('<A HREF="httpdisabled://g.163.com/c?AID=33876&FlightID=756&Values=3536047884&Redirect=http://a814.oadz.com/link/C/814/88637/UoFr9DZA7GBQz2OagEiruxYJZCc_/a/108/http://www.m18.com/market/front.aspx?pno=wan-hp-s1&url=/im" target="_blank"><IMG SRC="httpdisabled://img1.126.net/channel5/008981/190300a_110406.swf" WIDTH=190 HEIGHT=300 BORDER=0></A>');
-}
-//-->
-</SCRIPT>
-<NOEMBED>
-<A HREF="httpdisabled://g.163.com/c?AID=33876&FlightID=756&Values=3536047884&Redirect=http://a814.oadz.com/link/C/814/88637/UoFr9DZA7GBQz2OagEiruxYJZCc_/a/108/http://www.m18.com/market/front.aspx?pno=wan-hp-s1&url=/im" target="_blank"><IMG SRC="../img1.126.net/channel5/008981/190300a_110406.swf" WIDTH=190 HEIGHT=300 BORDER=0></A>
-</NOEMBED>
-<NOSCRIPT>
-<A HREF="httpdisabled://g.163.com/c?AID=33876&FlightID=756&Values=3536047884&Redirect=http://a814.oadz.com/link/C/814/88637/UoFr9DZA7GBQz2OagEiruxYJZCc_/a/108/http://www.m18.com/market/front.aspx?pno=wan-hp-s1&url=/im" target="_blank"><IMG SRC="../img1.126.net/channel5/008981/190300a_110406.swf" WIDTH=190 HEIGHT=300 BORDER=0></A>
-</NOSCRIPT> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x300&location=2.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x300&location=2.html
deleted file mode 100755
index 30e84fdd6..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x300&location=2.html
+++ /dev/null
@@ -1 +0,0 @@
-<html><head></head><body></body></html>
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=textlinkhouse&location=1.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=textlinkhouse&location=1.html
deleted file mode 100755
index 3ab2840d4..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=textlinkhouse&location=1.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<style>
-body {background:#fff; font-size:12px;}
-a,a:visited {float:left;line-height:21px;overflow:hidden;width:120px;color:#1E50A2;text-decoration:none;}
-a:hover {color:#ba2636;}
-</style>
-<script type="text/javascript" src="../img3.126.net/rpic/fld3/flsclasses.js"></script>
-<script type="text/javascript" src="../img3.126.net/rpic/fld3/fld_homepage.js"></script>
-<script type="text/javascript">
-<!--
-if(typeof(qita)!=='undefined'){
- var prov=qita;
- echoa();
-}
-//-->
-</script>
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=textlinkhouse&location=2.html b/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=textlinkhouse&location=2.html
deleted file mode 100755
index 9f7a6d7fc..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=textlinkhouse&location=2.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<style>
-body {background:#fff; font-size:12px;}
-a,a:visited {float:left;line-height:21px;overflow:hidden;width:120px;color:#1E50A2;text-decoration:none;}
-a:hover {color:#ba2636;}
-</style>
-<script type="text/javascript" src="../img3.126.net/rpic/fld3/flsclasses.js"></script>
-<script type="text/javascript" src="../img3.126.net/rpic/fld3/fld_homepage.js"></script>
-<script type="text/javascript">
-<!--
-if(typeof(qita)!=='undefined'){
- var prov=qita;
- echob();
-}
-//-->
-</script>
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel1/55x20_bai.gif b/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel1/55x20_bai.gif
deleted file mode 100755
index 456c1ace4..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel1/55x20_bai.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel1/55x20_lan.gif b/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel1/55x20_lan.gif
deleted file mode 100755
index 8ec96875f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel1/55x20_lan.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel5/008976/bolon_110302.png b/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel5/008976/bolon_110302.png
deleted file mode 100755
index 895a9cdfc..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel5/008976/bolon_110302.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel5/360/360100_110318.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel5/360/360100_110318.jpg
deleted file mode 100755
index db9b316ca..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.126.net/channel5/360/360100_110318.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/6/20110406182512d4541.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/6/20110406182512d4541.jpg
deleted file mode 100755
index 07620cc2f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/6/20110406182512d4541.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408075741e084c.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408075741e084c.jpg
deleted file mode 100755
index 2ddd7ddf1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408075741e084c.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040808080199ae7.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040808080199ae7.jpg
deleted file mode 100755
index f6845bd03..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040808080199ae7.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080835397174e.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080835397174e.jpg
deleted file mode 100755
index 12a505972..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080835397174e.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080847137e997.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080847137e997.jpg
deleted file mode 100755
index 39a395822..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080847137e997.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408085323b9296.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408085323b9296.jpg
deleted file mode 100755
index 53386b1e8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408085323b9296.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408092834ed61d.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408092834ed61d.jpg
deleted file mode 100755
index 738834c3d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408092834ed61d.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080930016f866.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080930016f866.jpg
deleted file mode 100755
index d1905964f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080930016f866.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080934433598e.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080934433598e.jpg
deleted file mode 100755
index b3581ab92..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104080934433598e.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040809550649773.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040809550649773.jpg
deleted file mode 100755
index 9d23f2ddb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040809550649773.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408104255a47ce.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408104255a47ce.jpg
deleted file mode 100755
index 3df984301..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/20110408104255a47ce.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104081119113f37f.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104081119113f37f.jpg
deleted file mode 100755
index da1e5d887..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/201104081119113f37f.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040811445023471.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040811445023471.jpg
deleted file mode 100755
index ddf8cc047..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040811445023471.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040814544385564.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040814544385564.jpg
deleted file mode 100755
index 3e770a2c8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040814544385564.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040815090608fd9.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040815090608fd9.jpg
deleted file mode 100755
index 5f01a91e0..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/8/2011040815090608fd9.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/9/20110409022720f974c.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/9/20110409022720f974c.jpg
deleted file mode 100755
index 9e06a8f0c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/2011/4/9/20110409022720f974c.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/netease/wzdzbs.gif b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/netease/wzdzbs.gif
deleted file mode 100755
index b224d7532..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/cnews/netease/wzdzbs.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/digi/linzj/1102/03/191.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/digi/linzj/1102/03/191.jpg
deleted file mode 100755
index b8ac59042..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/digi/linzj/1102/03/191.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/img09/icon/icon.png b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/img09/icon/icon.png
deleted file mode 100755
index 6c53687d5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/img09/icon/icon.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/attr.png b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/attr.png
deleted file mode 100755
index f4e5da8d4..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/attr.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/icon_product_listv0.0.3.png b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/icon_product_listv0.0.3.png
deleted file mode 100755
index 96302b004..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/icon_product_listv0.0.3.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/iconv0.0.7.png b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/iconv0.0.7.png
deleted file mode 100755
index 1c194a320..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/iconv0.0.7.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/neteasy_mallv0.0.1.png b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/neteasy_mallv0.0.1.png
deleted file mode 100755
index b3ca15626..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/neteasy_mallv0.0.1.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/theme_blue.png b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/theme_blue.png
deleted file mode 100755
index ee56407d7..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/theme_blue.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/yodao_bg_blue.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/yodao_bg_blue.jpg
deleted file mode 100755
index 5a0b12ac5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img1.cache.netease.com/www/v2011/img/yodao_bg_blue.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/game/20110216/ql/x/390x100.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/game/20110216/ql/x/390x100.jpg
deleted file mode 100755
index 4d66e1bcb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/game/20110216/ql/x/390x100.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/game/20110216/ql/x/600x80.gif b/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/game/20110216/ql/x/600x80.gif
deleted file mode 100755
index 9a4b4d09f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/game/20110216/ql/x/600x80.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/hr/20110216/hz/360x100.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/hr/20110216/hz/360x100.jpg
deleted file mode 100755
index 6a0790453..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/hr/20110216/hz/360x100.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/03/ly/390x100.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/03/ly/390x100.jpg
deleted file mode 100755
index 69dca1a0d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/03/ly/390x100.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/hy/190x100.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/hy/190x100.jpg
deleted file mode 100755
index 42b7b5088..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/hy/190x100.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/wb/360x65.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/wb/360x65.jpg
deleted file mode 100755
index 9fcb0fbd9..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/wb/360x65.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/yd/190x180.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/yd/190x180.jpg
deleted file mode 100755
index 738bf4f52..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.126.net/xoimages/sales/2011/04/yd/190x180.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/7/20110407093718ef414.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/7/20110407093718ef414.jpg
deleted file mode 100755
index 7305d4c89..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/7/20110407093718ef414.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/7/20110407202028db993.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/7/20110407202028db993.jpg
deleted file mode 100755
index d2b333d6f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/7/20110407202028db993.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104080728304dcb2.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104080728304dcb2.jpg
deleted file mode 100755
index cf3d891a5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104080728304dcb2.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408082635b6897.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408082635b6897.jpg
deleted file mode 100755
index a388b07ff..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408082635b6897.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104080828458908d.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104080828458908d.jpg
deleted file mode 100755
index 61d31fdd9..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104080828458908d.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040808393075049.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040808393075049.jpg
deleted file mode 100755
index d58ddb9f1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040808393075049.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040809433960d68.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040809433960d68.jpg
deleted file mode 100755
index 7c4ff5447..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040809433960d68.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408100357df2b1.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408100357df2b1.jpg
deleted file mode 100755
index 80d2d32da..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408100357df2b1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408115631ad273.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408115631ad273.jpg
deleted file mode 100755
index abb727cf2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408115631ad273.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408120203d0f08.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408120203d0f08.jpg
deleted file mode 100755
index 1370087a3..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408120203d0f08.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104081242198a4ba.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104081242198a4ba.jpg
deleted file mode 100755
index 0308b659c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104081242198a4ba.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040812525484a8f.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040812525484a8f.jpg
deleted file mode 100755
index 86e9a6af2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040812525484a8f.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408125931e0a79.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408125931e0a79.jpg
deleted file mode 100755
index 2208ff048..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408125931e0a79.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408140704d246b.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408140704d246b.jpg
deleted file mode 100755
index 86e50ca7f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408140704d246b.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408144428d419d.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408144428d419d.jpg
deleted file mode 100755
index 0f0cd9d38..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/20110408144428d419d.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040814452013ef7.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040814452013ef7.jpg
deleted file mode 100755
index b45184d5a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040814452013ef7.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040814525199c07.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040814525199c07.jpg
deleted file mode 100755
index d17750711..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/2011040814525199c07.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104082245192ae96.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104082245192ae96.jpg
deleted file mode 100755
index 7af2c4000..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/cnews/2011/4/8/201104082245192ae96.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/www/v2011/css/theme_blue1227.css b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/www/v2011/css/theme_blue1227.css
deleted file mode 100755
index 6605aff4a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/www/v2011/css/theme_blue1227.css
+++ /dev/null
@@ -1 +0,0 @@
-/* theme blue */ .mod .hd,.wgt-yodao-search .ui-btn-submit,.weather-location,.search-category-more,.yodao-search-category .current,.search-category-item a:hover,.yodao-dialog .ui-btn-submit,.yodao-dialog-close,.mod .hd,.tab-hd,.mod-function,.function-close,.product-list li {background:url("../../../../img1.cache.netease.com/www/v2011/img/theme_blue.png") no-repeat;} /* mod color */ .jstxlan,.c-entry,a.c-entry:visited,.c-entry a,.c-entry a:visited,.hd,.hd a,.hd a:visited,.tab-hd,.tab-hd a,.tab-hd a:visited,.search-category-item a {color:#1E50A2;} a.c-entry:hover,.c-entry a:hover,.hd a:hover,.jstxlan:hover{color:#ba2636;} .mod .bd,.mod .hd,.mod-function,.aboutNetease,.ntes-yodao {border:1px solid #B1C8D7;} .mod .bd {border-top:none;} .tab-hd {border-left:1px solid #B1C8D7;} .tab-hd .tab-u {border-top:1px solid #B1C8D7; border-right:1px solid #B1C8D7;} .area-sub .bd,.tab-u-5 .current,.product-tab .current,.aboutNetease {background-color:#F5F8FC;} .mod .hd,.tab-hd,.mod-function,.tab-hd-gg-left li,.tab-hd-gg-right li {background-color:#E6EEF7;} .tab-hd-gg-left .current,.tab-hd-gg-right .current {background-color:#D4E6F5;} /* yodao color */ .ntes-yodao {background:url("../../../../img1.cache.netease.com/www/v2011/img/yodao_bg_blue.jpg") left top no-repeat #D4E6F5;} .wgt-yodao-search .ui-btn-submit {color:#fff; background-color:#3981BD;} .yodao-search-category .current,.search-category-item a:hover {font-weight:bold; color:#fff;} .search-category-item a:hover {color:#fff;} .yodao-dialog {border:1px solid #B1C8D7; background:#fff;} .yodao-dialog .hd {background:#D4E6F5;} .yodao-dialog .bd {background:#E6EEF7;} .category-more-list {border:1px solid #B1C8D7; background:#fff;} .category-more-list a:hover {color:#fff; background:#1E50A2;} .aa_highlight {color:#fff;background:#1E50A2;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/www/v2011/img/tg_news.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/www/v2011/img/tg_news.jpg
deleted file mode 100755
index e4cd6bf2b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img2.cache.netease.com/www/v2011/img/tg_news.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/163homepage/biaoshi.gif b/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/163homepage/biaoshi.gif
deleted file mode 100755
index b8be1daef..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/163homepage/biaoshi.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/163homepage/bj110.gif b/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/163homepage/bj110.gif
deleted file mode 100755
index 2c9b488ee..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/163homepage/bj110.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/rpic/fld3/fld_homepage.js b/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/rpic/fld3/fld_homepage.js
deleted file mode 100755
index 45a11363b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/rpic/fld3/fld_homepage.js
+++ /dev/null
@@ -1,987 +0,0 @@
-
-var quanguo=new section(
-
-'³ÄÜÁìÐã³ÇÂþɽÏãÊû',
-'http://g.163.com/a?CID=1631&Values=979604783&Redirect=http://jn.house.163.com/topic/hz/lxcmsxs/index.shtml',
-
-'µ½ÎÞÎýÌì¶ìºþ³­µ×È¥',
-'http://g.163.com/a?CID=1632&Values=481254470&Redirect=http://wx.house.163.com/topic/hz/wxteh/',
-
-'ÎÞÎýµØ±êµÄ¼ÛֵͶ×Ê',
-'http://g.163.com/a?CID=1633&Values=3231158258&Redirect=http://wx.house.163.com/topic/hz/wxhd/',
-
-'ÌÆɽÍò´ïÏÖ·¿ÈÈÏú',
-'http://g.163.com/a?CID=1634&Values=3016013117&Redirect=http://www.tangshanwanda.com/',
-
-'µÚÒ»´Î¹º·¿Î¨Ñ¡Íò¿Æ',
-'http://g.163.com/a?CID=1635&Values=1850202326&Redirect=http://wh.vanke.com/Decoration/Index.aspx',
-
-'´óÏóȺרע»¥¶¯ÐÐÏú',
-'http://g.163.com/a?CID=1636&Values=2652887900&Redirect=http://www.daxiangqun.com/',
-
-'ÊÀ½ç±­¾º²ÂÓ®µçÄÔ',
-'http://g.163.com/a?CID=1637&Values=1890633164&Redirect=http://beijing.chineseoffice.com.cn',
-
-'ËæʱËæµØÊÕ·¢Óʼþ',
-'http://dxyy.mail.163.com/smspack/userconf/dxtz.do',
-
-'·¿ÀÏ´ó£¬Ô²ÄãÓмÒÃÎ',
-'http://g.163.com/a?CID=1639&Values=2962722568&Redirect=http://www.foloda.com',
-
-'´óÏóȺ רע»¥¶¯ÐÐÏú',
-'http://g.163.com/a?CID=1640&Values=1297729454&Redirect=http://www.daxiangqun.com/'
-
-);
-
-var anhui=new section(
-
-'ÍøÒ×·¿²úºÏ·Ê³ÏƸ',
-'http://g.163.com/a?CID=1431&Values=140707824&Redirect=http://hf.house.163.com/news2/101019/15/715993-1.shtml',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1432&Values=3444093944&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1433&Values=3930620465&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1434&Values=3400740464&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1435&Values=3330699301&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Ê׸¶15ÍòÍò¿Æ×°ÐÞ·¿',
-'http://g.163.com/a?CID=1436&Values=2716708116&Redirect=http://wh.vanke.com/indexad.asp?Title=0221163wzl&UrlTo=/house/goldencity/register.asp',
-
-'Íò´ïÔ¼»áÉãÓ°¡°´ï¡±ÈË',
-'http://g.163.com/a?CID=1437&Values=665590924&Redirect=http://hf.house.163.com/news2/110303/1/770167-1.shtml',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1438&Values=2211550380&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1439&Values=305957742&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'ËÕÖݹųǺËÐĽÖÆÌ',
-'http://g.163.com/a?CID=1440&Values=528917216&Redirect=http://suzhou.house.163.com/topic/suzhou/xintiandidd/index.htm'
-
-);
-
-var chongqing=new section(
-
-'÷ÈÁ¦Ö®³ÇÉý¼¶°æ£¡',
-'http://g.163.com/a?CID=1501&Values=1183866730&Redirect=http://wh.vanke.com/indexad.asp?Title=wangyiyouxiang&UrlTo=/house/usonian/register.asp',
-
-'¡°µ÷¿Ø¡±or¡°µ÷Ï·¡±',
-'http://g.163.com/a?CID=1502&Values=2836950569&Redirect=http://cq.house.163.com/topic/cq/tk/index.html',
-
-'°ëɽ»ª¸®2ÆÚ½«ÆôÄ»',
-'http://g.163.com/a?CID=1503&Values=1431490966&Redirect=http://cq.house.163.com/topic/cq/bshf110401/index.html',
-
-'Çá¹ì¸Ä±äÖØÇìÂ¥ÊÐ',
-'http://g.163.com/a?CID=1504&Values=936064134&Redirect=http://cq.house.163.com/topic/cq/qggbsh/index.html',
-
-'ÍøÒ×·¿²ú³É¶¼³ÏƸ',
-'http://g.163.com/a?CID=1505&Values=4093663140&Redirect=http://cq.house.163.com/news2/101019/8/715995-1.shtml',
-
-'ÏÞ¹º·ç±©Ç¿ÊÆÀ´Ï®',
-'http://g.163.com/a?CID=1506&Values=3046797410&Redirect=http://cq.house.163.com/topic/cq/xgl/index.html',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1507&Values=2696576883&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'±±Â´Ô­¿ªÅÌÈÈÏúÖÐ',
-'http://g.163.com/a?CID=1508&Values=2037757007&Redirect=http://cq.house.163.com/topic/cq/zybly110314/index.html',
-
-'ÍøÒ×·¿²úÖØÇìÕ¾ÕÐƸ',
-'http://g.163.com/a?CID=1509&Values=3615659065&Redirect=http://cq.house.163.com/topic/cq/cqzp/index.html',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1510&Values=3155480230&Redirect=http://www.foloda.com'
-
-);
-
-var fujian=new section(
-
-'ÍøÒ×·¿²ú¸£ÖݳÏƸ',
-'http://g.163.com/a?CID=1391&Values=440153523&Redirect=http://fz.house.163.com/news2/110106/8/749421-1.shtml',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1392&Values=875135822&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Ê¢ÊÀÍò´ï ÕÀ·ÅÕÄÖÝ',
-'http://g.163.com/a?CID=1393&Values=1352019128&Redirect=http://xm.house.163.com/topic/xm/zhangzhouwdgcdianji/zhangzhouwdgcdianji/index.html',
-
-'ÄÏÖйú¼Ò×å´óÕ¬',
-'http://g.163.com/a?CID=1394&Values=3905919256&Redirect=http://xm.house.163.com/topic/xm/ydzzyj/ydzz.htm',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1395&Values=3761932044&Redirect=http://www.chineseoffice.com.cn/',
-
-'ÍøÒ×·¿²úÏÃÃųÏƸ',
-'http://g.163.com/a?CID=1396&Values=1528249410&Redirect=http://xm.house.163.com/news2/110215/8/762587-1.shtml',
-
-'ȪÖÝÆÖÎ÷Íò´ï¹ã³¡',
-'http://g.163.com/a?CID=1397&Values=168539782&Redirect=http://xm.house.163.com/topic/xm/qzpxwdgc/',
-
-'ÐǾÛÍò´ï ÁìÒ«º£Î÷',
-'http://g.163.com/a?CID=1398&Values=942518717&Redirect=http://xm.house.163.com/topic/xm/wdzc/',
-
-'ÕÄÖÝ·¿Ô´ Ò»Íø´ò¾¡',
-'http://g.163.com/a?CID=1399&Values=658166132&Redirect=http://zhangzhou.house.163.com',
-
-'ËÕÖݹųǺËÐĽÖÆÌ',
-'http://g.163.com/a?CID=1400&Values=2760702008&Redirect=http://suzhou.house.163.com/topic/suzhou/xintiandidd/index.htm'
-
-);
-
-var gansu=new section(
-
-'ÍøÒ×·¿²úÀ¼ÖݳÏƸ',
-'http://g.163.com/a?CID=1591&Values=696978067&Redirect=http://lz.house.163.com/news2/101020/3/716104-1.shtml',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1592&Values=339419003&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Ê×´´¹ú¼Ê³ÇÁìÏα±³Ç',
-'http://g.163.com/a?CID=1593&Values=3649096630&Redirect=http://km.house.163.com/topic/xa/scgjcba/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1594&Values=1495066886&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1595&Values=3004257764&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1596&Values=3723417916&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1597&Values=3731340378&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1598&Values=1663707362&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1599&Values=621830313&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1600&Values=1511589405&Redirect=http://www.foloda.com'
-
-);
-
-var guangxi=new section(
-
-'ÍøÒ×·¿²úÄÏÄþ³ÏƸ',
-'http://g.163.com/a?CID=1531&Values=1077111064&Redirect=http://nn.house.163.com/news2/101019/15/716001-1.shtml',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1532&Values=2705180565&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1533&Values=972094116&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'Àì½­À¶ÍåÁëÓòµ½À¶Íå',
-'http://g.163.com/a?CID=1534&Values=1337672369&Redirect=http://www.v9666.com',
-
-'°ëɽ»ª¸®2ÆÚ½«ÆôÄ»',
-'http://g.163.com/a?CID=1535&Values=440431970&Redirect=http://cq.house.163.com/topic/cq/bshf110401/index.html',
-
-'÷ÈÁ¦Ö®³ÇÉý¼¶°æ£¡',
-'http://g.163.com/a?CID=1536&Values=554921589&Redirect=http://wh.vanke.com/indexad.asp?Title=wangyiyouxiang&UrlTo=/house/usonian/register.asp',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1537&Values=1603859496&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'±±Â´Ô­¿ªÅÌÈÈÏúÖÐ',
-'http://g.163.com/a?CID=1538&Values=4242251342&Redirect=http://cq.house.163.com/topic/cq/zybly110314/index.html',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1539&Values=974017740&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1540&Values=722714999&Redirect=http://www.foloda.com'
-
-);
-
-var guizhou=new section(
-
-'ÍøÒ×·¿²ú¹óÑô³ÏƸ',
-'http://g.163.com/a?CID=1511&Values=1125427351&Redirect=http://gy.house.163.com/news2/101019/15/715994-1.shtml',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1512&Values=2565614707&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1513&Values=2983829438&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'Àì½­À¶ÍåÁëÓòµ½À¶Íå',
-'http://g.163.com/a?CID=1514&Values=1065898650&Redirect=http://www.v9666.com',
-
-'°ëɽ»ª¸®2ÆÚ½«ÆôÄ»',
-'http://g.163.com/a?CID=1515&Values=4068513241&Redirect=http://cq.house.163.com/topic/cq/bshf110401/index.html',
-
-'÷ÈÁ¦Ö®³ÇÉý¼¶°æ£¡',
-'http://g.163.com/a?CID=1516&Values=917345527&Redirect=http://wh.vanke.com/indexad.asp?Title=wangyiyouxiang&UrlTo=/house/usonian/register.asp',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1517&Values=3140966748&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'±±Â´Ô­¿ªÅÌÈÈÏúÖÐ',
-'http://g.163.com/a?CID=1518&Values=2970839809&Redirect=http://cq.house.163.com/topic/cq/zybly110314/index.html',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1519&Values=1000416879&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1520&Values=3039296944&Redirect=http://www.foloda.com'
-
-);
-
-var hebei=new section(
-
-'´óÏóȺרעµØ²ú»¥¶¯',
-'http://g.163.com/a?CID=1481&Values=3857846246&Redirect=http://www.daxiangqun.com/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1482&Values=3641079257&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1483&Values=2276506178&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1484&Values=1308762028&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'È¥ÄÏ´÷ºÓ ÁÙº£ÌýÌÎ',
-'http://g.163.com/a?CID=1485&Values=674631556&Redirect=http://qhd.house.163.com/topic/hz/lhtt0331/',
-
-'Ê׸¶15ÍòÍò¿Æ×°ÐÞ·¿',
-'http://g.163.com/a?CID=1486&Values=185257524&Redirect=http://wh.vanke.com/indexad.asp?Title=0221163wzl&UrlTo=/house/goldencity/register.asp',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1487&Values=2245822886&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1488&Values=2492828518&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1489&Values=709633319&Redirect=http://beijing.chineseoffice.com.cn',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1490&Values=1922383439&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp'
-
-);
-
-var heilongjiang=new section(
-
-'Íò´ï¹«¹Ý ºÀÕ¬µä·¶',
-'http://g.163.com/a?CID=1561&Values=3878478489&Redirect=http://www.wandamansion.com',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1562&Values=3205384429&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Ê×´´¹ú¼Ê³ÇÁìÏα±³Ç',
-'http://g.163.com/a?CID=1563&Values=2478625523&Redirect=http://km.house.163.com/topic/xa/scgjcba/',
-
-'Ô¶Ñóʱ´ú³ÇÐÂÆ·³ö»÷',
-'http://g.163.com/a?CID=1564&Values=119944109&Redirect=http://www.yysdc.com/',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1565&Values=34746919&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'´óÏóȺרעµØ²ú»¥¶¯',
-'http://g.163.com/a?CID=1566&Values=3771046252&Redirect=http://www.daxiangqun.com/',
-
-'ËÕÖݹųǺËÐĽÖÆÌ',
-'http://g.163.com/a?CID=1567&Values=3020440879&Redirect=http://suzhou.house.163.com/topic/suzhou/xintiandidd/index.htm',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1568&Values=1549320734&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'È¥ÄÏ´÷ºÓ ÁÙº£ÌýÌÎ',
-'http://g.163.com/a?CID=1569&Values=117217106&Redirect=http://qhd.house.163.com/topic/hz/lhtt0331/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1570&Values=1423017304&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp'
-
-);
-
-var henan=new section(
-
-'ÍøÒ×·¿²úÖ£ÖÝÕ¾ÕÐƸ',
-'http://g.163.com/a?CID=1471&Values=2531271616&Redirect=http://zz.house.163.com/news2/101020/1/716068-1.shtml',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1472&Values=2927214491&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Íò´ï¾«×°SOHO½«Èϳï',
-'http://g.163.com/a?CID=1473&Values=303570349&Redirect=http://zz.house.163.com/topic/hz/zywanda/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1474&Values=2822872691&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'Ö£ÖÝÂò·¿£¬ÍøÒ×°ïæ',
-'http://g.163.com/a?CID=1475&Values=846902695&Redirect=http://zz.house.163.com/topic/hz/zzhx/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1476&Values=3992464607&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1477&Values=2041088546&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1478&Values=95266873&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1479&Values=1720943188&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1480&Values=4032443472&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp'
-
-);
-
-var hubei=new section(
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1371&Values=1761110635&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'ËÕÖݹųǺËÐĽÖÆÌ',
-'http://g.163.com/a?CID=1372&Values=1606976687&Redirect=http://suzhou.house.163.com/topic/suzhou/xintiandidd/index.htm',
-
-'÷ÈÁ¦Ö®³ÇÉý¼¶°æ£¡',
-'http://g.163.com/a?CID=1373&Values=1784622907&Redirect=http://wh.vanke.com/indexad.asp?Title=wangyiyouxiang&UrlTo=/house/usonian/register.asp',
-
-'2011ÎÒÃÇÒ»ÆðÂò·¿°É',
-'http://g.163.com/a?CID=1374&Values=3122894164&Redirect=http://wh.house.163.com/topic/wh/wankezh0317/index.htm',
-
-'°ëɽ»ª¸®2ÆÚ½«ÆôÄ»',
-'http://g.163.com/a?CID=1375&Values=767698364&Redirect=http://cq.house.163.com/topic/cq/bshf110401/index.html',
-
-'±±Â´Ô­3ÔÂ26ÈÕ¿ªÅÌ',
-'http://g.163.com/a?CID=1376&Values=3250660165&Redirect=http://cq.house.163.com/topic/cq/zybly110314/index.html',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1377&Values=3657120673&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'ÍøÒ×·¿²úÎ人վÕÐƸ',
-'http://g.163.com/a?CID=1378&Values=1352200508&Redirect=http://wh.house.163.com/topic/hz/whzp/index.html',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1379&Values=3241571470&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1380&Values=2788700399&Redirect=http://www.foloda.com'
-
-);
-
-var hunan=new section(
-
-'ÍøÒ×·¿²úºþÄÏÕÐƸ',
-'http://g.163.com/a?CID=1491&Values=172820044&Redirect=http://cs.house.163.com/news2/101207/13/737830-1.shtml',
-
-'ºã´óÂÌÖÞ ÐÂÆ·Ò«ÊÀ',
-'http://g.163.com/a?CID=1492&Values=3746216837&Redirect=http://ad.foloda.com/11dy/cshd/',
-
-'³¤É³Íò¿Æ ÐÂÆ··¢²¼',
-'http://g.163.com/a?CID=1493&Values=3517398304&Redirect=http://ad.foloda.com/10dy/cswkc',
-
-'³¤É³Íò´ï Ê×ϯºÀÕ¬',
-'http://g.163.com/a?CID=1494&Values=1457375266&Redirect=http://www.cswdgg.com/',
-
-'ÖÐÁ¸µØ²úÂÌÉ«¼ÎÄ껪',
-'http://g.163.com/a?CID=1495&Values=3615474435&Redirect=http://cs.house.163.com/news2/110323/4/779240-1.shtml',
-
-'±±Â´Ô­3ÔÂ26ÈÕ¿ªÅÌ',
-'http://g.163.com/a?CID=1496&Values=524253096&Redirect=http://cq.house.163.com/topic/cq/zybly110314/index.html',
-
-'Ïæ½­ÊÀ¼Í³Ç»¨Ô°´óÕ¬',
-'http://g.163.com/a?CID=1497&Values=599632246&Redirect=http://ad.foloda.com/11dy/xjsjc/',
-
-'ÉÏÎå¿ó΢²©£¬Ó®IPAD',
-'http://g.163.com/a?CID=1498&Values=133994750&Redirect=http://cs.house.163.com/news2/110321/4/777990-1.shtml',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1499&Values=2128022708&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1500&Values=728830475&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp'
-
-);
-
-var jiangsu=new section(
-
-'ÍøÒ×·¿²ú½­ËÕ³ÏƸ',
-'http://g.163.com/a?CID=1421&Values=1720134227&Redirect=http://nj.house.163.com/news2/101019/15/715992-1.shtml',
-
-'ÄϾ©Íò´ïÖÐÐÄÆô¶¯ÖÐ',
-'http://g.163.com/a?CID=1422&Values=909788656&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1423&Values=3971362695&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1424&Values=336124741&Redirect=http://www.chineseoffice.com.cn/',
-
-'ËÕÖÝÂ¥ÅÌÐÅÏ¢Ò»ÀÀ',
-'http://g.163.com/a?CID=1425&Values=1954580977&Redirect=http://xf.house.163.com/suzhou/search!xfs.action',
-
-'´óÏóȺרעµØ²ú»¥¶¯',
-'http://g.163.com/a?CID=1426&Values=1687166304&Redirect=http://www.daxiangqun.com/',
-
-'Ͷ×ʾÍÒª´Ó³­µ×¿ªÊ¼',
-'http://g.163.com/a?CID=1427&Values=723479546&Redirect=http://suzhou.house.163.com/topic/suzhou/ganglongcaizhi/index.html',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1428&Values=199811649&Redirect=http://www.foloda.com',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1429&Values=4148656357&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'ËÕÖÝ×îз¿²ú×ÊѶ',
-'http://g.163.com/a?CID=1430&Values=1245676825&Redirect=http://suzhou.house.163.com/'
-
-);
-
-var jiangxi=new section(
-
-'ÍøÒ×·¿²úÄϲý³ÏƸ',
-'http://g.163.com/a?CID=1401&Values=650836040&Redirect=http://nc.house.163.com/news2/101020/8/716061-1.shtml',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1402&Values=2175178201&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1403&Values=2501733054&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1404&Values=3569609227&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1405&Values=1627759603&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'Ê׸¶15ÍòÍò¿Æ×°ÐÞ·¿',
-'http://g.163.com/a?CID=1406&Values=2762263709&Redirect=http://wh.vanke.com/indexad.asp?Title=0221163wzl&UrlTo=/house/goldencity/register.asp',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1407&Values=658658995&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1408&Values=2474916214&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1409&Values=3955873125&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'ËÕÖݹųǺËÐĽÖÆÌ',
-'http://g.163.com/a?CID=1410&Values=1856220854&Redirect=http://suzhou.house.163.com/topic/suzhou/xintiandidd/index.htm'
-
-);
-
-var jilin=new section(
-
-'ÍøÒ×·¿²ú³¤´º³ÏƸ',
-'http://g.163.com/a?CID=1551&Values=1375398756&Redirect=http://cc.house.163.com/news2/101019/13/716002-1.shtml',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1552&Values=1562763119&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Íò´ï¹«¹Ý ºÀÕ¬µä·¶',
-'http://g.163.com/a?CID=1553&Values=3787022975&Redirect=http://www.wandamansion.com',
-
-'Ô¶Ñóʱ´ú³ÇÐÂÆ·³ö»÷',
-'http://g.163.com/a?CID=1554&Values=1814382010&Redirect=http://www.yysdc.com/',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1555&Values=2362854501&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'´óÏóȺרעµØ²ú»¥¶¯',
-'http://g.163.com/a?CID=1556&Values=326828771&Redirect=http://www.daxiangqun.com/',
-
-'ËÕÖݹųǺËÐĽÖÆÌ',
-'http://g.163.com/a?CID=1557&Values=1762785357&Redirect=http://suzhou.house.163.com/topic/suzhou/xintiandidd/index.htm',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1558&Values=3876685191&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'È¥ÄÏ´÷ºÓ ÁÙº£ÌýÌÎ',
-'http://g.163.com/a?CID=1559&Values=2864408708&Redirect=http://qhd.house.163.com/topic/hz/lhtt0331/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1560&Values=2519885896&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp'
-
-);
-
-var liaoning=new section(
-
-'Íò´ï¹«¹Ý ºÀÕ¬µä·¶',
-'http://g.163.com/a?CID=1541&Values=2048003453&Redirect=http://www.wandamansion.com',
-
-'Ô¶Ñóʱ´ú³ÇÐÂÆ·³ö»÷',
-'http://g.163.com/a?CID=1542&Values=540544072&Redirect=http://www.yysdc.com/',
-
-'ÍøÒ×·¿²ú³ÏƸӢ²Å',
-'http://g.163.com/a?CID=1543&Values=2504234005&Redirect=http://sy.house.163.com/news2/110325/13/780322-1.shtml',
-
-'»ª¸®µ¤¿¤¼´½«ÆôÄ»',
-'http://g.163.com/a?CID=1544&Values=4239144350&Redirect=http://xf.house.163.com/sy/0KNQ.html',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1545&Values=3531852737&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1546&Values=432142392&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'ËÕÖݹųǺËÐĽÖÆÌ',
-'http://g.163.com/a?CID=1547&Values=3758417274&Redirect=http://suzhou.house.163.com/topic/suzhou/xintiandidd/index.htm',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1548&Values=1006342877&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'È¥ÄÏ´÷ºÓ ÁÙº£ÌýÌÎ',
-'http://g.163.com/a?CID=1549&Values=1969115744&Redirect=http://qhd.house.163.com/topic/hz/lhtt0331/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1550&Values=3058321033&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp'
-
-);
-
-var neimenggu=new section(
-
-'Íò´ï¹«¹Ý ºÀÕ¬µä·¶',
-'http://g.163.com/a?CID=1571&Values=4261276105&Redirect=http://www.wandamansion.com',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1572&Values=3151751761&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Ê×´´¹ú¼Ê³ÇÁìÏα±³Ç',
-'http://g.163.com/a?CID=1573&Values=2511114005&Redirect=http://km.house.163.com/topic/xa/scgjcba/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1574&Values=627933417&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1575&Values=1216993560&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1576&Values=553663321&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1577&Values=357376222&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1578&Values=759167894&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1579&Values=1481138169&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1580&Values=4211744630&Redirect=http://www.foloda.com'
-
-);
-
-var ningxia=new section(
-
-'Íò´ï¹«¹Ý ºÀÕ¬µä·¶',
-'http://g.163.com/a?CID=1601&Values=600487394&Redirect=http://www.wandamansion.com',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1602&Values=4056996756&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Ê×´´¹ú¼Ê³ÇÁìÏα±³Ç',
-'http://g.163.com/a?CID=1603&Values=3107658362&Redirect=http://km.house.163.com/topic/xa/scgjcba/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1604&Values=21683722&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1605&Values=152826465&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1606&Values=2002593813&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1607&Values=1061836462&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1608&Values=1151735200&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1609&Values=2910377874&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1610&Values=3427746272&Redirect=http://www.foloda.com'
-
-);
-
-var qinghai=new section(
-
-'Íò´ï¹«¹Ý ºÀÕ¬µä·¶',
-'http://g.163.com/a?CID=1611&Values=1125876318&Redirect=http://www.wandamansion.com',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1612&Values=422600227&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Ê×´´¹ú¼Ê³ÇÁìÏα±³Ç',
-'http://g.163.com/a?CID=1613&Values=2302037667&Redirect=http://km.house.163.com/topic/xa/scgjcba/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1614&Values=3372736983&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1615&Values=1038548139&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1616&Values=2301270961&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1617&Values=2904508348&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1618&Values=410602887&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1619&Values=4248627044&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1620&Values=1258697523&Redirect=http://www.foloda.com'
-
-);
-
-var qita=new section(
-
-'΢²©ÊÖ»ú¿Í»§¶Ë·¢²¼',
-'http://t.163.com/mobile',
-
-'ÊÖ»úËæʱÊÕ·¢Óʼþ',
-'http://mail.blog.163.com/blog/static/822094242010829103528389/',
-
-'ÍøÒ×2010ÄêÖղ߻®',
-'http://news.163.com/special/2010ending/',
-
-'ÓÊÏä13ÄêÔ¼»á°Éר³¡',
-'http://mail.blog.163.com/blog/static/822094242010112823415891/',
-
-'163/126¼æÈÝiPhone',
-'http://help.163.com/special/007525G0/163mail_guide.html?id=2716',
-
-'Íø¾Û°®µÄÁ¦Á¿°ïº¢×Ó',
-'http://gongyi.163.com/love365?mailsignresult=-1',
-
-'¿ìÀ´ÁìÏã¸ÛË«·ÉÓÎ',
-'http://quan.123.163.com/?from=163wenzilian',
-
-'ÊÖ»ú¿´¹ÉƱÿÈÕÕÇÍ£',
-'http://help.3g.163.com/stock/',
-
-'ÍøÒ×аæÊÖ»úÓÊÈí¼þ',
-'http://m.123.163.com/?sjysc1108',
-
-'½áÊøµ¥Éí±Ø±¸Èí¼þ',
-'http://bafang.163.com/'
-
-);
-
-var shan3xi=new section(
-
-'Ê×´´¹ú¼Ê³ÇÁìÏα±³Ç',
-'http://g.163.com/a?CID=1461&Values=2136197145&Redirect=http://km.house.163.com/topic/xa/scgjcba/',
-
-'ÍøÒ×·¿²úÎ÷°²ÕÐƸ',
-'http://g.163.com/a?CID=1462&Values=3316917425&Redirect=http://xa.house.163.com/topic/hz/xazp/',
-
-'×ðÏíÎ÷°²ºþ¾ÓÉú»î',
-'http://g.163.com/a?CID=1463&Values=149345275&Redirect=http://km.house.163.com/topic/xa/scgjcba/',
-
-'2011´º¼¾Î÷°²×¡²©»á',
-'http://g.163.com/a?CID=1464&Values=3712988329&Redirect=http://xa.house.163.com/news2/110118/8/753783-1.shtml',
-
-'Î÷°²ÈȵºÂò·¿Õýµ±Ê±',
-'http://g.163.com/a?CID=1465&Values=697392130&Redirect=http://xa.house.163.com/topic/xa/gxzt/',
-
-'´óÏóȺרעµØ²ú»¥¶¯',
-'http://g.163.com/a?CID=1466&Values=238246322&Redirect=http://www.daxiangqun.com/',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1467&Values=3040981522&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1468&Values=3374925437&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1469&Values=169976250&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'´ó¶¼ÊÐÇ×ˮʫÒâÉú»î',
-'http://g.163.com/a?CID=1470&Values=793011485&Redirect=http://xa.house.163.com/topic/hz/zsej/'
-
-);
-
-var shandong=new section(
-
-'½üÍò¸»ºÀÆë¾ÛÈýÑÇ',
-'http://g.163.com/a?CID=1441&Values=1689407094&Redirect=http://house.qingdaonews.com/content/2011-03/23/content_8710368.htm',
-
-'Ϋ·»Ãâ·Ñ¿´·¿',
-'http://g.163.com/a?CID=1442&Values=988792884&Redirect=http://house.weifang.hiao.com/content/2011-03/03/content_8685275.htm',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1443&Values=2706386599&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1444&Values=3392035014&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ɹÃÎÏëӮǧԪ´ó½±',
-'http://g.163.com/a?CID=1445&Values=2614083527&Redirect=http://i.hiao.com/hd/index190.html',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1446&Values=436911461&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1447&Values=1215367967&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'Çൺ¥ÊÐ315',
-'http://g.163.com/a?CID=1448&Values=112924560&Redirect=http://house.qingdaonews.com/node/node_42308.htm',
-
-'³ÇÊйۺ£±ðÊû',
-'http://g.163.com/a?CID=1449&Values=2667970567&Redirect=http://house.qingdaonews.com/gb/content/2011-03/15/content_8699694.htm',
-
-'Íþº£Ãâ·Ñ¿´·¿',
-'http://g.163.com/a?CID=1450&Values=1035911948&Redirect=http://house.weihai.hiao.com/node/node_39337.htm'
-
-);
-
-var shanghai=new section(
-
-'ÄÚ»·ÅÔ¼õ8Íò-10Íò',
-'http://g.163.com/a?CID=1381&Values=3418458884&Redirect=http://163.foloda.com/topic/sh/ycgg100913/',
-
-'ÕÐÉÌÍò¿Æ ÙÜɽ´óÖø',
-'http://g.163.com/a?CID=1382&Values=1445599854&Redirect=http://163.foloda.com/topic/sh/zsssly1231/',
-
-'ÖÐÓ¥ºÚÉ­Á־Ƶ깫Ԣ',
-'http://g.163.com/a?CID=1383&Values=1157074672&Redirect=http://163.foloda.com/topic/sh/hsl/',
-
-'ÐÇÔ¹ú¼ÊÉÌÎñÆì½¢',
-'http://g.163.com/a?CID=1384&Values=1190500672&Redirect=http://163.foloda.com/topic/sh/xygj313/',
-
-'ÒÕÊõÆ·¼øÀ¿´äÔ·',
-'http://g.163.com/a?CID=1385&Values=2729506797&Redirect=http://myforest-lcy.com/',
-
-'Öл·±ÌÔƾ«×°·¿78Íò',
-'http://g.163.com/a?CID=1386&Values=1105865289&Redirect=http://163.foloda.com/topic/sh/yzlj1129/',
-
-'סլÉý¼¶ ÇÄÈ»¶øÖÁ',
-'http://g.163.com/a?CID=1387&Values=2851867226&Redirect=http://kunshan.house.163.com/news2/110407/3/785623-1.shtml',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1388&Values=1103941632&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'ÁúºþºÃÍûɽµÇ¶¥ÙÜɽ',
-'http://g.163.com/a?CID=1389&Values=2072858580&Redirect=http://163.foloda.com/topic/sh/longhu323/',
-
-'ºçÇÅÉÌ°ì14800Ôª/©O',
-'http://g.163.com/a?CID=1390&Values=2853946711&Redirect=http://163.foloda.com/topic/sh/bswd316/'
-
-);
-
-var shanxi=new section(
-
-'ÍøÒ×·¿²úÌ«Ô­³ÏƸ',
-'http://g.163.com/a?CID=1451&Values=2703525003&Redirect=http://ty.house.163.com/news2/101019/1/715996-1.shtml',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1452&Values=1268981401&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1453&Values=1884424223&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1454&Values=2833138962&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1455&Values=258898259&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Ê׸¶15ÍòÍò¿Æ×°ÐÞ·¿',
-'http://g.163.com/a?CID=1456&Values=4253558500&Redirect=http://wh.vanke.com/indexad.asp?Title=0221163wzl&UrlTo=/house/goldencity/register.asp',
-
-'ËÕÖݹųǺËÐĽÖÆÌ',
-'http://g.163.com/a?CID=1457&Values=4069211149&Redirect=http://suzhou.house.163.com/topic/suzhou/xintiandidd/index.htm',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1458&Values=2510006128&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1459&Values=1167961316&Redirect=http://www.chineseoffice.com.cn/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1460&Values=1466984727&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp'
-
-);
-
-var tianjin=new section(
-
-'ÍøÒ×Ìì½òÕ¾ÕÐƸ',
-'http://g.163.com/a?CID=1361&Values=2929173111&Redirect=http://tj.house.163.com/news2/101019/1/715997-1.shtml',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1362&Values=3777304491&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'Ê׸¶15ÍòÍò¿Æ×°ÐÞ·¿',
-'http://g.163.com/a?CID=1363&Values=3440031390&Redirect=http://wh.vanke.com/indexad.asp?Title=0221163wzl&UrlTo=/house/goldencity/register.asp',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1364&Values=929124833&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1365&Values=90205709&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1366&Values=3689197257&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1367&Values=1968599507&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'ËÕÖݹųǺËÐĽÖÆÌ',
-'http://g.163.com/a?CID=1368&Values=810850245&Redirect=http://suzhou.house.163.com/topic/suzhou/xintiandidd/index.htm',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1369&Values=1611213978&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1370&Values=860811041&Redirect=http://www.foloda.com'
-
-);
-
-var xinjiang=new section(
-
-'Íò´ï¹«¹Ý ºÀÕ¬µä·¶',
-'http://g.163.com/a?CID=1581&Values=3365491210&Redirect=http://www.wandamansion.com',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1582&Values=336470330&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Ê×´´¹ú¼Ê³ÇÁìÏα±³Ç',
-'http://g.163.com/a?CID=1583&Values=3472861197&Redirect=http://km.house.163.com/topic/xa/scgjcba/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1584&Values=1804131147&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1585&Values=3609375102&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1586&Values=993300697&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1587&Values=460987308&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1588&Values=1431906569&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1589&Values=956197227&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1590&Values=4241274752&Redirect=http://www.foloda.com'
-
-);
-
-var xizang=new section(
-
-'Íò´ï¹«¹Ý ºÀÕ¬µä·¶',
-'http://g.163.com/a?CID=1621&Values=1130191017&Redirect=http://www.wandamansion.com',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1622&Values=1292665924&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'Ê×´´¹ú¼Ê³ÇÁìÏα±³Ç',
-'http://g.163.com/a?CID=1623&Values=2757938531&Redirect=http://km.house.163.com/topic/xa/scgjcba/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1624&Values=1197009682&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1625&Values=3326422532&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1626&Values=2856965099&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1627&Values=3569650124&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1628&Values=2300324860&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1629&Values=3612030918&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1630&Values=3299402376&Redirect=http://www.foloda.com'
-
-);
-
-var yunnan=new section(
-
-'ÍøÒ×·¿²úÀ¥Ã÷³ÏƸ',
-'http://g.163.com/a?CID=1521&Values=631016055&Redirect=http://km.house.163.com/news2/101019/15/716000-1.shtml',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1522&Values=1485880991&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1523&Values=2669915245&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'Àì½­À¶ÍåÁëÓòµ½À¶Íå',
-'http://g.163.com/a?CID=1524&Values=2351486230&Redirect=http://www.v9666.com',
-
-'°ëɽ»ª¸®2ÆÚ½«ÆôÄ»',
-'http://g.163.com/a?CID=1525&Values=1629509434&Redirect=http://cq.house.163.com/topic/cq/bshf110401/index.html',
-
-'÷ÈÁ¦Ö®³ÇÉý¼¶°æ£¡',
-'http://g.163.com/a?CID=1526&Values=497803574&Redirect=http://wh.vanke.com/indexad.asp?Title=wangyiyouxiang&UrlTo=/house/usonian/register.asp',
-
-'Íò¿Æ½ðÓòÀ¶Í彫¿ªÅÌ',
-'http://g.163.com/a?CID=1527&Values=3247905635&Redirect=http://wh.vanke.com/indexad.asp?Title=163sywzl0321&UrlTo=/house/paradiso/register.asp',
-
-'±±Â´Ô­¿ªÅÌÈÈÏúÖÐ',
-'http://g.163.com/a?CID=1528&Values=1569929022&Redirect=http://cq.house.163.com/topic/cq/zybly110314/index.html',
-
-'פ¾©°ìÊ´¦Ñ¡Ö·´óÈ«',
-'http://g.163.com/a?CID=1529&Values=533233735&Redirect=http://beijing.chineseoffice.com.cn',
-
-'¶þÊÖ·¿×â·¿--·¿ÀÏ´ó',
-'http://g.163.com/a?CID=1530&Values=2870090898&Redirect=http://www.foloda.com'
-
-);
-
-var zhejiang=new section(
-
-'ÕãÉ̲Ƹ»ÖÐÐÄÔ¤¿ªÅÌ',
-'http://g.163.com/a?CID=1411&Values=3567176511&Redirect=http://hz.house.163.com/topic/nb/morect/index.html',
-
-'Íò´ïÕÐÉÌÈ«ÃæÆô¶¯',
-'http://g.163.com/a?CID=1412&Values=1748498680&Redirect=http://xm.house.163.com/topic/hz/xmwd/index.html',
-
-'±ÈÈËÆøÓ®IPHONE4£¡',
-'http://g.163.com/a?CID=1413&Values=3953215278&Redirect=http://www.xici.net/d143476647.htm',
-
-'ÉÌÒµµØ²úͶ×ÊÇ÷»ð±¬',
-'http://g.163.com/a?CID=1414&Values=958729281&Redirect=http://ts.house.163.com//topic/hz/tswd001/index1.html',
-
-'ÁìÐã³Ç×¼ÏÖ·¿·¢ÊÛÖÐ',
-'http://g.163.com/a?CID=1415&Values=2306815090&Redirect=http://jn.house.163.com/topic/hz/lnzygy/',
-
-'¹ú¼ÊÍò´ï£¬ÔìÐĽ­Òõ',
-'http://g.163.com/a?CID=1416&Values=3583016750&Redirect=http://wx.house.163.com/topic/hz/jywd/',
-
-'Íò´ïÖÐÐÄÉÌÎñÇøÆô¶¯',
-'http://g.163.com/a?CID=1417&Values=1066762875&Redirect=http://nj.house.163.com/topic/hz/njwd/',
-
-'Íò´ïºÀÕ¬ ÔÙÒ«ºÏ·Ê',
-'http://g.163.com/a?CID=1418&Values=3834533750&Redirect=http://hf.house.163.com/topic/hz/hfwdgg2/',
-
-'ËÕÖݹųǺËÐĽÖÆÌ',
-'http://g.163.com/a?CID=1419&Values=2659532313&Redirect=http://suzhou.house.163.com/topic/suzhou/xintiandidd/index.htm',
-
-'Ê×´´¹ú¼Ê³ÇÁìÏα±³Ç',
-'http://g.163.com/a?CID=1420&Values=3110216503&Redirect=http://km.house.163.com/topic/xa/scgjcba/'
-
-);
-
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/rpic/fld3/flsclasses.js b/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/rpic/fld3/flsclasses.js
deleted file mode 100755
index e3e5d8082..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/rpic/fld3/flsclasses.js
+++ /dev/null
@@ -1,30 +0,0 @@
-//ÀàÄ£°å
-function section(a1,a2,b1,b2,c1,c2,d1,d2,e1,e2,f1,f2,g1,g2,h1,h2,k1,k2,p1,p2){
- this.string0=a1; this.link0=a2;
- this.string1=b1; this.link1=b2;
- this.string2=c1; this.link2=c2;
- this.string3=d1; this.link3=d2;
- this.string4=e1; this.link4=e2;
- this.string5=f1; this.link5=f2;
- this.string6=g1; this.link6=g2;
- this.string7=h1; this.link7=h2;
- this.string8=k1; this.link8=k2;
- this.string9=p1; this.link9=p2;
-}
-//Êä³öº¯Êý
-function echoa(clicks){
- //Êä³öÎÄ×Ö
- void('<a href="' + prov.link0 + '" target="_blank">' + prov.string0 + '</a>');
- void('<a href="' + prov.link1 + '" target="_blank">' + prov.string1 + '</a>');
- void('<a href="' + prov.link2 + '" target="_blank">' + prov.string2 + '</a>');
- void('<a href="' + prov.link3 + '" target="_blank">' + prov.string3 + '</a>');
- void('<a href="' + prov.link4 + '" target="_blank">' + prov.string4 + '</a>');
-}
-function echob(clicks){
- //Êä³öÎÄ×Ö
- void('<a href="' + prov.link5 + '" target="_blank">' + prov.string5 + '</a>');
- void('<a href="' + prov.link6 + '" target="_blank">' + prov.string6 + '</a>');
- void('<a href="' + prov.link7 + '" target="_blank">' + prov.string7 + '</a>');
- void('<a href="' + prov.link8 + '" target="_blank">' + prov.string8 + '</a>');
- void('<a href="' + prov.link9 + '" target="_blank">' + prov.string9 + '</a>');
-} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/techpro/shangpin/20110331/36-65.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/techpro/shangpin/20110331/36-65.jpg
deleted file mode 100755
index 5e63909a8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/techpro/shangpin/20110331/36-65.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/techpro/tuangou/20110218/170-80.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/techpro/tuangou/20110218/170-80.jpg
deleted file mode 100755
index b5e7492cf..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/techpro/tuangou/20110218/170-80.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/yodaoimages/pack.r091221/scripts/autocomplete.163.165290.js b/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/yodaoimages/pack.r091221/scripts/autocomplete.163.165290.js
deleted file mode 100755
index 69ad0da6f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/yodaoimages/pack.r091221/scripts/autocomplete.163.165290.js
+++ /dev/null
@@ -1 +0,0 @@
-var SC={create:function(){return function(){this.initialize.apply(this,arguments)}}};function $S(){var _=[],$;for(var A=0;A<arguments.length;A++){$=arguments[A];if(typeof $=="string")$=document.getElementById($);_.push($)}return _.length<2?_[0]:_}function $SA(_){if(!_)return[];if(_.toArray)return _.toArray();else{var $=[];for(var A=0;A<_.length;A++)$.push(_[A]);return $}}Object.sextend=function(A,$){for(var _ in $)A[_]=$[_];return A};Function.prototype.sbind=function(){var $=this,_=$SA(arguments),A=_.shift();return function(){return $.apply(A,_.concat($SA(arguments)))}};Function.prototype.sbAEListener=function(_){var $=this;return function(A){return $.call(_,A||window.event)}};var SElement=new Object();SElement.Methods={visible:function($){return $S($).style.display!="none"},hide:function(){for(var _=0;_<arguments.length;_++){var $=$S(arguments[_]);$.style.display="none"}},show:function(){for(var _=0;_<arguments.length;_++){var $=$S(arguments[_]);$.style.display=""}},getHeight:function($){$=$S($);return $.offsetHeight},addClassName:function($,_){if(!($=$S($)))return;$.className=(""==$.className)?_:($.className+" "+_)},removeClassName:function($,_){if(!($=$S($)))return;var A=new RegExp("(^| )"+_+"( |$)");$.className=$.className.replace(A,"$1").replace(/ $/,"")}};Object.sextend(SElement,SElement.Methods);var SEvent=new Object();SEvent.Methods={element:function($){return $.target||$.srcElement},observers:false,_observeAndCache:function(_,A,B,$){if(!this.observers)this.observers=[];if(_.addEventListener){this.observers.push([_,A,B,$]);_.addEventListener(A,B,$)}else if(_.attachEvent){this.observers.push([_,A,B,$]);_.attachEvent("on"+A,B)}},unloaddisabledCache:function(){if(!SEvent.observers)return;for(var $=0;$<SEvent.observers.length;$++){SEvent.stopObserving.apply(this,SEvent.observers[$]);SEvent.observers[$][0]=null}SEvent.observers=false},observe:function(_,A,B,$){var _=$S(_);$=$||false;if(A=="keypress"&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||_.attachEvent))A="keydown";this._observeAndCache(_,A,B,$)},stopObserving:function(_,A,B,$){var _=$S(_);$=$||false;if(A=="keypress"&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||_.detachEvent))A="keydown";if(_.removeEventListener)_.removeEventListener(A,B,$);else if(_.detachEvent)_.detachEvent("on"+A,B)}};Object.sextend(SEvent,SEvent.Methods);if(navigator.appVersion.match(/\bMSIE\b/))SEvent.observe(window,"unloaddisabled",SEvent.unloaddisabledCache,false);var SP={cumOffset:function(_){var $=0,A=0;do{$+=_.offsetTop||0;A+=_.offsetLeft||0;_=_.offsetParent}while(_);return[A,$]}},SK=SC.create();Object.sextend(SK,{BACKSPACE:8,TAB:9,RETURN:13,ESC:27,LEFT:37,UP:38,RIGHT:39,DOWN:40,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,INSERT:45,SHIFT:16,CTRL:17,ALT:18});var AutoComplete=SC.create();AutoComplete.prototype={initialize:function(E,_,C,$,A,B,D,F){SEvent.observe(document,"click",this.hide2.sbAEListener(this));SEvent.observe(document,"blur",this.hide2.sbAEListener(this));this.oN=this.defSugName;if(C)this.oN=C;this.IE=(navigator&&navigator.userAgent.toLowerCase().indexOf("msie")!=-1);this.browserInfo();if($)this.hI=true;else this.hI=false;if(A)this.hC=true;else this.hC=false;this.iconUrl=this.defSugIconUrl;if(B)this.iconUrl=B;this.box=$S(E);this.frameBox=$S(_);if(this.box){SEvent.observe(this.box,"keypress",this.onkeydown.sbAEListener(this));this.box.onblur=this.onblur.sbAEListener(this);SEvent.observe(this.box,"dblclick",this.dblClick.sbAEListener(this));if(!this.hI)this.setSugIcon(this.iconUrl)}this.count=0;this.sugServ=this.defSugServ;if(F)this.sugServ=F;this.sugMoreParams="";this.logServ=this.defSugServ;this.searchServ=this.defSearchServ;this.searchParamName=this.defSearchParamName;this.searchMoreParams="";this.kf=this.defKeyfrom+this.KEYFROM_POST;this.hcb=null;this.scb=null;this.sugFlag=true;this.clickEnabled=true;this.sptDiv=document.createElement("div");document.body.appendChild(this.sptDiv);this.sdiv=document.createElement("div");this.sdiv.style.position="absolute";this.sdiv.style.zIndex=10000;SElement.hide(this.sdiv);document.body.appendChild(this.sdiv);this.bdiv=document.createElement("div");this.vis=false;this.lq="";this.initVal="";if(this.box&&this.box.value!="")this.initVal=this.box.value;this.oldVal=this.initVal;this.oldValForCtrlZ=new Array(this.CZNUM);this.oldValForCtrlZNum=0;this.ctrlZFlag=false;this.upDownTag=false;this.blurCount=0;window.onresize=this.winResize.sbind(this);this.doReq("");this.clean();if(!D)this.timeoutId=setTimeout(this.sugReq.sbind(this),this.REQUEST_TIMEOUT)},setInputId:function($){this.box=$S($);if(this.box){SEvent.observe(this.box,"keypress",this.onkeydown.sbAEListener(this));this.box.onblur=this.onblur.sbAEListener(this);SEvent.observe(this.box,"dblclick",this.dblClick.sbAEListener(this));if(!this.hI)this.setSugIcon(this.iconUrl)}},start:function(){this.timeoutId=setTimeout(this.sugReq.sbind(this),this.REQUEST_TIMEOUT);if(this.box&&this.box.value!=""){this.initVal=this.box.value;this.oldVal=this.initVal}},setObjectName:function($){this.oN=$},setSelectCallBack:function($){this.scb=$.sbind(this)},setHoverCallBack:function($){this.hcb=$.sbind(this)},setSugServer:function($){this.sugServ=$;this.logServ=$;this.doReq("");this.clean()},setSugMoreParams:function($){this.sugMoreParams=$},setLogServer:function($){this.logServ=$},setSearchServer:function($){this.searchServ=$},setSearchParamName:function($){this.searchParamName=$},setSearchMoreParams:function($){this.searchMoreParams=$},setKeyFrom:function($){if($.indexOf(this.KEYFROM_POST)>0)this.kf=$;else this.kf=$+this.KEYFROM_POST},getSearchUrl:function($){return encodeURI(this.searchServ+this.searchParamName+"="+$+"&keyfrom="+this.kf+this.searchMoreParams)},getSugQueryUrl:function(_,A,$){return encodeURI(this.sugServ+this.S_QUERY_URL_POST+_+"&o="+this.oN+"&count="+$+"&keyfrom="+this.kf+this.sugMoreParams+this.time())},log:function(D,C,B,_,$){var A="";if(C)A+=C;if(B)A+=B;if(_)A+=_;if($)A+=$;var E=new Image();E.src=encodeURI(this.logServ+this.S_LOG_URL_POST+D+A+this.time());return true},setSugIcon:function(C){var B=this.oN+"_icon";if(document.getElementById(B))document.body.removeChild(document.getElementById(B));this.icon=document.createElement("img");this.icon.id=B;this.icon.src=C;this.icon.style.position="absolute";this.icon.style.zIndex="99";this.icon.style.width="13px";this.icon.style.height="10px";this.icon.style.cursor="pointer";var $=this.frameBox,A=SP.cumOffset($),_=0;this.icon.style.left=(A[0]+_+$.offsetWidth-13*1.5)+"px";this.icon.style.top=(A[1]+($.offsetHeight-10)/2)+"px";this.icon.style.display="";document.body.appendChild(this.icon);SEvent.observe(this.icon,"click",this.pressPoint.sbAEListener(this));SEvent.observe(this.icon,"mouseover",this.onmouseover2.sbAEListener(this));SEvent.observe(this.icon,"mouseout",this.onmouseout2.sbAEListener(this))},dblClick:function(){if(this.box.createTextRange){var $=this.box.createTextRange();$.moveStart("character",0);$.select()}else if(this.box.setSelectionRange)this.box.setSelectionRange(0,this.box.value.length);if(this.sugFlag){if(this.box.value!=""){if(this.lq==this.box.value){if(this.sdiv.childNodes.length>0)if(!this.vis)this.show();else this.hide();return}this.doReq()}}else if(this.box.value!="")this.insertSugHint()},winResize:function(){if(this.vis)this.show();if(!this.hI)this.setSugIcon(this.iconUrl)},storeOldValue:function(){if(this.oldValForCtrlZNum<this.CZNUM){this.oldValForCtrlZ[this.oldValForCtrlZNum]=this.oldVal;this.oldValForCtrlZNum++}else{for(var $=0;$<this.CZNUM-1;++$)this.oldValForCtrlZ[$]=this.oldValForCtrlZ[$+1];this.oldValForCtrlZ[this.CZNUM-1]=this.oldVal}},clearOldValue:function(){this.oldValForCtrlZNum=0},onkeydown:function(_){if(_.ctrlKey){var $=_.keyCode;if($==0)$=_.charCode;if($==90||$==122){if(this.oldValForCtrlZNum>0){this.box.value=this.oldValForCtrlZ[--this.oldValForCtrlZNum];if(this.box.value!="")this.ctrlZFlag=true;else this.oldVal="";this.upDownTag=false}if(this.IE)_.returnValue=false;else _.preventDefault();return false}return true}switch(_.keyCode){case SK.PAGE_UP:case SK.PAGE_DOWN:case SK.END:case SK.HOME:case SK.INSERT:case SK.CTRL:case SK.ALT:case SK.LEFT:case SK.RIGHT:case SK.SHIFT:case SK.TAB:return true;case SK.ESC:this.hide();return false;case SK.UP:if(this.vis&&this.sugFlag){this.upDownTag=true;this.up()}else{if(this.sdiv.childNodes.length>1)if(this.lq==this.box.value)if(this.sugFlag){this.show();return false}if(this.box.value!="")this.doReq()}if(this.IE)_.returnValue=false;else _.preventDefault();return false;case SK.DOWN:if(this.vis&&this.sugFlag){this.upDownTag=true;this.down()}else{if(this.sdiv.childNodes.length>1)if(this.lq==this.box.value)if(this.sugFlag){this.show();return false}if(this.box.value!="")this.doReq()}if(this.IE)_.returnValue=false;else _.preventDefault();return false;case SK.RETURN:if(this.vis&&this.curNodeIdx>-1)if(!this.select()){if(this.IE)_.returnValue=false;else _.preventDefault();return false}return true;case SK.BACKSPACE:if(this.box.value.length==1){this.storeOldValue();this.oldVal=""}default:this.upDownTag=false;return true}},sugReq:function(){if(this.box.value!=""&&this.box.value!=this.initVal){this.initVal="";if(this.lq!=this.box.value)if(!this.upDownTag)if(typeof(isYdDefault)!=undefined){if(!isYdDefault())this.doReq()}else this.doReq()}else if(this.lq!=""){this.lq="";if(this.vis){this.hide();this.clean()}}if(this.timeoutId!=0)clearTimeout(this.timeoutId);this.timeoutId=setTimeout(this.sugReq.sbind(this),this.REQUEST_TIMEOUT)},getSiteResult:function(B){var D=new RegExp("<[s][p][a][n].*>.*</[s][p][a][n]>");m=D.exec(B);if(m==null){D=new RegExp("<[aA].*>.*</[aA]>");m=D.exec(B)}if(m==null){var F=B.indexOf("HREF=\"");if(F!=-1){var E=B.indexOf("\"",F+6),_=B.substring(F+6,E);return _}return null}else{var $=new RegExp("[hH][rR][eE][fF]=.*><[fF][oO][nN][tT]"),C=$.exec(m);if(C[0].length<=13)return null;var A=C[0].split(" "),_;if(A.length>1)_=A[0].substr(6,A[0].length-7);else _=A[0].substr(6,A[0].length-13);return _}},getSelValue:function($){return $.replace(/this.txtBox.value=/,"").replace(/\'/g,"")},select:function($){if($){if(this.getCurNode()){var _=this.getCurNode().innerHTML,A=this.getSiteResult(_);if(A!=null){this.log(this.LOG_MOUSE_SELECT,"&q="+this.oldVal,"&index=0","&select="+A,"&direct=true");this.hide();void(A,"_blank")}else{try{var D=this.getCurNode().getAttribute(this.ITEM_SEL_ATTR_NAME),C=this.getSelValue(D);if(this.oldVal!=C)this.storeOldValue();this.log(this.LOG_MOUSE_SELECT,"&q="+this.oldVal,"&index="+this.curNodeIdx,"&select="+C);this.oldVal=C;this.hide();if(this.scb!=null)this.scb(C,this);else{this.clearOldValue();var B=this.getSearchUrl(C);void(B,"_blank")}}catch($){}}}}else if(this.getCurNode()){_=this.getCurNode().innerHTML,A=this.getSiteResult(_);if(A!=null){this.log(this.LOG_KEY_SELECT,"&q="+this.oldVal,"&index=0","&select="+A,"&direct=true");this.hide();void(A,"_blank")}else{try{D=this.getCurNode().getAttribute(this.ITEM_SEL_ATTR_NAME),C=this.getSelValue(D);if(this.oldVal!=C)this.storeOldValue();if(this.box.value!=C)return true;else this.log(this.LOG_KEY_SELECT,"&q="+this.oldVal,"&index="+this.curNodeIdx,"&select="+C);this.oldVal=C;this.hide();if(this.scb!=null)this.scb(this.box.value,this);else{this.clearOldValue();B=this.getSearchUrl(C);void(B,"_blank")}}catch($){}}}return false},doReq:function($){if(!this.sugFlag)return;if($=="undefined"||$==null){if(this.oldVal!=this.box.value&&!this.ctrlZFlag)this.storeOldValue();this.oldVal=this.box.value;this.ctrlZFlag=false;this.lq=this.box.value;var $=this.box.value}this.count++;var A=encodeURIComponent(document.URL),_=this.getSugQueryUrl($,A,this.count);this.excuteCall(_)},clean:function(){this.size=0;this.curNodeIdx=-1;this.sdiv.innerHTML="";this.bdiv.innerHTML=""},onComplete:function(){setTimeout(this.updateContent.sbind(this,arguments[0]),5)},cleanScript:function(){while(this.sptDiv.childNodes.length>0)this.sptDiv.removeChild(this.sptDiv.firstChild)},isValidNode:function($){return($.nodeType==1)&&($.getAttribute(this.ITEM_SEL_ATTR_NAME))},getReqStr:function($){if($&&$.getElementsByTagName("div").length>0)return $.getElementsByTagName("div")[0].getAttribute("id");return null},updateContent:function(){this.cleanScript();var C=this.box.value;if(this.bdiv.innerHTML=="")if(this.sdiv.innerHTML!=""&&this.getReqStr(this.sdiv)==C)return;else{this.hide();this.clean();return}if(this.getReqStr(this.bdiv)!=C)if(this.sdiv.innerHTML!=""&&this.getReqStr(this.sdiv)==C)return;else{this.hide();return}var A,_=false,B=(((this.bdiv.getElementsByTagName("table"))[1]).getElementsByTagName("tr"));for(var D=0;D<B.length;D++){A=B[D];if(this.isValidNode(A)){_=true;break}}if(_){this.sdiv.innerHTML=this.bdiv.innerHTML;var $=this.sdiv.getElementsByTagName("table");B=$[1].getElementsByTagName("tr");this.size=0;this.childs=new Array();for(D=0;D<B.length;D++){A=B[D];if(this.isValidNode(A)){A.setAttribute(this.ITEM_INDEX_ATTR_NAME,this.size);SEvent.observe(A,"mousemove",this.onmousemove.sbAEListener(this));SEvent.observe(A,"mouseover",this.onmouseover.sbAEListener(this));SEvent.observe(A,"mouseout",this.onmouseout.sbAEListener(this));SEvent.observe(A,"click",this.select.sbAEListener(this));this.childs.push(A);this.size++}}if(Number($.length)>=3)this.bindATagWithMouseEvent($[2],false);this.show();this.mouseTag=false}else{this.hide();this.clean()}},showContent:function(){var $=this.frameBox,A=SP.cumOffset($),B=0;this.sdiv.style.top=A[1]+($.offsetHeight+B)+"px";var _=0;if(this.bName=="IE");else _=1;this.sdiv.style.left=A[0]+_+"px";this.sdiv.style.cursor="default";this.sdiv.style.width=$.offsetWidth+"px";SElement.show(this.sdiv);this.vis=true;this.curNodeIdx=-1},show:function(){if(this.sdiv.childNodes.length<1)return;if(this.sugFlag)if(this.getReqStr(this.sdiv)!=this.box.value)return;this.showContent()},hide:function(){this.hlOff();SElement.hide(this.sdiv);this.curNodeIdx=-1;this.vis=false},hide2:function(){if(this.clickEnabled){this.hide();this.clickEnabled=false;setTimeout(this.enableClick.sbind(this),60)}},onblur:function(){this.hide();var $=true;if(this.IE)if(this.blurCount==0){$=false;this.blurCount++}if(typeof(ydInputBlur)!=undefined&&$)ydInputBlur(this.box)},enableClick:function(){this.clickEnabled=true},onmousemove:function($){this.mouseTag=true;this.onmouseover($)},onmouseover:function(_){this.box.onblur=null;if(!this.mouseTag){this.mouseTag=true;return}var A=SEvent.element(_);while(A.parentNode&&(!A.tagName||(A.getAttribute(this.ITEM_INDEX_ATTR_NAME)==null)))A=A.parentNode;var $=(A.tagName)?A.getAttribute(this.ITEM_INDEX_ATTR_NAME):-1;if($==-1||$==this.curNodeIdx)return;this.hlOff();this.curNodeIdx=Number($);this.hlOn(false)},onmouseout:function(){this.hlOff();this.curNodeIdx=-1;this.box.onblur=this.onblur.sbAEListener(this)},getNode:function($){if(this.childs&&($>=0&&$<this.childs.length))return this.childs[$];else return undefined},getCurNode:function(){return this.getNode(this.curNodeIdx)},hover:function($,_){if(this.hcb!=null)this.hcb($,_,this);else if(!$)this.box.value=_},hlOn:function(_){if(this.getCurNode()){var B=this.getCurNode().getElementsByTagName("td");this.procInstantResult();for(var C=0;C<B.length;++C)SElement.addClassName(B[C],this.ITEM_HIGHLIGHT_STYLE);try{var A=this.getCurNode().getAttribute(this.ITEM_SEL_ATTR_NAME);this.hover(!_,this.getSelValue(A))}catch($){}}},hlOff:function(){if(this.getCurNode()){var $=this.getCurNode().getElementsByTagName("td");for(var _=0;_<$.length;++_)SElement.removeClassName($[_],this.ITEM_HIGHLIGHT_STYLE);this.procInstantResultBack()}},procInstantResult:function(){var _=this.getCurNode().innerHTML;if(_.indexOf("red_font")==-1)return;var $=document.getElementById("red_font");if($)$.setAttribute("color","#ffffff");$=document.getElementById("gray_font");if($)$.setAttribute("color","#ffffff")},procInstantResultBack:function(){var _=this.getCurNode().innerHTML;if(_.indexOf("red_font")==-1)return;var $=document.getElementById("red_font");if($)$.setAttribute("color","red");$=document.getElementById("gray_font");if($)$.setAttribute("color","#008000")},up:function(){var $=this.curNodeIdx;if(this.curNodeIdx>0){this.hlOff();this.curNodeIdx=$-1;this.hlOn(true)}else if(this.curNodeIdx==0){this.hlOff();this.curNodeIdx=$-1;this.box.value=this.oldVal}else{this.curNodeIdx=this.size-1;this.hlOn(true)}},down:function(){var $=this.curNodeIdx;if(this.curNodeIdx<0){this.curNodeIdx=$+1;this.hlOn(true)}else if(this.curNodeIdx<(this.size-1)){this.hlOff();this.curNodeIdx=$+1;this.hlOn(true)}else{this.hlOff();this.curNodeIdx=-1;this.box.value=this.oldVal}},excuteCall:function(_){var $=document.createElement("script");$.src=_;this.sptDiv.appendChild($)},updateCall:function($){$=unescape($);$=$.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,"\"").replace(/&amp;/g,"&").replace(/&#39;/g,"'");this.bdiv.innerHTML=$;if(this.bdiv.childNodes.length<2)this.bdiv.innerHTML="";this.onComplete()},closeSuggest:function($){this.sugFlag=false},focusBox:function(){this.box.focus();if(this.box.createTextRange){var $=this.box.createTextRange();$.moveStart("character",this.box.value.length);$.select()}else if(this.box.setSelectionRange)this.box.setSelectionRange(this.box.value.length,this.box.value.length)},pressPoint:function($){if(this.clickEnabled){this.clickEnabled=false;setTimeout(this.enableClick.sbind(this),20);this.log(this.LOG_ICON_PRESS,"&q="+this.box.value,"&visible="+this.vis);this.focusBox();if(!this.vis){if(this.sugFlag){if(this.box.value=="")this.insertInputHint();else{if(typeof(ydInputFocus)!=undefined)if(ydInputFocus(this.box))return;if(this.lq!=this.box.value){this.doReq();setTimeout(this.showNoSug.sbind(this),200)}else if(this.sdiv.innerHTML==""){this.doReq();setTimeout(this.showNoSug.sbind(this),200)}else if(this.sdiv.childNodes.length<2)this.insertNoSugHint();else this.show()}}else this.insertSugHint()}else this.hide()}},showNoSug:function(){if(this.sdiv.childNodes.length<1)this.insertNoSugHint()},showSugHint:function(){if(this.sdiv.childNodes.length<1)return;this.showContent()},onCompleteHint:function(){setTimeout(this.showSugHint.sbind(this,arguments[0]),5)},onmouseover2:function($){this.box.onblur=null},onmouseout2:function(){this.box.onblur=this.onblur.sbAEListener(this)},bindATagWithMouseEvent:function(C,_){try{if(this.hC)if(C.parentNode){C.parentNode.removeChild(C);return}}catch(A){}var $=C.getElementsByTagName("A");if($.length==0)$=C.getElementsByTagName("a");var B=$[0];if(_)SEvent.observe(B,"click",this.turnOnSuggest.sbAEListener(this));else SEvent.observe(B,"click",this.turnOffSuggest.sbAEListener(this));SEvent.observe(B,"mouseover",this.onmouseover2.sbAEListener(this));SEvent.observe(B,"mouseout",this.onmouseout2.sbAEListener(this))},insertSugHint:function(){this.insertHint("\u63d0\u793a\u529f\u80fd\u5df2\u5173\u95ed","\u6253\u5f00\u63d0\u793a\u529f\u80fd",true)},insertInputHint:function(){this.insertHint("\u5728\u641c\u7d22\u6846\u4e2d\u8f93\u5165\u5173\u952e\u5b57\uff0c\u5373\u4f1a\u5728\u8fd9\u91cc\u51fa\u73b0\u63d0\u793a","\u5173\u95ed\u63d0\u793a\u529f\u80fd",false)},insertNoSugHint:function(){this.insertHint("\u6ca1\u6709\u53ef\u7528\u7684\u63d0\u793a","\u5173\u95ed\u63d0\u793a\u529f\u80fd",false)},insertHint:function(_,A,$){this.sdiv.innerHTML=this.hintCode1+_+this.hintCode2+A+this.hintCode3;var B=this.sdiv.getElementsByTagName("table")[2];this.bindATagWithMouseEvent(B,$);this.onCompleteHint()},turnOnSuggest:function(){var $=this.sugServ+this.S_PREF_URL_POST+"suggest=suggest"+"&o="+this.oN+this.time(),_=new Image();_.src=encodeURI($);this.sugFlag=true;this.lq="";this.initVal=this.box.value;this.oldVal=this.initVal;this.upDownTag=false;if(this.vis)this.hide();this.clean();return false},turnOffSuggest:function(){var $=this.sugServ+this.S_PREF_URL_POST+"&o="+this.oN+this.time(),_=new Image();_.src=encodeURI($);if(this.vis)this.hide();this.clean();this.sugFlag=false;return false},time:function(){return"&time="+new Date()},browserInfo:function(){this.bName="";this.bVer="";var _=navigator.userAgent,A=/MS(IE)\s([^.]+)/i,$=_.match(A);if($==null){A=/(Firefox)\/([^.]+)/i;$=_.match(A);if($==null)return}this.bName=$[1];this.bVer=$[2]},LOG_MOUSE_SELECT:"mouseSelect",LOG_KEY_SELECT:"keySelect",LOG_ICON_PRESS:"iconPress",hintCode1:"<div><table cellpadding=0 cellspacing=1 border=0 width=100% bgcolor=#979797 align=center><tr><td valign=top><table cellpadding=0 cellspacing=0 border=0 width=100% align=center><tr><td align=left bgcolor=white class=remindtt752>",hintCode2:"</td></tr></table><table cellpadding=0 cellspacing=0 border=0 width=100% align=center><tr><td height=1px bgcolor=#DDDDDD></td></tr><tr><td align=right height=17px bgcolor=#ECF0EF class=jstxhuitiaoyou><a class=jstxlan onclick=\"javascript:return false;\">",hintCode3:"</a></td></tr></table></td></tr></table></div>",REQUEST_TIMEOUT:7,ITEM_INDEX_ATTR_NAME:"s_index",ITEM_HIGHLIGHT_STYLE:"aa_highlight",ITEM_SEL_ATTR_NAME:"onSelect",CZNUM:10,KEYFROM_POST:".suggest",S_QUERY_URL_POST:"/suggest/suggest.s?query=",S_LOG_URL_POST:"/suggest/clog.s?type=",S_PREF_URL_POST:"/suggest/setpref.s?",defSugServ:"httpdisabled://"+document.domain,defSearchServ:"httpdisabled://"+document.domain+"/search?",defSearchParamName:"q",defKeyfrom:document.domain.replace(/.youdao.com/,""),defSugName:"aa",defSugIconUrl:"httpdisabled://shared.youdao.com/images/downarrow.gif"};function turnOffSuggest(){return true}function closeSuggest($){if($==null||$=="undefined")$=AutoComplete.defSugName;if(typeof $!="object")return;$.closeSuggest();return true} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/auto/2011/3/30/20110330215354a8c7a.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/auto/2011/3/30/20110330215354a8c7a.jpg
deleted file mode 100755
index d02a1b83e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/auto/2011/3/30/20110330215354a8c7a.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/7/201104071025387042e.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/7/201104071025387042e.jpg
deleted file mode 100755
index 10c4d2750..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/7/201104071025387042e.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/7/20110407103153df111.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/7/20110407103153df111.jpg
deleted file mode 100755
index 0ddd02375..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/7/20110407103153df111.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/8/20110408105903d5d53.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/8/20110408105903d5d53.jpg
deleted file mode 100755
index 58ddf9f21..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/8/20110408105903d5d53.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/8/20110408110145beb70.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/8/20110408110145beb70.jpg
deleted file mode 100755
index 07dff8fea..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/book/2011/4/8/20110408110145beb70.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/cnews/js/ntes_jslib_1.x.js b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/cnews/js/ntes_jslib_1.x.js
deleted file mode 100755
index a5616b342..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/cnews/js/ntes_jslib_1.x.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * NetEase Javascript Library v1.2.5
- *
- * Modified from
- * jRaiser Javascript Library
- * http://code.google.com/p/jraiser/
- * Copyright 2008-2010 Heero.Luo (http://heeroluo.net/)
- *
- * licensed under MIT license
- *
- * Creation date: 2008/2/6
- * Modified date: 2010/8/4
- */
-(function(R,f){var b="1.2.5 Build 201008041550",_="NTES";if(R[_]&&R[_].version>=b)return;var A=R.$,c=R.document,T=R[_]=R.$=function($,_){if(!$)return $;"string"===typeof $&&($=L($,_));return M($)};T.one=function($,_){return M(L($,_,1))};T.all=function($,_){return M(L($,_,0))};function L(_,B,$){var A=s.exec(_,B||c);if($!==f)if(A){var C=T.util.isArray(A);if(1===$&&C)return A[0];else if(0===$&&!C)return[A]}else if(0===$)return[];return A}function M(A){if(A&&!A[_])if(A.nodeType){if("unknown"!==typeof A.getAttribute)for(var $ in T.element)f===A[$]&&(A[$]=T.element[$])}else A=T.util.extend(T.util.toArray(A),T.element);return A}T.version=b;T.resume=function(){A=R.$;R.$=R[_]=T;return T};T.retire=function(){R.$=A;return A};var O=c.createElement("div");O.innerHTML="<p class='TEST'></p>";var s={SPACE:/\s*([\s>~+,])\s*/g,ISSIMPLE:/^#?[\w\u00c0-\uFFFF_-]+$/,IMPLIEDALL:/([>\s~\+,]|^)([#\.\[:])/g,ATTRVALUES:/=(["'])([^'"]*)\1]/g,ATTR:/\[\s*([\w\u00c0-\uFFFF_-]+)\s*(?:(\S?\=)\s*(.*?))?\s*\]/g,PSEUDOSEQ:/\(([^\(\)]*)\)$/g,BEGINIDAPART:/^(?:\*#([\w\u00c0-\uFFFF_-]+))/,STANDARD:/^[>\s~\+:]/,STREAM:/[#\.>\s\[\]:~\+]+|[^#\.>\s\[\]:~\+]+/g,ISINT:/^\d+$/,enableQuerySelector:O.querySelectorAll&&O.querySelectorAll(".TEST").length>0,tempAttrValues:[],tempAttrs:[],idName:_+"UniqueId",id:0,exec:function($,I){var _,G,E,C,B,J,K,F,H,L,D=this;$=$.trim();if(""===$)return;if(D.ISSIMPLE.test($))if(0===$.indexOf("#")&&typeof I.getElementById!=="undefined")return D.getElemById(I,$.substr(1));else if(typeof I.getElementsByTagName!=="undefined")return T.util.toArray(I.getElementsByTagName($));if(D.enableQuerySelector&&I.nodeType){try{return T.util.toArray(I.querySelectorAll($))}catch(A){}}I=I.nodeType?[I]:T.util.toArray(I);G=$.replace(D.SPACE,"$1").replace(D.ATTRVALUES,D.analyzeAttrValues).replace(D.ATTR,D.analyzeAttrs).replace(D.IMPLIEDALL,"$1*$2").split(",");E=G.length;C=-1;_=[];while(++C<E){J=I;$=G[C];if(D.BEGINIDAPART.test($))if(typeof I[0].getElementById!=="undefined"){J=[D.getElemById(I[0],RegExp.$1)];if(!J[0])continue;$=RegExp.rightContext}else $=G[C];if($!==""){if(!D.STANDARD.test($))$=" "+$;K=$.match(D.STREAM)||[];F=K.length;B=0;while(B<F){H=K[B++];L=K[B++];J=D.operators[H]?D.operators[H](J,L):[];if(0===J.length)break}}T.util.merge(_,J)}D.tempAttrValues.length=D.tempAttrs.length=0;return _.length>1?D.unique(_):_},analyzeAttrs:function(_,B,A,$){return"[]"+(s.tempAttrs.push([B,A,$])-1)},analyzeAttrValues:function($,A,_){return"="+(s.tempAttrValues.push(_)-1)+"]"},generateId:function(_){var B=this.idName,$;try{$=_[B]=_[B]||new Number(++this.id)}catch(A){$=_.getAttribute(B);if(!$){$=new Number(++this.id);_.setAttribute(B,$)}}return $.valueOf()},unique:function(C){var A=[],D=0,B={},_,$;while(_=C[D++])if(1===_.nodeType){$=this.generateId(_);if(!B[$]){B[$]=true;A.push(_)}}return A},attrMap:{"class":"className","for":"htmlFor"},getAttribute:function($,A){var _=this.attrMap[A]||A,B=$[_];if("string"!==typeof B)if("undefined"!==typeof $.getAttributeNode){B=$.getAttributeNode(A);B=f==B?B:B.value}else if($.attributes)B=String($.attributes[A]);return null==B?"":B},getElemById:function(A,$){var _=A.getElementById($);if(_&&_.id!==$&&A.all){_=A.all[$];if(_){_.nodeType&&(_=[_]);for(var B=0;B<_.length;B++)if(this.getAttribute(_[B],"id")===$)return _[B]}}else return _},getElemsByTagName:function(F,H,E,D,_){var A=[],I=-1,G=F.length,$,C,B;D!=="*"&&(B=D.toUpperCase());while(++I<G){$=F[I][H];C=0;while($&&(!_||C<_)){if(1===$.nodeType){($.nodeName.toUpperCase()===B||!B)&&A.push($);C++}$=$[E]}}return A},checkElemPosition:function(G,H,J,A){var $=[];if(!isNaN(H)){var C=G.length,D=-1,_={},B,E,I,F;while(++D<C){B=G[D].parentNode;E=this.generateId(B);if(f===_[E]){I=0;F=B[J];while(F){1===F.nodeType&&I++;if(I<H)F=F[A];else break}_[E]=F||0}else F=_[E];G[D]===F&&$.push(G[D])}}return $},getElemsByPosition:function(A,C,_){var D=C,B=A.length,$=[];while(D>=0&&D<B){$.push(A[D]);D+=_}return $},getElemsByAttribute:function(B,D){var _=[],$,E=0,A=this.attrOperators[D[1]||""],C="~="===D[1]?" "+D[2]+" ":D[2];if(A)while($=B[E++])A(this.getAttribute($,D[0]),C)&&_.push($);return _},operators:{"#":function(_,$){return s.getElemsByAttribute(_,["id","=",$])}," ":function(A,_){var B=A.length;if(1===B)return A[0].getElementsByTagName(_);else{var $=[],C=-1;while(++C<B)T.util.merge($,A[C].getElementsByTagName(_));return $}},".":function($,_){return s.getElemsByAttribute($,["class","~=",_])},">":function(_,$){return s.getElemsByTagName(_,"firstChild","nextSibling",$)},"+":function(_,$){return s.getElemsByTagName(_,"nextSibling","nextSibling",$,1)},"~":function(_,$){return s.getElemsByTagName(_,"nextSibling","nextSibling",$)},"[]":function($,_){_=s.tempAttrs[_];if(_){if(s.ISINT.test(_[2]))_[2]=s.tempAttrValues[_[2]];return s.getElemsByAttribute($,_)}else return $},":":function(_,A){var $;if(s.PSEUDOSEQ.test(A)){$=parseInt(RegExp.$1);A=RegExp.leftContext}return s.pseOperators[A]?s.pseOperators[A](_,$):[]}},attrOperators:{"":function($){return $!==""},"=":function(_,$){return $===_},"~=":function(_,$){return(" "+_+" ").indexOf($)>=0},"!=":function(_,$){return $!==_},"^=":function(_,$){return _.indexOf($)===0},"$=":function(_,$){return _.substr(_.length-$.length)===$},"*=":function(_,$){return _.indexOf($)>=0}},pseOperators:{"first-child":function($){return s.checkElemPosition($,1,"firstChild","nextSibling")},"nth-child":function(_,$){return s.checkElemPosition(_,$,"firstChild","nextSibling")},"last-child":function($){return s.checkElemPosition($,1,"lastChild","previousSibling")},"nth-last-child":function(_,$){return s.checkElemPosition(_,$,"lastChild","previousSibling")},"odd":function($){return s.getElemsByPosition($,0,2)},"even":function($){return s.getElemsByPosition($,1,2)},"lt":function(_,$){return s.getElemsByPosition(_,$-1,-1)},"gt":function(_,$){return s.getElemsByPosition(_,$+1,1)}}};T.element={get:function($){return this.nodeType===f?this[$]:(0==$?this:f)},$:function($){return T("number"===typeof $?this.get($):$,this)},hasClass:function($){return T.style.hasClass(this,$)},addCss:function($){return T.style.addCss(this,$)},removeCss:function($){return T.style.removeCss(this,$)},addEvent:function(_,A,$){return T.event.addEvent(this,_,A,$)},removeEvent:function($,_){return T.event.removeEvent(this,$,_)},attr:function(A,B){var _=this;A=s.attrMap[A]||A;if(B!==f)return T.dom.eachNode(_,function($,_){this[$]=T.util.isFunction(_)?_.call(this):_},arguments);else{var $=this.get(0);return $?$[A]:f}},each:function($){return T.dom.eachNode(this,$)}};T.element[_]=T.element.$;R.addEvent=c.addEvent=T.element.addEvent;R.removeEvent=c.removeEvent=T.element.removeEvent;var W={},r=Array.prototype.slice,S=Object.prototype.toString;T.util={isArray:function($){return S.call($)==="[object Array]"},isFunction:function($){return S.call($)==="[object Function]"},toArray:function($){if(T.util.isArray($))return $;var A;try{A=r.call($)}catch(_){A=[];var B=$.length;while(B)A[--B]=$[B]}return A},merge:function(_,$){var B=$.length,A=_.length;while(--B>=0)_[A+B]=$[B];return _},parseTpl:function(A,$,_){if(null==A)return;if(null==$)return A;var B=W[A];if(!B){B=new Function("obj","var _=[];with(obj){_.push('"+A.replace(/[\r\t\n]/g," ").replace(/'(?=[^#]*#>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<#=(.+?)#>/g,"',$1,'").split("<#").join("');").split("#>").join("_.push('")+"');}return _.join('');");_!==false&&(W[A]=B)}return B($)},extend:function($,A){for(var _ in A)$[_]=A[_];return $},each:function(A,_,$){var D=-1,B=A.length,C=B===f||T.util.isFunction(A);if($){if(C){for(D in A)if(false===_.apply(A[D],$))break}else while(++D<B)if(false===_.apply(A[D],$))break}else if(C){for(D in A)if(false===_.call(A[D],D,A[D]))break}else while(++D<B)if(false===_.call(A[D],D,A[D]))break;return A}};T.parseTpl=T.util.parseTpl;T.each=T.util.each;var V=[],C,$;if(c.addEventListener)$=function(){c.removeEventListener("DOMContentLoaded",$,false);j()};else if(c.attachEvent)$=function(){if("complete"===c.readyState){c.detachEvent("onreadystatechange",$);j()}};function X(){if(T.dom.isReady)return;try{c.documentElement.doScroll("left")}catch($){setTimeout(X,1);return}j()}function j(){if(!T.dom.isReady){if(!c.body)return setTimeout(j,13);T.dom.isReady=true;if(V){var _=-1,$=V.length;while(++_<$)V[_].call(c,T);V=null}}}function Q(){if(C)return;if("complete"===c.readyState)return j();if(c.addEventListener){c.addEventListener("DOMContentLoaded",j,false);R.addEventListener("loaddisabled",j,false)}else if(c.attachEvent){c.attachEvent("onreadystatechange",j);R.attachEvent("onloaddisabled",j);var _;try{_=R.frameElement==null}catch($){}c.documentElement.doScroll&&_&&X()}C=true}T.dom={wrapByArray:function($){if($)if($.nodeType!==f||$.setInterval)return[$];else if($.length)return T.util.toArray($);return[]},eachNode:function(_,A,$){T.each(T.dom.wrapByArray(_),A,$);return _},ready:function($){Q();if(T.dom.isReady)$.call(c,T);else V.push($);return this}};T.ready=T.dom.ready;var k=/\s*([:;])\s*/g,a=/[^:;]+?(?=:)/g,J=/[^:;]+/g,d=/[^\s]+/g,E=/-([a-z])/gi,Z=O.style.styleFloat!==f?"styleFloat":"cssFloat",o=/^float$/i;function u($,B,_){if(this.className){var A=" "+this.className+" ",C=-1;while(++C<B)-1===A.indexOf(" "+$[C]+" ")&&(A+=($[C]+" "));this.className=A.trim()}else this.className=_}function h($,B,_){switch(this.className){case _:this.className="";break;case"":return;break;default:var A=" "+this.className+" ",C=-1;while(++C<B)A=A.replace(" "+$[C]+" "," ");this.className=A.trim();break}}function t(A,_){if(""===this.style.cssText&&"string"===typeof _)this.style.cssText=_;else for(var $ in A)this.style[$]!==f&&(this.style[$]=A[$])}function m(_){for(var $ in _)this.style[$]!==f&&(this.style[$]="")}T.style={fixStyleName:function($){return o.test($)?Z:$.replace(E,function(_,$){return $.toUpperCase()})},hasClass:function(_,$){_=T.dom.wrapByArray(_);var A=_.length;if(A>0){$=" "+$+" ";while(--A>=0)if((" "+_[A].className+" ").indexOf($)>=0)return true}return false},parse:function(C){if("string"===typeof C){var B=C.indexOf(";")>=0,_=C.indexOf(":")>=0,$;if(B||_){$={};C=C.trim().replace(k,"$1").replace(_?a:J,T.style.fixStyleName).match(J);var A=C.length,D=0;if(_){if(A%2!==0)throw"invalid inline style";while(D<A)$[C[D++]]=C[D++]}else while(D<A)$[C[D++]]=""}else $=C.match(d)||[];return $}return C},addCss:function(_,A){var $=T.style.parse(A);if(T.util.isArray($))T.dom.eachNode(_,u,[$,$.length,A]);else T.dom.eachNode(_,t,[$,A]);return _},removeCss:function(_,A){var $=T.style.parse(A);if(T.util.isArray($))T.dom.eachNode(_,h,[$,$.length,A]);else T.dom.eachNode(_,m,[$]);return _},getCurrentStyle:function(A,_,$){if(!A)return f;!A.nodeType&&(A=A[0]);_=T.style.fixStyleName(_);return A.style[_]||((A.currentStyle||($||R).getComputedStyle(A,null))[_])}};function n(A,B,_){var $=this;B=T.event.delegate($,A,B,_);if($.attachEvent)$.attachEvent("on"+A,B);else if($.addEventListener)$.addEventListener(A,B,false)}function g(_,A){var $=this;A=T.event.getDelegate($,_,A);if($.detachEvent)$.detachEvent("on"+_,A);else if($.removeEventListener)$.removeEventListener(_,A,false)}var H=/\s*,\s*/,D=0;T.event={idName:_+"EventId",eventSpace:_+"Events",addEvent:function(_,A,C,$){A=A.split(H);var B=A.length;while(--B>=0)T.dom.eachNode(_,n,[A[B],C,$]);return _},removeEvent:function($,_,B){_=_.split(H);var A=_.length;while(--A>=0)T.dom.eachNode($,g,[_[A],B]);return $},delegate:function(_,E,G,C){var A=T.event,B=_[A.eventSpace]=_[A.eventSpace]||{},$=G[A.idName]=G[A.idName]||++D;B[E]=B[E]||{};var F=B[E][$];if(!F){F=function($){$=A.fix($);var B=G.call(_,$,C);false===B&&$.preventDefault();return B};B[E][$]=F}return F},getDelegate:function($,B,C){var A=T.event;try{return $[A.eventSpace][B][C[A.idName]]}catch(_){}return C},fix:function(_){!_.target&&(_.target=_.srcElement||c);3==_.target.nodeType&&(_.target=_.target.parentNode);null==_.timeStamp&&(_.timeStamp=Date.now());_.preventDefault=_.preventDefault||function(){this.returnValue=false};_.stopPropagation=_.stopPropagation||function(){this.cancelBubble=true};if(f===_.pageX&&f!==_.clientX){var A=c.documentElement,$=c.body;_.pageX=_.clientX+(A.scrollLeft||$.scrollLeft||0)-(A.clientLeft||0);_.pageY=_.clientY+(A.scrollTop||$.scrollTop||0)-(A.clientTop||0)}if(!_.which&&((_.charCode||_.charCode===0)?_.charCode:_.keyCode))_.which=_.charCode||_.keyCode;if(!_.which&&_.button!==f)_.which=(_.button&1?1:(_.button&2?3:(_.button&4?2:0)));return _}};var q=R.navigator.userAgent.toLowerCase(),i=/(webkit)[ \/]([\w.]+)/.exec(q)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(q)||/(msie) ([\w.]+)/.exec(q)||!/compatible/.test(q)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(R.navigator.userAgent.toLowerCase());T.browser={};if(i){T.browser[i[1]||""]=true;T.browser.version=i[2]||"0"}T.ajax={createXhr:function(){var _;try{_=R.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()}catch($){}if(!_)throw"failed to create XMLHttpRequest object";return _},send:function(G,C,B,H,A){A=A||T.ajax.createXhr();var E;"string"===typeof C&&(C=C.toUpperCase());C=C!=="GET"&&C!=="POST"?"GET":C;H=H||{};H.async="boolean"===typeof H.async?H.async:true;var _;if(B){_=[];for(var $ in B)B[$]!=null&&_.push($+"="+encodeURIComponent(B[$]));_=_.join("&").replace(/%20/g,"+");if("GET"===C){G+=("?"+_);_=f}}H.async&&!isNaN(H.timeout)&&H.timeout>0&&setTimeout(function(){if(!E){A.abort();H.onTimeout&&H.onTimeout(A)}},H.timeout);A.onreadystatechange=function(){if(4==A.readyState){E=true;var $=200==A.status?"onSuccess":"onError";H[$]&&H[$](A)}};void(C,G,H.async,H.username,H.password);var D=[];"POST"===C&&D.push("application/x-www-form-urlencoded");A.setRequestHeader("X-Requested-With","XMLHttpRequest");if(H.headers)for(var F in H.headers)if("content-type"===F.toLowerCase())D.push(H.headers[F]);else A.setRequestHeader(F,H.headers[F]);D.length&&A.setRequestHeader("Content-Type",D.join(";").replace(/;+/g,";").replace(/;$/,""));A.send(_);return A},importJs:function(C,$,A,_){_=_||c;var B=_.createElement("script");B.language="javascript";B.type="text/javascript";A&&(B.charset=A);B.onloaddisabled=B.onreadystatechange=function(){if(!B.readyState||"loaddisableded"==B.readyState||"complete"==B.readyState){$&&$();B.onloaddisabled=B.onreadystatechange=null;B.parentNode.removeChild(B)}};B.src=C;T.one("head",_).appendChild(B)}};var v=/[smhdMy]$/,K={s:1,m:60,h:60*60,d:24*60*60,M:30*24*60*60,y:365*24*60*60};T.cookie={encoder:R.encodeURIComponent,decoder:R.decodeURIComponent,get:function(B,D){var _=T.cookie;B=_.encoder(B)+"=";var $=c.cookie,A=$.indexOf(B),C;if(-1===A)return D?f:"";A+=B.length;C=$.indexOf(";",A);if(C===-1)C=$.length;return _.decoder($.substring(A,C))},set:function(C,G,A,F,E,D){var _=T.cookie,B=[_.encoder(C)+"="+_.encoder(G)];if(A){var H,$;if("[object Date]"===S.call(A))H=A;else{if("string"===typeof A&&v.test(A)){A=A.substring(0,A.length-1);$=RegExp.lastMatch}if(!isNaN(A)){H=new Date();H.setTime(H.getTime()+A*K[$||"m"]*1000)}}H&&B.push("expires="+H.toUTCString())}E&&B.push("path="+E);F&&B.push("domain="+F);D&&B.push("secure");c.cookie=B.join(";")},del:function($,A,_){c.cookie=T.cookie.encoder($)+"="+(_?";path="+_:"")+(A?";domain="+A:"")+";expires=Thu, 01-Jan-1970 00:00:01 GMT"}};var N=/^\s+|\s+$/g;!String.prototype.trim&&(String.prototype.trim=function(){return this.replace(N,"")});String.prototype.left=function($){return this.substr(0,$)};String.prototype.right=function($){return this.slice(-$)};String.format=function($){var _=arguments,A=new RegExp("%([1-"+_.length+"])","g");return String($).replace(A,function(A,$){return _[$]})};Function.prototype.bind=function(){if(!arguments.length)return this;var _=this,$=r.call(arguments),A=$.shift();return function(){return _.apply(A,$.concat(r.call(arguments)))}};!Array.prototype.indexOf&&(Array.prototype.indexOf=function(A,_){var $=this.length,_=Number(_)||0;_=_<0?Math.ceil(_):Math.floor(_);_<0&&(_+=$);for(;_<$;_++)if(this[_]===A)return _;return-1});Array.prototype.remove=function($){$>=0&&this.splice($,1);return this};function B($){return $<10?"0"+$:$}var U,F,p,P,Y,G;function l($){switch($){case"yyyy":return U;case"yy":return U.toString().slice(-2);case"MM":return B(F);case"M":return F;case"dd":return B(p);case"d":return p;case"HH":return B(P);case"H":return P;case"hh":return B(P>12?P-12:P);case"h":return P>12?P-12:P;case"mm":return B(Y);case"m":return Y;case"ss":return B(G);case"s":return G;default:return $}}Date.now=Date.now||function(){return+new Date};Date.prototype.format=function($){U=this.getFullYear();F=this.getMonth()+1;p=this.getDate();P=this.getHours();Y=this.getMinutes();G=this.getSeconds();return $.replace(/y+|m+|d+|h+|s+|H+|M+/g,l)};O=null;T.ui={};function e(_,$){return(_+1)%$}function I(_,$){return _<=0?$-1:(_-1)%$}T.ui.Slide=function(_,B,G,E,A,F){if(!arguments.length)return;var $=this;$.total=B.length;if(_&&$.total!==_.length)throw"can not match ctrls("+_.length+") and contents("+$.total+")";$.constructor=arguments.callee;$._curIndex=-1;$._ctrls=_;$._contents=B;$._css=G;$._eventName=E;$.interval=A;$.playMode=e;$.rollbackMode=I;$.delay=F;if($._ctrls&&$._ctrls.length&&$._eventName){var D,C;if(F){D=function(_,$){!this._delayTimer&&(this._delayTimer=setTimeout(this.show.bind(this,$),this.delay));_.preventDefault()}.bind($);C=function(){if(this._delayTimer){clearTimeout(this._delayTimer);delete this._delayTimer}}.bind($)}else D=function(_,$){this.show($);_.preventDefault()}.bind($);for(var H=$.total-1;H>=0;H--){T.event.addEvent($._ctrls[H],E,D,new Number(H));C&&T.event.addEvent($._ctrls[H],"mouseout",C)}}$.interval&&$.play()};T.ui.Slide.prototype={show:function(_){var A=this;_=_<0?0:_>=A.total?A.total-1:_;var B=A._ctrls?A._ctrls[_]:null,$=A._contents[_];if(-1===A._curIndex)A._curIndex=0;T.style.removeCss(A._ctrls,A._css);T.style.removeCss(A._contents,A._css);T.style.addCss(B,A._css);T.style.addCss($,A._css);A.onShow&&A.onShow(_,B,$);A._curIndex=_},showNext:function(){this.show(this.playMode(this._curIndex,this.total))},showPrevious:function(){this.show(this.rollbackMode(this._curIndex,this.total))},play:function(A){var _=this;if(!isNaN(A))_.interval=parseInt(A);if(!_._playTimer){if(!_._hasEvent){var $=_.pause.bind(_),B=_.play.bind(_);T.event.addEvent(_._ctrls,"mouseover",$);T.event.addEvent(_._ctrls,"mouseout",B);T.event.addEvent(_._contents,"mouseover",$);T.event.addEvent(_._contents,"mouseout",B);_._hasEvent=1}_._playTimer=setInterval(_.showNext.bind(_),_.interval)}},pause:function(){var _=this;if(_._playTimer){clearInterval(_._playTimer);delete _._playTimer;if(_.onStop){var $=_._curIndex;_.onStop($,_._ctrls[$],_._contents[$])}}}}})(window) \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/edu/2011/4/6/20110406220601277f0.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/edu/2011/4/6/20110406220601277f0.jpg
deleted file mode 100755
index 5b5196e03..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/edu/2011/4/6/20110406220601277f0.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/edu/2011/4/9/20110409001451f646c.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/edu/2011/4/9/20110409001451f646c.jpg
deleted file mode 100755
index 70ed0e1d4..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/edu/2011/4/9/20110409001451f646c.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/ent/2011/4/8/20110408183341f6142.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/ent/2011/4/8/20110408183341f6142.jpg
deleted file mode 100755
index dea0d8151..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/ent/2011/4/8/20110408183341f6142.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/20110408091923ca1d8.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/20110408091923ca1d8.jpg
deleted file mode 100755
index 96ffed42f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/20110408091923ca1d8.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/20110408100456977e5.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/20110408100456977e5.jpg
deleted file mode 100755
index 4cc85bb49..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/20110408100456977e5.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/2011040810253254779.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/2011040810253254779.jpg
deleted file mode 100755
index bca502e55..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/game/2011/4/8/2011040810253254779.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/house/2011/4/7/201104070846149dec5.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/house/2011/4/7/201104070846149dec5.jpg
deleted file mode 100755
index 055085914..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/house/2011/4/7/201104070846149dec5.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/house/2011/4/8/20110408094024dfb90.gif b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/house/2011/4/8/20110408094024dfb90.gif
deleted file mode 100755
index 99437cf5c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/house/2011/4/8/20110408094024dfb90.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/lady/2011/4/7/20110407235235eb565.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/lady/2011/4/7/20110407235235eb565.jpg
deleted file mode 100755
index f713b42e5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/lady/2011/4/7/20110407235235eb565.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/lady/2011/4/8/20110408082553b8653.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/lady/2011/4/8/20110408082553b8653.jpg
deleted file mode 100755
index 9c0c5c07f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/lady/2011/4/8/20110408082553b8653.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/2/24/20110224214610e49c1.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/2/24/20110224214610e49c1.jpg
deleted file mode 100755
index 9bc68eb6d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/2/24/20110224214610e49c1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/1/20110401105148c65f3.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/1/20110401105148c65f3.jpg
deleted file mode 100755
index 801b96f5a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/1/20110401105148c65f3.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/6/20110406140048c8dea.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/6/20110406140048c8dea.jpg
deleted file mode 100755
index d7f80b1b7..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/6/20110406140048c8dea.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/6/201104061402503e782.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/6/201104061402503e782.jpg
deleted file mode 100755
index 8aec592cb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/6/201104061402503e782.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/8/20110408175702d86a7.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/8/20110408175702d86a7.jpg
deleted file mode 100755
index 96f759352..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/life/2011/4/8/20110408175702d86a7.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/mobile/2011/4/8/201104080904537def0.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/mobile/2011/4/8/201104080904537def0.jpg
deleted file mode 100755
index b39226233..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/mobile/2011/4/8/201104080904537def0.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408164530e0dfd.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408164530e0dfd.jpg
deleted file mode 100755
index 63bdc7ec5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408164530e0dfd.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408224146ca253.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408224146ca253.jpg
deleted file mode 100755
index 2490e0049..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408224146ca253.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408234759dabf8.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408234759dabf8.jpg
deleted file mode 100755
index 1e5070f86..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/sports/2011/4/8/20110408234759dabf8.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/travel/2011/4/7/2011040719553034b7b.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/travel/2011/4/7/2011040719553034b7b.jpg
deleted file mode 100755
index 96d79968b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/travel/2011/4/7/2011040719553034b7b.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/video/2011/4/8/20110408143144afad3.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/video/2011/4/8/20110408143144afad3.jpg
deleted file mode 100755
index ca696080d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/video/2011/4/8/20110408143144afad3.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/www/logo/logo_png.png b/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/www/logo/logo_png.png
deleted file mode 100755
index ab64111bd..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/www/logo/logo_png.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/auto/2011/4/8/20110408091859b1da7.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/auto/2011/4/8/20110408091859b1da7.jpg
deleted file mode 100755
index 859793089..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/auto/2011/4/8/20110408091859b1da7.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/auto/2011/4/8/201104080930543aaa8.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/auto/2011/4/8/201104080930543aaa8.jpg
deleted file mode 100755
index 117db6400..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/auto/2011/4/8/201104080930543aaa8.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/book/2011/4/8/20110408102221db369.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/book/2011/4/8/20110408102221db369.jpg
deleted file mode 100755
index 56d8aa80d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/book/2011/4/8/20110408102221db369.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/digi/2011/4/8/20110408144717d8da9.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/digi/2011/4/8/20110408144717d8da9.jpg
deleted file mode 100755
index 3fcd833e8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/digi/2011/4/8/20110408144717d8da9.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/20110408074407aed87.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/20110408074407aed87.jpg
deleted file mode 100755
index 70e4f432f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/20110408074407aed87.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/201104080804383b8a7.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/201104080804383b8a7.jpg
deleted file mode 100755
index e69632d7e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/201104080804383b8a7.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/2011040809044637924.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/2011040809044637924.jpg
deleted file mode 100755
index 48d1cbeec..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/ent/2011/4/8/2011040809044637924.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/5/2011040502293054a8f.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/5/2011040502293054a8f.jpg
deleted file mode 100755
index 22ea2359b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/5/2011040502293054a8f.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/201104081007164a116.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/201104081007164a116.jpg
deleted file mode 100755
index 1bc323fb7..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/201104081007164a116.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/201104081009084803f.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/201104081009084803f.jpg
deleted file mode 100755
index 469cd947f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/201104081009084803f.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/2011040811265683661.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/2011040811265683661.jpg
deleted file mode 100755
index 8ade4a76e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/game/2011/4/8/2011040811265683661.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/home/2011/4/7/20110407131936bb4ec.png b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/home/2011/4/7/20110407131936bb4ec.png
deleted file mode 100755
index 67dc83f75..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/home/2011/4/7/20110407131936bb4ec.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/house/2011/4/8/201104080927161a54f.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/house/2011/4/8/201104080927161a54f.jpg
deleted file mode 100755
index bad3e99ca..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/house/2011/4/8/201104080927161a54f.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/7/2011040711484089cba.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/7/2011040711484089cba.jpg
deleted file mode 100755
index c9af6f553..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/7/2011040711484089cba.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/8/20110408014720d3fc0.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/8/20110408014720d3fc0.jpg
deleted file mode 100755
index 095fa915f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/8/20110408014720d3fc0.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/8/20110408224817711dd.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/8/20110408224817711dd.jpg
deleted file mode 100755
index 01aa86757..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/lady/2011/4/8/20110408224817711dd.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/life/2011/3/7/20110307134125752e1.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/life/2011/3/7/20110307134125752e1.jpg
deleted file mode 100755
index c2fb3a188..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/life/2011/3/7/20110307134125752e1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/mobile/2011/4/8/2011040809135520264.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/mobile/2011/4/8/2011040809135520264.jpg
deleted file mode 100755
index 071c5b508..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/mobile/2011/4/8/2011040809135520264.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/photo/0008/2010-01-30/120x90_5U980MMS294H0008.JPG b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/photo/0008/2010-01-30/120x90_5U980MMS294H0008.JPG
deleted file mode 100755
index c423c7d24..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/photo/0008/2010-01-30/120x90_5U980MMS294H0008.JPG
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/sports/2011/4/8/20110408211535eae49.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/sports/2011/4/8/20110408211535eae49.jpg
deleted file mode 100755
index 49c8d3d8f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/sports/2011/4/8/20110408211535eae49.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/3/1/201103010846298829b.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/3/1/201103010846298829b.jpg
deleted file mode 100755
index 3dd6b7429..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/3/1/201103010846298829b.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/201104080929109dd6d.png b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/201104080929109dd6d.png
deleted file mode 100755
index be9ceb616..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/201104080929109dd6d.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/20110408121505602ea.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/20110408121505602ea.jpg
deleted file mode 100755
index 6f965185f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/20110408121505602ea.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/20110408183832fdfa0.png b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/20110408183832fdfa0.png
deleted file mode 100755
index 0594e7eaa..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/stock/2011/4/8/20110408183832fdfa0.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/7/20110407105038a01d2.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/7/20110407105038a01d2.jpg
deleted file mode 100755
index d74033eff..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/7/20110407105038a01d2.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/7/2011040715531564880.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/7/2011040715531564880.jpg
deleted file mode 100755
index 82ba96528..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/7/2011040715531564880.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/8/2011040809594909a0a.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/8/2011040809594909a0a.jpg
deleted file mode 100755
index 777b26f58..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/img4.cache.netease.com/video/2011/4/8/2011040809594909a0a.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/40YCPhfL6uaLg3xA4ISWew==/4227754150194064440.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/40YCPhfL6uaLg3xA4ISWew==/4227754150194064440.jpg
deleted file mode 100755
index cd8aab98e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/40YCPhfL6uaLg3xA4ISWew==/4227754150194064440.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/F4Oc-9fe_HYFRsSk0SRMmA==/4223532025543403580.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/F4Oc-9fe_HYFRsSk0SRMmA==/4223532025543403580.jpg
deleted file mode 100755
index 670faae54..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/F4Oc-9fe_HYFRsSk0SRMmA==/4223532025543403580.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/VfPeCwJ6ufovjjY9ueyUxA==/4224939400426958880.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/VfPeCwJ6ufovjjY9ueyUxA==/4224939400426958880.jpg
deleted file mode 100755
index e38c1a9cb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/VfPeCwJ6ufovjjY9ueyUxA==/4224939400426958880.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/chRhUK9Mxz9gdCzkEUzn5w==/4226346775310512150.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/chRhUK9Mxz9gdCzkEUzn5w==/4226346775310512150.jpg
deleted file mode 100755
index 7810ff872..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/chRhUK9Mxz9gdCzkEUzn5w==/4226346775310512150.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/nSvNUs-5vbkySqbYp-lnLw==/4226628250287222807.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/nSvNUs-5vbkySqbYp-lnLw==/4226628250287222807.jpg
deleted file mode 100755
index f4688f176..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/imgrc.ph.126.net/nSvNUs-5vbkySqbYp-lnLw==/4226628250287222807.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/oimagea4.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2FPjU3g b/mobile/android/tests/browser/chrome/tp5/163.com/oimagea4.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2FPjU3g
deleted file mode 100755
index f74d4c71b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/oimagea4.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2FPjU3g
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F2WEnFW b/mobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F2WEnFW
deleted file mode 100755
index 6f53696ad..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F2WEnFW
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F2x2iAO b/mobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F2x2iAO
deleted file mode 100755
index a9ab30ed2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F2x2iAO
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F40hcYl b/mobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F40hcYl
deleted file mode 100755
index e4a9ce855..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/oimagea8.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F40hcYl
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/oimageb2.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F46NVMe b/mobile/android/tests/browser/chrome/tp5/163.com/oimageb2.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F46NVMe
deleted file mode 100755
index f54b9dfbc..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/oimageb2.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F46NVMe
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/oimageb3.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2FTyjFq b/mobile/android/tests/browser/chrome/tp5/163.com/oimageb3.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2FTyjFq
deleted file mode 100755
index 48677fe17..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/oimageb3.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2FTyjFq
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/oimagec1.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F3SWBUh b/mobile/android/tests/browser/chrome/tp5/163.com/oimagec1.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F3SWBUh
deleted file mode 100755
index eedfe0d68..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/oimagec1.ydstatic.com/image@w=80&h=80&url=http%3A%2F%2F126.fm%2F3SWBUh
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/oimagec7.ydstatic.com/image@w=128&h=128&url=http%3A%2F%2F126.fm%2F3cAjJD b/mobile/android/tests/browser/chrome/tp5/163.com/oimagec7.ydstatic.com/image@w=128&h=128&url=http%3A%2F%2F126.fm%2F3cAjJD
deleted file mode 100755
index 834f897ac..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/oimagec7.ydstatic.com/image@w=128&h=128&url=http%3A%2F%2F126.fm%2F3cAjJD
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/img/mail1.gif b/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/img/mail1.gif
deleted file mode 100755
index 9d43acd77..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/img/mail1.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/img/mail2.gif b/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/img/mail2.gif
deleted file mode 100755
index 8336f8bb9..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/img/mail2.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/ntes_mail_info_www_1222.js b/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/ntes_mail_info_www_1222.js
deleted file mode 100755
index 6d0e40559..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/ntes_mail_info_www_1222.js
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * ÍøÒ×ÓÊÏäͨÓÃÏÔʾÓʼþÊý,¿ÉÒÔÌí¼Óµ½ÈÎÒâ163ÓòϵÄÒ³Ãæ
- */
-function NtesMailInfo(){
- // ¸ù¾ÝÏÔʾ²»Í¬ÐèÇóÅäÖÃ
- // ÏÔʾÕʺÅ
- this.showAccount = true;
- // ÏÔʾÓʼþÊý
- this.showMsgCount = true;
- // ÏÔʾÍ˳ö|µÇ¼
- this.showLoginout = true;
- // ÏÔʾÕʺźó׺
- this.showAccountSuffix = true;
- // ÏÔʾÕʺÅ×î¶àµÄ³¤¶È
- this.maxAccountLength = 7;
-
- this.getCookie = function (sName){
- var sSearch = sName + "=";
- if(document.cookie.length > 0) {
- var sOffset = document.cookie.indexOf(sSearch);
- if(sOffset != -1) {
- sOffset += sSearch.length;
- sEnd = document.cookie.indexOf(";", sOffset);
- if(sEnd == -1) sEnd = document.cookie.length;
- return unescape(document.cookie.substring(sOffset, sEnd));
- }
- else return "";
- }
- };
- // ³õʼ»¯
- this.init = function (){
- if(this.P_INFO){ // Èç¹ûcookieÓÐpinfo,»ñÈ¡ÕʺÅ
- var arr = this.P_INFO.split("|");
- this.username = arr[0];
- if(this.username.indexOf("@126.com") > -1){
- this.domain = "126.com";
- }
- if(this.username.indexOf("@yeah.net") > -1){
- this.domain = "yeah.net";
- }
- if(this.username.indexOf("@163.com") > -1){
- this.domain = "163.com";
- }
- /*if(this.username.indexOf("@188.com") > -1){
- this.domain = "188.com";
- }
- if(this.username.indexOf("@vip.163.com") > -1){
- this.domain = "vip.163.com";
- }*/
- if(arr[2] == 1){
- this.isLogin = true;
- }
- }else{// ·ñÔò·µ»Ø
- return;
- }
- if(this.cm_newmsg){// Èç¹ûÓÐÐÂÓʼþÊýÄ¿cookie,²¢ÇÒÕʺźÍpinfoÀïÃæµÄÒ»ÖÂ,ÉèÖÃhasnew±ê¼ÇΪtrue
- var arr = this.cm_newmsg.split("&");
- if(arr[0]){
- var sUserName = arr[0].substr(5);
- if(sUserName == this.username){
- this.hasnew = true;
- if(arr[1]){
- this.newCount = arr[1].substr(4);
- }
- }
- }
- }
- };
- // Éú³Éhtml
- this.render = function (){
- if(this.domain == "") return;
- if(this.hasnew){
- var sUserName = this.username;
- if(sUserName.indexOf("@") > -1){
- sUserName = sUserName.split("@")[0];
- }
- if(sUserName.length > this.maxAccountLength){
- sUserName = sUserName.substring(0, this.maxAccountLength) + "..";
- }
- this.$("dvNewMsg").style.display = ""; // ÏÔʾ½çÃæ
-
- this.$("imgNewMsg").title = "ÄúÓÐ"+ this.newCount +"·âδ¶ÁÓʼþ";
- this.$("lnkNewMsg").innerHTML = this.newCount > 999 ? "999+" : this.newCount; // ÐÂÓʼþÊýÄ¿
- if(this.newCount == 0){ // ÓʼþÊýΪ0»òÕß´óÓÚ0ÊÇÏÔʾ²»Í¬µÄͼ±ê
- this.$("imgNoNewMsg").style.display = "";
- this.$("imgNewMsg").style.display = "none";
- }else{
- this.$("imgNoNewMsg").style.display = "none";
- this.$("imgNewMsg").style.display = "";
- }
-
- this.$("lnkNewMsg").href = this.$("lnkMsgImg").href = this.getLoginUrl(); // ÉèÖÃÓʼþÊýµÄÁ´½Ó
- }else{
- if(this.domain != "163.com" && location.hostname.indexOf("163.com") > -1){
- location.href = this.getShowNewMsgUrl();
- }else{
- if(!window.gGetNewCount){
- window.gGetNewCount = true;
- void('<iframe src="about:blank" style="display:none;" id="ifrmNtesMailInfo" onloaddisabled="gNtesMailInfo=new NtesMailInfo();"></iframe>');
- this.$("ifrmNtesMailInfo").src = this.getNewCountUrl();
- }
- }
- }
- };
- this.redirect = function (bType){
- if(this.redirected) return;
- this.redirected = true;
- if(bType == "iframe"){
- this.$("ifrmNtesMailInfo").src = this.getShowNewMsgUrl();
- }else{
- location.href = this.getShowNewMsgUrl();
- }
- };
- this.$ = function (sId){
- return document.getElementById(sId);
- };
- this.P_INFO = this.getCookie("P_INFO"); // »ñÈ¡pinfocookie
- this.cm_newmsg = this.getCookie("cm_newmsg"); // »ñÈ¡ÐÂÓʼþÊýÄ¿cookie
- this.isLogin = this.getCookie("S_INFO") ? true : false; // µ±Ç°ÊÇ·ñµÇ¼urs
- this.username = ""; // ÕʺÅ
- this.hasnew = false; // cookieÊÇ·ñÓÐÐÂÓʼþÊýÄ¿
- this.domain = ""; // ÓòÃû
- this.newCount = 0; // ÐÂÓʼþÊýÄ¿
- this.redirected = false; // ÊÇ·ñredirect
- this.isHomePage = location.hostname == "www.163.com" ? true : false;
- // ÀàÐÍ,show:ÏÔʾÊýÄ¿Ò³Ãæ, crossdomain:¿çÓòÌøתҳÃæ, init:ÒýÓÃjsµÄ163ƵµÀÒ³Ãæ
- this.type = (location.href.indexOf("/mailinfo/shownewmsg_0225.htm") > -1 ? "show" : (location.href.indexOf("/mailinfo/crossdomain_0225.htm") > -1 ? "crossdomain" : "init"));
-
- this.getShowNewMsgUrl = function (){// ÏÔʾÓʼþÊýÄ¿ÐÅÏ¢Ò³Ãæ
- return "httpdisabled://p.mail."+ this.domain +"/mailinfo/shownewmsg_www_1222.htm";
- };
-
- this.getNewCountUrl = function (){ // »ñÈ¡ÐÂÓʼþ½Ó¿Úurl
- return "httpdisabled://msg.mail."+ this.domain +"/cgi/mc?funcid=getusrnewmsgcnt&fid=1&addSubFdrs=1&language=0&style=0&template=newmsgres_setcookie.htm&username=" + this.username;
- };
- this.getLoginUrl = function (){ // »ñÈ¡µÇ¼url
- var oEntryUrl = {
- "163.com" : "httpdisabled://entry.mail.163.com/coremail/fcg/ntesdoor2?lightweight=1&verifycookie=1&language=-1&style=-1&from=newmsg_www",
- "126.com" : "httpdisabled://entry.mail.126.com/cgi/ntesdoor?lightweight=1&verifycookie=1&language=-1&style=-1&from=newmsg_www",
- "yeah.net" : "httpdisabled://entry.mail.yeah.net/cgi/ntesdoor?lightweight=1&verifycookie=1&language=-1&style=-1&from=newmsg_www"
- };
- if(!this.isLogin){
- oEntryUrl = {
- "163.com" : "httpdisabled://email.163.com/?from=newmsg#163",
- "126.com" : "httpdisabled://email.163.com/?from=newmsg#126",
- "yeah.net" : "httpdisabled://email.163.com/?from=newmsg#yeah"
- }
- }
- return oEntryUrl[this.domain];
- };
-
- // if(!this.isLogin) return; // Èç¹ûûÓеǼֱ½Ó·µ»Ø
- this.init(); // ³õʼ»¯
- this.render();// Éú³Éhtml
-}
-var gNtesMailInfo = new NtesMailInfo(); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/shownewmsg_www_1222.htm.html b/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/shownewmsg_www_1222.htm.html
deleted file mode 100755
index 242b68253..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/shownewmsg_www_1222.htm.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "httpdisabled://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="httpdisabled://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<title>ÍøÒ×ÓÊÏä</title>
-
-<style type="text/css">
-<!--
-
-body{ margin:0; padding:0; font:normal 12px Arial; line-height:18px; padding-top:5px}
-.gray{color:#666}
-img{vertical-align:middle}
-a{color:#727171; text-decoration:none}
-a:hover{ color:#ba2636; text-decoration:underline}
-a.blueLink:link,a.blueLink:visited{color:#1e50a2}
-a.blueLink:hover{color:#ba2636}
--->
-</style></head>
-
-<body>
-<div id="dvNewMsg" style="display:none;">(&nbsp;<a href="shownewmsg_www_1222.htm.html#" id="lnkMsgImg" target="_blank"><img src="img/mail2.gif" id="imgNoNewMsg" style="display:none" alt="ûÓÐÐÂÓʼþ" width="16" height="16" align="absmiddle" border="0" /><img src="img/mail1.gif" id="imgNewMsg" alt="" width="16" height="16" align="absmiddle" border="0" /></a> <b><a class="blueLink" href="shownewmsg_www_1222.htm.html#" id="lnkNewMsg" target="_blank"></a></b>&nbsp;)
- </div>
-</body>
-<SCRIPT LANGUAGE="JavaScript" src="ntes_mail_info_www_1222.js"></SCRIPT>
-</html>
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/pro.163.com/js.ng/site=netease&affiliate=homepage&cat=homepage&type=flash&location=1 b/mobile/android/tests/browser/chrome/tp5/163.com/pro.163.com/js.ng/site=netease&affiliate=homepage&cat=homepage&type=flash&location=1
deleted file mode 100755
index 5cd6aafc7..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/pro.163.com/js.ng/site=netease&affiliate=homepage&cat=homepage&type=flash&location=1
+++ /dev/null
@@ -1 +0,0 @@
- void('<HTML>\n <BODY>\n'); void('<script src=\'http://pre.ra.icast.cn/a/1/6/5/5/16206.js\'></script>'); void('\n </BODY>\n</HTML>'); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/qn.163.com/images/qnyh20110411.jpg b/mobile/android/tests/browser/chrome/tp5/163.com/qn.163.com/images/qnyh20110411.jpg
deleted file mode 100755
index 9fcba1373..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/qn.163.com/images/qnyh20110411.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/show.mediav.com/s@type=1&db=mediav&pub=118_2620_36413&cus=0_0_0_0_0&wh=360x100&btype=1&js=1.html b/mobile/android/tests/browser/chrome/tp5/163.com/show.mediav.com/s@type=1&db=mediav&pub=118_2620_36413&cus=0_0_0_0_0&wh=360x100&btype=1&js=1.html
deleted file mode 100755
index efee43154..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/show.mediav.com/s@type=1&db=mediav&pub=118_2620_36413&cus=0_0_0_0_0&wh=360x100&btype=1&js=1.html
+++ /dev/null
@@ -1,8 +0,0 @@
-void("<SCRIPT LANGUAGE='Javascript'>");
-void("mvas_14576=36413;mv_acquire=1;mv_bid=14576;");
-void("mvcu_14576='http://show.mediav.com/c?type=2&db=mediav&pub=118_2620_36413&cus=6_221_7977_14576_0&ref=http://www.163.com/&url=http://www.masamaso.com/interface.php?id=103387&url=http://www.masamaso.com?from=r_wy_sy04ztlfdx';");
-void("</SCR"+"IPT>");
-
-function getbrowse(){var info=navigator.userAgent.toLowerCase();if(info.indexOf('msie')!=-1)return 'IE';if(info.indexOf('firefox')!=-1)return 'FF';if(info.indexOf('opera')!=-1)return 'OP';if(info.indexOf('chrome')!=-1)return 'CHROME';if(info.indexOf('safari')!=-1)return 'SAFARI';}function mvflash_make(){var swfroot=arguments[0];if(swfroot=="body")swfroot=(document.compatMode&&document.compatMode!="BackCompat")?document.documentElement:document.body;var swfid=arguments[1];var swfwidth=arguments[2];var swfheight=arguments[3];var swfsrc=arguments[4];var clickurl=arguments[5];var swfwmode=arguments[6];var type=arguments[7];var strflash='<objectdisabled id='+swfid+' codeBase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7" classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000 width='+swfwidth+' height='+swfheight+' type=application/x-shockwave-flash><PARAM NAME="Movie" VALUE="'+swfsrc+'"><PARAM NAME="FlashVars" VALUE="mv_clickurl='+escape(clickurl)+'"><PARAM NAME="WMode" VALUE="'+swfwmode+'"><PARAM NAME="Quality" VALUE="High"><PARAM NAME="AllowScriptAccess" VALUE="always"><PARAM NAME="Scale" VALUE="ShowAll"><PARAM NAME="AllowNetworking" VALUE="all"><PARAM NAME="AllowFullScreen" VALUE="false"><embeddisabled id="'+swfid+'" width="'+swfwidth+'px" height="'+swfheight+'px" src="httpdisabled://show.mediav.com/'+swfsrc+'" quality="High" pluginspage="httpdisabled://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="'+swfwmode+'" allowscriptaccess="always" FlashVars="mv_clickurl='+escape(clickurl)+'"></embed></OBJECT>';if(type==1){var strdiv=strflash;}else{var strdiv='<div style="position: relative; z-index: 1; width:'+swfwidth+'px; height:'+swfheight+'px;"><div style="position: absolute; left: 0pt; top: 0pt; z-index: 2; width:'+swfwidth+'px; height:'+swfheight+'px;">';strdiv+=strflash;strdiv+='</div><a id="mvclicka" target="_blank" href="httpdisabled://show.mediav.com/'+clickurl+'"><img border="0" style="position: absolute; left: 0px; top: 0px; z-index: 3; width:'+swfwidth+'px;height:'+swfheight+'px;" src="httpdisabled://static.mediav.com/1x1.gif"/></a></div>';}if(swfroot==""){void(strdiv);}else{swfroot.innerHTML=strdiv;}}function mvflash_make_button(){var swfroot=arguments[0];if(swfroot=="body")swfroot=(document.compatMode&&document.compatMode!="BackCompat")?document.documentElement:document.body;var swfid=arguments[1];var swfwidth=arguments[2];var swfheight=arguments[3];var swfsrc=arguments[4];var clickurl=arguments[5];var swfwmode=arguments[6];var type=arguments[7];var strflash='<objectdisabled id='+swfid+' codeBase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7" classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000 width='+swfwidth+' height='+swfheight+' type=application/x-shockwave-flash><PARAM NAME="Movie" VALUE="'+swfsrc+'"><PARAM NAME="FlashVars" VALUE="mv_clickurl='+escape(clickurl)+'"><PARAM NAME="WMode" VALUE="'+swfwmode+'"><PARAM NAME="Quality" VALUE="High"><PARAM NAME="AllowScriptAccess" VALUE="always"><PARAM NAME="Scale" VALUE="ShowAll"><PARAM NAME="AllowNetworking" VALUE="all"><PARAM NAME="AllowFullScreen" VALUE="false"><embeddisabled id="'+swfid+'" width="'+swfwidth+'px" height="'+swfheight+'px" src="httpdisabled://show.mediav.com/'+swfsrc+'" quality="High" pluginspage="httpdisabled://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="'+swfwmode+'" allowscriptaccess="always" FlashVars="mv_clickurl='+escape(clickurl)+'"></embed></OBJECT>';if(type==1){var strdiv=strflash;}else{var strdiv='<a href="httpdisabled://show.mediav.com/'+clickurl+'" target="_blank" hidefocus>';if(getbrowse()=="IE"){strdiv+='<button disabled style="width:'+swfwidth+';height:'+swfheight+';border:none">';}strdiv+=strflash;strdiv+='</a>';}if(swfroot==""){void(strdiv);}else{swfroot.innerHTML=strdiv;}}eval('mediav_fini'+mvas_14576+'=1');var mediav_fini2010010688=1;void("<SCRIPT LANGUAGE=\"JavaScript\">\n");
-void(" if(typeof(sinamvadflag0688)!=\"number\"){mvflash_make(\"\",\"mv_14576\",360,100,\"httpdisabled://img1.126.net/channel5/360/masa_360100_10406.swf\",mvcu_14576,\"Opaque\",2);}\n");
-void("</SCR"+"IPT>");
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/www.163.com/index.html b/mobile/android/tests/browser/chrome/tp5/163.com/www.163.com/index.html
deleted file mode 100755
index 7d457afda..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/www.163.com/index.html
+++ /dev/null
@@ -1,4024 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
-<title>ÍøÒ×</title>
-<base target="_blank" />
-<meta content="initial-scale=1.0, maximum-scale=2.0, minimum-scale=1.0, user-scalable=yes, width=device-width" name="viewport">
-<meta name="Keywords" content="ÍøÒ×,ÓÊÏä,ÓÎÏ·,ÐÂÎÅ,ÌåÓý,ÓéÀÖ,Å®ÐÔ,ÑÇÔË,ÂÛ̳,¶ÌÐÅ,ÊýÂë,Æû³µ,ÊÖ»ú,²Æ¾­,¿Æ¼¼,Ïà²á" />
-<meta name="Description" content="ÍøÒ×ÊÇÖйúÁìÏȵĻ¥ÁªÍø¼¼Êõ¹«Ë¾£¬ÎªÓû§ÌṩÃâ·ÑÓÊÏä¡¢ÓÎÏ·¡¢ËÑË÷ÒýÇæ·þÎñ£¬¿ªÉèÐÂÎÅ¡¢ÓéÀÖ¡¢ÌåÓýµÈ30¶à¸öÄÚÈÝƵµÀ£¬¼°²©¿Í¡¢ÊÓƵ¡¢ÂÛ̳µÈ»¥¶¯½»Á÷£¬Íø¾ÛÈ˵ÄÁ¦Á¿¡£" />
-<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
-<meta name="robots" content="index, follow" />
-<meta name="googlebot" content="index, follow" />
-<link rel="apple-touch-icon-precomposed" href="httpdisabled://img1.cache.netease.com/www/logo/logo-ipad-icon.png" >
-<script charset="gb2312" src="../img3.cache.netease.com/cnews/js/ntes_jslib_1.x.js" language="javascript" type="text/javascript"></script>
-<link id="setSkin" type="text/css" rel="stylesheet" href="../img2.cache.netease.com/www/v2011/css/theme_blue1227.css" />
-<style type="text/css">
-html {overflow-y:scroll;}
-body {margin:0; padding:29px 0 0; font:12px "\5B8B\4F53",san-serif;background:#ffffff;}
-div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,blockquote,p{padding:0; margin:0;}
-table,td,tr,th{font-size:12px;}
-li{list-style-type:none;}
-img{vertical-align:top;border:0;}
-ol,ul {list-style:none;}
-h1,h2,h3,h4,h5,h6 {font-size:12px; font-weight:normal;}
-address,cite,code,em,th {font-weight:normal; font-style:normal;}
-.ntes-passport a {color:#727171;}
-.ntes-passport a:hover {color:#ba2636;}
-.fB{font-weight:bold;}
-.f12px{font-size:12px;}
-.f14px{font-size:14px;}
-.left{float:left;}
-.right{float:right;}
-.I_V_ {background:url(../img1.cache.netease.com/img09/icon/icon.png) left center no-repeat; padding-left:18px;}
-.I_M_ {background:url(../img1.cache.netease.com/img09/icon/icon.png) -457px center no-repeat; padding-left:18px;}
-.I_cleardot_ {background:#fff; padding:0 0 0 10px; margin:0 6px 0 -10px; float:left; vertical-align:middle; cursor:pointer;}
-.I_cleardot_:hover {text-decoration:underline;}
-.foot{margin:0 auto; width:960px; line-height:21px; clear:both; color:#4d4d4d;}
-.foot .text{padding:4px 0 5px; border-bottom:1px solid #4d4d4d; margin:0 0 5px;}
-.foot a,.foot a:visited{color:#4d4d4d;}
-.foot a:hover {color:#ba2636;}
-/* ntes grid u */
-.grid-u-5,.grid-u-9,.grid-u-10,.grid-u-19 {float:left;_display:inline;}
-.grid-u-5,.area-sub {float:left; width:200px; _display:inline;}
-.grid-u-19,.area-main {float:right; width:760px;}
-.grid-u-9,.main-col-9 {float:left; width:360px;}
-.grid-u-10,.main-col-10 {float:left; width:400px;}
-.clearfix,.area,.header,.footer,.content,.area-sub,.area-main,.main-col-10,.main-col-9,.tab-con {*zoom:1;}
-.clearfix:after,.area:after,.header:after,.footer:after,.content:after,.area-sub:after,.area-main:after,.main-col-10:after,.main-col-9:after,.tab-con:after {display:block; overflow:hidden; clear:both; height:0; visibility:hidden; content:".";}
-.header,.content,.footer {clear:both; width:960px; margin:0 auto;}
-.header,.footer {margin-bottom:10px;}
-.main-col-10 .mod,.area-sub .mod {margin-right:10px;}
-/* link css */
-a {color:#2b2b2b; text-decoration:none;}
-a:visited {text-decoration:none;}
-a:hover {color:#ba2636;text-decoration:underline;}
-a:active {color:#ba2636;}
-.sub-list a,.sub-list a:visited {color:#585858;}
-.cDGray,.cDGray:visited,.cDGray a{color:#727171;}
-.cBlue,.cBlue:visited,.cBlue a{color:#1E50A2;}
-.cDRed,.cDRed:visited,.cDRed a{color:#ba2636;}
-.cRed {color:#ff0000;}
-.tab-u a:hover,.cRed a:hover,a.cRed:hover,.sub-list a:hover,.cBlue a:hover,a.cBlue:hover,.cDRed a:hover,a.cDRed:hover,.cGray a:hover,a.cGray:hover,.cDGray a:hover,a.cDGray:hover,.cWhite a:hover,a.cWhite:hover,.cBlack a:hover,a.cBlack:hover,.cGreen a:hover,a.cGreen:hover,.cYellow a:hover,a.cYellow:hover{color:#ba2636;}
-/* templet */
-.imgText-temp-1 {overflow:hidden; padding-left:132px; margin-bottom:3px;}
-.imgText-temp-1 .main-img {position:absolute; _display:inline; margin-left:-132px;}
-.imgText-temp-1 .main-list {float:left;}
-.imgText-temp-2 {overflow:hidden; padding:0 0 10px 80px;}
-.imgText-temp-2 .imgText-img {float:left; _display:inline; margin-left:-80px; border:1px solid #dcdddd;}
-.imgText-temp-2 .imgText-titleTop {margin:6px 0 3px -80px; line-height:21px; font-weight:bold;}
-.imgText-temp-2 .sub-list {float:left;}
-.imgText-temp-3 {overflow:hidden; padding-left:132px; margin-bottom:15px;}
-.imgText-temp-3 .main-img {float:left; _display:inline; margin-left:-132px;}
-.imgText-temp-3 .main-list {float:left;}
-.temp-1-2 {margin-top:6px;}
-.temp-1-2 .temp-u {_display:inline; width:180px;}
-/* ntes modules mod */
-.user-logined,.login-name,.logined-begin,.logined-after,.main-list li,.specialTopic-list li,.sub-list li,.stock-search .ui-btn-submit,.i-setIndex,.i-help,.i-rss,.ui-select-box,.ui-btn-login,.ntes-passport,.product-item-mail .icon,.product-item-game .icon,.product-item-serv .icon,.product-item-reco .icon,.theme-blue,.theme-gray,.theme-green,.theme-pink,.theme-yellow {background:url("../img1.cache.netease.com/www/v2011/img/iconv0.0.7.png") no-repeat;}
-.mod .hd,.mod-function {background-position:left -30px;}
-.mod {margin-bottom:10px;}
-.mod .hd {height:24px; line-height:24px;}
-.mod .bd {overflow:hidden;}
-.mod-title {float:left; font-weight:bold; text-indent:10px;}
-.mod-entry {float:right; padding-right:6px;}
- .area-main .bd {padding:12px 8px 0 10px;}
- .area-sub .bd {padding:12px 9px 0;}
-.main-title {height:22px; line-height:25px; margin-bottom:3px; overflow:hidden; fo nt-family:\9ED1\4F53; font-size:14px; font-weight:bold;}
-.main-subtitle {height:19px; overflow:hidden; font-weight:bold; font-size:14px; line-height:19px;}
-.mod-list {margin-bottom:4px; width:100%;}
-.mod-list li {overflow:hidden; clear:both;}
-.mod-list .dotline {margin-bottom:4px; padding-bottom:4px;}
- .main-list li,.specialTopic-list li {padding-left:12px; height:25px; font-size:14px; line-height:25px;}
- .main-list li {background-position:-124px -80px;}
- .specialTopic-list li {background-position:-123px -112px;}
- .sub-list li {padding-left:12px; height:21px; line-height:21px; background-position:-124px -82px;}
- .sub-list .title {background:none; padding-left:0; font-weight:bold;}
- .trends-list li {height:21px; line-height:21px;}
-.mod-img img {clear:both;}
-.mod-img p {margin:1px 0 0; line-height:19px;}
-.mod-img cite {clear:both; float:left; width:100%; height:14px; overflow:hidden; margin-top:9px; cursor:pointer;}
- .main-img {overflow:hidden; width:122px;}
- .main-img img { border:1px solid #dcdddd;}
- .main-img .stock-img {border:none;}
- .sub-img {overflow:hidden; width:170px; margin-bottom:9px;}
-.mod-imgText {clear:both; margin:0 0 4px; line-height:0; zoom:1;}
- .imgText-img {float:left; line-height:1em;}
- .imgText-title {line-height:1.5; font-weight:bold;}
- .imgText-digest {margin:3px 0 0;line-height:21px;text-indent:2em;}
-.mod-imgList {float:left; _display:inline;}
-.mod-imgList li {float:left; overflow:hidden; _display:inline;}
-.mod-imgList img {border:1px solid #dcdddd;}
-.mod-imgList p {line-height:19px; margin-top:4px;}
- .imgList-w80 {margin:0 0 4px -14px;}
- .imgList-w80 li {margin:0 0 13px 15px; width:80px; height:103px;}
- .imgList-w80 img {border:none;}
- .imgList-w80_1 {margin:9px 0 4px -14px;}
- .imgList-w80_1 li {margin:0 0 5px 15px; width:80px; height:103px;}
- .imgList-w80_1 img {border:none;}
- .imgList-w90 {margin:0 0 4px -27px;}
- .imgList-w90 li {margin:0 0 4px 29px; width:92px; height:115px;}
- .imgList-w120 {margin-left:-2px;}
- .imgList-w120 li {margin:0 0 25px 2px; width:122px; height:115px;}
- .imgList-w160 {margin-left:-16px;}
- .imgList-w160 li {margin:0 0 4px 16px; width:162px; height:115px;}
- .imgList-w160-2 {margin-left:-16px; margin-bottom:5px;}
- .imgList-w160-2 li {margin:0 0 4px 16px; width:162px; height:123px;}
-.mod-keyword {clear:both;}
- .keyword-hd {margin-bottom:3px; line-height:21px;}
- .keyword-bd {float:left; _display:inline; margin-left:-25px; line-height:23px;}
- .keyword-bd a {float:left; _display:inline; white-space:nowrap; margin-left:25px; font-size:14px;}
-.custom-mod-hd {height:26px; line-height:26px;}
-.custom-title {float:left;}
-.custom-entry {float:right;}
-.specialTopic {margin-top:4px;}
-.specialTopic-hd {margin-bottom:6px;}
-.specialTopic-title {height:20px; overflow:hidden; padding-top:5px;}
-.product-mod {margin-bottom:10px;}
-.product-mod .bd {padding:0;}
-.trends-mod .bd {padding:5px 9px;}
-.mod-function {height:19px; overflow:hidden; margin-bottom:6px; line-height:20px;}
-.function-date {float:left; _display:inline; margin:0 0 0 6px;}
-.function-close,.function-info {float:right;}
-.function-close {cursor:pointer; _display:inline; width:47px; height:17px; line-height:17px; overflow:hidden; visibility:hidden; text-indent:12px; margin:1px 1px 0 6px; background-position:-101px 0;}
-/* ntes widget wgt */
-.wgt-tab {clear:both;}
-.tab-u {float:left; text-align:center; cursor:pointer; font-family:Verdana,\5B8B\4F53,san-serif;}
-.tab-hd {overflow:hidden; height:26px; line-height:25px; background-position:right -29px;}
-.tab-hd .current{font-weight:bold;}
-.tab-u-10 .tab-u {width:96px; font-size:14px;}
-.tab-u-10 .current {width:97px; background:#fff;}
-.tab-u-5 .tab-u {width:46px;}
-.tab-u-5 .current {width:47px;}
-.tab-u-9 .tab-u {width:89px; font-size:14px;}
-.tab-u-9 .current {width:88px; background:#fff;}
-.product-tab .tab-u {width:93px;}
-.product-tab .current {width:94px;}
-.stock-search {clear:both; width:100%; height:19px;}
-.stock-search label {position:absolute; left:0; top:0; color:#999; line-height:19px; text-indent:3px;}
-.stock-search-input {float:left; height:17px; width:100px; padding-right:20px;}
-.stock-search .ui-btn-submit {float:left; width:16px; height:13px; margin:3px 0 0 -19px; text-indent:-100em; overflow:hidden; background-position:-46px -190px;}
-/* common */
-.main-title .I_V_ {font-weight:bold;}
-.imgText-title .I_V_ {font-weight:bold;}
-.entry {line-height:21px;}
-.entry a {height:21px; overflow:hidden;}
-.display-control .tab-con {display:none;}
-.display-control .current {display:block;}
-.dotline {border-bottom:1px dotted #dcdddd;}
-.new {text-decoration:underline;}
-.attitude {float:left; padding-right:63px; background:url("../img1.cache.netease.com/www/v2011/img/attr.png") no-repeat scroll right 1px transparent;}
-.gg,.gg_reset {background:#E6F4FF;}
-.gg {margin-bottom:10px;}
-.mb-6 {margin-bottom:6px;}
-.mb-12 {margin-bottom:12px;}
-.blank3 {clear:both; height:3px; overflow:hidden; display:block;}
-.blank6 {clear:both; height:6px; overflow:hidden; display:block;}
-.code-en {font:13px "Verdana";}
-.area-sub .gg {width:190px;}
-.main-col-9 .gg {width:360px;}
-.main-col-10 .gg {width:390px;}
-.gg-h65 {height:65px;}
-.gg-h180 {height:180px;}
-.gg-h100 {height:100px;}
-.gg-h300 {height:300px;}
-.gg-h290 {height:290px;}
-.gg-h65,.gg-h100,.gg-h180,.gg-h290,.gg-h300 {overflow:hidden; clear:both;}
-.ggw600h80 {width:600px; height:80px; overflow:hidden;}
-.area-main ul.dotline {padding-bottom:4px;}
-.area-sub ul.dotline {padding-bottom:4px;}
-.main-bn-blog {margin-bottom:18px;}
-/* ntes snippet */
- h1 {display:none;}
- .logo {float:left; _display:inline; margin: 19px 7px 0 16px;}
- .channel {float:right; height:80px; overflow:hidden;}
- .channel-col {float:left; _display:inline; margin:10px 0 0 -1px; padding:0 0 0 16px; line-height:20px; border-left:1px solid #dcdddd;}
- .channel-col a {float:left; margin:0 6px 0 0; width:24px;}
- .channel-col .w3 {float:left; margin:0 6px 0 0; width:36px;}
- .channel-col strong {float:left; margin-right:6px;}
- .channel-col strong a {width:26px;}
-.col-w .nowrap {float:left; width:138px;}
-.col .nowrap {float:left; width:108px;}
-.col-w3 .nowrap {float:left; width:120px;}
-/* ntes snippet passport */
-.ui-pos-rel {position:relative; z-index:1;}
-.ui-pos-abs {position:absolute; display:none;}
-.ui-pos-active {visibility:visible;}
-.ui-ipt-enter[data-state="disable"] {background:#fbfbfb; border:1px solid #e3e3e3;}
-.ui-ipt-enter[data-state="error"] {background:#FFFCF0; border:1px solid #e3e3e3;}
-.ui-ipt-enter {border-style:solid; border-width:1px; border-color:#BABABA #E3E3E3 #E3E3E3 #BABABA; font-family:Verdana,san-serif,\5B8B\4F53; color:#2b2b2b; background:#fff;}
-.ui-btn-submit {padding:0; border:none; cursor:pointer;}
-.ui-btn-submit[data-state="disable"] {border:1px solid #ccc; color:#727171; cursor:default; background:#f3f3f3;}
-.ntes-passport {position:absolute; left:0; top:0; z-index:2; clear:both; width:100%; min-width:960px; height:29px; color:#727171; background-position:left bottom; background-repeat:repeat-x;}
- .passport-main {width:960px; margin:0 auto;}
- .passport-login {float:left;}
- .login-info {line-height:29px;}
- .passport-login .label {overflow:hidden; float:left; margin:4px 0 0; height:20px; padding:2px 0 0; line-height:16px;}
- .passport-entry {float:right; line-height:29px;}
- .i-setIndex {padding:2px 0 0 15px; cursor:pointer; background-position:-117px -28px;}
- .i-help {padding:2px 0 0 20px; background-position:-113px 3px;}
- .i-rss {float:right; margin:7px 0 0 6px; width:23px; height:13px; overflow:hidden; text-indent:-100em; background-position:left -90px;}
-.ui-select {float:left;}
- .form-ipt {float:left; _display:inline; overflow:hidden; margin:5px 5px 0; font-size:12px;}
- .form-ipt input {float:left; overflow:hidden; font-size:12px; height:16px; line-height:16px;}
- .form-ipt-user,.form-ipt-pwd {width:100px;}
- .ui-btn-login {_display:inline; float:left; width:39px; height:18px; margin:5px 11px 0 6px; font-size:12px; color:#727171; cursor:pointer; border:none; background-position:-5px -190px;}
- .ui-select-box {position:relative; z-index:1; width:79px; height:18px; margin:5px 0 0 0; line-height:18px; text-align:left; background-position:left -150px;}
- .ui-select-selected {display:block; overflow:hidden; width:79px; height:18px; text-indent:3px; cursor:pointer;}
- .ui-select-list {display:none; width:112px; position:absolute; top:17px; left:0; border:1px solid #b4b4b4; cursor:pointer; background:#fff;}
- .ui-select-list li {margin:1px; text-indent:5px; line-height:21px; color:#4b4b4b;}
- .ui-select-list .disable {color:#ccc; cursor:default;}
- .ui-select-list .interval {border-bottom:1px solid #c4c4c4;}
- .ui-select-list a {clear:both; display:block; width:110px; height:18px; text-indent:2px; cursor:pointer; background:#fff; color:#2b2b2b;}
- .ui-select-list a:visited {color:#2b2b2b;}
- .ui-select-list a:hover {text-decoration:none; color:#fff; background:#85B6EA;}
-.product-item-mail,.product-item-game,.product-item-serv,.product-item-reco {clear:both; padding:7px 0 7px 45px;}
-.product-item-mail strong,.product-item-game strong,.product-item-serv strong,.product-item-reco strong {float:left; _display:inline; width:40px; height:100%; margin-left:-45px; overflow:hidden;}
-.product-item-mail a,.product-item-game a,.product-item-serv a,.product-item-reco a {float:left; width:70px; overflow:hidden; line-height:19px;}
- .product-item-mail .icon,.product-item-game .icon,.product-item-serv .icon,.product-item-reco .icon {width:30px;}
- .product-item-mail .icon {margin:1px 0 0 9px; padding-top:18px; background-position:1px 2px;}
- .product-item-game .icon {margin:20px 0 0 8px; padding-top:21px; background-position:left -50px;}
- .product-item-serv .icon {margin:0 0 0 7px; padding-top:24px; background-position:-28px top;}
- .product-item-reco .icon {margin:10px 0 0 7px; padding-top:20px; background-position:-27px -50px;}
- .product-item-game,.product-item-reco {background:#fff;}
- .product-item-serv {height:45px; overflow:hidden; padding-bottom:0;}
- .product-item-reco {height:82px; overflow:hidden;}
-.product-list li {float:left; width:100%; height:27px; overflow:hidden; background-position:-202px -2px; }
-.item-mail,.item-microBlog,.item-blog,.item-photo,.item-money,.item-tie,.item-wan,.item-book,.item-yuehui,.item-caipiao
-{display:block; clear:both; float:left; padding-left:30px; height:28px; line-height:28px; background:url("../img1.cache.netease.com/www/v2011/img/icon_product_listv0.0.3.png") left top no-repeat;}
-.item-mail {background-position:6px 8px;}
-.item-microBlog {background-position:6px -19px;}
-.item-blog {background-position:6px -47px;}
-.item-photo {background-position:6px -74px;}
-.item-money {background-position:6px -103px;}
-.item-tie {background-position:4px -132px;}
-.item-wan {background-position:4px -160px;}
-.item-book {background-position:4px -186px;}
-.item-yuehui {background-position:4px -215px;}
-.item-caipiao {background-position:4px -243px;}
-.product-entry {_display:inline; clear:both; float:right; margin-right:6px; height:30px; line-height:30px;}
-/* end */
-.ntes-yodao {position:relative; clear:both; z-index:1; height:63px; width:958px; border-style:solid; border-width:1px;}
-.yodao-main {float:right; width:818px;}
-.yodao-sub {float:left; _display:inline; width:140px;}
- .yodao-logo {float:left; width:114px; height:23px; overflow:hidden; margin-top:29px; text-indent:-100em;}
- .wgt-yodao-weather {visibility:hidden; float:left; width:140px; margin:9px 0 0;}
- .yodao-weather-info {width:70px; float:left;}
- .weather-location {padding-right:10px; float:right; clear:both; cursor:pointer; height:21px; overflow:hidden; line-height:21px; background-position:right -75px;}
- .weather-temperature {float:right; width:100%; text-align:right; clear:both; line-height:16px;}
- .yodao-weather-icon {width:65px; padding-left:5px; line-height:20px; text-align:center; float:left;}
- .wgt-yodao-search {float:left; _display:inline; width:460px; margin:6px 0 0 4px;}
- .wgt-yodao-search label {display:none;}
- .wgt-yodao-search .ui-ipt-enter {float:left; padding:3px 0 0 3px; width:380px; height:21px; font-size:14px; border-left:1px solid #8c8c8c; border-top:1px solid #8c8c8c; border-bottom:1px solid #cbccce; border-right:none;}
- .wgt-yodao-search .ui-btn-submit {float:left; width:67px; height:26px; text-align:center; line-height:26px; font-size:14px; font-weight:bold; background-position:left top;}
- .yodao-search-category {height:20px; margin-bottom:3px;}
- .yodao-search-category .current,.search-category-item a:hover {font-weight:bold; color:#fff; background-position:-67px top;}
- .search-category-item a:hover {text-decoration:none;}
- .search-category-item a {float:left; padding:2px 0 4px; width:34px; text-align:center; margin-right:8px; cursor:pointer;}
- .search-category-more {float:left; margin:2px 0 0 5px; padding-right:10px; margin-right:8px; cursor:pointer; background-position:right -78px;}
- .yodao-search-category label {display:none;}
- .category-more-list {width:72px; left:0; top:15px; zoom:1; z-index:2;}
- .category-more-list a {clear:both; width:100%; _height:170px; float:left; height:21px; line-height:21px; text-indent:3px;}
- .category-more-list a:hover {color:#fff; text-decoration:none;}
- .category-more-list .interval {border-bottom:1px solid #dcdddd;}
- .yodao-entry {float:right; width:225px;}
- .yodao-entry-mine {display:block; width:110px; height:19px; text-align:center; line-height:19px;}
- .yodao-entry-link {visibility:hidden; margin:13px 0 0; height:14px; overflow:hidden;}
- .wgt-theme {position:absolute; right:10px; top:6px; height:10px; overflow:hidden;}
- .theme-blue,.theme-gray,.theme-green,.theme-pink,.theme-yellow {_display:inline; float:left; width:11px; height:21px; overflow:hidden; margin-left:8px; cursor:pointer;}
- .theme-blue {background-position:-26px -168px;}
- .theme-gray {background-position:-15px -168px;}
- .theme-green {background-position:-4px -168px;}
- .theme-pink {background-position:-48px -168px;}
- .theme-yellow {background-position:-37px -168px;}
-.wgt-theme .current {margin-top:-11px;}
-.yodao-dialog {width:135px; left:-1px; top:21px;}
-.yodao-dialog .hd {height:20px; padding:0 3px; line-height:20px;}
- .yodao-dialog-title {float:left;}
- .yodao-dialog-close {float:right; _display:inline; width:8px; height:12px; text-indent:-100em; overflow:hidden; margin:6px 2px 0 0; cursor:pointer; background-position:-139px -17px;}
-.yodao-dialog .bd {height:76px; padding:6px 12px 12px;}
- .yodao-dialog-item {float:left; display:block; height:20px; margin:3px 0 0;}
- .yodao-dialog select {width:64px;}
-.yodao-dialog .ui-btn-submit {width:54px; height:21px; margin:9px 0 0 36px; background-position:-148px top;}
-.aboutNetease{height:25px; margin-bottom:10px;}
-.aboutNetease li{padding:4px 0 0; color:#1E50A2;}
-.aboutNetease li a{color:#1E50A2; padding:0 5px;}
-.aboutNetease li a:visited{ color:#1E50A2;}
-.footer {padding:0 0 5px; text-align:center; line-height:21px; color:#000;}
-.footer a,.footer a:visited {color:#1E50A2;}
-.footer img{margin:4px 0 0;}
-.gg-g24 {clear:both; height:139px; overflow:hidden; margin:0 auto 10px; text-align:left; border:1px solid #dcdddd;}
- .tab-hd-gg-left,.tab-hd-gg-right {_display:inline; width:22px; height:138px; overflow:hidden;}
- .tab-hd-gg-left .current,.tab-hd-gg-right .current {background-image:url("../img1.cache.netease.com/www/v2011/img/iconv0.0.7.png"); background-repeat:no-repeat;}
- .tab-hd-gg-left li,.tab-hd-gg-right li {width:11px; overflow:hidden; overflow:hidden; margin-top:1px; line-height:14px; cursor:pointer;}
- .tab-hd-gg-left {float:left; margin-left:1px;}
- .tab-hd-gg-left li {padding:8px 4px 9px 3px; text-align:left;}
- .tab-hd-gg-left .current {padding-right:8px; background-position:18px -168px;}
- .tab-hd-gg-right {float:right; margin-right:1px;}
- .tab-hd-gg-right li {float:right; padding:8px 3px 9px 4px; text-align:right;}
- .tab-hd-gg-right .current {padding-left:8px; background-position:-126px -168px;}
- .link_gg {line-height:21px;}
-.tab-bd-gg,.gg-g24-main {float:left; overflow:hidden;}
-.tab-bd-gg {width:137px; margin:7px 0 0 5px;}
-.tab-bd-gg {line-height:21px;}
-.gg-g24-main {width:600px; height:129px; margin:5px 10px;}
- .g24-main-textTop{display:block; overflow:hidden; margin:2px 0 1px; height:21px;}
- .g24-main-textBottom{display:block; overflow:hidden; margin:3px 0 0 0; height:21px;}
- .g24-main-textTop a,.g24-main-textBottom a {float:left; overflow:hidden; width:120px; line-height:21px;}
-#g5n1 .bd,#gy .bd,#g5n2 .bd,#recommend .bd {height:261px;}
-#g5n3 .bd {height:261px;}
-#product .bd {height:300px;}
-#news .bd {height:598px;}
-#vedio .bd {height:429px;}
-#moneySub .bd {height:223px;}
-#nie .bd {height:269px;}
-#trends .bd {height:63px;}
-#sportSub .bd,#gameSub .bd {height:221px;}
-#money .bd,#auto .bd,#sports .bd,#house .bd,#ent .bd,#game .bd,#tech .bd,#book .bd,#lady .bd,#t .bd {height:341px;}
-#market .bd,#blog .bd,#hz .bd,#bbs .bd,#marketSub .bd,#siteRank .bd {height:261px;}
-/* neteasy_mall */
-#neteasy_mall{height:273px;line-height:26px;padding-right:0;}
-#neteasy_mall .dotline{ margin-bottom:5px;width:170px;line-height:1px;font-size:1px;height:1px;}
-.neteasy_mall_title{color:#2B2B2B;font-weight:bold;line-height:18px;margin-top:-5px;}
-.neteasy_mall_phone,.neteasy_mall_value{width:93px;height:19px;border:1px solid #86A2BD;color:#727171;padding-left:5px;}
-.neteasy_mall_phone{*padding-top:2px;*height:17px;}
-.neteasy_mall_value{width:60px;height:20px;padding-left:0}
-.neteasy_mall_submit{width:35px;height:20px;background:url("../img1.cache.netease.com/www/v2011/img/neteasy_mallv0.0.1.png") no-repeat;border:none;color:#BA2636;cursor:pointer;margin-left:5px;}
-#phone_err{width:14px;height:14px;line-height:1px;font-size:1px;display:inline-block;background:url("../img1.cache.netease.com/www/v2011/img/neteasy_mallv0.0.1.png") -39px 0 no-repeat;margin-left:3px;}
-.mall_flash{margin-bottom:8px;}
-.mall_price{_line-height:30px}
-.mall_img{margin-top:-2px;*margin-top:7px;}
-/* youdao start by jiemengen */
-.remindtt75 {font-size:100%; padding:2px;}
-.remindtt752 {font-size:100%; padding-left:2px; padding-right:2px;color:#9E9E9E}
-.jstxhuitiaozuo {background-color:#eaf1fd; color:#8D9DBE; font-size:100%; padding-left:5px; padding-top:1px;}
-.jstxhuitiaoyou {font-size:100%;padding-right:5px;}
-.jstxlan {font-size:100%;cursor:pointer}
-.jstxlan:hover {text-decoration:underline;}
-.aa_highlight {color:#fff;}
-/* ¹ÉƱËÑË÷µ¯´° */
-.tcbox { float:left; position: absolute; width: 270px; z-index: 99; top: 25px; left: 0; margin-left:0px; margin-top:6px; border: 1px solid #DCDDDD; background:#FFFFFF;}
-.tbText { border-collapse: collapse; line-height: 20px; font-size: 12px; text-align: left; color:#2B2B2B; width: 268px; margin-top:3px;}
-.tbText th,.tbText td { height: 20px; padding: 0 6px; text-align: left;}
-.tbText th { background: #E2F7FD; color:#1E50A2; font-weight:normal;}
-.tbText .nline {padding: 1px; color:#2B2B2B; display: block; outline-color: -moz-use-text-color; outline-style: none; outline-width: medium; text-decoration: none; width: 100%;}
-.tbText tr.alter td { background: #CCEDF7; }
-.tbText tr:hover {background: #CCEDF7;}
-.login-after-inner {position:relative; z-index:10; float:left; margin-right:9px;}
-.login-after-select {display:none; position:absolute; width:100%; _width:170px; left:0; top:23px; overflow:hidden; background:#fff; line-height:18px; text-align:left; color:#2b2b2b;}
-.login-after-select .user-entry {display:block; border:1px solid #dcdddd; padding:1px;}
-.login-after-select a {display:block; clear:both; width:100%; _width:166px; height:21px; line-height:21px; text-indent:3px; font-weight:normal; color:#2b2b2b;}
-.login-after-select a:hover{ background-color:#4472AE; color:#fff; text-decoration: none; }
-#NTES_Login { position:relative; }
-.login-tips { background:#FFFCF0; border:1px solid #dcdddd; padding:0px 2px; height:16px; line-height:16px; position:absolute; top: 22px; left: 29px; display: none; }
-.login-tips a.cBlue{ color: #1E50A2; }
-.login-tips a.cBlue:hover { color:#BA2636; }
-.login-tips a.login-tips-close{ color: #999; }
-.login-tips a.login-tips-close:hover{ color: #000; text-decoration: none; }
-.login-auto-list{ border-collapse: collapse; background: #fff; position: absolute; left: 29px; top: 22px; border: 1px solid #E3E3E3; z-index: 10; }
-.login-auto-list th,.login-auto-list td{ line-height: 22px; height: 22px; padding: 0 5px; font-family: Verdana,san-serif,\5B8B\4F53; }
-.login-auto-list td{cursor:pointer;}
-.login-auto-list th{text-align:left; background-color:#F6F6F6;}
-.login-auto-list td.hover{ background-color:#4472AE; color:#fff; }
-.ui-select-list li.hover{ background-color:#4472AE; color:#fff; }
-.ui-select-list, .ui-select-box{ }
-.login-tips-username{ z-index: 5; font-family: Verdana,san-serif,\5B8B\4F53; }
-.login-tips-password{ z-index: 5; left: 142px; }
-.login-tips-mobile{ z-index: 1; }
-/* webkit */
-.ui-ipt-enter,.ui-btn-submit{-webkit-appearance: none !important;}
-.user-logined {float:left; height:21px; margin-top:3px; padding-left:6px; line-height:21px; font-family:Verdana,\5B8B\4F53,san-serif; background-position:left -213px;}
-.login-name {float:left; cursor:pointer; padding-right:18px; background-position:right -233px;}
-.user-logined:hover {background-position:left -253px;}
-.user-logined:hover .login-name {background-position:right -273px;}
-/* gg style b31t9e41 */
-.b31t9e41 {background:url('../img1.126.net/channel5/008976/bolon_110302.png') right 50% no-repeat; padding-right:60px;}
-.tg_news {display:block; text-indent:-100em; overflow:hidden; width:250px; height:25px; background:url("../img2.cache.netease.com/www/v2011/img/tg_news.jpg") left top no-repeat;}
-/* gg ¼Òµç */
-.homeAppliances{display:inline;background: url(../img1.126.net/channel1/55x20_lan.gif) no-repeat right center; padding:0 55px 0 3px;}
-.current .homeAppliances{ background-image:url(../img1.126.net/channel1/55x20_bai.gif);}
-/* end */
-</style>
-</head>
-<body id="warpperBody">
-<div class="ntes-passport">
- <div class="passport-main">
- <div class="passport-login" id="NTES_Login">
- <form id="login_form" class="left" method="POST" name="loginForm" target="_blank" action="httpdisabledsdisabled://reg.163.com/logins.jsp">
- <input name="product" value="163" type="hidden">
- <input name="type" value="1" type="hidden">
- <input name="ursname" value="" type="hidden">
- <input name="selected" value="" type="hidden">
- <label class="label" for="login_username">ÕʺÅ</label>
- <div class="form-ipt"><input id="login_username" class="form-ipt-user ui-ipt-enter" name="username" autocomplete="off" data-state="disable" type="text"></div>
- <label class="label" for="login_password">ÃÜÂë</label>
- <div class="form-ipt"><input id="login_password" class="form-ipt-pwd ui-ipt-enter" name="password" data-state="disable" type="password"></div>
- <div id="login_select" class="ui-select passport-select">
- <div id="login_select_area" class="ui-select-box">
- <span id="login_selected" class="ui-select-selected">Ñ¡ÔñÈ¥Ïò</span>
- <ul id="login_select_main" class="ui-select-list">
- <li class="interval">ÍøÒ×ͨÐÐÖ¤</li>
- <li title="@163.com">163ÓÊÏä</li>
- <li title="@126.com">126ÓÊÏä</li>
- <li title="@vip.126.com">VIP126ÓÊÏä</li>
- <li title="@yeah.net">YeahÓÊÏä</li>
- <li title="@188.com">188²Æ¸»ÓÊ</li>
- <li title="@vip.163.com" class="interval">vipÓÊÏä</li>
- <li>ÍøÒײ©¿Í</li>
- <li>ÍøÒ×Ïà²á</li>
- <li>ͬ³ÇÔ¼»á</li>
- <li>ÍøÒ×ÂÛ̳</li>
- <li>ÍøÒ×΢²©</li>
- </ul>
-
- </div>
- </div>
- <input value="怬" class="ui-btn-submit ui-btn-login" data-state="disable" type="submit">
- </form>
- <iframe style="display: none;" name="loginFrame" id="loginFrame" src="about:blank"></iframe>
- <span id="login_before" class="login-info"><a href="httpdisabled://reg.163.com/reg/reg.jsp?product=163&url=http://www.163.com&loginurl=http://www.163.com">×¢²áͨÐÐÖ¤</a> | <a href="httpdisabled://reg.email.163.com/mailregAll/reg0.jsp?from=163">×¢²áÃâ·ÑÓÊÏä</a></span>
- <span id="login_after" class="login-info" style="display:none;"><span class="left">»¶Ó­Ä㣬</span>
- <div class="login-after-inner">
- <div class="user-logined">
- <strong id="login_after_username" class="login-name">pInfo</strong>
- </div>
- <div id="login_after_select" class="login-after-select">
- <span class="user-entry">
- <a class="popo-link others-link" href="httpdisabled://reg.163.com/Main.jsp?username=pInfo">½øÈëͨÐÐÖ¤</a>
- <a class="select-mail-link" href="httpdisabled://entry.mail.163.com/coremail/fcg/ntesdoor2?verifycookie=1&lightweight=1">½øÈëÎÒµÄÓÊÏä</a>
- <a class="select-mail-link" href="httpdisabled://entry.mail.126.com/cgi/ntesdoor?verifycookie=1&lightweight=1&style=-1">½øÈëÎÒµÄÓÊÏä</a>
- <a class="select-mail-link" href="httpdisabled://reg.vip.126.com/enterMail.m">½øÈëÎÒµÄÓÊÏä</a>
- <a class="select-mail-link" href="httpdisabled://entry.yeah.net/cgi/ntesdoor?verifycookie=1&lightweight=1&style=-1">½øÈëÎÒµÄÓÊÏä</a>
- <a class="select-mail-link" href="httpdisabled://reg.mail.188.com/servlet/enter">½øÈëÎÒµÄÓÊÏä</a>
- <a class="select-mail-link" href="httpdisabled://reg.vip.163.com/enterMail.m?enterVip=true-----------">½øÈëÎÒµÄÓÊÏä</a>
- <a class="popo-link" href="httpdisabled://blog.163.com/passportIn.do?entry=163">½øÈëÎҵIJ©¿Í</a>
- <a class="popo-link" href="httpdisabled://photo.163.com/?username=pInfo">½øÈëÎÒµÄÏà²á</a>
- <a class="popo-link others-link" href="httpdisabled://yuehui.163.com/">½øÈëÎÒµÄÔ¼»á</a>
- <a class="others-link" href="httpdisabled://t.163.com">½øÈëÎÒµÄ΢²©</a>
- </span>
- </div>
- </div>
- <iframe allowTransparency="true" style="width: 61px; height:26px; float:left; mmargin-left: 2px; vertical-align: middle" id="ifrmNtesMailInfo" border="0" src="../p.mail.163.com/mailinfo/shownewmsg_www_1222.htm.html" frameBorder="0" scrolling="no"></iframe>
- | <a id="login_after_logout" href="httpdisabled://reg.163.com/Logout.jsp?username=accountName&url=http://www.163.com/" target="_self">°²È«Í˳ö </a>
- </span>
- </div>
- <div class="passport-entry">
- <a href="httpdisabled://www.163.com/rss/" class="i-rss">rss</a> <span class="right"><span class="cDRed"><a href="httpdisabled://email.163.com/">Ãâ·ÑÓÊÏä</a></span> <a href="httpdisabled://vipmail.163.com/">VIPÓÊÏä</a> | Ò»¿¨Í¨£º<a href="httpdisabled://pay.163.com/">³äÖµ</a> <a href="httpdisabled://ecard.163.com/">¹ºÂò</a> <a class="i-setIndex" target="_self" href="index.html" onClick="this.style.behavior='url(#default#homepage)';this.setHomePage('http://www.163.com/');" title="°ÑÍøÒ×ÉèΪÊ×Ò³">ÉèΪÊ×Ò³</a> <a href="httpdisabled://help.163.com?b01abh1" class="i-help">°ïÖúÖÐÐÄ</a></span>
- </div>
- </div>
-</div>
-<!-- ±³¾°¹ã¸æ -->
-<div class="header">
- <h1>ÍøÒ×</h1>
-<div class="logo">
- <a href="index.html"><img src="../img3.cache.netease.com/www/logo/logo_png.png" alt="ÍøÒ×" title="ÍøÒ×" border="0" height="37" width="118" /></a>
- </div>
- <div class="channel">
- <div class="channel-col col-w">
- <span class="nowrap"><strong><a href="httpdisabled://news.163.com/">ÐÂÎÅ</a></strong> <a href="httpdisabled://war.news.163.com/">¾üÊÂ</a> <a href="httpdisabled://news.163.com/review/">ÆÀÂÛ</a> <a href="httpdisabled://news.163.com/photo/">ͼƬ</a>
- <strong><a href="httpdisabled://sports.163.com/">ÌåÓý</a></strong> <a href="httpdisabled://sports.163.com/nba/">NBA</a> <a href="httpdisabled://cbachina.163.com/">CBA</a> <a href="httpdisabled://sports.163.com/yc/">Ó¢³¬</a>
- <strong><a href="httpdisabled://ent.163.com/">ÓéÀÖ</a></strong> <a href="httpdisabled://ent.163.com/movie/">µçÓ°</a> <a href="httpdisabled://ent.163.com/tv/">µçÊÓ</a> <a href="httpdisabled://ent.163.com/music/">ÒôÀÖ</a></span>
- </div>
- <div class="channel-col col-w">
- <span class="nowrap">
- <strong><a href="httpdisabled://money.163.com/">²Æ¾­</a></strong> <a href="httpdisabled://money.163.com/stock/">¹ÉƱ</a> <a href="httpdisabled://money.163.com/fund/">»ù½ð</a> <a href="httpdisabled://biz.163.com/">ÉÌÒµ</a>
- <strong><a href="httpdisabled://v.163.com/">ÊÓƵ</a></strong> <a href="httpdisabled://v.163.com/focus/">Èȵã</a> <a href="httpdisabled://v.163.com/zongyi/">×ÛÒÕ</a> <a href="httpdisabled://v.163.com/doc/">¼Íʵ</a>
- <strong><a href="httpdisabled://lady.163.com/">Å®ÈË</a></strong> <a href="httpdisabled://fashion.163.com/">ʱÉÐ</a> <a href="httpdisabled://lady.163.com/beauty/">ÃÀÈÝ</a> <a href="httpdisabled://lady.163.com/sense/">Çé°®</a>
- </span>
- </div>
- <div class="channel-col col-w3">
- <span class="nowrap">
- <strong><a href="httpdisabled://tech.163.com/">¿Æ¼¼</a></strong> <a href="httpdisabled://money.163.com/hkstock/">¸Û¹É</a> <a href="httpdisabled://tech.163.com/cnstock/" class="w3">¸ÅÄî¹É</a>
- <strong><a href="httpdisabled://mobile.163.com/">ÊÖ»ú</a></strong> <a href="httpdisabled://tech.163.com/3G/">3G</a> <a href="httpdisabled://product.tech.163.com/mobile/" class="w3">ÊÖ»ú¿â</a>
- <strong><a href="httpdisabled://digi.163.com/">ÊýÂë</a></strong> <a href="httpdisabled://hea.163.com/">¼Òµç</a> <a href="httpdisabled://tech.163.com/digi/nb/" class="w3">±Ê¼Ç±¾</a>
- </span>
- </div>
- <div class="channel-col col">
- <span class="nowrap">
- <strong><a href="httpdisabled://auto.163.com/">Æû³µ</a></strong> <a href="httpdisabled://auto.163.com/buy/">¹º³µ</a> <a href="httpdisabled://product.auto.163.com/">Ëѳµ</a>
- <strong><a href="httpdisabled://travel.163.com/">ÂÃÓÎ</a></strong> <a href="httpdisabled://discovery.163.com/">̽Ë÷</a> <a href="httpdisabled://sports.163.com/lottery/">²ÊƱ</a>
- <strong><a href="httpdisabled://house.163.com/" id="houseUrl">·¿²ú</a></strong> <a href="httpdisabled://home.163.com/">¼Ò¾Ó</a> <a href="httpdisabled://xf.house.163.com/gz/">Âò·¿</a>
- </span>
- </div>
- <div class="channel-col col">
- <span class="nowrap">
- <strong><a href="httpdisabled://bbs.163.com/">ÂÛ̳</a></strong> <a href="httpdisabled://bbs.163.com/rank/">ÈÈÌû</a> <a href="httpdisabled://photo.163.com/">ÉãÓ°</a>
- <strong><a href="httpdisabled://blog.163.com/?fromNavigation">²©¿Í</a></strong> <a href="httpdisabled://blog.163.com/blogger.html">Ãû²©</a> <a href="httpdisabled://edu.163.com/">½ÌÓý</a>
- <strong><a href="httpdisabled://game.163.com/">ÓÎÏ·</a></strong> <a href="httpdisabled://wan.163.com/">Ò³ÓÎ</a> <a href="httpdisabled://book.163.com/">¶ÁÊé</a>
- </span>
- </div>
- <div class="channel-col col">
- <span class="nowrap">
- <strong><a href="httpdisabled://t.163.com/" style="color:#ba2636;">΢²©</a></strong> <a href="httpdisabled://t.163.com/rank/daren">ÈËÎï</a> <a href="httpdisabled://t.163.com/rank">Èȵã</a>
- <strong><a href="httpdisabled://fushi.163.com/">·þÊÎ</a></strong> <a href="httpdisabled://baby.163.com/">Ç××Ó</a> <a href="httpdisabled://gongyi.163.com/">¹«Òæ</a>
- <strong><a href="httpdisabled://m.163.com/">Ó¦ÓÃ</a></strong> <a href="httpdisabled://mall.163.com/">É̳Ç</a> <a href="httpdisabled://media.163.com/">´«Ã½</a>
- </span>
- </div>
- </div>
- <div class="gg-g24 clearfix">
-<div id="" class="wgt-tab-gg left">
- <div class="tab-hd-gg-left">
- <ul><li class="tab-u current">ÈÈÏú</li><li class="tab-u">´òÕÛ</li><li class="tab-u">ÕÐÉú</li></ul>
- </div>
- <div class="left tab-bd-gg display-control">
- <div class="tab-con cBlue current">
-<a href="httpdisabled://g.163.com/a?CID=6261&Values=1096445235&Redirect=http://xf.house.163.com/hn/0IBQ.html">ÑžÓÀÖÇåË®Í幫Ԣ¿ªÊÛ</a><br />
-<a href="httpdisabled://g.163.com/a?CID=241&Values=2504187228&Redirect=http://mail.188.com/news/v4/188intro_different.htm?vip03">ÐÒÔËÓòÃûÍøÒ×188ÓÊ</a><br />
-<a href="httpdisabled://g.163.com/a?CID=5936&Values=4083566547&Redirect=http://l.163.com">½ø¿ÚÃûÆ·2ÕÛ¾¢±¬ÇÀ¹º</a><br />
-<a href="httpdisabled://caipiao.163.com/">À´ÍøÒײÊƱÄÃǧÍò´ó½±</a><br />
-<a href="httpdisabledsdisabled://epay.163.com/notice/chongzhi.jsp">ÊÖ»ú¿¨¹ºµã¿¨±ã½Ý°²È«</a><br />
-<a href="httpdisabled://hn.house.163.com/11/0302/13/6U55TBSB0206009S.html">º£ÄÏ·¿²úÕмÇÕßÈô¸ÉÃû</a><br />
- </div>
- <div class="tab-con cBlue">
-<a href="httpdisabled://g.163.com/a?CID=242&Values=2202967901&Redirect=http://activity.vip.163.com/activity/art/index.mx?theme=Citroen&c5">Ãâ·ÑÓ®iPad¿´Îè¾ç</a><br />
-<a href="httpdisabledsdisabled://epay.163.com/notice/chongzhi.jsp">ÊÖ»ú¿¨¹ºµã¿¨±ã½Ý°²È«</a><br />
-<a href="httpdisabled://gz.house.163.com/special/bbs_2011wedding/">ɹ»éÉ´ÕÕ Ëͺ£ÄÏË«·É</a><br />
-<a href="httpdisabled://help.3g.163.com/news/">ÊÖ»úÉÏÿÈÕ²éÐÇ×ùÔËÊÆ</a><br />
-<a href="httpdisabled://game.163.com/">ÍøÒ׵羺ƵµÀÉÏÏß</a><br />
-<a href="httpdisabled://haoma.163.com">¹Å¶­¼¶ÍøÒ×Õ˺ÅÅÄÂô</a><br />
- </div>
- <div class="tab-con cBlue">
-<a href="httpdisabled://blog.163.com/activities/blogbbfg/blogbbfg.do">ǧÍò²©¿Í»»·ô²»ÔÙ¼èÄÑ</a><br />
-<a href="httpdisabled://hr.163.com/job/loc_info.jsp?id=782">ÍøÒ×±±¾©Æ¸²úÆ·Éè¼Æʦ</a><br />
-<a href="httpdisabled://fm.163.com/?sdysc1108">°ÙÍò°×Áì±Ø±¸ÓÊÏä¹Ü¼Ò</a><br />
-<a href="httpdisabled://mail.blog.163.com/blog/static/822094242010131169929/edit/?mode=prev">ÍøÒ×ÓÊÏä¡°Ò»ÏäË«ºÅ¡±</a><br />
-<a href="httpdisabled://tech.163.com/digi/buy/">Íò¿îÊýÂë²úÆ·Ñ¡¹ºÖ¸ÄÏ</a><br />
-<a href="httpdisabled://lady.163.com/">ʱÉÐÃÀÀö¾¡ÔÚÍøÒ×Å®ÈË</a><br />
- </div>
- </div>
- </div>
-<div class="gg-g24-main cBlue">
- <div class="g24-main-textTop">
- <iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=textlinkhouse&amp;location=1.html" width="600" height="21" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
- </div>
- <div class="ggw600h80"><iframe id="iframe_banner1" name="iframe_banner1" src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column600x80&amp;location=1.html" width="600" height="80" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-</div>
- <span class="g24-main-textBottom"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=textlinkhouse&amp;location=2.html" width="600" height="21" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
- </span>
- </div>
-<div id="cAn1_r" class="wgt-tab-gg right">
- <div class="tab-hd-gg-right">
- <ul><li class="tab-u current">×îÐÂ</li><li class="tab-u">½ÌÓý</li><li class="tab-u">ÕÐÉÌ</li></ul>
- </div>
- <div class="right tab-bd-gg display-control">
- <div class="tab-con cBlue current">
-<a href="httpdisabled://g.163.com/a?CID=6669&Values=806667841&Redirect=http://as.kejet.com/afaclick?u/NjM4Q0I1RjgwQzMwN0Mx/o/NzgyM0VCRUE3MkJDQ0RE/m/MDRGNzE2Mjk0NTBGQkU1?http://auto.163.com/11/0402/16/70LAUH6N00081G98.html">±¼ÌÚµ¼º½ÀñçÍ·×ϲÁ¬Á¬</a><br />
-<a href="httpdisabled://g.163.com/a?CID=242&Values=2202967901&Redirect=http://activity.vip.163.com/activity/art/index.mx?theme=Citroen&c5">Ãâ·ÑÓ®iPad¿´Îè¾ç</a><br />
-<a href="httpdisabled://mail.blog.163.com/blog/static/822094242011231101848784/">ÍøÒ×ÓÊÏäEmail°ÙÇéÊé</a><br />
-<a href="httpdisabled://reg.mail.188.com/servlet/regist?vip08">ÍøÒ×VIP¸ß¶Ë·þÎñƽ̨</a><br />
-<a href="httpdisabled://g.163.com/a?CID=247&Values=1421022587&Redirect=http://survey2.163.com/html/dict_youdao2011q1/paper.html">ÇáµãÊó±êÓ®¾ªÏ²´ó½±</a><br />
-<a href="httpdisabled://pmxj.wan.163.com/">Æ®Ãì¶à·çÔÆÏɽ£ÏÔÎäÁÖ</a><br />
- </div>
- <div class="tab-con cBlue">
-<a href="httpdisabled://hn.house.163.com/11/0302/13/6U55TBSB0206009S.html">º£ÄÏ·¿²úÕмÇÕßÈô¸ÉÃû</a><br />
-<a href="httpdisabled://g.163.com/a?CID=5943&Values=3636039039&Redirect=http://www.wtqx.net/vote/">ͶƱѡ³ö×îÃÀÀöУ԰</a><br />
-<a href="httpdisabled://yuehui.163.com/">2011·¢ÊIJ»ÔÙ×öʣŮ</a><br />
-<a href="httpdisabled://caipiao.163.com">À´ÍøÒײÊƱÄÃǧÍò´ó½±</a><br />
-<a href="httpdisabled://so.auto.163.com/">º£Á¿³µÑ¶¡°ËѳµÓеÀ¡±</a><br />
-<a href="httpdisabled://mail.163.com/html/110127_imap/index.htm">ÊÓƵ½ÌÄãÉèÖÃÓÊÏäIMAP</a><br />
- </div>
- <div class="tab-con cBlue">
-<a href="httpdisabled://yxp.163.com/photo/ep.html">ÕÕƬ³åÓ¡½ö0.45Ôª/ÕÅ</a><br />
-<a href="httpdisabled://fm.163.com/?100208fmgwwzl01">ÍøÒ×Ê׿î×ÀÃæÓÊÏäÈí¼þ</a><br />
-<a href="httpdisabled://bafang.163.com/">ÊÖ»ú²é¿´taÔÚÄÄÀï</a><br />
-<a href="httpdisabled://gongyi.163.com/love365?mailsignresult=-1">Ï£Íû¹¤³Ì365°®ÐÄÐж¯</a><br />
-<a href="httpdisabled://help.3g.163.com/stock/">ÊÖ»ú¿´¹ÉƱÿÈÕÕÇÍ£</a><br />
-<a href="httpdisabled://qn.163.com">ٻŮÓÄ»êÈÈ·¢¼¤»îÂë</a><br />
- </div>
- </div>
- </div>
- </div>
- <div class="ntes-yodao">
- <div class="yodao-main">
- <a href="httpdisabled://www.youdao.com/" class="yodao-logo" title="µã»÷½øÈëÓеÀÊ×Ò³">ÍøÒ×ÓеÀ</a>
- <form id="ydForm" method="get" action="httpdisabled://www.youdao.com/search" name="ydForm">
- <div class="wgt-yodao-search">
- <div class="yodao-search-category">
- <span class="search-category-item">
- <a class="current" onClick="return false">ÍøÒ³</a>
- <a href="httpdisabled://image.youdao.com" onClick="changeProduct('image');return false" target="_blank">ͼƬ</a>
- <a href="httpdisabled://news.youdao.com" onClick="changeProduct('news');return false" target="_blank">ÈÈÎÅ</a>
- <a href="httpdisabled://gouwu.youdao.com" onClick="changeProduct('gouwu');return false" target="_blank">¹ºÎï</a>
- <a href="httpdisabled://mp3.youdao.com" onClick="changeProduct('mp3');return false" target="_blank">ÒôÀÖ</a>
- <a href="httpdisabled://video.youdao.com" onClick="changeProduct('video');return false" target="_blank">ÊÓƵ</a>
- <a href="httpdisabled://dict.youdao.com" onClick="changeProduct('dict');return false" target="_blank">´Êµä</a>
- <a href="httpdisabled://fanyi.youdao.com" target="_blank">·­Òë</a>
- </span>
- <div class="search-category-more ui-pos-rel c-entry" id="yodaoMore"><span>¸ü¶à</span>
- <span id="categoryMore" class="category-more-list ui-pos-abs"><a href="httpdisabled://blog.youdao.com" onClick="changeProduct('blog');return false">²©¿Í</a><a href="httpdisabled://tie.youdao.com" target="_blank">¿ìÌù</a><a href="httpdisabled://map.youdao.com" onClick="changeProduct('map');return false" target="_blank">µØͼ</a><a class="interval" href="httpdisabled://reader.youdao.com/" target="_blank">ÔĶÁ</a><a href="httpdisabled://m.youdao.com/help" target="_blank">ÊÖ»ú</a><a href="httpdisabled://shuqian.youdao.com" target="_blank">ÊéÇ©</a><a class="interval" href="httpdisabled://cidian.youdao.com" target="_blank">×ÀÃæ´Êµä</a><a href="httpdisabled://www.youdao.com/about/productlist.html" target="_blank">È«²¿²úÆ·</a></span>
- </div>
- </div>
- <label for="yodaoSearch">ÓеÀËÑË÷</label>
- <div id="ydQuery">
- <input id="query" class="ui-ipt-enter" type="text" name="q" autocomplete="off" /><button class="ui-btn-submit" type="submit" id="ydSubmit">ËÑ Ë÷</button>
- <input name="ue" value="gbk" type="hidden">
- <input name="keyfrom" value="163.index" type="hidden">
- </div>
- </div>
- </form>
- <div class="yodao-entry c-entry">
- <span class="yodao-entry-mine">
- <a href="httpdisabled://www.youdao.com/i?keyfrom=163.index" title="ÉÏÍøÊ×Ò³×Ô¼ºÔ죡">ÓеÀ¸öÐÔÊ×Ò³ <span class="code-en">&raquo;</span> </a>
- </span>
- <p id="ydHotKeys" class="yodao-entry-link"></p>
- </div>
- <div id="changeSkin" class="wgt-theme">
- <span class="theme-blue current" title="À¶É«Ö÷Ìâ"> </span>
- <span class="theme-gray" title="»ÒÉ«Ö÷Ìâ"> </span>
- <span class="theme-green" title="ÂÌÉ«Ö÷Ìâ"> </span>
- <span class="theme-pink" title="·ÛÉ«Ö÷Ìâ"> </span>
- <span class="theme-yellow" title="»ÆÉ«Ö÷Ìâ"> </span>
- </div>
- </div>
- <div class="yodao-sub">
- <div id="wgt_weather" class="wgt-yodao-weather">
- <div class="yodao-weather-info c-entry">
- <div class="ui-pos-rel weather-area">
- <div id="weather">
- <span class="weather-location" id="setChange"></span>
- </div>
- <div id="ydAreas" class="ui-pos-abs yodao-dialog">
- <div class="hd">
- <span class="yodao-dialog-title">ÇëÑ¡Ôñ³ÇÊÐ</span>
- <span id="closeWeather" class="yodao-dialog-close">X</span>
- </div>
- <div class="bd">
- <label class="yodao-dialog-item">
- Ê¡·Ý£º<select id="selectProvince">
- <option>ÇëÑ¡Ôñ</option>
- </select>
- </label>
- <label class="yodao-dialog-item">
- ³ÇÊУº<select id="selectCity">
- <option value="">ÇëÑ¡Ôñ</option>
- </select>
- </label>
- <button id="ydaSubmit" class="ui-btn-submit">±£´æ</button>
- </div>
- </div>
- </div>
- </div>
- <div id="weatherIcon" class="yodao-weather-icon c-entry"></div>
- </div>
- </div>
- </div>
-</div>
-<script type="text/javascript">
-//<![CDATA[
-//widget theme
-var temp_value = [" http://img2.cache.netease.com/www/v2011/css/theme_blue1227.css", "httpdisabled://img2.cache.netease.com/www/v2011/css/theme_bluegray1227.css", "httpdisabled://img2.cache.netease.com/www/v2011/css/theme_green1227.css", "httpdisabled://img2.cache.netease.com/www/v2011/css/theme_pink1227.css", "httpdisabled://img2.cache.netease.com/www/v2011/css/theme_yellow1227.css"];
-var skin = {_skinRef: $("#setSkin"),_ctrls: $("#changeSkin > span"),_srcs: temp_value, _cookieName: "NTES_SKIN",save: function (i){ NTES.cookie.set(this._cookieName, i, 30 * 24 * 60);},change:function (i){var t = this, pos = isNaN(i) ? t._ctrls.indexOf(i):i;if (pos >= 0 && pos < t._srcs.length){NTES.style.removeCss(t._ctrls, "current"); NTES.style.addCss(t._ctrls[pos], "current");t._skinRef.href = t._srcs[pos];t.save(pos);}},init:function (){var t = this;if(NTES.cookie.get(t._cookieName)){var pos = parseInt(NTES.cookie.get(t._cookieName));}if(isNaN(pos)){t._skinRef.href = "httpdisabled://img2.cache.netease.com/www/v2011/css/theme_blue1227.css";};if(!isNaN(pos)){t.change(pos);}t._ctrls.addEvent("click",function(e){e.preventDefault();t.change(this); });}};skin.init();
-//]]>
-</script>
-<div class="content">
-<!-- news & vedio -->
-<div class="area">
- <div class="area-main">
- <div class="main-col-10">
- <div id="news" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-10 clearfix">
- <span class="tab-u current"><a href="httpdisabled://news.163.com/">ÐÂÎÅ</a></span>
- <span class="tab-u"><a href="httpdisabled://news.163.com/photo/" class="b31t9e41">ͼƬ</a></span>
- <span class="tab-u"><a href="httpdisabled://focus.163.com/">Éî¶È</a></span>
- <span class="tab-u"><a href="httpdisabled://war.news.163.com/">¾üÊÂ</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix" style="height:139px;">
- <div class="mod-img main-img">
- <a href="httpdisabled://news.163.com/photoview/4JC70001/13961.html"><img src="../img1.cache.netease.com/cnews/2011/4/8/20110408085323b9296.jpg" alt="ÈÕ±¾·¢Éú7.1¼¶µØÕð" title="ÈÕ±¾·¢Éú7.1¼¶µØÕð" height="90" width="120" /><cite>ÈÕ±¾·¢Éú7.1¼¶µØÕð</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://news.163.com/special/rbdblhddz/">Öйú¹ØÇÐÈÕ±¾Ïò̫ƽÑóÅŷź˷ÏÒº</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://v.news.163.com/video/2011/4/D/2/V70606SD2.html"><em class='I_V_'>µØÕð˲¼ä</em></a> <a href="httpdisabled://news.163.com/11/0408/08/713R20NL0001121M.html"><em class='I_V_'>ÕðºóÌì¿ÕÏÖ¹Ö¹â</em></a></li>
- <li><a href="httpdisabled://news.163.com/11/0408/23/715ERLUE00014JB6.html">¸»Ê¿É½µÈ20»ðɽ»ò±¬·¢</a> <a href="httpdisabled://news.163.com/11/0409/00/715ILM5U00014JB5.html">ÈÕÆó¹ºÊß²Ë</a></li>
- <li><a href="httpdisabled://news.163.com/11/0407/23/712SQFMQ00014JB6.html">¸£µººËµçÕ¾Õý³£</a> <a href="httpdisabled://news.163.com/photoview/00AO0001/13968.html">º«¹ú½µ"·øÉäÓê"</a></li>
- <li><a href="httpdisabled://news.163.com/11/0407/20/712J2PR000014JB5.html">½­Ëչ㶫Êß²Ë</a> <a target="_blank" href="httpdisabled://news.163.com/11/0408/06/713L1DH50001124J.html">ɽÎ÷µØ±íË®ÏÖ·ÅÉäÎï</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list dotline">
- <li><a href="httpdisabled://news.163.com/11/0409/04/7162TAHI00014JB6.html" data-t-h="05">ÃÀ¹ú·¢±í2010ÄêÈËȨ±¨¸æ ³ÆÖйúÈËȨ״¿ö¶ñ»¯</a></li>
- <li><a href="httpdisabled://news.163.com/11/0409/02/715QH3GC00014AED.html" data-t-h="02">ÃÀ¹úÁª°îÕþ¸®¹ØÃŵ¹¼Æʱ 80Íò¹«ÎñÔ±»ò·Å¼Ù</a></li>
- <li><a href="httpdisabled://news.163.com/11/0409/01/715NJRRE0001124J.html" data-t-h="01">ºÓÄÏÊÝÈ⾫°¸Ï¸½ÚÆعâ Ö÷ÒªÒÉ·¸2007Äêºó±©¸»</a></li>
- <li><a href="httpdisabled://news.163.com/11/0409/02/715RGS6V00014JB5.html" data-t-h="03">ÐðÀûÑǶàµØÃñÖÚÓÎÐÐʾÍþ ÒªÇóÀ©´óÃñÖ÷³ÍÖθ¯°Ü</a></li>
- <li><a href="httpdisabled://news.163.com/11/0409/03/715TTHDR00011229.html" data-t-h="03">¾¯³µ×²ËÀÈËÒý·¢´åÃñ¶Â· ¹Ù·½³ÆÎó½âÒÑÏû³ý</a></li>
- <li><a href="httpdisabled://news.163.com/special/party90/"><em class='cDRed'>µ³Ê·½ñÌì:Öܶ÷À´ÓëÕÅѧÁ¼»á̸</em></a> <a href="httpdisabled://news.163.com/11/0407/19/712HBQS800014JB5.html "><em class='cDRed'>Ê®¶þÎå</em></a> <a href="httpdisabled://news.163.com/11/0408/15/714KU3PH00014JB6.html"><em class='cDRed'>¹úаìÁÁÏàiPad</em></a></li>
- </ul>
- <ul class="mod-list main-list dotline">
- <li><a href="httpdisabled://news.163.com/11/0409/04/7162E16400011229.html" data-t-h="04">¹ã¶«ÖÐɽ¾¯·½»ØÓ¦·ò¸¾Âã±¼º°Ô©Ê¼þ:²»´æÔÚ°ü±Ó</a></li>
- <li><a href="httpdisabled://news.163.com/11/0409/01/715NKCS300014AED.html" data-t-h="02">ÄÐ×ÓÁ¬Í±7Å®ÐÔ±»¾Ð ¾¯·½³ÆÆäÒò˼ÄîÇ°Å®ÓÑÐÐÐ×</a></li>
- <li><a href="httpdisabled://news.163.com/special/libiyawar/">ÃÀ¹ú½«¾ü³Æ¿¼ÂÇÏòÀû±ÈÑÇÅÉDzµØÃ沿¶Ó</a></li>
- <li><a href="httpdisabled://news.163.com/11/0409/01/715NCEBD00014AED.html" data-t-h="02">½¯·½ÖÛ³ÆÇ廪ѧÉúΪ¼ÈµÃÀûÒæÕß Ð£·½³ÆÓ¦·´Ë¼</a></li>
- <li><a href="httpdisabled://news.163.com/11/0409/01/715NDEAK00014AED.html" data-t-h="02">±±¾©ÊÐÃñɹ¡°¹«³µÍ£³µÖ¤¡± ³ÆÈ·ÔøÏíÊÜÃâ·Ñ´ýÓö</a></li>
- <li><a href="httpdisabled://news.163.com/11/0408/14/714HOGUR0001124J.html">¹óÖÝÎÀÊÓ¡¶ÈËÉú¡·À¸Ä¿Òò·Å´óÒþ˽±»ÓÀ¾ÃÍ£²¥</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://news.163.com/" class="fB attitude left">ÐÂÎÅ</a> <a href="httpdisabled://m.163.com/newsapp/" class="right tg_news">ÍøÒ×ÐÂÎÅÊÖ»ú¿Í»§¶Ë</a></li>
- <li><a href="httpdisabled://news.163.com/special/163theotherside/" class="fB">ÁíÒ»Ãæ</a> | <a href="httpdisabled://news.163.com/special/reviews/governmentshutdown.html">»¨Ç®¹ý¶È£¬Õþ¸®¹ØÃÅ</a> | <a href="httpdisabled://news.163.com/special/reviews/binzangbaoli.html">éëÔᱩÀû£ºÉúÄÑ»¶ËÀ¶à¿à</a> </li>
- <li><a href="httpdisabled://discover.news.163.com/special/00014INC/discoverer.html" class="fB">·¢ÏÖÕß</a> | <a href="httpdisabled://discover.news.163.com/special/formerhome/">Ó¢¹úÈËÈçºÎ±£»¤¹Ê¾Ó</a> | <a href="httpdisabled://discover.news.163.com/special/godzilla/">¸£µººËÎÛË®È뺣֮ÓÇ</a> </li>
- <li><a href="httpdisabled://news.163.com/special/000113C4/163kanke.html" class="fB">¿´¿Í</a> | <a href="httpdisabled://news.163.com/photoview/3R710001/13844.html">¿¨Ôú·ÆµÄ·¨¹úÇé³ð</a> | <a href="httpdisabled://news.163.com/photoview/19BR0001/13895.html">Ò»ÖÜͼƬ¾«Ñ¡µÚ69ÆÚ</a> </li>
- <li><a href="httpdisabled://focus.163.com/" class="fB">Éî¶È</a> | <a href="httpdisabled://focus.news.163.com/11/0408/13/714EJNHS00011SM9.html">´óѧÉú´å¹ÙµÄ¡°Éý¹ÙÖ®µÀ¡±</a> | <a href="httpdisabled://focus.news.163.com/11/0407/18/712DHM9100011SM9.html">Òþ²Ø°ëÊÀ¼ÍµÄÔ®³¯Ó¢ÐÛ</a> </li>
- </ul>
- </div>
- <div class="tab-con">
- <ul class="mod-imgList imgList-w120 clearfix">
- <li><a href="httpdisabled://news.163.com/photoview/00AO0001/13966.html"><img src="../img2.cache.netease.com/cnews/2011/4/8/2011040812525484a8f.jpg" alt="°ÍÎ÷У԰ǹս13ÈËËÀ" title="°ÍÎ÷У԰ǹս13ÈËËÀ" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/photoview/00AO0001/13966.html">°ÍÎ÷У԰ǹս13ÈËËÀ</a></p></li>
- <li><a href="httpdisabled://news.163.com/photoview/00AO0001/13969.html"><img src="../img2.cache.netease.com/cnews/2011/4/8/20110408120203d0f08.jpg" alt="·¨¾ü½â¾ÈÈÕ±»À§´óʹ" title="·¨¾ü½â¾ÈÈÕ±»À§´óʹ" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/photoview/00AO0001/13969.html">·¨¾ü½â¾ÈÈÕ±»À§´óʹ</a></p></li>
- <li><a href="httpdisabled://news.163.com/photoview/00AN0001/13978.html"><img src="../img2.cache.netease.com/cnews/2011/4/8/201104082245192ae96.jpg" alt="¸ÊËàËíµÀÓ͹޳µ±¬Õ¨" title="¸ÊËàËíµÀÓ͹޳µ±¬Õ¨" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/photoview/00AN0001/13978.html">¸ÊËàËíµÀÓ͹޳µ±¬Õ¨</a></p></li>
- <li><a href="httpdisabled://news.163.com/photoview/00AO0001/13968.html"><img src="../img2.cache.netease.com/cnews/2011/4/8/20110408115631ad273.jpg" alt="º«¹úÍ£¿Î±Ü&quot;·øÉäÓê&quot;" title="º«¹úÍ£¿Î±Ü&quot;·øÉäÓê&quot;" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/photoview/00AO0001/13968.html">º«¹úÍ£¿Î±Ü"·øÉäÓê"</a></p></li>
- <li><a href="httpdisabled://news.163.com/photoview/00AP0001/13962.html"><img src="../img2.cache.netease.com/cnews/2011/4/8/20110408100357df2b1.jpg" alt="¶«Ý¸Í»¼ìÉæ»Æ³¡Ëù" title="¶«Ý¸Í»¼ìÉæ»Æ³¡Ëù" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/photoview/00AP0001/13962.html">¶«Ý¸Í»¼ìÉæ»Æ³¡Ëù</a></p></li>
- <li><a href="httpdisabled://news.163.com/photoview/00AO0001/13970.html"><img src="../img2.cache.netease.com/cnews/2011/4/8/20110408140704d246b.jpg" alt="ÒÔÉ«ÁÐÁ½»ð³µÏàײ" title="ÒÔÉ«ÁÐÁ½»ð³µÏàײ" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/photoview/00AO0001/13970.html">ÒÔÉ«ÁÐÁ½»ð³µÏàײ</a></p></li>
- <li><a href="httpdisabled://news.163.com/11/0408/01/71364DV200014AED.html"><img src="../img1.cache.netease.com/cnews/2011/4/8/20110408104255a47ce.jpg" alt="ýÌåÆعâµØÏÂѪÍø" title="ýÌåÆعâµØÏÂѪÍø" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/11/0408/01/71364DV200014AED.html">ýÌåÆعâµØÏÂѪÍø</a></p></li>
- <li><a href="httpdisabled://news.163.com/photoview/05RQ0001/13971.html"><img src="../img2.cache.netease.com/cnews/2011/4/8/2011040814525199c07.jpg" alt="ÈÕ±¾Ôֺ󽨼òÒ×סլ" title="ÈÕ±¾Ôֺ󽨼òÒ×סլ" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/photoview/05RQ0001/13971.html">ÈÕ±¾Ôֺ󽨼òÒ×סլ</a></p></li>
- <li><a href="httpdisabled://news.163.com/photoview/00AQ0001/13959.html"><img src="../img1.cache.netease.com/cnews/2011/4/8/2011040809550649773.jpg" alt="Ö±»÷Öйú¾ü¶ÓCSÁ·±ø" title="Ö±»÷Öйú¾ü¶ÓCSÁ·±ø" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/photoview/00AQ0001/13959.html">Ö±»÷Öйú¾ü¶ÓCSÁ·±ø</a></p></li>
- <li><a href="httpdisabled://news.163.com/photoview/00AN0001/13967.html"><img src="../img1.cache.netease.com/cnews/2011/4/8/201104081119113f37f.jpg" alt="ÃÀ´óʹÔÚÉϺ£Æï¹þÀ×" title="ÃÀ´óʹÔÚÉϺ£Æï¹þÀ×" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/photoview/00AN0001/13967.html">ÃÀ´óʹÔÚÉϺ£Æï¹þÀ×</a></p></li>
- <li><a href="httpdisabled://news.163.com/11/0408/12/714AP6C900014AEF.html"><img src="../img2.cache.netease.com/cnews/2011/4/8/201104081242198a4ba.jpg" alt="ÄÐ×ÓÔÚÆÞ×ÓÁ³ÉÏ¿Ì×Ö" title="ÄÐ×ÓÔÚÆÞ×ÓÁ³ÉÏ¿Ì×Ö" height="90" width="120"></a><p><a href="httpdisabled://news.163.com/11/0408/12/714AP6C900014AEF.html">ÄÐ×ÓÔÚÆÞ×ÓÁ³ÉÏ¿Ì×Ö</a></p></li>
- <li><a href="httpdisabled://war.news.163.com/photoview/00AQ0001/13954.html"><img src="../img1.cache.netease.com/cnews/2011/4/8/2011040814544385564.jpg" alt="¶íÅ®¼äµýʱװÖÜ×ßÐã" title="¶íÅ®¼äµýʱװÖÜ×ßÐã" height="90" width="120"></a><p><a href="httpdisabled://war.news.163.com/photoview/00AQ0001/13954.html">¶íÅ®¼äµýʱװÖÜ×ßÐã</a></p></li>
- </ul>
- <p class="entry c-entry right"><a href="httpdisabled://news.163.com/photo/">¸ü¶à <span class="code-en">&raquo;</span> </a></p>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://news.163.com/special/reviews/governmentshutdown.html"><img src="../img1.cache.netease.com/cnews/2011/4/9/20110409022720f974c.jpg" alt="»¨Ç®¹ý¶È£¬Õþ¸®¹ØÃÅ" title="»¨Ç®¹ý¶È£¬Õþ¸®¹ØÃÅ" height="90" width="120" /><cite>»¨Ç®¹ý¶È£¬Õþ¸®¹ØÃÅ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://focus.news.163.com/11/0408/13/714EJNHS00011SM9.html">´óѧÉú´å¹ÙµÄ¡°Éý¹ÙÖ®µÀ¡±</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://focus.news.163.com/11/0408/13/714F3NLI00011SM9.html">±«²ª¡¤µÏÂ×µÄÖÇÁ¦</a></li>
- <li><a href="httpdisabled://focus.news.163.com/11/0408/12/714B46B300011SM9.html">¡°Õê²ÙÊÇ×îºÃÅã¼Þ¡±</a></li>
- <li><a href="httpdisabled://discover.news.163.com/11/0408/09/71411PAP00012IH2.html">Ó¡¶ÈÔÚÒûÓÃË®Öз¢ÏÖ³¬¼¶Ï¸¾ú</a></li>
- <li><a href="httpdisabled://discover.news.163.com/special/formerhome/">Ó¢¹úÃûÈ˹ʾӱ£»¤:ÎÄ»¯ÓëµØ²ú²©ÞÄ</a></li>
- </ul>
- </div>
- <div class="temp-1-2 dotline clearfix">
- <h3 class="main-subtitle c-entry"><a href="httpdisabled://focus.news.163.com/">Éî¶È</a></h3>
- <div class="temp-u left">
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://focus.news.163.com/11/0407/18/712DHM9100011SM9.html">Òþ²ØÁË°ëÊÀ¼ÍµÄÔ®³¯Ó¢ÐÛ</a></li>
- <li><a href="httpdisabled://focus.news.163.com/11/0407/18/712CSAB900011SM9.html">¾È¾ÈÎÒÃǵijÇÊÐ</a></li>
- <li><a href="httpdisabled://focus.news.163.com/11/0407/17/71290G4V00011SM9.html">±±¾©µÚÒ»ÀÃβ¥ÄÚÄ»</a></li>
- <li><a href="httpdisabled://focus.news.163.com/11/0407/16/712707RP00011SM9.html">ְУÄù˜„</a></li>
- <li><a href="httpdisabled://focus.news.163.com/11/0406/22/71092VNS00011SM9.html">ÇൺµÄ¸çάȨ¼Ç</a></li>
- </div>
- <div class="temp-u right">
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://focus.news.163.com/11/0406/19/70VUIN4E00011SM9.html">½­Î÷°ÙÈËÒò³¾·Î²¡ÖÂËÀ </a></li>
- <li><a href="httpdisabled://focus.news.163.com/11/0406/19/70VTHTGK00011SM9.html">Öйú¼Í¼ƬÊг¡ÏÖ×´</a></li>
- <li><a href="httpdisabled://focus.news.163.com/11/0406/19/70VT0F1500011SM9.html">¶«¾©µçÁ¦¹«Ë¾¡°°ó¼Ü¡±ÈÕ±¾</a></li>
- <li><a href="httpdisabled://focus.news.163.com/11/0406/11/70V31TR900011SM9.html">ÎåÄ꣬ȫÃæ¿ØÑÌ£¿</a></li>
- <li><a href="httpdisabled://focus.news.163.com/11/0406/11/70V2KKR700011SM9.html">¿ÓÑʹÊƵ·¢»§Íâ¹ÜÀíÍѽÚ</a></li>
- </ul>
- </div>
- </div>
- <div class="temp-1-2 dotline clearfix">
- <h3 class="main-subtitle c-entry"><a href="httpdisabled://news.163.com/review/">ÆÀÂÛ</a></h3>
- <div class="temp-u left">
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://news.163.com/11/0408/18/714UHI5500012Q9L.html">½À»ðÍÈÍì²»»ØÏû·ÑÕßµÄÐÅÈÎ</a></li>
- <li><a href="httpdisabled://news.163.com/11/0408/18/714UE3I600012Q9L.html">Ó¦ÖØÊÓ³Ѹ֮×ӵĸöÈ˼ÛÖµ</a></li>
- <li><a href="httpdisabled://news.163.com/11/0408/18/714U80N800012Q9L.html">Ç¿ÖÆÖÖÆÏÌÑÊÇΨGDPÂÛ</a></li>
- <li><a href="httpdisabled://news.163.com/11/0408/18/714U1KSO00012Q9L.html">Ï×Ѫָ±êÑøÓý¡°ÑªÍ·¡±ÓÄÁé</a></li>
- <li><a href="httpdisabled://news.163.com/11/0408/18/714TOSL400012Q9L.html">½¡È«Öƶȱ£»¤²¡È˵ÄÀûÒæ</a></li>
- </div>
- <div class="temp-u right">
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://news.163.com/11/0407/21/712N21BO00012Q9L.html">ÑëÐмÓÏ¢Ö®ÓÇÂǺ͡°»Ã¾õ¡±</a></li>
- <li><a href="httpdisabled://news.163.com/11/0407/21/712MTPIA00012Q9L.html">ÖιÙÔ±³¬±à²»¿É¿¿¡°Î²¹¡±</a></li>
- <li><a href="httpdisabled://news.163.com/11/0407/21/712MIPA000012Q9L.html">²»×ðÖØÇîÈ˲ÅÊǸßѧÀúÖ®³Ü</a></li>
- <li><a href="httpdisabled://news.163.com/11/0407/17/712A9KRR00012Q9L.html">²ðÒû±ùÊÒ£ººóÈ˸´°§ºóÈËÒ²</a></li>
- <li><a href="httpdisabled://news.163.com/11/0407/17/71297UM000012Q9L.html">¼ÓÏ¢»òÊÇ·¿¼Ûµ÷ÕûµÄÈ󻬼Á</a></li>
- </ul>
- </div>
- </div>
- <div class="temp-1-2 dotline clearfix">
- <h3 class="main-subtitle c-entry"><a href="httpdisabled://discovery.163.com/">̽Ë÷</a></h3>
- <div class="temp-u left">
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://discover.news.163.com/11/0408/10/7142PDP6000125LI.html">Èâ··ÓÃÓж¾·ÛÄ©Í¿ÖíÈâ±£ÏÊ</a></li>
- <li><a href="httpdisabled://discover.news.163.com/11/0408/10/71429VJL000125LI.html">Ѫͷ×é֯ѧÉúÃñ¹¤ÂôѪIJÀû</a></li>
- <li><a href="httpdisabled://discover.news.163.com/11/0408/09/71411PAP00012IH2.html">Ó¡¶ÈÔÚÒûÓÃË®Öз¢ÏÖ³¬¼¶Ï¸¾ú</a></li>
- <li><a href="httpdisabled://discover.news.163.com/11/0408/10/7142RCVR000125LI.html">ÈÕ±¾ºË·øÉäÐÎÊÆÆÀ¹À</a></li>
- <li><a href="httpdisabled://discover.news.163.com/11/0408/10/7143N0AT000125LI.html">·ÂÉúÑÛ¾µÖúäÈËÖØ»ñ¹âÃ÷</a></li>
- </div>
- <div class="temp-u right">
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://discover.news.163.com/11/0407/10/711FPHRM000125LI.html">ר¼Ò³ÆÓ¦ÆÀ¹ÀÖйúº£Ð¥·çÏÕ</a></li>
- <li><a href="httpdisabled://discover.news.163.com/11/0407/10/711HMTF0000125LI.html">ÃÀ¾ÞÐÍ»ð¼ý¿ÉËÍÈËÀàÉÏ»ðÐÇ</a></li>
- <li><a href="httpdisabled://discover.news.163.com/11/0407/11/711JEUKO000125LI.html">³¬¼¶Ï¸¾úÖ®ÍõCRKPÏÖÉíÃÀ¹ú</a></li>
- <li><a href="httpdisabled://discover.news.163.com/11/0407/11/711LA7RJ000125LI.html">µÂÅ®º¢°ÑĸţѵÁ·³É"ÈüÂí"</a></li>
- <li><a href="httpdisabled://discover.news.163.com/11/0407/10/711GS2DT000125LI.html">ÈËÔìÓãβÈòм²È˱äÃÀÈËÓã</a></li>
- </ul>
- </div>
- </div>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://war.news.163.com/photoview/00AQ0001/13959.html"><img src="../img2.cache.netease.com/cnews/2011/4/7/20110407202028db993.jpg" alt="ÄϾ©¾üÇøij²¿ÒÔCSÁ·±ø" title="ÄϾ©¾üÇøij²¿ÒÔCSÁ·±ø" height="90" width="120" /><cite>ÄϾ©¾üÇøij²¿ÒÔCSÁ·±ø</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://war.news.163.com/11/0407/20/712KL6ED00014J0G.html">ÍßÁ¼¸ñ½«³ÉΪÖйúÊ×ËÒʵսÐͺ½Ä¸</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://t.163.com/wxsun/status/-5374398591249521056#retweet">ËïÀñ£ºÀû·´¶ÔÅÉÊ×ÅúʯÓÍÔËÍùÖйú</a></li>
- <li><a href="httpdisabled://t.163.com/fyjsyfy/status/-9113848012304784652#retweet">ÔÆ·ÉÑÓÖÒ»ËÒ054A»¤ÎÀ½¢³É¾üÁË</a></li>
- <li><a href="httpdisabled://t.163.com/3580035945/status/-6113039237267459001#retweet">ÕÅÃ÷£º¹ÒÔØ4öӥ»÷83µÄ·É±ª(ͼ)</a></li>
- <li><a href="httpdisabled://t.163.com/sedna/status/-7903894352043047591#retweet">ËÉÊó£ºÒÔÉ«ÁÐÔÚ×·Çó¡°¾ø¶Ô°²È«¡±</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list dotline">
- <li><a href="httpdisabled://war.news.163.com/11/0408/10/714232PL00013COV.html">̨¾ü£º´ó½Ê×ËÒº½Ä¸²¿ÊðÄϺ£ Ó¦¶ÔÍ»·¢Õù¶Ë</a></li>
- <li><a href="httpdisabled://war.news.163.com/11/0408/10/7142MFUD00011MTO.html">ÃÀ˾Áî³ÆÀû·´¶ÔÅÉÍÆ·­¿¨Ôú·Æ¿ÉÄÜÐÔºÜС</a> <a target="_blank" href="httpdisabled://news.163.com/special/libiyawar/">רÌâ</a></li>
- <li><a href="httpdisabled://war.news.163.com/11/0408/00/7130CEUT00014JB5.html">ÃÀÌØʹ£º¿¨Ôú·ÆÍËλ¿ÉÒÔ»»È¡·ÇÃËÈÙÓþÖ÷ϯ</a></li>
- <li><a href="httpdisabled://war.news.163.com/11/0408/10/7141QADN00011MTO.html">ÒÔÉ«ÁÐÌúñ·ÏµÍ³Ê×´ÎʵսÀ¹½Ø»ð¼ýµ¯³É¹¦(ͼ)</a></li>
- <li><a href="httpdisabled://war.news.163.com/11/0408/09/71415JND00011MTO.html">ÖйúÖÇÄܵ¯Ò©£ºÅÚÉä"Ä©Ãôµ¯"¹Ø¼ü¼¼Êõ»ñÍ»ÆÆ</a></li>
- <li><a href="httpdisabled://war.news.163.com/11/0407/18/712DHM9100011SM9.html">¡¶Ó¢ÐÛ¶ùÅ®¡·Íõ³ÉÔ­ÐÍÒòÔø±»·ýÂñÃû50Äê(ͼ)</a></li>
- </ul>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://war.news.163.com/11/0408/11/7146U0O400011MTO.html">ÃÀ¾üÁ½¿ÅSTSSÎÀÐdzɹ¦ÊµÏÖ¶Ôµ¼µ¯Á¢Ìå¸ú×Ù</a></li>
- <li><a href="httpdisabled://war.news.163.com/11/0408/11/7146D6O500011MTO.html">ÃÀý×ܽáÃÀ¹úºÃÕ½Îå´óÔ­Òò£ºÃ»ÓÐÕæÕýµÐÈË</a></li>
- <li><a href="httpdisabled://war.news.163.com/11/0408/10/714475KD00011MTO.html">Ӣý£º½â·Å¾ü¸ß½Ì»ú¾º±êÁ½ÐÍ·É»ú¾ù²»ÍêÉÆ</a></li>
- <li><a href="httpdisabled://war.news.163.com/11/0408/10/7142EVJ600011MTO.html">¼òÊÏ£ºÖйúÓµÓÐÎäÆ÷Ñз¢È¨ÆóÒµ2/3ϵÃñÆó</a></li>
- <li><a href="httpdisabled://war.news.163.com/11/0408/11/7147TN1N00011MTO.html">Ì©¹ú½¾ü¹ºÂò200Á¾ÎÚ¿ËÀ¼"±¤ÀÝ"Ö÷ս̹¿Ë</a></li>
- <li><a href="httpdisabled://war.news.163.com/11/0408/10/71440DDQ00011MTO.html">ÈÕý³ÆÖйú½«¸üÒÀÀµ¾üʼ°¾­¼ÃʵÁ¦½â¾öÕù¶Ë</a></li>
- </ul>
- <ul class="temp-1-2 clearfix">
- <li class="temp-u left">
- <h3 class="main-subtitle cBlue"><a href="httpdisabled://war.news.163.com/">¾üʲ©¿Í</a></h3>
- <div class="mod-imgText imgText-temp-2 clearfix">
- <h4 class="imgText-titleTop"><a href="httpdisabled://zhouf601117.blog.163.com/blog/static/12655106620113603443750/">Ë®²´·ÇÖÞ£ºÎÞ½âµÄË÷ÂíÀﺣµÁ</a></h4>
- <a href="httpdisabled://zhouf601117.blog.163.com/blog/static/12655106620113603443750/"><img class="imgText-img" src="../img2.cache.netease.com/cnews/2011/4/8/2011040814452013ef7.jpg" alt="Ë®²´·ÇÖÞ£ºÎÞ½âµÄË÷ÂíÀﺣµÁ" title="Ë®²´·ÇÖÞ£ºÎÞ½âµÄË÷ÂíÀﺣµÁ" height="70" width="70" /></a>
- <p class="imgText-digest">ÖÁ½ñÈÔûÓÐÄĸö¹ú¼ÒÔ¸ÒâÁìÏδò»÷º£µÁ¡£<span class="cDRed"><a href="httpdisabled://zhouf601117.blog.163.com/blog/static/12655106620113603443750/">[Ïêϸ]</a></span></p>
- </div>
- </li>
- <li class="temp-u right">
- <h3 class="main-subtitle cBlue"><a href="httpdisabled://war.news.163.com/">¾üÇé¹Û²ìÊÒ</a></h3>
- <div class="mod-imgText imgText-temp-2 clearfix">
- <h4 class="imgText-titleTop"><a href="httpdisabled://war.news.163.com/11/0404/13/70Q5IQA200014J0G.html">¶«·ç16½«´ó·ùÌáÉý·´½éÈëÄÜÁ¦</a></h4>
- <a href="httpdisabled://war.news.163.com/11/0404/13/70Q5IQA200014J0G.html"><img class="imgText-img" src="../img2.cache.netease.com/cnews/2011/4/7/20110407093718ef414.jpg" alt="¶«·ç16½«´ó·ùÌáÉý·´½éÈëÄÜÁ¦" title="¶«·ç16½«´ó·ùÌáÉý·´½éÈëÄÜÁ¦" height="70" width="70" /></a>
- <p class="imgText-digest">¶«·ç16ÄܽϿìÐγɶԳåÉþÃÀ¾üѹÖÆÄÜÁ¦¡£<span class="cDRed"><a href="httpdisabled://war.news.163.com/11/0404/13/70Q5IQA200014J0G.html">[Ïêϸ]</a></span></p>
- </div>
- </li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- <div class="main-col-9">
- <div class="mod-function">
- <span class="function-date">04ÔÂ09ÈÕ ÐÇÆÚÁù</span>
- <span class="function-close" id="updateBtn"></span>
- <span class="function-info" id="updateInfo"></span>
- </div>
-<div class="gg_reset mb-6 gg-h65"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=banner360x65&amp;location=1.html" width="360" height="65" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-</div>
- <div class="gg_reset mb-6 gg-h65"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=banner360x65&amp;location=2.html" width="360" height="65" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-</div>
- <div id="vedio" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-9 clearfix">
- <span class="tab-u current"><a href="httpdisabled://v.163.com/">ÊÓƵ</a></span>
- <span class="tab-u"><a href="httpdisabled://v.163.com/focus/">Èȵã</a>¡¤<a href="httpdisabled://v.163.com/zongyi/">×ÛÒÕ</a></span>
- <span class="tab-u"><a href="httpdisabled://v.163.com/doc/">¼Íʵ</a>¡¤<a href="httpdisabled://v.163.com/fashion/">·çÉÐ</a></span>
- <span class="tab-u"><a href="httpdisabled://v.163.void/">ÍøÒ×¹«¿ª¿Î</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://v.163.com/special/nvtop34/"><img src="../img1.cache.netease.com/cnews/2011/4/6/20110406182512d4541.jpg" alt="±¾ÖÜ×î»ðÍøÂçÊÓƵtop5" title="±¾ÖÜ×î»ðÍøÂçÊÓƵtop5" height="90" width="120" /><cite>±¾ÖÜ×î»ðÍøÂçÊÓƵtop5</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://v.163.com/special/issue201053/">¡°ËÀÎÞÔáÉíÖ®µØ¡±³ÉΪÏÖʵ£¿</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://v.163.com/video/2011/4/B/F/V70633PBF.html#ld=V6VAOISBD">ÈÕ±¾ÔÙÔâÇ¿µØÕðÏ®»÷Ìì¿ÕÏÖÇ¿¹â</a></li>
- <li><a href="httpdisabled://v.163.com/video/2011/4/0/2/V70647J02.html#ld=V68F91IG1">Ò©¼Òöο´ÊØËùÉîÇéÑÝÒ´«Ææ¡·</a></li>
- <li><a href="httpdisabled://v.163.com/video/2011/4/4/B/V7066OF4B.html#ld=V6VAOISBD">ʵÅÄ£º×íººµ÷Ï·Çå´¿Å®ÉúÔâȺŹ</a></li>
- <li><a href="httpdisabled://v.163.com/video/2011/4/B/7/V7064C0B7.html#ld=V63F88H2T">ÈÕ±¾"·­Á³¹·"±¬ºìÒ»ÎÕÊ־ͱäÁ³</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list dotline">
- <li><a href="httpdisabled://v.163.com/nv/"><em class=' I_V_'>[ÍøÊÓ]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/D/0/V704BTTD0.html">¶ñ¸ã£º±±¾©µÄ·¿×ÓÄã×â²»Æð</a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/Q/T/V7043J6QT.html">Éú»î¸ãЦ˲¼ä</a></li>
- <li><a href="httpdisabled://v.163.com/nv/"><em class=' I_V_'>[Èȵã]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/T/T/V6VND1KTT.html#ld=V68F91IG1">ºÏÉùÆ÷³¬¸øÁ¦ÓÎÏ·ÒôÀÖ</a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/H/B/V70126QHB.html#ld=V68F7PNND">Èý¹úɱ×îÇ¿ÄÚ¼é</a></li>
- <li><a href="httpdisabled://v.163.com/fashion/"><em class='I_V_'>[·çÉÐ]</em></a> <a href="httpdisabled://v.163.com/video/2011/4/O/I/V701VL5OI.html#ld=V675K0B8K">³Â¹ÚÏ£:ÎÒµ±Å¼ÏñÒ²ºÜ¿à</a> <a href="httpdisabled://v.163.com/video/2011/4/8/C/V70468T8C.html#ld=V675K0B8K">Ó¾×°·è¿ñParty</a></li>
- <li><a href="httpdisabled://v.163.com/doc/"><em class='I_V_'>[¼Íʵ]</em></a> <a href="httpdisabled://v.163.com/video/2011/3/R/H/V6V3FL1RH.html#ld=V5G0IPI1S">ÓɵÁĹÒý·¢µÄÁ¬»·Ñª°¸</a> <a href="httpdisabled://v.163.com/video/2011/3/7/H/V6VGDIF7H.html#ld=V5G0IPI1S">½ÒÃØ¡°ÎüÐǴ󷨡±</a></li>
- <li><a href="httpdisabled://v.163.void/"><em class=' I_V_'>[¹«¿ª¿Î]</em></a> <a target="_blank" href="httpdisabled://v.163.com/special/programming/">¡¶±à³Ì·½·¨Ñ§¡·µÚ14¿Î£º¼ÆËã»úÄÚ´æ</a></li>
- <li><a href="httpdisabled://v.163.void/"><em class=' I_V_'>[¹«¿ª¿Î]</em></a> <a target="_blank" href="httpdisabled://v.163.com/voidcourse/equations.html">пÎÍƼö£ºÂéÊ¡¡¶Î¢·Ö·½³Ì¡·1-3¿Î</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://v.163.com/special/weekly_e/"><em class='cBlack fB'>Ò×ÖÜ¿¯</em></a> | <a target="_blank" href="httpdisabled://v.163.com/special/issue201052/">Èç¹ûÄãÖÐÁËһǧÍò</a> | <a target="_blank" href="httpdisabled://v.163.com/special/issue201051/">¿åµôµÄºÃѧÉúÒ©¼ÒöÎ</a></li>
- <li><a href="httpdisabled://v.163.com/special/nvtop34/"><em class='cBlack fB'>·çÔÆ°ñ</em></a> | <a target="_blank" href="httpdisabled://v.163.com/special/nvtop34/">öµÑÀ¸çÍøÂ籬ºì</a> | <a target="_blank" href="httpdisabled://v.163.com/special/nvtop33/">ÄÐ×Ó±»±ëº·Å®ÈËÇ¿ÎÇ</a></li>
- <li><a href="httpdisabled://v.163.com/zongyi/"><em class='fB'>×ÛÒÕ</em></a> | <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/R/4/V705BELR4.html#ld=V5MC3DG9J">¡¶ladyßÉßÉ¡·¡°Ã÷ÐÇÀ±Â衱ÁõÜ¿ º¢×ÓÊ×Æعâ</a></li>
- <li><a href="httpdisabled://v.163.com/zongyi/"><em class='cBlack fB'>×ÛÒÕ</em></a> | <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/F/U/V7059EDFU.html#ld=V5MC3DG9J">¡¶Ëµ³öÄãµÄ¹ÊÊ¡·ÖÜѸÒä³É³¤ ÔøΪÀîÃ×Í´¿Þ</a></li>
- <li><a href="httpdisabled://v.163.void/"><em class='fB'>°®ÉϹ«¿ª¿Î</em></a> | <a target="_blank" href="httpdisabled://v.163.com/special/fudanseminars4/"><em class='cDRed'>¸´µ©Ê׿ªÍøÂ繫¿ª¿Î¡¶Ö´ÞֵĵÍÒô¡·</em></a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://v.163.com/video/2011/4/0/2/V70647J02.html#ld=V68F91IG1"><img src="../img1.cache.netease.com/cnews/2011/4/8/201104080934433598e.jpg" alt="Ò©¼Òöο´ÊØËù³ª" title="Ò©¼Òöο´ÊØËù³ª" height="90" width="120" /><cite>Ò©¼Òöο´ÊØËù³ª<´«Ææ></cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://v.163.com/video/2011/4/G/P/V7066ANGP.html#ld=V6VAOISBD">ʵÅÄ£ºÍµ³µÔô±»×¥ÔâÊÐÃñȺŹ</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://v.163.com/video/2011/4/O/7/V703EJFO7.html#ld=V6VAOISBD">À¬»øÏ侪ÏÖÈ˽ŠÒɽØÖ«ºó¶ªÆú</a></li>
- <li><a href="httpdisabled://v.163.com/video/2011/4/T/U/V703FSBTU.html#ld=V6VAOISBD">ΪŮÓÑÂòÀñÎïС»ï¾¹´ò½Ù³¬ÊÐ</a></li>
- <li><a href="httpdisabled://v.163.com/video/2011/4/C/T/V703EB4CT.html#ld=V661IGBQL">¹úÍⳬÏÖʵ¶ÌƬ¡¶ÉúËÀÈý·ÖÖÓ¡·</a></li>
- <li><a href="httpdisabled://v.163.com/video/2011/4/G/T/V703JHKGT.html#ld=V6VAOJSVO">˾»úÒò30ԪŹ´òÊÕ·ÑÔ±ÄðѪ°¸ </a></li>
- </ul>
- </div>
- <ul class="mod-list main-list dotline">
- <li><a href="httpdisabled://v.163.com/special/008546TE/jinyeyouxi.html"><em class=' I_V_'>[½ñÒ¹ÓÐÏ·]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/8/I/V705AML8I.html#ld=V5MC3DG9J">ÕŹúÇ¿ËÄʮһ ½âÃÜÖÐÄêÄÐÈËÃÜÂë</a></li>
- <li><a href="httpdisabled://v.163.com/special/008546TE/zuijiaxianchang.html"><em class=' I_V_'>[×î¼ÑÏÖ³¡]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/K/L/V705BEIKL.html#ld=V5MC3DG9J">´¢ÖDz© Íõ¾²Ò»¶ÔºÃÅóÓѵÄϲÀÖ¹ÊÊÂ</a></li>
- <li><a href="httpdisabled://v.163.com/special/scndgs/"><em class=' I_V_'>[˵³öÄãµÄ¹ÊÊÂ]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/R/G/V702S4ARG.html#ld=V5MC3DG9J">ÖÜѸÒä³É³¤Àú³Ì ÔøΪÀîÃ×Í´¿Þ</a></li>
- <li><a href="httpdisabled://v.163.com/special/fnms/"><em class=' I_V_'>[·ÇÄãĪÊô]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/G/U/V6VR12VGU.html#ld=V6VD27JAE">ÑÇÖÞС½ãºÎÑÇÃÈÇóÖ° ÀÏ°å·è¿ñÇÀ¶á</a></li>
- <li><a href="httpdisabled://v.163.com/special/008546TD/fcwrzh.html"><em class=' I_V_'>[·Ç³ÏÎðÈÅ]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/Q/2/V6VPDSQQ2.html#ld=V6VD26AIN">"Èî¾­Ìì"ÒýÕù¶áÕ½ ÀÖ¼ÎÆØÁµ°®¾­Àú</a></li>
- <li><a href="httpdisabled://v.163.com/special/008546TE/yanglan.html"><em class=' I_V_'>[ÑîÀ½·Ã̸¼]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/8/9/V6VOI2089.html#ld=V5MC3DG9J">´ÈÉƼұ˵ᤰͷÆÌØ£º×öÄã×Ô¼º</a></li>
- </ul>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://v.163.com/special/00853MGO/cqgs.html"><em class=' I_V_'>[´«Ææ¹ÊÊÂ]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/C/J/V702JAJCJ.html#ld=V5HPAJTGO">Å®×Óлé1ÄêÔâÕÉ·òÅ°´ýÖÂËÀ ÉÏ</a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/S/2/V7055T0S2.html#ld=V5HPAJTGO">ÏÂ</a></li>
- <li><a href="httpdisabled://v.163.com/special/00853MGO/wgjgs"><em class=' I_V_'>[Íõ¸Õ½²¹ÊÊÂ]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/U/D/V702JFSUD.html#ld=V6MUD7LC2">ÏÊ»¨±³ºóµÄѪ°¸</a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/6/3/V7058U863.html#ld=V6MUD7LC2">²¡Î£ÕÉ·òµÄÐÁËáÊÂ</a></li>
- <li><a href="httpdisabled://v.163.com/special/00853MGO/tv_fzjxs.html"><em class=' I_V_'>[·¨ÖνøÐÐʱ]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/L/P/V701DKSLP.html#ld=V5G0COMVI">ÇàÄêÄÐÅ®¾ÆµêÄÚÎü¶¾ÒùÂÒ°ËÈ˱»ÇÜ</a></li>
- <li><a href="httpdisabled://v.163.com/special/ssll/"><em class=' I_V_'>[˵ÊÂÀ­Àí]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/B/R/V702LN9BR.html#ld=V6TN5CABJ">¸É²¿¡°Ç¿¼é¡±Å®ÑÝÔ±25Äêºó±»ÅÐÎÞ×ï</a></li>
- <li><a href="httpdisabled://v.163.com/special/gszx/"><em class=' I_V_'>[¹ÉÊÐÔÚÏß]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/0/M/V703MO50M.html#ld=V6UODFJCN">ͨÕͱ³¾°ÏÂÑ¡¹É</a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/M/7/V703O55M7.html#ld=V6UODFJCN">3000µã³ÉΪÐÂÆðµã</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://v.163.com/video/2011/4/F/7/V701QHKF7.html#ld=V675K0B8K"><img src="../img4.cache.netease.com/video/2011/4/8/2011040809594909a0a.jpg" alt="93ÄêͯÐÇÈë½­É´ç±Ð´Õæ" title="93ÄêͯÐÇÈë½­É´ç±Ð´Õæ" height="90" width="120" /><cite>93ÄêͯÐÇÈë½­É´ç±Ð´Õæ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://v.163.com/video/2011/4/L/I/V705D74LI.html#ld=V62BI5Q6R">¿´Ã÷ÐDZÙÒ¥¸ßÕдò±£ÎÀÕ½ A</a> <a href="httpdisabled://v.163.com/video/2011/4/H/S/V705DCNHS.html#ld=V62BI5Q6R">B</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://v.163.com/video/2011/4/H/R/V703T9UHR.html#ld=V5PO8FVQG">¼õ·ÊÃÀÌå¶ÇƤÎè</a> <a href="httpdisabled://v.163.com/video/2011/4/M/T/V701PBHMT.html#ld=V5PO8FVQG">ÊÝÍÈ·¨Èý²¿Çú</a></li>
- <li><a href="httpdisabled://v.163.com/video/2011/4/K/4/V7045LTK4.html#ld=V5PO8E0TJ">½ñ´º±Ø°ÜÏÔÊÝÆ· Ï°ëÉí³¬Îü¾¦</a></li>
- <li><a href="httpdisabled://v.163.com/video/2011/3/A/J/V6VAD2AAJ.html#ld=V6MRLT82B">Õâ±²×ÓÒ»¶¨ÒªÈ¥µÄ³¬ÃÀÃλþ°µã</a></li>
- <li><a href="httpdisabled://v.163.com/video/2011/4/M/B/V702I9JMB.html#ld=V6PBSMULG">ÎÒ°®ËÀÈ¥½ã½ãµÄÀϹ«ÒªÓëËû½á»é</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list dotline">
- <li><a href="httpdisabled://v.163.com/fashion/"><em class='I_V_'>[·çÉÐ]</em></a> <a href="httpdisabled://v.163.com/video/2011/4/A/6/V701RGNA6.html#ld=V675K0B8K">Ella²àÅĺÿɰ®</a> <a href="httpdisabled://v.163.com/video/2011/4/H/8/V6VT89HH8.html#ld=V7012O1MC">Íø¹ºÉݳÞÆ·¿Éר¹ñÑé»õ?</a></li>
- <li><a href="httpdisabled://v.163.com/fashion/"><em class=' I_V_'>[¸öÐÔ]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/D/3/V704A8UD3.html#ld=V675K0B8K">AmandaËÄÔÂÒýÁìÀÙË¿·ç³±</a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/A/1/V704AQ2A1.html#ld=V675K0B8K">±±Å·É­Å®·ç¸ñ</a></li>
- <li><a href="httpdisabled://v.163.com/fashion/"><em class=' I_V_'>[·ÖÏí]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/L/E/V704AD6LE.html#ld=V62LNRVBJ">ÊÝСÄÐÉúµÄ´©ÒÂÐÄ»ú</a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/7/M/V703S547M.html#ld=V62LNRVBJ">Ã×Ъ¶û×îвÊ×±°Ü¼Ò</a></li>
- <li><a href="httpdisabled://v.163.com/special/nrwzd/"><em class=' I_V_'>[Å®ÈËÎÒ×î´ó]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/4/Q/V701K1I4Q.html#ld=V5PO8E0TJ">³¬ÈËÆø£¡´ºÏÄÈÈÂôÈÕϵÉÌÆ·Ô¤¸æ</a></li>
- <li><a href="httpdisabled://v.163.com/special/mlthg/"><em class=' I_V_'>[ÂéÀ±Ììºó¹¬]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/J/6/V7045AJJ6.html#ld=V69VV7M1S">ÎÞÂÛСÈýÔõôÏùÕÅÆÛ¸º ÎÒ»¹ÒªÍì»Ø</a></li>
- <li><a href="httpdisabled://v.163.com/special/shgj/"><em class=' I_V_'>[Éú»î¹ã½Ç]</em></a> <a target="_blank" href="httpdisabled://v.163.com/video/2011/4/I/1/V702U0SI1.html#ld=V6KJJ2B07">Ç×Éú½ãµÜÓÉ°®×ªºÞ ¾Þ¶îË÷ÅâµÄÕæÏà</a></li>
- </ul>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://v.163.com/doc/"><em class='I_V_'>[¼Íʵ]</em></a> <a href="httpdisabled://v.163.com/video/2011/4/B/N/V6VQPQABN.html#ld=V5O75D4ND">÷ÑÞ·¼ÒòÕŹúÈÙ¶øËÀ£¿</a> <a href="httpdisabled://v.163.com/video/2011/4/F/0/V701J90F0.html#ld=V5G0IPI1S">¹Ö²¡²øÉíËļ¾ÍÑƤ</a></li>
- <li><a href="httpdisabled://v.163.com/doc/"><em class='I_V_'>[ÈËÎï]</em></a> <a href="httpdisabled://v.163.com/video/2011/3/V/8/V6VBJ1TV8.html#ld=V5O75D4ND">Ò»´úèÉÐÛÕÅ×÷ÁØ</a> <a href="httpdisabled://v.163.com/video/2011/4/F/G/V6VKMPNFG.html#ld=V5PQKE4F5">ÆÞ×ÓÓò˵¶¿³ÕÉ·ò16µ¶</a></li>
- <li><a href="httpdisabled://v.163.com/doc/"><em class='I_V_'>[¿Ö²À]</em></a> <a href="httpdisabled://v.163.com/video/2011/3/N/G/V6VE9MGNG.html#ld=V5G0IPI1S">ÍâÐÇÎüѪ¹í·ÃµØÇò</a> <a href="httpdisabled://v.163.com/video/2011/3/7/A/V6VFHVH7A.html#ld=V5O75D4ND">¸üÔ©¸ü²Ò!ÑîÈý½ã¸æ×´</a></li>
- <li><a href="httpdisabled://v.163.com/doc/"><em class='I_V_'>[ÀúÊ·]</em></a> <a href="httpdisabled://v.163.com/video/2011/3/8/B/V6UUJ0R8B.html#ld=V5O75AD5H">Õë¶ÔÃÀ¹úµÄ¿Ö²À¿ÕÏ®</a> <a href="httpdisabled://v.163.com/video/2011/3/A/S/V6V5DGJAS.html#ld=V5G0IPI1S">¼ûѪ·âºíÆæÒì¹ÖÊ÷</a></li>
- <li><a href="httpdisabled://v.163.com/doc/"><em class='I_V_'>[̽Ë÷]</em></a> <a href="httpdisabled://v.163.com/video/2011/3/N/G/V6V02Q0NG.html#ld=V5O75D4ND">ÈÕ±¾µÚÒ»ÉñÃØÅ®¼äµý</a> <a href="httpdisabled://v.163.com/video/2011/3/L/I/V6V08VQLI.html#ld=V5G0IPI1S">ÔâÓöµØÇòֹͣת¶¯£¡</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-3 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://v.163.com/special/introductiontopsychology/"><img src="../img3.cache.netease.com/video/2011/4/8/20110408143144afad3.jpg" alt="Ү³´óѧ£ºÐÄÀíѧµ¼ÂÛ" title="Ү³´óѧ£ºÐÄÀíѧµ¼ÂÛ" height="90" width="120" /><cite>Ү³´óѧ£ºÐÄÀíѧµ¼ÂÛ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://v.163.com/special/programming/"><em class='cDRed'>ÐÂÍÆ£ºË¹Ì¹¸£¡¶±à³Ì·½·¨Ñ§¡·</em></a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://v.163.void/">[ÈËÎï]</a> <a href="httpdisabled://v.163.com/special/milton/">ÃÖ¶û¶Ù£ºÓ¢¹úÖøÃûÊ«ÈË</a></li>
- <li><a href="httpdisabled://v.163.void/">[½ðÈÚ]</a> <a href="httpdisabled://v.163.com/special/financialmarkets/">½ðÈÚÊг¡£ºÓëÇ®¸ü½Ó½ü</a></li>
- <li><a href="httpdisabled://v.163.void/">[ÒÕÊõ]</a> <a href="httpdisabled://v.163.com/special/listeningtomusic/">ñöÌýÒôÀÖ£ºáäáàÔÚÌìÌÃ</a></li>
- <li><a href="httpdisabled://v.163.void/">[ÕÜѧ]</a> <a href="httpdisabled://v.163.com/special/justice/">¹«Õý£ºÌ½¾¿¹ÌÓйÛÄî</a></li>
- </ul>
- </div>
- <div class="imgText-temp-3 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://v.163.com/voidcourse/cs50.html"><img src="../img4.cache.netease.com/video/2011/4/7/2011040715531564880.jpg" alt="¹þ·ð£º¼ÆËã»ú¿ÆѧCS50" title="¹þ·ð£º¼ÆËã»ú¿ÆѧCS50" height="90" width="120" /><cite>¹þ·ð£º¼ÆËã»ú¿ÆѧCS50</cite></a>
-</div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://v.163.com/10/1021/12/6JH5JG3V008563G9.html">ÍøÒ×¹«¿ª¿Î×îз­Òë½ø¶È</a></li>
- <li><a href="httpdisabled://v.163.com/special/programming/">±à³Ì·½·¨Ñ§(14)</a> <a target="_blank" href="httpdisabled://v.163.com/voidcourse/algorithms.html">Ëã·¨µ¼ÂÛ(2)</a></li>
- <li><a href="httpdisabled://v.163.com/special/sp/singlevariablecalculus.html">µ¥±äÁ¿Î¢»ý·Ö(11)</a> <a target="_blank" href="httpdisabled://v.163.com/voidcourse/knowledgewharton.html">ÎÖ¶ÙѧÎÊ(1)</a></li>
- <li><a href="httpdisabled://v.163.com/voidcourse/weijifen.html">΢»ý·ÖÖصã(10)</a> <a target="_blank" href="httpdisabled://v.163.com/voidcourse/classicalmechanics.html">¾­µäÁ¦Ñ§(30)</a></li>
- <li><a href="httpdisabled://v.163.com/voidcourse/iphonekaifa.html">iphone¿ª·¢½Ì³Ì(3)</a> <a target="_blank" href="httpdisabled://v.163.com/voidcourse/robotics.html">»úÆ÷ÈË(1)</a></li>
- </ul>
- </div>
- <div class="imgText-temp-3 clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://img4.cache.netease.com/video/2011/4/8/20110408152901a2026.jpg"><img src="../img4.cache.netease.com/video/2011/4/7/20110407105038a01d2.jpg" alt="¡¶ÅúÅÐÐÔÍÆÀíÈëÃÅ¡·" title="¡¶ÅúÅÐÐÔÍÆÀíÈëÃÅ¡·" height="90" width="120" /><cite>¡¶ÅúÅÐÐÔÍÆÀíÈëÃÅ¡·</cite></a>
-</div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://v.163.com/voidcourse/equations.html">Ð¿ΣºÂéÊ¡¡¶Î¢·Ö·½³Ì¡·1-3¿Î</a></li>
- <li><a href="httpdisabled://v.163.com/special/innercore/">ÈËÐÔ</a> | <a target="_blank" href="httpdisabled://v.163.com/special/philosophy-death/">ËÀÍö</a> | <a target="_blank" href="httpdisabled://v.163.com/special/justice/">¹«Õý</a> | <a target="_blank" href="httpdisabled://v.163.com/voidcourse/anthropology.html">ÈËÀàѧ</a></li>
- <li><a href="httpdisabled://v.163.com/special/introductiontotheoldtestament/">¾ÉԼȫÊéµ¼ÂÛ</a> | <a href="httpdisabled://v.163.com/special/introductiontopsychology/">ÐÄÀíѧµ¼ÂÛ</a></li>
- <li><a href="httpdisabled://v.163.com/special/socialcognition/">Éç»áÈÏÖªÐÄÀíѧ</a> | <a target="_blank" href="httpdisabled://v.163.com/special/profilesinleadership/">Áìµ¼ÄÜÁ¦</a></li>
- <li><a href="httpdisabled://v.163.com/10/1019/15/6JCC3DT8008563GR.html"><em class='cDRed'>¹«¿ª¿ÎƵµÀ³¤ÆÚÕÐļ·­ÒëÈËÔ±</em></a></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="area-sub">
- <div id="product" class="mod product-mod">
- <h2 class="hd clearfix">
- <span class="mod-title"><a href="httpdisabled://sitemap.163.com/">ÍøÒ×ÍƼö</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="product-map cBlue">
- <div class="product-item-mail clearfix">
- <strong><a class="icon" href="httpdisabled://email.163.com/">ÓÊÏä</a></strong>
- <a href="httpdisabled://email.163.com/">Ãâ·ÑÓÊÏä</a> <a href="httpdisabled://vipmail.163.com/">VIPÓÊÏä</a> <a href="httpdisabled://qiye.163.com/">ÆóÒµÓÊÏä</a> <a href="httpdisabled://fm.163.com/client">ÓÊÏä¿Í»§¶Ë</a>
- </div>
- <div class="product-item-game clearfix">
- <strong><a href="httpdisabled://nie.163.com/" class="icon">ÓÎÏ·</a></strong>
- <a href="httpdisabled://xyq.163.com/">ÃλÃÎ÷ÓÎ</a> <a href="httpdisabled://xy2.163.com/">´ó»°Î÷Ó΢ò</a> <a href="httpdisabled://tx2.163.com/">ÌìÏ·¡</a> <a href="httpdisabled://xy3.163.com/">´ó»°Î÷ÓÎ3</a> <a href="httpdisabled://www.warcraftchina.com/">ħÊÞÊÀ½ç</a> <a href="httpdisabled://pk.163.com/">Õ½¸è</a> <a href="httpdisabled://ff.163.com/">зɷÉ</a> <a href="httpdisabled://dt2.163.com/fab.html?from=163">´óÌÆÎÞË«</a> <a href="httpdisabled://csxy.163.com/">´´ÊÀÎ÷ÓÎ</a> <a href="httpdisabled://qn.163.com/" style="color:#ba2636;">ٻŮÓÄ»ê</a>
- </div>
- <div class="product-item-serv clearfix">
- <strong><a href="httpdisabled://sitemap.163.com/" class="icon">ÉçÇø</a></strong>
- <a href="httpdisabled://blog.163.com/?fromService">²©¿Í</a> <a href="httpdisabled://photo.163.com/">Ïà²á</a> <a href="httpdisabled://dream.163.com/">ÃλÃÈËÉú</a> <a href="httpdisabled://yuehui.163.com/">ͬ³ÇÔ¼»á</a>
- </div>
- <div class="product-item-reco clearfix">
- <strong><a href="httpdisabled://sitemap.163.com/" class="icon">ÍƼö</a></strong>
- <a href="httpdisabled://mall.163.com/">ÍøÒ×É̳Ç</a> <a href="httpdisabled://fanxian.163.com/?keyfrom=163indexleft.fanxian">¹ºÎï·µÏÖ</a> <a href="httpdisabled://caipiao.163.com/index.html?from=www">ÍøÒײÊƱ</a> <a href="httpdisabled://tuan.163.com/">ÍøÒ×ÍŹº</a> <a href="httpdisabled://cidian.youdao.com/">ÓеÀ´Êµä</a> <a href="httpdisabled://bafang.163.com/">ÍøÒ×°Ë·½</a> <a href="httpdisabled://L.163.com/">ÍøÒ×ÉÐÆ·</a> <a href="httpdisabled://m.163.com/newsapp/">ÐÂÎÅ¿Í»§¶Ë</a>
- </div>
- </div>
- </div>
- <div class="tab-con">
- <ul class="product-list">
- <li><span><a href="httpdisabled://mail.163.com/" class="item-mail c-entry">163ÓÊÏä</a></span></li>
- <li><span><a href="httpdisabled://t.163.com/" class="item-microBlog c-entry">΢²©</a></span></li>
- <li><span><a href="httpdisabled://blog.163.com/passportIn.do?entry=163" class="item-blog c-entry">²©¿Í</a></span></li>
- <li><span><a href="httpdisabled://photo.163.com/?username=pInfo" class="item-photo c-entry">Ïà²á</a></span></li>
- <li><span><a href="httpdisabled://tie.163.com/reply/myaction.jsp?action=reply&username=pInfo" class="item-tie c-entry">¸úÌù</a></span></li>
- <li><span><a href="httpdisabled://i.money.163.com/" class="item-money c-entry">Ͷ×Ê</a></span></li>
- <li><span><a href="httpdisabled://wan.163.com/" class="item-wan c-entry">ÍøÒ³ÓÎÏ·µ¼º½</a></span></li>
- <li><span><a href="httpdisabled://book.163.com/" class="item-book c-entry">¶ÁÊéÖÐÐÄ</a></span></li>
- <li><span><a href="httpdisabled://yuehui.163.com/myidate.do" class="item-yuehui c-entry">ͬ³ÇÔ¼»á</a></span></li>
- <li><span><a href="httpdisabled://caipiao.163.com/" class="item-caipiao c-entry">²ÊƱ</a></span></li>
- </ul>
- <span class="product-entry"><a href="httpdisabled://reg.163.com/" class="c-entry">½øÈëÍøÒ×ͨÐÐÖ¤<span class="code-en">&raquo;</span> </a></span>
- </div>
- </div>
- </div>
-<div id="g5n1" class="mod wgt-tab">
-<div class="tab-hd tab-u-5 clearfix">
- <span class="tab-u current">×ÊѶ</span>
- <span class="tab-u">»î¶¯</span>
- <span class="tab-u">ÍƼö</span>
- <span class="tab-u">¾«Æ·</span>
- </div>
- <div class="bd display-control">
- <div class="tab-con current">
-<ul class="mod-list sub-list">
-<li class="title"><a href="httpdisabledsdisabled://epay.163.com/notice/chongzhi.jsp">ÊÖ»ú¿¨³äÖµÒ²ÄÜÍø¹ºÀ²</a></li>
-<li><a href="httpdisabled://lady.163.com/special/00261ID9/2009DeluxeReport.html">×îÊÜÉÌÎñÈËÊ¿ÖÓ°®Æ·ÅÆ</a></li>
-<li><a href="httpdisabled://survey2.163.com/html/dict_youdao2011q1/paper.html">ÇáµãÊó±êÓ®¾ªÏ²´ó½±</a></li>
-<li><a href="httpdisabled://mail.163.com/html/110127_imap/index.htm">ÊÓƵ½ÌÄãÉèÖÃÓÊÏäIMAP</a></li>
-<li><a href="httpdisabled://pmxj.wan.163.com/">Æ®Ãì¶à·çÔÆÏɽ£ÏÔÎäÁÖ</a></li>
-<li><a href="httpdisabled://money.163.com/2011NAEC/">2011ÍøÒ×¾­¼Ãѧ¼ÒÄê»á</a></li>
- </ul>
- <ul class="mod-list sub-list">
-<li><a href="httpdisabled://tech.163.com/11/0322/10/6VO99FLI000915BF.html">ÍøÒ×ÐÂÎÅ¿Í»§¶Ë¡ÖØÉÏÏß</a></li>
-<li><a href="httpdisabled://g.163.com/a?CID=240&Values=53963900&Redirect=http://mhxx.dream.163.com?101222mhxx002">¹úÄÚÊ׿î2Dºá°æÍøÓÎ</a></li>
-<li><a href="httpdisabled://xyq.163.com/xyq?acctsn=MH22-2128-3554-7248">ºÍËûÒ»Æð×ö×îÀËÂþµÄÊÂ</a></li>
-<li><a href="httpdisabled://yuehui.163.com/">ллÍøÒ×ÈÃÎÒÓö¼ûÁËËû</a></li>
-<li><a href="httpdisabled://bafang.163.com/">²é¿´Å®ÓѾßÌåλÖà </a></li>
-<li><a href="httpdisabled://v.163.void/">ÍøÒ×¹«¿ª¿Î ºÃ¿ÎÃâ·ÑÌý</a></li>
- </ul>
- </div>
- <div class="tab-con">
- </div>
- <div class="tab-con">
- </div>
- <div class="tab-con">
- </div>
- </div>
- </div>
- <script>
- NTES.ready( function(){
- var aChange = new AChange({
- temp: "/special/00774IHC/11zy1-",
- content: "#g5n1",
- num: "5"
- });
-});
- </script>
- </div>
-</div>
-<!-- end -->
-<div class="area">
- <div class="clearfix">
- <div class="area-sub">
- <div class="gg gg-h100"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=logo190x100&amp;location=1.html" width="190" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-</div>
- </div>
-<div class="area-main">
- <div class="main-col-10">
- <iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column390x100&amp;location=1.html" width="390" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-
- </div>
- <div class="main-col-9">
- <iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column360x100&amp;location=1.html" width="360" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-
- </div>
- </div>
- </div>
-</div>
-<!-- sports & ent -->
-<div class="area">
- <div class="area-main">
- <div class="main-col-10">
- <div id="sports" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-10 clearfix">
- <span class="tab-u current"><a href="httpdisabled://sports.163.com/">ÌåÓý</a></span>
- <span class="tab-u"><a href="httpdisabled://sports.163.com/nba/">NBA</a></span>
- <span class="tab-u"><a href="httpdisabled://cbachina.163.com/">CBA</a></span>
- <span class="tab-u"><a href="httpdisabled://sports.163.com/world/">¹ú¼Ê×ãÇò</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://sports.163.com/photoview/0AI90005/66272.html#p=714GEI7O0AI90005"><img src="../img4.cache.netease.com/sports/2011/4/8/20110408211535eae49.jpg" alt="ÉíÅûºþÈËÕ½ÅÛµÄÃ÷ÐÇ" title="ÉíÅûºþÈËÕ½ÅÛµÄÃ÷ÐÇ" height="90" width="120" /><cite>ÉíÅûºþÈËÕ½ÅÛµÄÃ÷ÐÇ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://live.cbachina.163.com/2010/match/report/2010291.html">CBA-¹ã¶«ÏÕʤ×ܱȷÖ3-0½ú¼¶×ܾöÈü</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://live.cbachina.163.com/2010/match/report/2010290.html">н®Ê¤½­ËÕ </a> <a target="_blank" href="httpdisabled://cbachina.163.com/11/0408/22/715D57FI00052UUC.html">×ܾöÈüÁ¬ÐøÈýÄêÕ½¹ã¶«</a></li>
- <li><a href="httpdisabled://cbachina.163.com/11/0408/10/7143UFAR00052UUC.html">ÄÐÀº¼¯ÑµÃûµ¥¹«²¼:Ò¦Ã÷ÍõÖÎÛ¤ÔÚÁÐ</a></li>
- <li><a href="httpdisabled://t.163.com/zt/sports/ztqftdr">[΢·Ã̸]ÕÅÌúȪ:ÌìϵÚÒ»¿¿´ò³öÀ´</a></li>
- <li><a href="httpdisabled://nba.sports.163.com/2010/match/preview/11887.html">7:30²¥ÈÈ»ð-ɽè</a> <a target="_blank" href="httpdisabled://nba.sports.163.com/2010/match/preview/11894.html">10:00ºþÈË-¿ªÍØÕß</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://sports.163.com/11/0409/00/715IAOR600051CA1.html" data-t-h="22">ÀºÍøÐû²¼µÂ¡½«½ÓÊÜÊÖÍóÊÖÊõ</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/22/715CRAHE00051CA1.html">¾ôÊ¿ÖзæÄ´Ö¸¹ÇÁÑÈü¼¾±¨Ïú</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/12/71499QKD00051CA1.html">½Ü¿ËÑ·ÆؿƱÈÔøµ±ÃæÌôÐÆÇǵ¤</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/18/7150FJDD00051CA1.html">ĪÀ×Ã÷È·±í̬ÓûÐøÔ¼Ò¦Ã÷</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/22/715CUOLQ00051CD5.html">ÆعúÃ×½«³öÊÛ˹ÄÚµÂÈûÈø¶ûÇóС·¨</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/09/713UVQ5M00051CD5.html">ÆØÌØά˹ÃÜ»á¹úÃ׸߲ã</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/17/714R4JPT00051CCL.html">ÀûÎïÆÖÐû²¼½ÜÀ­µÂÈü¼¾±¨Ïú</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/09/713UR5OM00051C8V.html">¸¥¸ñÉ­Óû´Ó»ÊÂíÍÚÆë´ïÄÚ°®×Ó</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/21/7157SB9S00051CAQ.html">É£À¼¸°ÃÀ´ò¹Ù˾Ë÷ÅâÒ»ÒÚÃÀÔª</a> <a target="_blank" href="httpdisabled://sports.163.com/photoview/0B6P0005/66274.html#p=714HUFL60B6P0005">ͼ¼¯:ÍôáÔÓë»·ÇòС½ã·ÖÊÖ</a></li>
- <li><a href="httpdisabled://sports.163.com/photoview/00800005/66264.html#p=71400JTG00800005">ͼ¼¯:С±´·ò¸¾Íâ³ö¾Í²Í À±ÃÃ"ÔÐζ"È«ÎÞ</a> <a target="_blank" href="httpdisabled://sports.163.com/photoview/00DE0005/66263.html#p=713SVUCU00DE0005">CÂÞ¹Û¿´ÀºÇòÈü</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://sports.163.com/special/000502KO/lingdujiao.html" class="fB attitude">ÌåÓý</a> | <a href="httpdisabled://sports.163.com/special/000502KO/lingdujiao.html"><em class='cBlack fB'>Áã¶È½Ç</em></a> | <a target="_blank" href="httpdisabled://sports.163.com/special/nbabusiness/">NBAÇòÐǵÄÉÌÒµµÛ¹ú</a></li>
- <li><a href="httpdisabled://sports.163.com/pl/"><em class='cBlack fB'>µ¥µ¶</em></a> | <a target="_blank" href="httpdisabled://tiyuriping.blog.163.com/blog/static/1636490272011388520798/">Å©ÃñÊÔѵǹÊÖÖ»ÊǸöÃÎ</a> | <a target="_blank" href="httpdisabled://litong1976.blog.163.com/blog/static/1211929201137115723970/">Öйú×ãÇò½øÈë´µNBʱ´ú</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://sports.163.com/photoview/0AI90005/66278.html#p=714P08VJ0AI90005"><img src="../img3.cache.netease.com/sports/2011/4/8/20110408224146ca253.jpg" alt="»ÊµÛ±³ºó¶àʵÄĸÇ×" title="»ÊµÛ±³ºó¶àʵÄĸÇ×" height="90" width="120" /><cite>»ÊµÛ±³ºó¶àʵÄĸÇ×</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://sports.163.com/11/0408/18/7150FJDD00051CA1.html">ĪÀ×±í̬ÓûÐøÔ¼Ò¦Ã÷̾ÆäÖÁ¹ØÖØÒª</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://nba.sports.163.com/2010/match/preview/11887.html">7:30ÈÈ»ð-ɽè</a> <a target="_blank" href="httpdisabled://nba.sports.163.com/2010/match/preview/11894.html">10µãºþÈË-¿ªÍØÕß</a></li>
- <li><a href="httpdisabled://nba.sports.163.com/2010/match/report/11881.html">ÂÞ˹30+8¹«Å£Ê¤Â̾ü¹®¹Ì¶«²¿µÚÒ»</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/08/713SE3OP00051CA1.html">°ÝÄÉÄ·ÅÚºäÈ«¶Ó:ÎÒÃÇ´òµÃºÜÓÞ´À</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/12/71499QKD00051CA1.html">ìøʦÆعâ¿Æ±Èµ±ÃæÌôÐÆÇǵ¤¾ÉÊÂ</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://sports.163.com/11/0408/21/715A9F0600051CA1.html">¸ñÀï·Ò:´ÓδÏë¹ý×Ô¼ºÈç´Ë³É¹¦</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/20/7155D72Q00051CA1.html">ÃÀý·íÒ»ÈËÊÇ"°¢ÁªµÚ¶þ"</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/09/713VIFML00051CA1.html">·Ñ¸ù:°¢Ë§ÈôÀëÈÎÂåÀïÊܳå»÷</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/15/714L9VOT00051CA1.html">»ð¼ýÖÚ½«±íʾÂúÒâÏÖÓÐÕóÈÝ</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/19/7150Q2U000051CA1.html">ΤµÂΪ¼¾ºóÈü»òÔÝ·ÅÆú¸´³ö</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/20/7155VG8I00051CA1.html">µ¤Æ¤¶ûºÀÑÔÈÈ»ðÖзæÎÞ¿ÉÆ¥µÐ</a></li>
- <li><a href="httpdisabled://sports.163.com/special/nbabusiness/">²ß»®:NBAÇòÐǵÄÉÌÒµµÛ¹úµÞÔìÊ·</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/10/7144S0VE00051CA1.html">ƤÅîÍ­ÏñÁÁÏàÁªºÏÖÐÐÄ</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/17/714R2FNM00051CA1.html">ÄÉʲÔÞС²¼Ä˳öÉ«µÃ·ÖÊÖ</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/10/7142IAQJ00051CA1.html">¶ÅÀ¼ÌØ:MVPÆÀÑ¡ÎÞÊÓÎҵĴæÔÚ</a></li>
- <li><a href="httpdisabled://sports.163.com/photoview/00MK0005/66282.html#p=7152GRIO00MK0005">ͼ¼¯:¿¨´÷ɺ±È»ùÄáÐԸзâÃæÕÕ</a> <a target="_blank" href="httpdisabled://v.sports.163.com/video/2011/4/4/2/V70646942.html"><em class=' I_V_'>»ÊµÛÖ÷Ì⶯»­ÕýʽÉÏÓ³</em></a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://sports.163.com/special/nbacolumn/"><em class='cBlack fB'>רÀ¸</em></a> | <a target="_blank" href="httpdisabled://sports.163.com/11/0406/14/70VC6HC500051CA1.html">ÍõÓñ¹ú:Âí´ÌÓÖÍæ¼ÙËÀ°ÑÏ· °Í¿ËÀûÔ¤ÑÔÄÜ·ñ³ÉÕæ?</a></li>
- <li><a href="httpdisabled://sports.163.com/special/nbastatscool/"><em class='cBlack fB'>Êý¾Ý¿á</em></a> | <a target="_blank" href="httpdisabled://sports.163.com/11/0408/21/715ALJC400051CA1.html">ÂÞ˹Èü¼¾Öú¹¥ÆÆ600 ¾ôʿʤÂÊ28ÄêµÚ¶þµÍ</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://cbachina.163.com/photoview/4E9G0005/66277.html#p=714MR3E24E9G0005"><img src="../img3.cache.netease.com/sports/2011/4/8/20110408164530e0dfd.jpg" alt="ÄÐÀº¼¯Ñµ¶ÓÈ«Ãæ&quot;À©ÕÐ&quot;" title="ÄÐÀº¼¯Ñµ¶ÓÈ«Ãæ&quot;À©ÕÐ&quot;" height="90" width="120" /><cite>ÄÐÀº¼¯Ñµ¶ÓÈ«Ãæ"À©ÕÐ"</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://live.cbachina.163.com/2010/match/report/2010290.html">н®ºáɨ½­ËÕ</a> <a target="_blank" href="httpdisabled://cbachina.163.com/11/0408/22/715D57FI00052UUC.html">×ܾöÈüÔÙÏÖ½®ÔÁÕù°Ô</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://live.cbachina.163.com/2010/match/report/2010291.html"><em class=' I_V_'>¹ã¶«4·ÖÏÕʤºáɨ¶«Ý¸½ú¼¶×ܾöÈü</em></a></li>
- <li><a href="httpdisabled://cbachina.163.com/11/0408/22/715E3J1K00052UUC.html">¶­å«÷ë×ÔÐŹ㶫Æ߳ɸÅÂʶáÏÂ×ܹھü</a></li>
- <li><a href="httpdisabled://cbachina.163.com/11/0408/22/715C3R9500052UUC.html">¸ê¶ûÏ£Íû¹ã¶«¶á×ܹھü³ÆÍâÔ®¶¨³É°Ü</a></li>
- <li><a href="httpdisabled://cbachina.163.com/11/0409/00/715JVM1M00052UUC.html" data-t-h="01">½¯ÐËȨ:¿ªÊ¼×¼±¸´ò¹ã¶«×ÊÁÏ»¹²»¹»</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://cbachina.163.com/11/0408/22/715COHAI00052UUC.html">¹ã¶«¶Óð󼲸´·¢ÈÇÅ­Àî´º½­</a> <a target="_blank" href="httpdisabled://cbachina.163.com/11/0409/00/715ILMMG00052UUC.html">ÓûӮн®ÍâÏßÏÞÖƶűȳɹؼü</a></li>
- <li><a href="httpdisabled://cbachina.163.com/11/0408/21/715AA83R00052UUC.html">¹þµÂÉ­8¼ÇÈý·Ö¿ñì­41·Ö</a> <a target="_blank" href="httpdisabled://cbachina.163.com/11/0408/23/715F50CF00052UUC.html">¹þµÂÉ­:ûÏëË¢·Ö±ðÄÃÎҺͶűȱÈ</a></li>
- <li><a href="httpdisabled://cbachina.163.com/11/0408/22/715D3BHS00052UUC.html">ԼʲÏÕÔìÄæתȴ·ÅÆúͶ¾øɱÇò</a> <a target="_blank" href="httpdisabled://cbachina.163.com/11/0408/22/715CM57Q00052UUC.html">¸ê¶ûÔÝͣʧÎóɥʧ·­ÅÌÁ¼»ú</a></li>
- <li><a href="httpdisabled://cbachina.163.com/photoview/4E9G0005/66281.html#p=7151PV9O4E9G0005">ͼ¼¯-Öì·¼Óê°®×Ó³ÉÈü³¡Ð¡"ÀÍÄ£"</a> <a target="_blank" href="httpdisabled://cbachina.163.com/photoview/4E9G0005/66285.html#p=7155S2NQ4E9G0005">±¦±´Ð¡ÕæÕæ±äÉíÑݼ¼ÅÉ</a></li>
- <li><a href="httpdisabled://cbachina.163.com/11/0408/10/7143UFAR00052UUC.html">ÄÐÀº37È˳¬´ó¼¯ÑµÃûµ¥Ò¦Ò×ÈëÑ¡</a> <a target="_blank" href="httpdisabled://cbachina.163.com/11/0408/22/715BB62Q00052UUC.html">ËÕȺ:¹«²¼¸úû¹«²¼Ò»Ñù</a></li>
- <li><a href="httpdisabled://cbachina.163.com/11/0408/22/715DMJKQ00052UUC.html">áÛ·åÈü¹ù°¬Â×È·ÈÏ´ú±í¹ú¼Ê¶Ó³öÕ½</a> <a target="_blank" href="httpdisabled://cbachina.163.com/11/0408/15/714K4FN500052UUC.html">NCAAÇò¶ÓÑûµË»ªµÂÖ´½Ì</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://cbachina.163.com/photoview/4E9G0005/66280.html"><em class='cBlack fB'>ͼ¼¯</em></a> | <a target="_blank" href="httpdisabled://cbachina.163.com/photoview/4E9G0005/66280.html">³¬Ä£³¡Íâ"¼¤¶·"Ô¤ÑݾöÈü</a> <a target="_blank" href="httpdisabled://cbachina.163.com/photoview/4E9G0005/66251.html#p=712I7BHH4E9G0005">н®ÍâÔ®¹ÖÁ¦ËéÀº°å</a></li>
- <li><a href="httpdisabled://t.163.com/zt/sports/nldmd"><em class='cBlack fB'>΢²©</em></a> | <a target="_blank" href="httpdisabled://t.163.com/zt/sports/nldmd ">ÄÐÀºÅÓ´ó¼¯ÑµÃûµ¥ÒýÈÈÒé</a> <a target="_blank" href="httpdisabled://t.163.com/zt/sports/tzd500">500ÍòÂòÌÆÕý¶«Öµ²»Öµ?</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://sports.163.com/11/0408/10/7143VMGH00051C8V.html"><img src="../img3.cache.netease.com/sports/2011/4/8/20110408234759dabf8.jpg" alt="Î÷¼×Ê®´ó90ºóÌì²Å" title="Î÷¼×Ê®´ó90ºóÌì²Å" height="90" width="120" /><cite>Î÷¼×Ê®´ó90ºóÌì²Å</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://sports.163.com/11/0408/22/715CUOLQ00051CD5.html">¹úÃ׳öÊÛ˹ÄÚµÂÈûÈø¶ûÈ«Á¦ÇóС·¨?</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://sports.163.com/11/0409/00/715KCC1I00051C8V.html" data-t-h="20">¹Ï˧£º°ÍÈø5½«ÊÖÊÆδÌôÐÆ»ÊÂí</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/08/713SLSN700051CD5.html">Ã×À¼Ë«ÐÛÓû·Ö±ðÖØ°õÇó¹ºCÂÞ÷Î÷?</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/08/713R6UHN00051C8V.html">°ÍÈøÓû¹º21ËêÌì²Å ËûÊÇÊÀ½ç±­½ðÑ¥</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/17/714R4JPT00051CCL.html">ÀûÎïÆÖ¹Ù·½Ö¤Êµ½ÜÀ­µÂ±¾Èü¼¾±¨Ïú</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://sports.163.com/11/0408/08/713TO53F00051CCL.html">Ó¢×ã×ÜвÆȲÃÅÐָ֤³Äá?</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/19/71521IA800051CCL.html">¸¥¸ñÉ­·ßÅ­ ÅÚºäÓ¢×ã×ܲ»¹«Æ½</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/19/7153IF7S00051CCL.html">PFAÄê¶È×î¼ÑºòÑ¡:ÄÉÄáÈëÐÂÐãÃûµ¥</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/16/714NR4BE00051CCL.html">ÂüÁªÎªÄÚά¶û°ì¼ÍÄîÈü</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/09/713V7CHJ00051CD5.html">¹úÃ×»òÓëÇжûÎ÷Õù¶á¹ÏµÏ°ÂÀ­</a> <a target="_blank" href="httpdisabled://sports.163.com/photoview/00CO0005/66290.html#p=715MNCNF00CO0005">ͼ¼¯:¹úÃ×ÀúÊ·´óÀ£°Ü»Ø¹Ë</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/09/7140ONHF00051C8V.html">»ÊÂíPKÂüÁªÕùÓ¢³¬¿Õ°ÔÌúÑü</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/09/713UR5OM00051C8V.html">¸¥¸ñÉ­Óû´Ó»ÊÂíÍÚÆë´ïÄÚÖ®×Ó</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/11/7146C9G700051CD5.html">°ÝÈÊ1500Íò+1ÈËÇó¹ºÂÞ±ÈÄá°Â</a> <a target="_blank" href="httpdisabled://sports.163.com/photoview/00CO0005/66261.html#p=713RTJPK00CO0005">²©ÁÐÂåÐÂÅ®ÓÑÕýʽÆعâ(ͼ)</a></li>
- <li><a href="httpdisabled://sports.163.com/11/0408/09/71415N6400051C97.html">ÀͶûÓÐÍûÐøԼɳ¶û¿ËÖÁ2013Äê</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/09/7141DPCC00051C97.html">ÀÕ·òÅúÆÀµÂ¼×ÁªÈüÒý·¢ÖÚÅ­</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><strong><a href="httpdisabled://sports.163.com/world/">Èȵã</a></strong> | <a href="httpdisabled://sports.163.com/11/0408/19/7150SL9M00051C8V.html">ÅÁÀÕĪÐû²¼½ñÏÄÍËÒÛ</a> <a href="httpdisabled://sports.163.com/11/0408/13/714FA53300051C97.html"><em class='I_V_'>Ö£´óÊÀÍ·³¯µØ¾±×µÖØÉË</em></a></li>
- <li><strong><a href="httpdisabled://sports.163.com/lottery/">²ÊƱ</a></strong> | <a href="httpdisabled://sports.163.com/11/0408/11/7146HD3N00052DT2.html">570ÍòµÃÖ÷¸ÐÑÔ:ûǮ±ðÅöÅ®ÈË</a> <a target="_blank" href="httpdisabled://sports.163.com/11/0408/22/715BUTMV00052DT2.html">×ã²Êר¼Ò36ÆÚ»ã×Ü</a></li>
- </ul>
- </div>
- </div>
- </div>
-<div class="gg gg-h100"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column390x100&amp;location=2.html" width="390" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-</div>
- </div>
- <div class="main-col-9">
- <div id="ent" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-9 clearfix">
- <span class="tab-u current"><a href="httpdisabled://ent.163.com/">ÓéÀÖ</a></span>
- <span class="tab-u"><a href="httpdisabled://ent.163.com/movie/">µçÓ°</a></span>
- <span class="tab-u"><a href="httpdisabled://ent.163.com/tv/">µçÊÓ</a></span>
- <span class="tab-u"><a href="httpdisabled://ent.163.com/music/">ÒôÀÖ</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix" style="height:130px;">
- <div class="mod-img main-img">
- <a href="httpdisabled://ent.163.com/11/0408/18/714V0T5000031H2L.html"><img src="../img3.cache.netease.com/ent/2011/4/8/20110408183341f6142.jpg" alt="¾Æ¾®·¨×Ó̽·ÃÁ÷À˶ùͯ" title="¾Æ¾®·¨×Ó̽·ÃÁ÷À˶ùͯ" height="90" width="120" /><cite>¾Æ¾®·¨×Ó̽·ÃÁ÷À˶ùͯ</cite></a>
-</div>
- <!-- some code --> <h3 class="main-title"><a href="httpdisabled://ent.163.com/11/0408/05/713I9FPR00031H2L.html">Ö£ÖлùÅ®ÓÑδ»éÏÈÔÐÃØÃÜ´ý²ú</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://ent.163.com/11/0408/04/713FNOTG00031H2L.html">Ç°ÑëÊÓÃû×ì·½ºê½øÀë»é°¸¿ªÍ¥</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/00/71329KLS00031H2L.html">Íõçóµ¤ÔâÓö³µ»ö¶îÍ··ìÕë</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/08/713SR0UD00031H2L.html">³ÂºÃÏÖÉí±±¾©Ð¡¸¹Â¡ÆðÒÉËÆÓÐÔÐ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/09/7140UVP700032DGD.html">´«ãÆÄÝÒÑÀë»é½á½»80ºóÄÐÑÝÔ±</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://ent.163.com/special/2011wdyj/">[΢µçÓ°½Ú]µ¼Ñݳ´óÃ÷£ºÎ¢µçÓ°µÄ´´×÷ºÜ×ÔÓÉ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/06/713KR54M00032DGD.html">¾Æ¾®·¨×ÓÅĽû¶¾Ðû´«Æ¬ ³ÆÑÝÒÕ¹¤×÷ÉÐÎ޼ƻ®(ͼ¼¯)</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/00/7132OPE500031H2L.html">¿ìÅ®Áõϧ¾ý±»ÆØÆ­È¡·ÛË¿Ç®²Æ ¾¯·½ÒÑÁ¢°¸Õì²é(ͼ)</a></li>
- <li><a href="httpdisabled://ent.163.com/photoview/00AJ0003/43935.html#p=712RO3N100AJ0003">ͼ¼¯:Åí˳·¢»Ó¡¶B+Õì̽¡·´´Òâ ÊÖ»úÅÄÉã΢µçÓ°</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0407/21/712M5VGI00031H2L.html">¡¶ÈâÆÑÍÅ¡·Ö÷½ÇÔ­É´ÑëÀòÒýÍË</a> <a href="httpdisabled://ent.163.com/11/0408/07/713QLNTE00031H2L.html">À¶Ñà³ÎÇå×Ôɱ´«ÎÅ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/03/713ACTAD00032DGD.html">Å˳¤½­×ÔÚ¼±ÈÕÔ±¾É½ÑóÆø</a> <a href="httpdisabled://ent.163.com/11/0408/01/7135VU5G00032DGD.html">·¶çâç÷:»éÀñ´©Æ½µ×Ь</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://ent.163.com/" class="fB attitude">ÓéÀÖ</a> | <a href="httpdisabled://ent.163.com/special/hybdhz/"><em class='fB'>ÐÐÒµ±¨µÀ</em></a>|<a target="_blank" href="httpdisabled://ent.163.com/special/pfhg1103/">3ÔµçӰƱ·¿Æ£Èí</a></li>
- <li><a href="httpdisabled://ent.163.com/special/zhuanyejieduhuiz/"><em class='fB'>¼â·å»°Ìâ</em></a>|<a target="_blank" href="httpdisabled://ent.163.com/special/waixingren/ ">ÎÒÃÇÖ»»á³ç°Ý"ÍâÐÇÈË"</a>|<a target="_blank" href="httpdisabled://ent.163.com/special/weiquan/">½âÆÊ"µÁ°æÊÜÒæÕß"</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://ent.163.com/photoview/00B50003/43948.html#p=713PVANJ00B50003"><img src="../img4.cache.netease.com/ent/2011/4/8/2011040809044637924.jpg" alt="Êæä¿ÁõìÇÐÂƬÆغ£±¨" title="Êæä¿ÁõìÇÐÂƬÆغ£±¨" height="90" width="120" /><cite>Êæä¿ÁõìÇÐÂƬÆغ£±¨</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://ent.163.com/special/moviestory003/">[µçÓ°¹ÊÊÂ]¶Åç÷·å±±ÉÏÌÔ½ð¼Ç</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://ent.163.com/11/0407/22/712PQM1F000300B1.html">¡¶ºèÃÅÑç¡·¿ª»úÁõÒà·ÆÊÎÑÝÓݼ§</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/00/7130EP32000300B1.html">³Â´óÃ÷£ºÎ¢µçÓ°µÄ´´×÷ºÜ×ÔÓÉ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0407/23/712SPQPE000300B1.html">Ò¦³¿·ñÈϲÎÑÝ·ëС¸ÕÐÂƬ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0407/23/712SNS3P000300B1.html">3D¶¯»­Æ¬¡¶ÀïÔ¼´óðÏÕ¡·Ê×Ó³</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://ent.163.com/photoview/00B50003/43950.html#p=713QJ8A600B50003">¡¶ÍòÓÐÒýÁ¦¡·¶À¼Ò¾çÕÕ(ͼ¼¯)</a> <a target="_blank" href="httpdisabled://ent.163.com/11/0408/05/713I5GEN00032DGD.html">¹ùÌÎÑÝ´²Ï·ÒªÇëʾ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/08/713SENLN000300B1.html">¡¶¹ØÔƳ¤¡·ÎäÏ·½âÃÜ</a> <a target="_blank" href="httpdisabled://ent.163.com/11/0408/08/713T8JU9000300B1.html">¡¶Õ½¹ú¡·Æض¯×÷ƪ»¨Ðõ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/05/713I9IHA00032DGD.html">С¶¶«³ÉÎ÷¾Í¡·½«¿ª»ú</a> <a target="_blank" href="httpdisabled://ent.163.com/11/0408/00/71308QBC00032DGD.html">¡¶ÐÁº¥¸ïÃü¡·10ÔµDZ±ÃÀ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/09/713UNFBJ000300B1.html">¡¶º©¶¹Ìع¤2¡··¢Ô¤¸æ</a> <a target="_blank" href="httpdisabled://ent.163.com/11/0408/03/713AAPJG00032DGD.html">¡¶¹þÀû²¨ÌØ¡·×îÖÕÕÂÊÔƬ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/09/713UGCK3000300B1.html">¡¶Ëٶȼ¤Çé5¡·5Ô»òÉÏÓ³</a> <a target="_blank" href="httpdisabled://ent.163.com/11/0408/08/713U5GG5000300B1.html">¡¶ÉÙÅ®Ìع¥¶Ó¡·ÔªËضà</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/03/713AB9MR00032DGD.html">¡¶ÔÚÒ»Æð¡·°ì¼ûÃæ»á</a> <a target="_blank" href="httpdisabled://ent.163.com/11/0408/03/713ABDPP00032DGD.html">¡¶¿×Áîѧ¡·ËïÄþ»ñ·¶Î°Á¦Í¦</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://ent.163.com/special/moviestories/"><em class='fB'>µçÓ°¹ÊÊÂ</em></a> | <a target="_blank" href="httpdisabled://ent.163.com/special/moviestories002/">¡¶µ¶¼ûЦ¡·:ÎÚ¶ûÉƵĴ³¹ØÓÎÏ·</a></li>
- <li><a href="httpdisabled://ent.163.com/special/hybdhz/"><em class='fB'>ÐÐÒµ±¨µÀ</em></a> |<a target="_blank" href="httpdisabled://ent.163.com/special/yinjin/">WTO²Ã¾öÄѺ³Ó°ÊÐ</a> <a target="_blank" href="httpdisabled://ent.163.com/special/hepaipianxinfengxiang/">ÖиۺÏÅÄƬзçÏò</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://ent.163.com/11/0408/00/712VKNLN00032KMI.html#p=713116NF00B70003"><img src="../img4.cache.netease.com/ent/2011/4/8/20110408074407aed87.jpg" alt="ÑîÃÝ:¹«Ë¾°²ÅÅÏàÇ×" title="ÑîÃÝ:¹«Ë¾°²ÅÅÏàÇ×" height="90" width="120" /><cite>ÑîÃÝ:¹«Ë¾°²ÅÅÏàÇ×</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://ent.163.com/11/0408/01/7135PRSL00032KMI.html">¡¶ÎÒµÄÇà´ºÔÚÑÓ°²¡·É±Çà</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://ent.163.com/11/0408/01/7135HBRN00031GVS.html">·´ÌØÐüÒɾ硶¸æÃÜÕß¡·¿ª²¥ </a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/09/713VFT8J00031GVS.html">Ó¢¹úÅĵçÊӰ桶̩̹Äá¿ËºÅ¡· </a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/02/7136UO4A00032KMI.html">³Â¼ü·æоç±äÅä½Ç ¼á³ÆÊÇÒ»Ïß</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/04/713GAV9700031GVS.html">¡¶Ïã¸ñÀïÀ­¡·Íê³ÉºóÆÚÖÆ×÷ </a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://ent.163.com/11/0408/08/713U93U000031GVS.html">¡¶ÀϹ«¿´ÄãµÄ¡·ÍÆÃ÷ÐÇר³¡ ÀÖ¼ÎÓëÓ«Ä»Çé¹ýÕÐ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/08/713S8H0U00031GVS.html">Ò»Öܸ۾çÊÕÊÓ£ºÉîÒ¹¹í¾ç¡¶ÆߺŲî¹Ý¡·´óÈÈ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/01/7134DU3A00032DGD.html">¡¶·Ç³Ï¡·±±¾©Ä¼¼Î±ö </a> <a target="_blank" href="httpdisabled://ent.163.com/11/0408/06/713KTRCS00032DGD.html">¡¶ÃÎÏëÐã¡·¸ßƵ¹ã¸æÒýÕùÒé</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/04/713F4HFV00031H2L.html">ÕÔ±¾É½½«ÅÄ"¶«±±ºÚµÀ·çÔÆ"</a> <a target="_blank" href="httpdisabled://ent.163.com/11/0408/06/713N005000032DGD.html">¡¶ÄÜÈË·ëÌì¹ó¡·½«²¥ </a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/05/713I9H1N00032DGD.html">ºþÄÏÎÀÊÓÍƺìÉ«Çà´º¼¾</a> <a target="_blank" href="httpdisabled://ent.163.com/11/0408/05/713I2OKR00032DGD.html">»ÆÖ¾ÖÒ¡¶¼Ò³£²Ë¡·ÑݺÃÄÐÈË</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/03/713ANRVL00032DGD.html">×ÛÒÕ½èÊÆÓ°ÊÓ¾ç³É·ç³±</a> <a target="_blank" href="httpdisabled://ent.163.com/11/0408/05/713I5HS400032DGD.html">¡¶·Ç³Ï¡·¸ðÏþÀڳɹ¦Ç£ÊÖ </a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://ent.163.com/special/jianfenghuathz/"><em class='cBlack fB'>¹Û¾ç</em></a> |<a target="_blank" href="httpdisabled://ent.163.com/special/shbfsgj/">¡¶²»·ÖÊÖ¡·Ì¨´Ê¾È³¡</a> |<a target="_blank" href="httpdisabled://ent.163.com/special/fscq/fscqgj.html">¡¶·çÉù¡·Ç°10¼¯¾«²Ê</a></li>
- <li><a href="httpdisabled://ent.163.com/special/zhuanyejieduhuiz/"><em class='cBlack fB'>רҵ½â¶Á</em></a> |<a target="_blank" href="httpdisabled://ent.163.com/special/fscqcb/">¡¶·çÉù¡·´©°ï</a> | <a target="_blank" href="httpdisabled://ent.163.com/11/0329/17/70B4E9OE00034KRR.html">¡¶·çÉù¡·Ð̾ßÊ·¿¼</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://ent.163.com/11/0408/07/713PBK2E00031H0O.html"><img src="../img4.cache.netease.com/ent/2011/4/8/201104080804383b8a7.jpg" alt="ÖÁÉÏÀøºÏиèMVÊײ¥" title="ÖÁÉÏÀøºÏиèMVÊײ¥" height="90" width="120" /><cite>ÖÁÉÏÀøºÏиèMVÊײ¥</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://ent.163.com/11/0408/04/713G2HP300031H0O.html">Ã÷Äê¸ñÀ³ÃÀ½±Ï¼õÉÙ31¸ö</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://ent.163.com/11/0408/08/713SH5AN00031H0O.html">"¹â»ÔËêÔÂ"±±¾©Ê×ÑÝÈ·¶¨ÈÕÆÚ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/07/713QMUBK00031H0O.html">»ªÓïÒôÀÖ´«Ã½´ó½±½ÒÏþÌáÃûÃûµ¥</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/07/713QJU7U00031H0O.html">ºÎÔÏÊ«×ÔÆØÐÔÈ¡Ïò¿ª·Å(ͼ)</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/07/713PORKJ00031H0O.html"><em class='I_M_'>¼Í¼ÑËÉ¡¶½ðÓãµÄÑÛÀá¡·Êײ¥</em></a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://ent.163.com/11/0407/19/712GLFKS00031H0O.html"><em class=' I_V_'>Ïô»ÍÆæ:¡¶Ã»ÄÇô¼òµ¥¡·²»¿É¸´ÖÆ</em></a> <a target="_blank" href="httpdisabled://ent.163.com/11/0407/15/7120Q4G5000334I9.html"><em class=' I_V_'>ÐíáÔÁÄеú</em></a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/02/71394QIE00032DGD.html">ÍõÁ¦ºêÎåÔ¹ãÖÝ¿ª³ª MUSIC MANÑݳª»á×îºóÒ»Õ¾</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/05/713I9H0T00032DGD.html">À¿ªÆôÐÂÒ»ÂÖѲÑÝ ÎåÒ»À´ÉϺ£³ª¡¶´«Ææ¡·</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/01/7135OVCO00032DGD.html">½Ü¿ËÑ·Ò½Éú·ñÈϹýʧɱÈË ³ÆMJÒò²ÆÕþΣ»ú×Ôɱ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/01/7135OROS00032DGD.html">Áõϧ¾ý·ñÈÏÆ­È¡·ÛË¿Ç®²ÆÍæÏûʧ ¾Ü¾ø»ØÓ¦´«ÑÔ</a></li>
- <li><a href="httpdisabled://ent.163.com/11/0408/01/7135OROR00032DGD.html">붫Èý¶ÈÎü¶¾¾Ü¾ø²É·Ã ³ªÆ¬¹«Ë¾È¡Ïû·¢²¼»á</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://ent.163.com/special/zhuanyejieduhuiz/"><em class='cBlack fB'>רҵ½â¶Á</em></a> | <a href="httpdisabled://ent.163.com/special/2011kuainvchuangxin/">2011¿ìÅ®Îå´ó´´ÐÂ</a> <a href="httpdisabled://ent.163.com/special/ynbbdlss/">È¥Ô½ÄÏ¿´±«²ªµÏÂ×</a></li>
- <li><a href="httpdisabled://ent.163.com/special/hybdhz/"><em class='cBlack fB'>ÐÐÒµ±¨µÀ</em></a> | <a href="httpdisabled://ent.163.com/special/yinyuerenweiquan/">άȨսÖÐÒôÀÖ½çÊÇ·ñ±ÈÎÄѧ½çÈõÊÆ</a></li>
- </ul>
- </div>
- </div>
- </div>
-<div class="gg gg-h100"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column360x100&amp;location=2.html" width="360" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-</div>
- </div>
- </div>
- <div class="area-sub">
- <div id="gy" class="mod">
- <div class="hd clearfix">
- <h2 class="mod-title">ÍøÒ×¹«Ë¾ÐÂÎÅ</h2>
- </div>
- <div class="bd">
- <ul class="mod-list sub-list dotline">
- <li class="title"><a href="httpdisabled://tech.163.com/11/0401/17/70IS705000094JEO.html">ÍøÒ×΢²©·¢²¼°Ë°æÒƶ¯¿Í»§¶Ë</a></li>
- <li><a href="httpdisabled://tech.163.com/11/0401/11/70I4EANC00094JEO.html">¡¶Ù»Å®ÓĻ꡷4ÔÂ22ÈÕÄÚ²â</a></li>
- <li><a href="httpdisabled://tech.163.com/11/0401/17/70IP5SQ000094JEO.html">ÍøÒ×ÓÊÏä13ÖÜÄêÇìµäÍêÃÀÂäÄ»</a></li>
- <li><a href="httpdisabled://tech.163.com/11/0325/17/700QC0T600094JEO.html">ÍøÒ×ÓÊÏä2G¸½¼þÉÏ´«ÌáËÙ3±¶</a></li>
- <li><a href="httpdisabled://tech.163.com/11/0331/12/70FLRISG00094JEO.html">¶¡Àڼν±ÆóÒµÓÊÓÅÐã¾­ÏúÉÌ</a></li>
- <li><a href="httpdisabled://tech.163.com/11/0329/10/70AB9A1P00094JEO.html">ÐǼÊÕù°Ô2´ó½¿ª·ÅÃâ·Ñ¹«²â</a></li>
- </ul>
- <ul class="mod-list sub-list">
- <li><a href="httpdisabled://media.163.com/">[´«Ã½]</a> <a target="_blank" href="httpdisabled://media.163.com/11/0408/10/7142T8V800762H91.html">ÐÂÎÅÈÈÒé¾Ü¾ø¼Ù±¨µÀ</a></li>
- <li><a href="httpdisabled://media.163.com/11/0408/10/71434VLS00762H91.html">Õ½ÕùÏÖ³¡Öйú¼ÇÕß²»È±Ï¯</a></li>
- <li><a href="httpdisabled://media.163.com/11/0408/10/7142VL1R00762H91.html">΢²©ÀļÓVÖÂÍøÃñÐÅÈζÈϽµ</a></li>
- <li><a href="httpdisabled://gongyi.163.com/">[¹«Òæ]</a> <a href="httpdisabled://gongyi.163.com/11/0401/18/70ISJFF500933KC8.html">ÓéÀÖÐű¨Óн±µ÷²é</a></li>
- <li><a href="httpdisabled://gongyi.163.com/special/2011ditanditie/">2011µÍ̼µØÌúÉú»îÓн±µ÷²é</a></li>
- </ul>
- </div>
- </div>
-<div class="gg gg-h180"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=logo190x180&amp;location=1.html" width="190" height="180" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe></div>
- </div>
-</div>
-<!-- end -->
-<!-- money & auto -->
-<div class="area">
- <div class="area-main">
- <div class="main-col-10">
- <div id="money" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-10 clearfix">
- <span class="tab-u current"><a href="httpdisabled://money.163.com/">²Æ¾­</a></span>
- <span class="tab-u"><a href="httpdisabled://money.163.com/stock/">¹ÉƱ</a></span>
- <span class="tab-u"><a href="httpdisabled://biz.163.com/">ÉÌÒµ</a></span>
- <span class="tab-u"><a href="httpdisabled://money.163.com/licai/">Àí²Æ</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 clearfix">
-
- <div class="mod-img main-img">
- <a href="httpdisabled://money.163.com/photoview/0HH40025/1431.html"><img src="../img4.cache.netease.com/stock/2011/4/8/20110408183832fdfa0.png" alt="ÍøÒײƾ­Ò»ÖÜͼƬ¾«Ñ¡" title="ÍøÒײƾ­Ò»ÖÜͼƬ¾«Ñ¡" height="90" width="120" /><cite>ÍøÒײƾ­Ò»ÖÜͼƬ¾«Ñ¡</cite></a>
-</div>
-
- <h3 class="main-title"><a href="httpdisabled://money.163.com/special/oilcompany/">ÈýÓÍÆó¸ß²ãÉú±ä:¸µ³ÉÓñÕƶæÖÐʯ»¯</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://money.163.com/11/0408/10/7143PG4L002526O3.html">ÉϺ£µÏÊ¿ÄὫ½¨È«Çò×î¸ß×î´ó³Ç±¤</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/02/7138637T00253B0H.html">¹úÎñԺȦ¶¨16Ê¡¶½²éµØ·½Â¥Êе÷¿Ø</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/05/713HN73100253B0H.html">¹ú¼ÊÓͼÛ7ÈÕÍ»ÆÆ110ÃÀÔª ÔÙ´´Ð¸ß</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/02/7139D27200253B0H.html">±¦¸Öϵ÷5Ô¸ּÛ</a> <a target="_blank" href="httpdisabled://money.163.com/11/0408/06/713MUP7N002524SO.html">ÒµÄÚ³§ÉÌ»ò¸ú½ø</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://money.163.com/11/0408/06/713KEJ0600253B0H.html">·¢¸Äί£º¹ú¼Ò¶Ô¹ú¼ÊÓͼ۽øÒ»²½ÉÏÕÇÒÑÖƶ¨Ô¤°¸</a> <a target="_blank" href="httpdisabled://money.163.com/special/oilprice0406/">רÌâ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/09/713VJK5S00253B0H.html">Õã½­ÒÚÍò¸»½ãÎâÓ¢¶þÉóÈÏ×ï·Ç·¨Îü´æ</a> <a target="_blank" href="httpdisabled://money.163.com/11/0408/09/713VJMM600253B0H.html">Í¥Íâ½Ò·¢Òý³öÎÑ°¸</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/04/713ENNS200253B0H.html">ÖØÇì11ÒÚ»ÝÅ©Éç±£½ðÔâ½ØÁô »ù²ã¸É²¿¼¯Ì帯°ÜÏÖÏóÍ»³ö</a></li>
- <li><a href="httpdisabled://money.163.com/11/0407/23/712T6DV500253B0H.html">Ìì½òÎĽ»ËùÄÚÄ»£ºÉñÃØ80ºó¹É¶«¾ªÏÖÄ»ºó²Ù¿ØȺ</a> <a target="_blank" href="httpdisabled://money.163.com/special/tjartwork/"> רÌâ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0407/20/712HSFCS00252G50.html">±±Ê¦´ó½ÌÊÚ¶­·ª»ØÓ¦¡°4000Íò¡±Ö®Õù£ºÌ¸Ç®²¢²»ÒâζÃÄË×</a></li>
- <li><a href="httpdisabled://money.163.com/11/0407/18/712C24F3002534NU.html">±±¾©µØ²úÖнéÐû³ÆÄÜ°ìÄÉË°Ö¤Ã÷±»²é´¦</a> <a target="_blank" href="httpdisabled://money.163.com/11/0407/19/712EP0UR00253B0H.html">¹úÎñԺרÏ²é</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://money.163.com/" class="fB attitude">²Æ¾­</a> | <a href="httpdisabled://money.163.com/focus/"><em class='fB'>ÍøÒ×½â¶Á</em></a> | <a target="_blank" href="httpdisabled://money.163.com/special/focus271/">³ÇÊÐĹµØ²»¸Ã¹ý¶ÈÊг¡»¯</a></li>
- <li><a href="httpdisabled://money.163.com/news/"><em class='cBlack fB'>ÍøÒ×µÚÒ»Ïß</em></a> | <a target="_blank" href="httpdisabled://money.163.com/special/news75/"><em class='cBlack'>¾©ÏÞ¹ºÁîÄ¥ºÏϸ½Ú ¿ª·¢É̶ڷ¿±¸Õ½Ï°ëÄê</em></a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://money.163.com/11/0408/02/71386IL500253B0H.html"><img src="../img4.cache.netease.com/stock/2011/3/1/201103010846298829b.jpg" alt="ÂÞ½Ü˹:»Æ½ð³å»÷2000$" title="ÂÞ½Ü˹:»Æ½ð³å»÷2000$" height="90" width="120" /><cite>ÂÞ½Ü˹:»Æ½ð³å»÷2000$</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://money.163.com/stock/">ÊÕÆÀ£º»¦Ö¸ËõÁ¿ÕÇ0.74%ËÄÁ¬Ñô</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://money.163.com/11/0408/02/71376E0N00253B0H.html">Å·ÖÞÑëÐÐÈýÄêÀ´Ê׶ȼÓÏ¢</a> <a target="_blank" href="httpdisabled://money.163.com/11/0408/02/7139D6I500253B0H.html">ÀûºÃA¹É</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/05/713HN73100253B0H.html">¹ú¼ÊÓͼÛÔÙ´´Ð¸ß</a> <a target="_blank" href="httpdisabled://money.163.com/11/0408/05/713GMQAC00254ITK.html">ÆÚ½ðÁ¬´´Ð¸ß</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/16/714N86G400254IU4.html">»¦Ö¸ËÄÁ¬Ñô 108ÒÚ×ʽð·äÓµÈ볡</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/02/7139CUD800253B0H.html">ÉϺ£µÏÊ¿Äá½ñÈÕÆÆÍÁ¶¯¹¤</a> <a target="_blank" href="httpdisabled://money.163.com/10/1115/07/6LH00STQ00253EOS.html">Ͷ×ʲßÂÔ</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://money.163.com/11/0408/11/7146IFIG00253B0H.html">°Í·ÆÌؽâÊ͵±ÄêͶÖÐʯÓÍ:ËûÃdzÐŵÀûÈó45%·Öºì </a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/02/71376LJR00253B0H.html">ɳ¸Ö¹É·ÝÍ£ÅƽüÒ»Äê</a> <a target="_blank" href="httpdisabled://money.163.com/11/0408/09/7140B64P00254IU5.html">½ñ»Ö¸´ÉÏÊпªÅÌÕǽü100%</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/20/71559J6E00253B0H.html">½¹Ì¿ÆÚ»õ4ÔÂ15ÈÕÉÏÊн»Ò× Ê×ÈÕÕǵøÍ£°å8%</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/02/71376ABD00253B0H.html">¹úÎñÔº¶½²é16Ê¡µØ²úµ÷¿Ø</a> <a target="_blank" href="httpdisabled://money.163.com/11/0408/02/7138637T00253B0H.html">»ò¾ÀÆ«µØ·½µ÷¿ØÖ¸±ê</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/07/713O2VBR00253B0H.html">Ë®ÄàÒµÒµ¼¨´ó·ùÔö³¤</a> <a target="_blank" href="httpdisabled://money.163.com/11/0408/02/7139CI7D00253B0H.html">ά³Ö¸ß¾°Æø</a> <a target="_blank" href="httpdisabled://money.163.com/11/0408/02/71376S3E00253B0H.html">»ú¹¹Ë³ÊÆÅ×ÊÛ</a></li>
- <li><a href="httpdisabled://money.163.com/special/2010nianbao/">[Ä걨]</a> <a target="_blank" href="httpdisabled://money.163.com/11/0408/19/7150QKGR00254L67.html">ÖÐÐÅ֤ȯȥÄê¾»Àû113ÒÚÔª</a> <a target="_blank" href="httpdisabled://money.163.com/11/0408/18/71504JH800253B0H.html">±±¾©ÒøÐо»Àû68ÒÚÔª</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://money.163.com/stock/"><em class='cBlack fB'>Êг¡Èȵã</em></a> | <a href="httpdisabled://money.163.com/11/0408/02/71385HGS00253B0H.html">ÖÜÆڹɻ𱬠»ú¹¹·ê¸ß¼õ³Ö</a> <a href="httpdisabled://money.163.com/11/0408/02/7139DI3S00253B0H.html">À¶³ï¹ÉÂÖ¶¯¼ÌÐø</a></li>
- <li><a href="httpdisabled://money.163.com/blog/"><em class='cBlack fB'>°Ù¼ÒÂÛÊÐ</em></a> | <a target="_blank" href="httpdisabled://money.163.com/11/0408/02/7139CI7C00253B0H.html">Ê®»ú¹¹£ºÓÐЧվÉÏ3000µã ÏòÉÏ¿Õ¼ä´ò¿ª</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://money.163.com/11/0408/09/713VLIUP00253B0H.html"><img src="../img4.cache.netease.com/stock/2011/4/8/201104080929109dd6d.png" alt="ÐìСƽ£ºÃ¤Í¶µ½¶¯Õæ¸ñ" title="ÐìСƽ£ºÃ¤Í¶µ½¶¯Õæ¸ñ" height="90" width="120" /><cite>ÐìСƽ£ºÃ¤Í¶µ½¶¯Õæ¸ñ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://money.163.com/special/zgfneidou/">Õ湦·ò¼àÊÂÆðË̴߲ï±ê</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://money.163.com/11/0408/07/713OA76Q00253B0H.html">ÎÖ¶ûÂêÕýʽ½ø¾üÖйúÉÌÒµµØ²ú</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/01/7132TNP000253B0H.html">±¼³Û¡°Ë«ÏÞ¡±Áî¾­ÏúÉÌÏÝÁ½ÄÑ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/01/7132TS2I00253B0H.html">337ÒÚÃÀÔª HTCÊÐÖµÊ׳¬Åµ»ùÑÇ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/01/7132TJ0500253B0H.html">·ëÂØÒþÉíÄ»ºó רע´óÍòͨ×ʱ¾ÔË×÷</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://money.163.com/11/0408/07/713PJBIV00251LK6.html">Æ滢360¸ßÊÐÓ¯ÂÊÖ®ÀÛ ¿ª·Åƽ̨¶µÊÛÁ÷Á¿</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/08/713R58M500253B0H.html">²¨Òô¹«Ë¾¾ÍÆä737ÐÍ·É»ú³öÏÖÁÑ·ì×ö³ö½âÊÍ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/07/713P24H800251LJJ.html">ËÄ´¨³¤ºç¾»Àû2.92ÒÚ ÄÑÑÚÏÖ½ðÁ÷Òþ»¼ÖØÖØ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/09/713VJJMT00253B0H.html">ÖйúÆóÒµÐÅÏ¢°²È«Æð²½£ºÊ×ϯÒþ˽¹ÙºÎʱÂäµØ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/08/713SB71S00252FPI.html">ÀîÕ×»ù10ÒÚÔö³Öºã»ùµØ²ú ÈϹºÖ¤³É½»Ôö³¤9±¶</a></li>
- <li><a href="httpdisabled://t.163.com/rank/daren/1293764950255">[΢²©]</a> <a href="httpdisabled://t.163.com/xiabin">¾­¼Ãѧ¼ÒÏıó</a> <a href="httpdisabled://money.163.com/special/zgjrzl2020/">ÐÂÊ顶Öйú½ðÈÚÕ½ÂÔ£º2020¡·</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://money.163.com/interview/"><em class='cBlack fB'>²Æ¾­»á¿ÍÌü</em></a> | <a href="httpdisabled://money.163.com/special/sunzhenyao/">º£»Ô¼¯ÍÅËïÕñÒ«£ºÖйúÍâ°ü´óÓпÉΪ</a></li>
- <li><a href="httpdisabled://money.163.com/economist/"><em class='cBlack fB'>Òâ¼ûÖйú</em></a> | <a href="httpdisabled://money.163.com/special/zfzhaoxiao/">ÕÔÏþ£ºÖйúȱ·¦ÏÖ´úÍÁµØ²úȨÖƶÈ</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://money.163.com/11/0408/08/713TFEA100253B0H.html"><img src="../img4.cache.netease.com/stock/2011/4/8/20110408121505602ea.jpg" alt="±±¾©½ðÊμ۸ñÈ«ÃæÉϵ÷" title="±±¾©½ðÊμ۸ñÈ«ÃæÉϵ÷" height="90" width="120" /><cite>±±¾©½ðÊμ۸ñÈ«ÃæÉϵ÷</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://money.163.com/11/0408/09/713UQTJ000253B0H.html">½ÒÃØÀí²Æ²úÆ·ÊÕÒæÈçºÎ¡°±»Ëã¼Æ¡±</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://money.163.com/11/0408/05/713JVDEB00253B0H.html">ÉÏÖÜ18¿îÀí²Æ²úÆ·ÅÜÓ®CPI</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/09/7140FBCV00252V0H.html">Ö½²¬½ðͶ×ÊÊܳè ʵÎﲬ½ðÓöÀä</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/09/7141FDSJ00252V0H.html">¶ÌÆÚÒâÍâÏÕÎÞÓÌÔ¥ÆÚ Í˱£ÓÐËðʧ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/11/7147UDRA00252V0H.html">ÍòÄÜÏÕÅÜÊ䶨´æ ¶à¼Ò±£ÏÕ¹«Ë¾Í£ÊÛ</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://money.163.com/11/0409/00/715JD8ET00253B0H.html" data-t-h="00">½ð¼Û´´Ð¸ßÉϺ£Ïû·ÑÕß×·ÕÇ Ò»ÍíÊÛ³ö°Ù¸ù½ðÌõ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/04/713GFH8C00253B0H.html">Àí²Æʦ½¨Òé¼ÓÏ¢Ô¤ÆÚÏÂÓÅÏÈ¿¼ÂÇÈý¸öÔ¶¨´æ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/09/713VHFQ500253B0H.html">»õ»ùÊÕÒæË®ÕÇ´¬¸ß ´æ»îÆÚÒ»Ô²»ÈçÂò»õ»ùÒ»ÐÇÆÚ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/03/713A9L7900253B0H.html">¹ú¼Ê´ó×ÚÉÌÆ·ÃÍÕÇ ¹Ò¹³Àí²Æ²úÆ·Ô¤ÆÚÊÕÒæ´ï16%</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/10/7143K85C00252V0H.html">ÔÝÍ£¶àÄê·¿´ûÏÕÇÄÈ»»Ø³± ÒøÐÐ×øµØ½Ð¼Û°ÔÆø×ã</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/09/7141MHER00252V0H.html">°×Òø·çÍ·Ô¶¸Ç»Æ½ð Ëijɳ´½ð¿Íתս°×Òø</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/10/7144UQSS00252V0H.html">Ƶ·±×ª´æ²»»®Ëã ת´æ¶à¡°ÀÛ»µ¡±ÒøÐÐϵͳ</a></li>
- <li><a href="httpdisabled://money.163.com/11/0408/09/7141GAII00253B0H.html">3ÔÂÀí²Æ²úÆ·ÊÕÒæÆÕÕÇ 4ÔÂÓÐÍû½øÒ»²½×߸ß</a></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- <div class="main-col-9">
- <div id="auto" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-9 clearfix">
- <span class="tab-u current"><a href="httpdisabled://auto.163.com/">Æû³µ</a></span>
- <span class="tab-u"><a href="httpdisabled://auto.163.com/buy/">гµµ¼¹º</a></span>
- <span class="tab-u"><a href="httpdisabled://auto.163.com/depreciate/">³µÊÐÐÐÇé</a></span>
- <span class="tab-u"><a href="httpdisabled://club.auto.163.com/">Æû³µÉçÇø</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://auto.163.com/11/0408/07/713PU5JD00084P03.html"><img src="../img4.cache.netease.com/auto/2011/4/8/20110408091859b1da7.jpg" alt="×î±ãÒ˰µϽ«ÔÚ»ªÁÁÏà" title="×î±ãÒ˰µϽ«ÔÚ»ªÁÁÏà" height="90" width="120" /><cite>×î±ãÒ˰µϽ«ÔÚ»ªÁÁÏà</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://auto.163.com/special/sonata8/">°Ë´úË÷ÄÉËþÉÏÊÐ ÊÛ16.69ÍòÆð</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://auto.163.com/11/0407/16/7124DROB00082H5Q.html">ÊÛ5.99ÍòÔªÆð ±ÈÑǵÏG3RÉÏÊÐ</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0407/10/711GM44000081G9U.html">ºóÄê¹ú²ú »ª³¿±¦Âí»ì¶¯5ϵÆعâ</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0408/14/714H566200084MDJ.html">2011µÚ1ÅúÅöײ½á¹û:×ÔÖ÷³¬ºÏ×Ê</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0408/09/7140OUOI00084P03.html">ºÜСÇÉ ±¼³ÛA¼¶¸ÅÄî³µ¼´½«Ê×·¢</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://auto.163.com/">[гµ]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/09/713V9DFA00081S9K.html">±È;¹Û»¹Ð¡:°ÂµÏQ3Æعâ Å·ÖÞ27.6ÍòÔªÆðÊÛ</a></li>
- <li><a href="httpdisabled://club.auto.163.com/">[ÈÈÌû]</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_01m0/205676175.html">ÁÉBÅÆ×ӵijµÄãÉ˲»Æð</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_01m0/205675144.html">ÕâÊÇÎÒ¼û¹ý×îNµÄÍ£³µ</a></li>
- <li><a href="httpdisabled://auto.163.com/">[ÐÂÎÅ]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/07/713PG9S800084JTJ.html">·¢¸Äί³ÆÒѶÔÓͼÛÖƶ¨Ô¤°¸ ²»»áÈÎÓÉÉÏÕÇ</a></li>
- <li><a href="httpdisabled://auto.163.com/">[гµ]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/07/713O55VI00084IJ9.html">мÑÀÖ1.6LµÇ½Öйú</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/07/713O57K400084IJ9.html">2011¿îÐÂÁçÑòÉÏÊÐ</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0408/07/713QE4QA000816HU.html">[ÊÔ¼Ý]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/07/713QE4QA000816HU.html">²»¸øÖÐʯÓÍÃæ×Ó ÀÍ˹À³Ë¹ÍÆÁãÅŷŵ綯³µ</a></li>
- <li><a href="httpdisabled://auto.163.com/">[½µ¼Û]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0407/22/712Q1O0M00083KOO.html">°ÂµÏA5½µ4Íò5</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0407/21/712N8OKG00083KOO.html">Ììô¥½µ2Íò1</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0407/21/712M8DV300083KOU.html">Ú©¸èMDX½µ13Íò</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://club.auto.163.com/"><em class='fB'>ÈÈÌû</em></a> | <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_aaac/205598271.html">±»ÏÆ·­?¾¯³µµ×³¯Ìì</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_sichuan/205661670.html">³¬Å£ÆÕÉ£¸Ä×°³µ</a></li>
- <li><a href="httpdisabled://auto.163.com/"><em class='fB'>»î¶¯</em></a> | <a target="_blank" href="httpdisabled://auto.163.com/11/0328/09/707M12Q900084K9A.html">Ìîµ÷²éÓ®Åɿ˱Ê</a> <a target="_blank" href="httpdisabled://t.163.com/zt/auto/autogift">¹Ø×¢¹Ù²©ÇÀ˹°Í³³µÄ£</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://auto.163.com/11/0408/07/713QE4QA000816HU.html"><img src="../img4.cache.netease.com/auto/2011/4/8/201104080930543aaa8.jpg" alt="ÊÔ¼ÝÀÍ˹À³Ë¹102EX" title="ÊÔ¼ÝÀÍ˹À³Ë¹102EX" height="90" width="120" /><cite>ÊÔ¼ÝÀÍ˹À³Ë¹102EX</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://auto.163.com/special/shanghai-chezhan/">ÉϺ£³µÕ¹12¿îÈÈÃÅСÐͳµÅ̵ã</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://auto.163.com/special/cyb130/">¹º40-60ÍòÔªµÄÓÐÃæ×ÓÉÌÎñ½Î³µ</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0408/09/713V9DFA00081S9K.html">°ÂµÏQ3Å·ÖÞÆð²½¼Û27.6ÍòÔªÆð</a></li>
- <li><a href="httpdisabled://auto.163.com/special/sonata8/">±±¾©ÏÖ´úÐÂË÷ÄÉËþÉè¼Æ½âÎö</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0407/10/711GM44000081G9U.html">»ª³¿±¦Âí²åµçʽ»ì¶¯5ϵÆعâ</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://auto.163.com/special/shanghai-chezhan/">[³µÕ¹]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/09/7140OUOI00084P03.html">A¼¶¸ÅÄȫÇòÊ×·¢ ÉϺ£³µÕ¹±¼³ÛÕóÈÝÆعâ</a></li>
- <li><a href="httpdisabled://auto.163.com/special/shanghai-chezhan/">[³µÕ¹]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/09/713V0U3400084P03.html">ÄÉÖǽÝneoraÉϺ£Ê×·¢</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/08/713TKAJ400084IKF.html">¹ã·áMPVÒÝÖ³µÕ¹·¢²¼</a></li>
- <li><a href="httpdisabled://auto.163.com/">[µ¼¹º]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/08/713TD2KH00084IKF.html">°ÚÍÑÒ¡ºÅÏÞÐÐÖ®¿à ±±¾©Èý¿îµç¶¯Æû³µÍƼö</a></li>
- <li><a href="httpdisabled://auto.163.com/">[µ¼¹º]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/07/713OL5KG00084IK5.html">´ºÅ¯»¨¿ª 9¿îÊʺϼÒ̤ͥÇོÓγµÐÍÍƼö</a></li>
- <li><a href="httpdisabled://auto.163.com/">[гµ]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/07/713OL49A00084IK5.html">м׿dz泵չÊ×·¢</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0408/07/713OL48600084IK5.html">ÐÂʤ´ï»ò¹ú²úÊÛ20ÍòÆð</a></li>
- <li><a href="httpdisabled://auto.163.com/">[гµ]</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0407/11/711KQ9B500082H5S.html">±ÈÑǵÏS6½«5ÔÂÉÏÊÐ</a> <a target="_blank" href="httpdisabled://auto.163.com/11/0407/10/711IHA9N00082H5S.html">¹ãÆû¼ª°Â°ÂÐùG5½«ÏÂÏß</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://auto.163.com/test/"><em class='fB'>ÍøÒ×ÊÔ¼Ý</em></a> | <a target="_blank" href="httpdisabled://auto.163.com/special/touareghybrid/">µÍ̼¸ßÄÜ ÊÔ¼ÝÐÂ;Èñ»ìºÏ¶¯Á¦SUV</a></li>
- <li><a href="httpdisabled://auto.163.com/special/cxshhz/"><em class='fB'>³µÐÍÊ·»°</em></a> | <a target="_blank" href="httpdisabled://auto.163.com/11/0406/23/710A1ST500081GDM.html">ÀúÊ·Õù¶áÕ½ ÆÊÎöÉϺ£´óÖÚÈ«ÐÂÅÁÈøÌØ</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://auto.163.com/11/0407/13/711S5I1E00083QQV.html"><img src="../img4.cache.netease.com/photo/0008/2010-01-30/120x90_5U980MMS294H0008.JPG" alt="Ò»Æû±¼ÌÚB70ÓÅ»Ý1.2Íò" title="Ò»Æû±¼ÌÚB70ÓÅ»Ý1.2Íò" height="90" width="120" /><cite>Ò»Æû±¼ÌÚB70ÓÅ»Ý1.2Íò</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://auto.163.com/11/0407/13/711SL4K900083QQV.html">¶«·çÈÕ²úÆæ¿¥×î¸ßÓŻݴï1.8Íò</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://auto.163.com/11/0407/18/712CFFGD00083KOO.html">ÑÇè¡Ê©ÄÍÔóACS7ÏÖ³µµ½µê</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0407/21/712M8DV300083KOU.html">2011¿îÚ©¸èMDXȫϵֱ½µ13Íò</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0407/21/712MIG9A00083KOU.html">2010¿î±¼³ÛA180Ö±½µ7.3ÍòÔª</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0407/19/712FK6HL00083KOU.html">2011¿î±¦Âí3ϵ¸ßÅäÕûÌå½µ4Íò</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://auto.163.com/11/0407/21/712LSICE00083KOO.html">¸£ÌØÈñ½çÌáÏÖ³µ×î¸ß¼Ó¼Û5Íò</a> | <a target="_blank" href="httpdisabled://auto.163.com/11/0407/19/712GJILM00083KOU.html">´óÖÚÐÂ;°²½µ5000Ôª</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0407/22/712Q1O0M00083KOO.html">°ÂµÏA5ȫϵ×î¸ß½µ4.5Íò</a> | <a target="_blank" href="httpdisabled://auto.163.com/11/0407/18/712DUJ6P00083KOO.html">ººÀ¼´ï×î¸ßÓÅ»Ý1.8Íò</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0407/19/712F18UQ00083KOO.html">±¼³ÛE300LÖ±½µ½ü11ÍòÔª</a> | <a target="_blank" href="httpdisabled://auto.163.com/11/0407/13/711RT6AQ00083QQV.html">¸èʫͼ×î¸ßÓÅ»Ý1.5Íò</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0407/18/712CNQ9E00083KOO.html">´óÖڽݴï×î¸ßÓÅ»Ý4ǧ</a> | <a target="_blank" href="httpdisabled://auto.163.com/11/0407/20/712L3K3A00083KOU.html">Ñ©·ðÀ¼¾°³ÌÕûÌåÓÅ»Ý1.6Íò</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0407/18/712D9B5B00083KOO.html">·æ·¶ÓÅ»Ý1.1Íò</a> | <a target="_blank" href="httpdisabled://auto.163.com/11/0408/08/713TLQ4Q00084IJT.html">ÈÙÍþ550ÊÀ²©°æMT³µÐÍÓÅ»Ý1Íò</a></li>
- <li><a href="httpdisabled://auto.163.com/11/0407/11/711L1VMA00083QQV.html">ÐùÒÝ×î¸ß½µ6000Ôª</a> | <a target="_blank" href="httpdisabled://auto.163.com/11/0408/08/713T7QNK00084IJT.html">¾§Èñȫϵ88ÕÛ ×î¸ßÓÅ»ÝÍòÔª</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://auto.163.com/special/wysjhz/"><em class='fB'>ÍøÒ×ÊÔ¼Ý</em></a> | <a target="_blank" href="httpdisabled://auto.163.com/special/peugeot_3008/">¿ç½çÏÈ·æ ÊÔ¼Ý2011¿î±êÖÂ3008(¶àͼ)</a></li>
- <li><a href="httpdisabled://auto.163.com/special/rcpkhz/"><em class='fB'>ÈȳµPK̨</em></a> | <a target="_blank" href="httpdisabled://auto.163.com/special/x3pkglk/">ºÀ»ª³ÇÊÐSUV¶Ô¾ö ±¦ÂíX3 vs ±¼³ÛGLK</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://auto.163.com/special/show_girl/"><img src="../img3.cache.netease.com/auto/2011/3/30/20110330215354a8c7a.jpg" alt="ÉϺ£³µÕ¹ÃÀÅ®Ö÷²¥ÆÀÑ¡" title="ÉϺ£³µÕ¹ÃÀÅ®Ö÷²¥ÆÀÑ¡" height="90" width="120" /><cite>ÉϺ£³µÕ¹ÃÀÅ®Ö÷²¥ÆÀÑ¡</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://club.auto.163.com/bbs/auto_haiwai/205753679.html">µØÕðÖÐÓÎÀÀÈ«ÈÕ±¾×îÇ¿Âô³µµê</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://auto.163.com/special/yushengkanchetuan/">º¼ÖÝ:Óн±ÊÔ¼Ý10ÍòÔª×ÔÖ÷SUV</a></li>
- <li><a href="httpdisabled://club.auto.163.com/bbs/qingdao/205377190.html">Çൺ¸£ÈðµÏ³µÓÑÕª²ÝÝ®ÕÙ¼¯ÖÐ</a></li>
- <li><a href="httpdisabled://club.auto.163.com/bbs/auto_aaac/204446417.html">3Ô¸ÇÂ¥ÌùÆÀÑ¡ °ÙÔªÓÍ¿¨µÈÄãÄÃ</a></li>
- <li><a href="httpdisabled://club.auto.163.com/bbs/auto_bbtx/203993156.html">"½ÌÄãʹÓñ£ÏÕ" ²ÎÓëÓн± </a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://club.auto.163.com/">[ÓͼÛ]</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_01m0/205427558.html">Ô¹ÓͼÛÕÇ?ÔâÓö¼ÓÁÓÖÊÓ͸ü±¯¾ç</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_01m0/205427558.html">ºÜÅ£µÄ³µÌû</a></li>
- <li><a href="httpdisabled://club.auto.163.com/">[ÉϺ£³µÕ¹]</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_02z0/205707321.html">ËÄ´óŮħ(Ä£)?Æغ£Âí³µÄ£ÃÀͼ</a></li>
- <li><a href="httpdisabled://club.auto.163.com/">[³µÓÑ]</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_01lb/205596059.html">ÂÖÌ¥ÉÏÉ« ÈýÃÀÅ®ÆëÉÏÕó°ïæ(¾ø¶ÔÕæÈË°æ)</a></li>
- <li><a href="httpdisabled://club.auto.163.com/">[×ÔÆØ]</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/qingdao/205375530.html">ÆðÑǸ£ÈðµÏؤ°æ°µÓ£ºì´¦Å®Ìù ¶àͼ·ÅËÍ</a></li>
- <li><a href="httpdisabled://club.auto.163.com/">[Ìùͼ]</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_sichuan/205661670.html">ÆÕÉ£±©¸Ä³ÉÎ޵иÖÅÚ </a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_aaac/205598271.html">¾¯³µÊÇÈçºÎ½Å³¯ÌìµÄ</a></li>
- <li><a href="httpdisabled://club.auto.163.com/">[½ÖÅÄ]</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_haiwai/205611078.html">LP700ºÚ°×Ë«É·½ü¾àÀë½Ó´¥</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_yueye/205597738.html">С³Ç¸øÁ¦»é³µ¶Ó</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://club.auto.163.com/"><em class='fB'>´ºÓÎÈÕ¼Ç</em></a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_aaab/205051595.html">ͬѧ¾Û»á ·¬Ø®Ð¡ÖÞÔç²è¼Ç</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_aaac/201602614.html">·¢ÌûÓ®ÓÍ¿¨</a></li>
- <li><a href="httpdisabled://club.auto.163.com/bbs/auto_aaai/205364360.html"><em class='fB'>°®ÉãÍÅ</em></a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_aaai/205364360.html">4ÔÂ9ÈÕÏàÔ¼ÅÄÉ㡶°×Ñ©¹«Ö÷Óö¼ûÍÜÑÛÍõ×Ó¡· </a></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
-<div class="area-main">
- <div class="main-col-10">
- <iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column390x100&amp;location=3.html" width="390" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-
- </div>
- <div class="main-col-9">
- <iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column360x100&amp;location=3.html" width="360" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-
- </div>
- </div>
- </div>
- <div class="area-sub">
- <div id="g5n2" class="mod wgt-tab">
-<div class="tab-hd tab-u-5 clearfix">
- <span class="tab-u current">×ÊѶ</span>
- <span class="tab-u">»î¶¯</span>
- <span class="tab-u">ÍƼö</span>
- <span class="tab-u">¾«Æ·</span>
- </div>
- <div class="bd display-control">
- <div class="tab-con current">
-<ul class="mod-list sub-list">
-<li class="title"><a href="httpdisabledsdisabled://epay.163.com/notice/chongzhi.jsp">ÊÖ»ú¿¨³äÖµÒ²ÄÜÍø¹ºÀ²</a></li>
-<li><a href="httpdisabled://lady.163.com/special/00261ID9/2009DeluxeReport.html">×îÊÜÉÌÎñÈËÊ¿ÖÓ°®Æ·ÅÆ</a></li>
-<li><a href="httpdisabled://survey2.163.com/html/dict_youdao2011q1/paper.html">ÇáµãÊó±êÓ®¾ªÏ²´ó½±</a></li>
-<li><a href="httpdisabled://mail.163.com/html/110127_imap/index.htm">ÊÓƵ½ÌÄãÉèÖÃÓÊÏäIMAP</a></li>
-<li><a href="httpdisabled://pmxj.wan.163.com/">Æ®Ãì¶à·çÔÆÏɽ£ÏÔÎäÁÖ</a></li>
-<li><a href="httpdisabled://money.163.com/2011NAEC/">2011ÍøÒ×¾­¼Ãѧ¼ÒÄê»á</a></li>
- </ul>
- <ul class="mod-list sub-list">
-<li><a href="httpdisabled://tech.163.com/11/0322/10/6VO99FLI000915BF.html">ÍøÒ×ÐÂÎÅ¿Í»§¶Ë¡ÖØÉÏÏß</a></li>
-<li><a href="httpdisabled://g.163.com/a?CID=240&Values=53963900&Redirect=http://mhxx.dream.163.com?101222mhxx002">¹úÄÚÊ׿î2Dºá°æÍøÓÎ</a></li>
-<li><a href="httpdisabled://xyq.163.com/xyq?acctsn=MH22-2128-3554-7248">ºÍËûÒ»Æð×ö×îÀËÂþµÄÊÂ</a></li>
-<li><a href="httpdisabled://yuehui.163.com/">ллÍøÒ×ÈÃÎÒÓö¼ûÁËËû</a></li>
-<li><a href="httpdisabled://bafang.163.com/">²é¿´Å®ÓѾßÌåλÖà </a></li>
-<li><a href="httpdisabled://v.163.void/">ÍøÒ×¹«¿ª¿Î ºÃ¿ÎÃâ·ÑÌý</a></li>
- </ul>
- </div>
- <div class="tab-con">
- </div>
- <div class="tab-con">
- </div>
- <div class="tab-con">
- </div>
- </div>
- </div>
- <script>
- NTES.ready( function(){
- var aChange = new AChange({
- temp: "/special/00774IHC/11zy2-",
- content: "#g5n2",
- num: "4"
- });
-});
- </script>
- <div class="gg gg-h180"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=logo190x180&amp;location=2.html" width="190" height="180" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe></div>
- </div>
-</div>
-<!-- end -->
-<!-- tech & house -->
-<div class="area">
- <div class="area-main">
- <div class="main-col-10">
- <div id="tech" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-10 clearfix">
- <span class="tab-u current"><a href="httpdisabled://tech.163.com/">¿Æ¼¼</a></span>
- <span class="tab-u"><a href="httpdisabled://mobile.163.com/">ÊÖ»ú</a></span>
- <span class="tab-u"><a href="httpdisabled://digi.163.com/">ÊýÂë</a>¡¤<a href="httpdisabled://mobile.163.com/3g/">3G</a></span>
- <span class="tab-u"><a class="homeAppliances" href="httpdisabled://hea.163.com/">¼Òµç</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://tech.163.com/mobile/11/0408/05/713JK5U300112K88.html"><img src="../img3.cache.netease.com/mobile/2011/4/8/201104080904537def0.jpg" alt="³¬ÃÍ´¿Ò¯ÃǶù»ú´ó½µ¼Û" title="³¬ÃÍ´¿Ò¯ÃǶù»ú´ó½µ¼Û" height="90" width="120" /><cite>³¬ÃÍ´¿Ò¯ÃǶù»ú´ó½µ¼Û</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://tech.163.com/11/0407/22/712Q075F000915BD.html">¹È¸è֤ʵ¿ª·¢Æ½°åChrome OSϵͳ</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://tech.163.com/11/0408/17/714RUP8P000915BE.html">ÁªÍ¨½µµÍiPhone4Ô·ÑÃż÷:×îµÍ66Ôª</a></li>
- <li><a href="httpdisabled://tech.163.com/11/0408/00/712VNNF5000915BE.html">Öйú½¨³ÉÈ«Çò×î´óIPv6¹Ç¸ÉÍø</a></li>
- <li><a href="httpdisabled://tech.163.com/11/0408/07/713QDT6Q000915BF.html">¾Å³ÇQ4¾»¿÷4390Íò ³ÖÐø¿÷ËðÆß¼¾¶È</a></li>
- <li><a href="httpdisabled://tech.163.com/11/0407/17/71292O9G000915BE.html">Á½¸ßÔº£º5000ÌõÕ©Æ­¶ÌÐż´¿É¶¨×ï</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://digi.163.com">Ô¼40%Æ»¹û·ÛÉý¼¶4.3ºó¸ü·Ñµç</a> <a target="_blank" href="httpdisabled://tech.163.com/digi/11/0407/11/711M4HGC001618S7.html">iPod touch5¹¤³Ì»úÔâй¶</a></li>
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/05/713J8EVC0016192E.html">SNB¼¯ÌåÌøË® Ò»Öܱ¾±¾½µ¼ÛÅÅÐÐ</a> <a target="_blank" href="httpdisabled://tech.163.com/digi/11/0408/00/7132FT3J0016192R.html">´îÔØÐÂi7 ´÷¶ûXPS15ÆÀ²â</a></li>
- <li><a href="httpdisabled://t.163.com/zt/digi/image">´ºÌì¾ÍÔÚÄãµÄÏà»úÀï ÉãÓ°´ïÈ˽ÌÄãÅÄ´ºÌì</a> <a target="_blank" href="httpdisabled://t.163.com/imagejinfeng">¹Ø×¢½ù·å΢²©</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/05/713JD13H00112K8C.html">½µ¼Û°ñ:È«ÇòÈÈÏúÊÖ»úTOP10</a> <a target="_blank" href="httpdisabled://tech.163.com/mobile/11/0408/06/713LNSDO0011309K.html">1200ÔªÆð×î¸ßÈËÆøÊÖ»úTOP8</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/06/713N2LF000112K88.html">¸ß¶ËÆì½¢ÊÖ»ú¼Û¸ñ±©µø»ã×Ü</a> <a target="_blank" href="httpdisabled://tech.163.com/mobile/11/0408/06/713LNSCI0011309K.html">G7ÔÙ½µ:ÈÈÂôAndroidÊÖ»úÅ̵ã</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/06/713N135S00112K8D.html">Ç¿»ú×ßÊÆ:iPhone4ÏÖ4700Ôª</a> <a target="_blank" href="httpdisabled://tech.163.com/mobile/11/0408/06/713LNSE40011309K.html">Èý´óÍøÂçÐÔ¼Û±È×î¸ßµÄ3GÊÖ»ú</a></li>
-
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://tech.163.com/" class="fB attitude">¿Æ¼¼</a> | <a href="httpdisabled://tech.163.com/special/column/"><em class='fB'>רÀ¸</em></a> | <a target="_blank" href="httpdisabled://tech.163.com/11/0408/09/713UKKTD000949EP.html">¼½ÓÂÇ죺´ÓÓÀÖп´ÖйúÈí¼þÀ§¾Ö</a></li>
- <li><a href="httpdisabled://tech.163.com/dailysite"><em class='fB'>¿áÕ¾</em></a> | <a target="_blank" href="httpdisabled://tech.163.com/11/0406/23/710A9PED000938EN.html">Ö°³¡É罻ƽ̨</a> | <a target="_blank" href="httpdisabled://t.163.com/zt/pub/tech163"><em class='fB'>΢²©</em></a> | <a target="_blank" href="httpdisabled://t.163.com/2123575232/status/-2250570432325285320#retweet">ÁõÇ¿¶«:ITÐÐÒµµ­¼¾ÌáÇ°</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://tech.163.com/mobile/11/0408/05/713JD13H00112K8C.html"><img src="../img4.cache.netease.com/mobile/2011/4/8/2011040809135520264.jpg" alt="È«ÇòÈÈÏúÊÖ»úTOP10" title="È«ÇòÈÈÏúÊÖ»úTOP10" height="90" width="120" /><cite>È«ÇòÈÈÏúÊÖ»úTOP10</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://mobile.163.com/">N8ÆÆ2600Ôª Íâ¹ÛÐÔÄܶ¼Ã͵ÄÒ¯ÃÇ»ú</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/06/713LNSDO0011309K.html">×îµÍ½µÖÁ1200Ôª ×î¸ßÈËÆøÊÖ»úTOP8</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/06/713N2LF000112K88.html">Àï³Ì±®²»µ½2000Ôª ¸ß¶ËÊÖ»ú´ó½µ¼Û</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/06/713LNSCI0011309K.html">ÈÈÃÅAndroidÊÖ»ú:G7¼Û¸ñÎȶ¨¿ÉÈëÊÖ</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/06/713N135S00112K8D.html">Ç¿»ú¼Û¸ñ×ßÊÆ:iPhone 4µøÆÆ·¢ÐмÛ</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/09/7140QMTF001117A5.html">LGÊ׿î´óÆÁË«ºËÖÇÄÜÊÖ»úÊÔÍæ</a> <a target="_blank" href="httpdisabled://tech.163.com/mobile/11/0408/06/713LM42P0011309K.html">TDлúĦÍÐÂÞÀ­MT620ÆÀ²â</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/11/7147ER3B00112K8E.html">´«ÁªÍ¨ÍÆiPhone 4¹º»úÐÂÕþ×îµÍÿÔÂ66</a> <a target="_blank" href="httpdisabled://tech.163.com/mobile/11/0408/08/713STBVT00112K8E.html">CDMA°æ±ãÒËÉպŹó</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/06/713MVSB000112K8E.html">Á®¼ÛÖÇÄÜ»ú:ÈýÐÇPrevailÉÍÎö</a> <a target="_blank" href="httpdisabled://tech.163.com/mobile/11/0408/06/713LII220011309K.html">LGÇæÌìϵÁÐÈëÃÅ»ú½üÆÚÉÏÊÐ</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/06/713LIENF0011309K.html">HTCË«ºËCPUǧÍòÏñËؾµÍ·Ð»ú</a> <a target="_blank" href="httpdisabled://tech.163.com/mobile/11/0408/05/713JI3JU00112K8E.html">Symbian^3Éý¼¶ÎÞʵÖʸĽø</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/05/713JI3J200112K8E.html">4.3´çÆÁDroid XÉýË«ºË´¦ÀíÆ÷ ĦÍÐÂÞÀ­Droid X2Õæ»úÆعâ</a></li>
- <li><a href="httpdisabled://tech.163.com/mobile/11/0408/00/7131BH2V00112K95.html">Ë«ºË´¦ÀíÆ÷ÐÔÄÜÔ¶³¬µ¥ºË10±¶ Atrix/i9000ÉúËÀPK´óÕ½</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://tech.163.com/mobile/special/mobile20111/"><em class='cBlack fB'>i´ïÈË |</em></a> <a target="_blank" href="httpdisabled://tech.163.com/mobile/special/mobile20111/">ÊÖ»ú´ïÈËÍƼö£º2011²»µÃ²»ÍæµÄ5¿îÊÖ»úÓÎÏ·</a></li>
- <li><a href="httpdisabled://club.tech.163.com/"><em class='cBlack fB'>ÂÛ̳ |</em></a> <a target="_blank" href="httpdisabled://club.tech.163.com/bbs/mobile_activ/203210473.html">¿ìÇÀ£¡¸øÍøÒ×ÐÂÎÅ¿Í»§¶ËÆÀ·Ö¾ÍÄÜÄõ½´ó½±£¡</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://digibbs.tech.163.com/bbs/digifuns/205680163.html"><img src="../img4.cache.netease.com/digi/2011/4/8/20110408144717d8da9.jpg" alt="ÐÂÈëÊÖAcer 4750GÑÞÕÕ" title="ÐÂÈëÊÖAcer 4750GÑÞÕÕ" height="90" width="120" /><cite>ÐÂÈëÊÖAcer 4750GÑÞÕÕ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://tech.163.com/digi/11/0408/06/713ME3UM001624J3.html">Ë÷Äá½ðÉ«NEX-5CÒ¹¾°ÑùÕÅÉÍÎö</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/05/713J8DF60016192R.html">240Hz²»ÉÁ3D±¾ Ë÷ÄáF219Ê×·¢ÆÀ²â</a></li>
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/05/713J8EUE0016192E.html">¶ÀÏÔ´óÕ½Éý¼¶ мܹ¹ÓÎÏ·±¾ÍƼö</a></li>
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/02/7138LU3I001624J3.html">¹ã½Ç·À¶¶¿¨Æ¬»ú ¼ÑÄÜA3200 ISÆÀ²â</a></li>
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/05/713J1R6200163KQR.html">ÓÐÕÇÓнµ 4¿îÈÈÃŵ¥µç×îм۸ñ»ã×Ü</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/06/713MQPDL001618J1.html">À¶±¦µÚ2¿îAPU¼Ü¹¹ÃÔÄã°åÈÕ±¾ÉÏÊÐ</a> <a target="_blank" href="httpdisabled://tech.163.com/digi/11/0408/02/71394GG1001618JK.html">799Ôªµ½999ÔªÏÔ¿¨µ¼¹º</a></li>
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/08/713RGRV9001618JK.html">ÊÐÊÛǧԪ×óÓÒ¾«Æ·ÏÔʾÆ÷ÍƼö</a> <a target="_blank" href="httpdisabled://tech.163.com/digi/special/lepad/">ÁªÏëÀÖPadÁãÊÛ°æÊÓ¾õÆÀ²â</a></li>
- <li><a href="httpdisabled://mobile.163.com/3g/">[3G]</a> <a href="httpdisabled://tech.163.com/mobile/11/0408/08/713U2NHC0011309K.html">ͨ»°ÖÊÁ¿ÓÐÌá¸ß Æ»¹ûCƤ¶þ´úÐÂÆ·¸ßÇåͼÆعâ</a></li>
- <li><a href="httpdisabled://mobile.163.com/3g/">[3G]</a> <a href="httpdisabled://tech.163.com/mobile/11/0408/08/713TLQ2400112K8E.html">Ϊ·â¶ÂÔ½Óü ÏûÏ¢³ÆiOS 4.3.2½«ÔÚÁ½ÖÜÄÚ·¢²¼</a></li>
- <li><a href="httpdisabled://mobile.163.com/3g/">[3G]</a> <a href="httpdisabled://tech.163.com/mobile/11/0408/06/713LIENF0011309K.html">Ë«ºË´¦Àí1600ÍòÏñËØ HTC NEW EDEN¸ÅÄî»úÆعâ</a></li>
- <li><a href="httpdisabled://mobile.163.com/3g/">[3G]</a> <a href="httpdisabled://tech.163.com/mobile/11/0407/17/7129GSQ0001164LP.html">Flight Control£º¿ÕÖÐÖ¸»Ó¹Ù ¿¼ÑéÄãµÄ¿ØÖÆÁ¦</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><strong><a href="httpdisabled://digibbs.tech.163.com/">ÂÛ̳</a></strong> | <a href="httpdisabled://digibbs.tech.163.com/bbs/diginews/205444284.html">ÉñÈËÁ¬ÐøÉÏÍø454Сʱ ±£Ä·ÌùÉí¿´»¤</a></li>
- <li><strong><a href="httpdisabled://digibbs.tech.163.com/">ÂÛ̳</a></strong> | <a href="httpdisabled://digibbs.tech.163.com/bbs/notebook/205336929.html">±Ê¼Ç±¾´ïÈËÈÏÖ¤»úÖ÷»ðÈÈÕÐļÖÐ~~~£¡</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://tech.163.com/digi/11/0408/01/7134II58001618VK.html"><img src="../img1.cache.netease.com/digi/linzj/1102/03/191.jpg" alt="ÃÀµÄ500¿îмҵçÉÏÊÐ" title="ÃÀµÄ500¿îмҵçÉÏÊÐ" height="90" width="120" /><cite>ÃÀµÄ500¿îмҵçÉÏÊÐ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://tech.163.com/digi/11/0408/01/7133ENRJ001618VK.html">ÃÀµÄÈÕµçÎߺþÉú²ú»ùµØͶ×ʳ¬20ÒÚ</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/00/7132P3SC001618VS.html">¾«ÖÂÖÁ¼« Ë÷Äá24EX520Òº¾§µçÊÓÆÀ²â</a></li>
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/09/713V39R8001618VK.html">ÏûЭ³ÆÂô³¡ÐèÃ÷Âëʵ¼Û Î¥¹æ½«±»·£</a></li>
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/08/713U2JFT001628C1.html">¿Õµ÷»ÝÃñ²¹ÌùÈ¡Ïû ½«¼Ó¾ç¢¶Ï¸ñ¾Ö</a></li>
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/09/713VLFGU001618VK.html">°®ÊË´ï½ÓÅ̲½²½¸ß δ»ñµÃÓÅÖÊ×ʲú</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/08/713U164O001628C1.html">½µ¼Û×îÃÍ32´çµçÊÓÅ̵ã</a> <a href="httpdisabled://tech.163.com/digi/11/0408/06/713N6RJI001628C1.html">2Íò´òÔì35ƽС»§ÐÍÈ«Ì׼ҵ緽°¸</a></li>
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/00/7132P5VN001628C1.html">ÄÚÈÝȱʧ ÖÇÄܵçÊÓ»á·ñê¼»¨Ò»ÏÖ</a> <a href="httpdisabled://tech.163.com/digi/11/0408/00/7132P5VN001628C1.html">½üÆÚ¸ßÐԼ۱ȵçÊÓÍƼö</a></li>
- <li><a href="httpdisabled://tech.163.com/digi/11/0408/06/713NF3Q5001628C1.html">Éú»î±¦µä ±ùÏäÈÕ³£Ê¹ÓÃСÇÏÃÅ»ã×Ü</a> <a href="httpdisabled://tech.163.com/digi/11/0408/07/713QIG89001628C1.html">΢²¨Â¯Îó½âÏÖÏó½âÎö</a></li>
- <li><a href="httpdisabled://t.163.com/zt/digi/image">[΢²©] ´ºÅ¯»¨¿ª,ÉãӰʦ½ÌÄãÅijöÃÀÀöÕÕƬ</a></li>
- <li><a href="httpdisabled://t.163.com/wangluohao/status/251893127646805523#retweet">[΢²©] ÍõÂ޺ƣºÉ˲»Æð£¡Ï´Ò»úµÄÄÚͲ±ÈÀ¬»øÍ°»¹ÒªÔà</a></li>
- <li><a href="httpdisabled://t.163.com/yanjun/status/4389364559077117791#retweet">[΢²©] ´ïÈËÑÕ¿¡ÍƼöÓ¢¹úÖªÃûÐÔ¸ÐÅ®ÀÉÐãÂéÀ±Éí²ÄÉÍ</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://digibbs.tech.163.com/list/jiadian.html">ÂÛ̳</a> | <a target="_blank" href="httpdisabled://digibbs.tech.163.com/bbs/baidian/205545452.html">·øÉäÎÞ´¦²»ÔÚ ÄãÈçºÎµÖÓù¼Òµç·øÉä</a></li>
- <li><a href="httpdisabled://digibbs.tech.163.com/list/jiadian.html">ÂÛ̳</a> |<a target="_blank" href="httpdisabled://digibbs.tech.163.com/bbs/baidian/205552044.html">iPod½ø³ø·¿ ÒôÀÖµç×Ó³ÓÈÃ×ö·¹ºÜ¶¯¸Ð</a></li>
- </ul>
- </div>
- </div>
- </div>
- <div id="t" class="mod wgt-tab">
- <div class="tab-hd tab-u-10 clearfix">
- <span class="tab-u current"><a href="httpdisabled://t.163.com/">΢Éú»î</a></span>
- <span class="tab-u"><a href="httpdisabled://t.163.com/rank/daren">i´ïÈË</a></span>
- <span class="tab-u"><a href="httpdisabled://t.163.com/rank?f=nav">ÈÈÃÅ</a></span>
- </div>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://t.163.com/wenbixia/status/-2133696119988502451#retweet"><img src="../img3.cache.netease.com/life/2011/4/8/20110408175702d86a7.jpg" alt="αÌϼ£ºÕâ¸Ð¾õºÃÌرð" title="αÌϼ£ºÕâ¸Ð¾õºÃÌرð" height="90" width="120" /><cite>αÌϼ£ºÕâ¸Ð¾õºÃÌرð</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://t.163.com/zt/book/chuantongVSwangluo">ÍøÂçÎÄѧÓ봫ͳÎÄѧÊÇ·ñ¶ÔÁ¢£¿</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://t.163.com/duoyu/status/2054209277184657633">¶äÓ棺°¬Çà˵Ðì־ĦÊǸöÉ«ÇéÊ«ÈË </a></li>
- <li><a href="httpdisabled://t.163.com/lidaokui/status/3028352804215074228"> Àîµ¾¿û£ºÑëÐмÓÏ¢µÄÔ­ÒòÓëºó¹û </a></li>
- <li><a href="httpdisabled://t.163.com/bqxiong/status/-5397918089764545559#retweet">ÐܱûÆ棺¹þ·ð°ÑÀñÌý豾¿ÆÉú°ì»éÀñ</a></li>
- <li><a href="httpdisabled://t.163.com/zt/pub/supergirl2011">2011¿ìÀÖÅ®ÉùÍøÒ×΢²©Ö±Í¨Çø</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://t.163.com/zt/2011">´ºÌìÓÐÀñ</a> <a target="_blank" href="httpdisabled://t.163.com/zt/2011">7150ÈËÒÑ»ñ³äÖµ¿¨ ½ñÈÕ´ó½±Î¨Æ·»áÍòÔª´óÀñ°ü</a></li>
- <li><a href="httpdisabled://t.163.com/ye_zi_feng/status/-3618379367969276810">Ò¶×ӷ磺´ó½ÍøÓÑ£¬ÎÒ¿´²»ÆðÄãÃÇ£¬ÄãÃÇÊ·ÉÏ×îÊÆÀû </a></li>
- <li><a href="httpdisabled://t.163.com/jixiangsanbao/status/-4568484409001578815">¼ªÏéÈý±¦£º¡°°½Â³¹ÅÑŸèÎè¾ç¡±Àï×îСµÄÑÝÔ±²Å2Ëê8¸öÔ </a></li>
- <li><a href="httpdisabled://t.163.com/1339279689/status/8695815502864064091#retweet">ÒÁɳ£ºÍõÓÐβµÄ¾ø×÷¡¶»³ÔеÄÅ®¹í¡·ÊÇ¡°ÀäÊãÇ顱µÄµä·¶</a></li>
- <li><a href="httpdisabled://t.163.com/zt/void64">ÖйúÕì̽ʽ½âÃεÚÒ»È˳Éʵ×ÚÔÚÏßΪÄã½âÃÎ̽ѰÃξ³Ö®ÃÔ</a></li>
- <li><a href="httpdisabled://t.163.com/luoyonghao/status/9174094553196327643#retweet">ÂÞÓÀºÆ£º»Ø¹Ë×òÒ¹±«²ª¡¤µÏÂ×Ñݳª»á</a> <a target="_blank" href="httpdisabled://t.163.com/luoyonghao/status/-7475778234050622400#retweet">àÞÒ®£¡µÏÂ×£¡Å£±Æ£¡</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://t.163.com/zt/idaren"><em class='fB'>i´ïÈË</em></a> | <a target="_blank" href="httpdisabled://t.163.com/qinhui">¾­¼Ãѧ´ïÈË ÇØêÍ</a><a target="_blank" href="httpdisabled://t.163.com/bashusong"> °ÍÊïËÉ</a> |<a target="_blank" href="httpdisabled://t.163.com/japan_earthquake">ÈÕ±¾µØÕð×îÐÂÏûÏ¢</a></li>
- <li><a href="httpdisabled://t.163.com/rank/retweets"><em class='fB'>ÍƼö»°Ìâ</em></a> |<a target="_blank" href="httpdisabled://t.163.com/zt/pub/yushaolei">΢ÁÄÕ«</a> |<a target="_blank" href="httpdisabled://t.163.com/zt/pub/spring">ËæÊÖÅÄ´ºÌì</a> |<a target="_blank" href="httpdisabled://t.163.com/zt/pub/sixing">ÊÇ·ñÔÞ³ÉÈ¡ÏûËÀÐÌ</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <ul class="mod-imgList imgList-w80 clearfix">
- <li><a href="httpdisabled://t.163.com/xiaohan"><img src="../img3.cache.netease.com/life/2011/4/6/201104061402503e782.jpg" alt="img" title="Ïôå«" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/xiaohan">Ïôå«</a></p></li>
- <li><a href="httpdisabled://t.163.com/yuzhen0716"><img src="../img3.cache.netease.com/life/2011/4/6/20110406140048c8dea.jpg" alt="img" title="µËí²ÎÄ" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/yuzhen0716">µËí²ÎÄ</a></p></li>
- <li><a href="httpdisabled://t.163.com/xiaoshushiping"><img src="../oimagec7.ydstatic.com/image@w=128&amp;h=128&amp;url=http%253A%252F%252F126.fm%252F3cAjJD" alt="img" title="ЦÊñ" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/xiaoshushiping">ЦÊñ</a></p></li>
- <li><a href="httpdisabled://t.163.com/qinhui"><img src="../oimagea8.ydstatic.com/image@w=80&amp;h=80&amp;url=http%253A%252F%252F126.fm%252F40hcYl" alt="img" title="ÇØêÍ" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/qinhui">ÇØêÍ</a></p></li>
- <li><a href="httpdisabled://t.163.com/maoshoulong"><img src="../img4.cache.netease.com/life/2011/3/7/20110307134125752e1.jpg" alt="img" title="ëÊÙÁú" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/maoshoulong">ëÊÙÁú</a></p></li>
- <li><a href="httpdisabled://t.163.com/5461458243"><img src="../oimagea8.ydstatic.com/image@w=80&amp;h=80&amp;url=http%253A%252F%252F126.fm%252F2WEnFW" alt="img" title="ľ×ÓÃÀ" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/5461458243">ľ×ÓÃÀ</a></p></li>
- <li><a href="httpdisabled://t.163.com/wuzuolai"><img src="../oimagea4.ydstatic.com/image@w=80&amp;h=80&amp;url=http%253A%252F%252F126.fm%252FPjU3g" alt="img" title="ÎâìñÀ´" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/wuzuolai">ÎâìñÀ´</a></p></li>
- <li><a href="httpdisabled://t.163.com/ye_zi_feng"><img src="../oimagea8.ydstatic.com/image@w=80&amp;h=80&amp;url=http%253A%252F%252F126.fm%252F2x2iAO" alt="img" title="Ò¶×Ó·ç" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/ye_zi_feng">Ò¶×Ó·ç</a></p></li>
- <li><a href="httpdisabled://t.163.com/lianyue"><img src="../img3.cache.netease.com/life/2011/2/24/20110224214610e49c1.jpg" alt="img" title="Á¬ÔÀ" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/lianyue">Á¬ÔÀ</a></p></li>
- <li><a href="httpdisabled://t.163.com/1642658000"><img src="../oimageb3.ydstatic.com/image@w=80&amp;h=80&amp;url=http%253A%252F%252F126.fm%252FTyjFq" alt="img" title="ÕÂÚ±ºÍ" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/1642658000">ÕÂÚ±ºÍ</a></p></li>
- <li><a href="httpdisabled://t.163.com/luoyonghao"><img src="../oimagec1.ydstatic.com/image@w=80&amp;h=80&amp;url=http%253A%252F%252F126.fm%252F3SWBUh" alt="img" title="ÂÞÓÀºÆ" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/luoyonghao">ÂÞÓÀºÆ</a></p></li>
- <li><a href="httpdisabled://t.163.com/wuxiaobo"><img src="../oimageb2.ydstatic.com/image@w=80&amp;h=80&amp;url=http%253A%252F%252F126.fm%252F46NVMe" alt="img" title="ÎâÏþ²¨" height="80" width="80" /></a><p><a href="httpdisabled://t.163.com/wuxiaobo">ÎâÏþ²¨</a></p></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://t.163.com/zt/2011"><img src="../img3.cache.netease.com/life/2011/4/1/20110401105148c65f3.jpg" alt="ÍøÒ×΢²© ´ºÌìÓÐÀñ" title="ÍøÒ×΢²© ´ºÌìÓÐÀñ" height="90" width="120" /><cite>ÍøÒ×΢²© ´ºÌìÓÐÀñ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://t.163.com/zt/clientshipping">ÍøÒ×΢²©¿Í»§¶Ë¶à°æÆë·¢</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://t.163.com/Open/status/-2521154402529877591#retweet">Ó¦ÓÃÍƼö£º¿¿Æ×Áµ°®Æ½Ì¨</a></li>
- <li><a href="httpdisabled://t.163.com/Open/status/402613038294551289#retweet">Ó¦ÓÃÍƼö£ºÇÀŵÑÇ·½ÖÛ´¬Æ±</a></li>
- <li><a href="httpdisabled://t.163.com/Open/status/-2610850867517385007#retweet">Ó¦ÓÃÍƼö£º×îÁ÷ÐеÄ΢ÓÎÏ·</a></li>
- <li><a href="httpdisabled://t.163.com/Open/status/-8198518966669524288#retweet">Ó¦ÓÃÍƼö£º²â²â3ÄêºóÄãÊDz»ÊǸ»ÎÌ</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://t.163.com/zt/bbs/man">Ò×΢²©Æ·Åƻ㠵ÚÒ»ÆÚ£ºÐÍÄᦵä</a></li>
- <li><a href="httpdisabled://t.163.com/mobile/iphone"><em class='fB'>΢²©¿Í»§¶ËÊ¡Á÷Á¿</em></a> <a target="_blank" href="httpdisabled://3g.163.com/links/66">ÏÂÔØ£ºAndroid</a> <a target="_blank" href="httpdisabled://3g.163.com/links/65">S60V5</a> <a target="_blank" href="httpdisabled://3g.163.com/links/63">S60V3</a> <a target="_blank" href="httpdisabled://3g.163.com/links/3020">Java</a></li>
- <li><a href="httpdisabled://t.163.com/zt/pub/yyhf">º£ÐÄɳѰÕÒ"°Å½¶Ò¶Äк¢"</a></li>
- <li><a href="httpdisabled://tech.163.com/special/wdk05/">ÎåµÀ¿ÚɳÁú£ºÎ¢²©Ó¦ÓõÄÏÖ×´ÓëÉÌҵģʽ</a></li>
- <li><a href="httpdisabled://t.163.com/npdp_love/status/-1759136884114661834">Ϊ°®ÉÏÉ«£ºÏ£ÍûСѧÍâǽͿѻ»î¶¯</a></li>
- <li><a href="httpdisabled://t.163.com/wwfchina/status/1978538898632885672"><em class=' I_V_'>µØÇòһСʱ£ºÍõç󵤳«Òé»·±£</em></a> <a target="_blank" href="httpdisabled://t.163.com/wwfchina/status/5103287786315323769">ÓðȪ¾Ü¾øÒ»´ÎÐԲ;ß</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://t.163.com"><em class='cBlack fB'>ÍƼö</em></a> |<a target="_blank" href="httpdisabled://t.163.com/19394671">Ö°³¡£ºÃÀÀöСϰ¹ß</a> |<a target="_blank" href="httpdisabled://t.163.com/43204654">ÊýÂ룺ÉãÓ°·¢ÉÕÓÑ</a></li>
- <li><a href="httpdisabled://t.163.com"><em class='fB'>ÍøÕ¾</em></a> |<a target="_blank" href="httpdisabled://t.163.com/youku"> ÓÅ¿áÍø£º»Ø¹Ë°Â˹¿¨¾­µä</a> |<a target="_blank" href="httpdisabled://t.163.com/56wang"> 56Íø£º¹Ø×¢ÈÕ±¾µØÕð</a></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- <div class="main-col-9">
- <div id="house" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-9 clearfix">
- <span class="tab-u current"><a href="httpdisabled://gz.house.163.com/">¹ãÖÝ·¿²ú</a></span>
- <span class="tab-u"><a href="httpdisabled://house.163.com">ÒªÎÅ</a></span>
- <span class="tab-u"><a href="httpdisabled://bbs.gz.house.163.com/">·¿²úÂÛ̳</a></span>
- <span class="tab-u"><a href="httpdisabled://home.163.com/">¼Ò¾Ó</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://gz.house.163.com/11/0408/09/713UMB1I00873C6D.html"><img src="../img4.cache.netease.com/house/2011/4/8/201104080927161a54f.jpg" alt="²ðǨ»§·Ì°ùÈÎ־ǿ±»¾Ð" title="²ðǨ»§·Ì°ùÈÎ־ǿ±»¾Ð" height="90" width="120" /><cite>²ðǨ»§·Ì°ùÈÎ־ǿ±»¾Ð</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://gz.house.163.com/">"ÎåÒ»"¹ãÖÝÂ¥ÊÐÍÆ»õÔ¼4.5ÍòÌ×</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://gz.house.163.com/11/0408/08/713S0JHO00873C6D.html">¹úÎñÔº¶½²é16Ê¡·ÝÂ¥Êе÷¿ØÕþ²ß</a></li>
- <li><a href="httpdisabled://gz.house.163.com/11/0408/08/713RK3N500873C6D.html">Ò»¼¾¶È·¿µØ²úÆóÒµÏúÊÛ´ó·ùÏ´ì</a></li>
- <li><a href="httpdisabled://gz.house.163.com/11/0408/08/713RM5N600873C6D.html">·¿²úÖнé¹æ±ÜÏÞ¹ºÕþ²ß»¨Ñù°Ù³ö</a></li>
- <li><a href="httpdisabled://gz.house.163.com/11/0407/21/712M3K4S00873C6D.html">Ê®´ó·¿Æó¸ß²ã:µ÷¿ØÊÇÈëÊÐʱ»ú</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://gz.house.163.com/11/0408/08/713R1AKI00873C6D.html">¹ãÖÝÊÐÇøлõÉÏÊдÙ"Á¿¼ÛÆëÕÇ"</a> <a href="httpdisabled://gz.house.163.com/11/0408/07/713OD7DQ00873C6D.html">3Ô¶þÊÖÂ¥¼Û´´Ð¸ß</a></li>
- <li><a href="httpdisabled://gz.house.163.com/11/0408/07/713P1HI300873C6D.html">¹ãÖÝÂ¥ÊÐתÏòÖÐÐÄÇø¹©Ó¦</a> <a href="httpdisabled://gz.house.163.com/11/0408/07/713PJKVD00873C6D.html">Öнé¼Ó°àÂôĹµØ¿ª¼Û16Íò</a></li>
- <li><a href="httpdisabled://gz.house.163.com/11/0408/08/713TR26V00873L40.html">DZÁ¦ÇøÓòÖð¸öÊý:°ÂÌåгÇ</a> <a target="_blank" href="httpdisabled://gz.house.163.com/11/0408/08/713TUVHC00873L40.html">°×¶ì̶</a> <a target="_blank" href="httpdisabled://gz.house.163.com/11/0408/08/713U2U1U00873L40.html">°×ÔÆгÇ</a> <a target="_blank" href="httpdisabled://gz.house.163.com/11/0408/08/713U8KVT00873L40.html">º£Öé</a></li>
- <li><a href="httpdisabled://gz.house.163.com/11/0408/08/713TARIR00873L40.html">ÂåϪÔÙÏÖÐÂÅÌÍÆ»õ³±</a> <a target="_blank" href="httpdisabled://gz.house.163.com/11/0408/08/713TFJL100873L40.html">¹ãÖÝд×ÖÂ¥¿ÕÖÃÂʳ¬Á½³É</a></li>
- <li><a href="httpdisabled://gz.house.163.com/11/0407/10/711HGQHJ00873L40.html">¶þ´ÎÌáÈ¡¹«»ý½ðÊÖÐø¼ò»¯</a> <a target="_blank" href="httpdisabled://gz.house.163.com/special/xf_xinyejituan/">ÐÅÒµ¼¯Íźñ»ý´ý±¡·¢</a></li>
- <li>[<a target="_blank" href="httpdisabled://bbs.gz.house.163.com">ÂÛ̳</a>]<a href="httpdisabled://bbs.gz.house.163.com/photoview/2ALD0015/5011.html">Õ¬ÄÐÅ®ÉñÕÅÜ°Óè˽·¿ÕÕ</a> <a target="_blank" href="httpdisabled://bbs.gz.house.163.com/photoview/2ALD0015/5037.html">ÇÅѹ"×îţ¥·¿"15Äê</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://home.163.com/" class="fB">[¼Ò¾Ó]</a> | <a href="httpdisabled://home.163.com/11/0407/19/712FHPOC00104IJT.html">ͬСÇø´óÁ¿TOTOÂíÍ°¿ªÁÑ ³§¼Ò:ÖÊÁ¿ºÏ¸ñ</a></li>
- <li><a href="httpdisabled://home.163.com/" class="fB">[¼Ò¾Ó]</a> | <a href="httpdisabled://home.163.com/photoview/2OHS0010/1363.html#q=1">ÁÄÕ«·ç¸ñ ÄÐÖ÷ÈËÇ××ÔÉè¼Æ×°ÐÞÃ÷Ç帴¹ÅÎÝ</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://gz.house.163.com/11/0408/09/7140BPSG00873L40.html"><img src="../img3.cache.netease.com/house/2011/4/8/20110408094024dfb90.gif" alt="Öйú¸»ºÀ¿ñɨº£ÍâºÀÕ¬" title="Öйú¸»ºÀ¿ñɨº£ÍâºÀÕ¬" height="90" width="120" /><cite>Öйú¸»ºÀ¿ñɨº£ÍâºÀÕ¬</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://gz.house.163.com/11/0406/11/70V13CVI0087482R.html">ÓÎ×ÊÈÈÇ®Öð²½³·ÀëÒ»Ïß³ÇÊÐ</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://gz.house.163.com/11/0406/16/70VI1I6H00873CN3.html">²»ÏÞ¹º+È뻧¹ãÖÝ:80ÍòÂò´óÈý·¿</a></li>
- <li><a href="httpdisabled://gz.house.163.com/special/xf_securityroom/">Âò¼ÒÖÃÒµÔú¶ÑÔö³Ç´Ó»¯</a></li>
- <li><a href="httpdisabled://gz.house.163.com/11/0408/08/713T5S6200873L40.html">¹ãÖÝÊÐÇøлõÉÏÊдÙÁ¿¼ÛÆëÕÇ</a></li>
- <li><a href="httpdisabled://gz.house.163.com/11/0406/08/70UP8HAN00873L40.html">½ÒÃØÍøÂç·¿ÍеÄÄÇЩʶù</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://gz.house.163.com/11/0408/09/713VBEJ900873CN0.html">½£ÇÅ¿¤ÔÚÊÛ½­É½Â¥Íõ ÓŻݵǼÇÁ½ÍòµÖÁùÍò</a> <a href="httpdisabled://xf.house.163.com/gz/search!xfs.action?district=%B7%AC%D8%AE&plate=&property=&price=&keyword=">·¬Ø®ÈÈÅÌ</a></li>
- <li><a href="httpdisabled://gz.house.163.com/">[¹ãÖÝ]</a> | <a href="httpdisabled://gz.house.163.com/11/0322/14/6VONRKBA00873CN0.html">½ðÈ󲬹¬ÍÆ60-110©O²úÆ· Ê׸¶Îå³É½ö90Íò/Ì×Æð</a></li>
- <li><a href="httpdisabled://bj.house.163.com/">[±±¾©]</a> | <a href="httpdisabled://bj.house.163.com/">[ÓÅ»Ý]</a> <a target="_blank" href="httpdisabled://bj.house.163.com/11/0408/07/713QHE3I00073V0K.html">±±ËÄ»·Íû¾©ºÏÉú¡¤÷è÷ëÉç °ì¿¨ÏíÊÜ1ÍòµÖ5Íò</a></li>
- <li><a href="httpdisabled://sh.house.163.com/">[ÉϺ£]</a> | <a href="httpdisabled://sh.house.163.com/special/00073V4M/shxntfj.html">[ÌÔ·¿]</a> <a target="_blank" href="httpdisabled://sh.house.163.com/special/xntf-blyzy/">ÌÔµÏÊ¿Äáз¿:±£ÀûÓùé×</a> <a target="_blank" href="httpdisabled://sh.house.163.com/special/00074ACD/xntf-bjsxz.html">±Ï¼ÓË÷</a> <a target="_blank" href="httpdisabled://sh.house.163.com/special/00074ACD/xntf-jlgj.html">½ðÁì¹ú¼Ê</a></li>
- <li><a href="httpdisabled://sz.house.163.com/">[ÉîÛÚ]</a> | <a href="httpdisabled://sz.house.163.com/11/0408/10/7142SVJV00073V29.html">ÿÈÕÊý¾Ý£º4.7з¿³É½»62Ì× ¾ù¼Û19348Ôª</a></li>
- <li><a href="httpdisabled://bbs.gz.house.163.com/">[ÂÛ̳]</a> <a href="httpdisabled://bbs.gz.house.163.com/bbs/housestory/205466349.html">BFÓÐ10ÍòÂò·¿Ô۾Ͳ»·ÖÊÖ</a> <a target="_blank" href="httpdisabled://bbs.gz.house.163.com/photoview/2ALD0015/5046.html">µ±³èÎïÓöÉϺ¢×Ó</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://home.163.com/" class="fB">[¼Ò¾Ó]</a> | <a href="httpdisabled://home.163.com/special/lovecolor/">¡°Îª°®ÉÏÉ«¡±»î¶¯½áÊø 4ǧ¼þ×÷Æ·ÏÔ°®ÐÄ</a></li>
- <li><a href="httpdisabled://home.163.com/" class="fB">[¼Ò¾Ó]</a> | <a href="httpdisabled://home.163.com/photoview/2OHS0010/1364.html#q=1">³¬¹ýÔ¤ËãÁË£¡25Íò´òÔì105ƽµÍµ÷ÉÝ»ª¼Ò</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://bbs.gz.house.163.com/photoview/2ALD0015/5011.html"><img src="../img3.cache.netease.com/house/2011/4/7/201104070846149dec5.jpg" alt="Õ¬ÄÐÅ®ÉñÕÅÜ°Óè˽·¿ÕÕ" title="Õ¬ÄÐÅ®ÉñÕÅÜ°Óè˽·¿ÕÕ" height="90" width="120" /><cite>Õ¬ÄÐÅ®ÉñÕÅÜ°Óè˽·¿ÕÕ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://bbs.gz.house.163.com/">½ãÓÐ8ÍòÊ׸¶È´±»Öн鵱½ÖÁèÈè</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://xiaochongfan.blog.163.com/blog/static/13056609520113723936387/">¸ßѹʹ×ʱ¾Ä¿±êת¶þÈýÏß³ÇÊÐ</a></li>
- <li><a href="httpdisabled://gaunzhui01.blog.163.com/blog/static/11604175820113862511825/">¶­·ª°ÇÁ˾åŲƸ»Õߵĵ׿ã</a></li>
- <li><a href="httpdisabled://garydens.blog.163.com/blog/static/9988583320113755236416/">±£ÕÏ·¿ÈëÊÐ »ò¸Ä±äÊг¡¸ñ¾Ö</a></li>
- <li><a href="httpdisabled://lgs1.blog.163.com/blog/static/276736320113810177203/">¶½²éÄܶÔÕþ¸®Æðµ½¼ì²é×÷ÓÃÂð</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li>[<a target="_blank" href="httpdisabled://bbs.gz.house.163.com">Ã÷ÐÇ</a>] <a href="httpdisabled://bbs.gz.house.163.com/bbs/homegossip/205304885.html">·¶çâç÷Óµ6¶°ºÀÕ¬³ö¼Þ</a> <a target="_blank" href="httpdisabled://bbs.gz.house.163.com/bbs/homegossip/204594863.html">Îé×È1ÒÚÂôºÀ»ªÓÎͧ</a></li>
- <li>[<a target="_blank" href="httpdisabled://bbs.gz.house.163.com">լŮ</a>] <a href="httpdisabled://bbs.gz.house.163.com/bbs/share/205341065.html">¹ãƯµÄÎÒ3Äê×â·¿5´Î</a> <a target="_blank" href="httpdisabled://bbs.gz.house.163.com/photoview/2ALD0015/5037.html">"×îţ¥"±»Ñ¹ÇÅÏÂ15Äê</a></li>
- <li>[<a target="_blank" href="httpdisabled://bbs.gz.house.163.com">ºÏ×â</a>] <a href="httpdisabled://bbs.gz.house.163.com/bbs/share/204254000.html">ËýµÄÄÚÒ¹ҹ«¹²Ô¡ÊÒ</a> <a target="_blank" href="httpdisabled://bbs.gz.house.163.com/bbs/share/204466628.html">ͬ×âСÄÐÅ®ºÙßݲ»¹ØÃÅ</a></li>
- <li>[<a target="_blank" href="httpdisabled://bbs.gz.house.163.com">´µË®</a>] <a href="httpdisabled://bbs.gz.house.163.com/bbs/jinshangu/204635749.html">WCµÄºæÊÖ»úÒ²ÄÃÀ´¶ñ¸ã</a> <a target="_blank" href="httpdisabled://bbs.gz.house.163.com/bbs/housegossip/204633922.html">Öйú·¿²ú±©µøʱ¼ä±í</a></li>
- <li>[<a href="httpdisabled://bbs.home.163.com/list/sheji.html">»î¶¯</a>]<a href="httpdisabled://bbs.home.163.com/bbs/sheji/205669205.html">µÚËÄÆÚ¡¾Ãâ·Ñ»§ÐÍ·ÖÎö¡¿½áÊø£¬´ðÒɼ¯ÄÉ£¡</a></li>
- <li>[<a target="_blank" href="httpdisabled://bbs.home.163.com/list/sheji.html">¹¥ÂÔ</a>]<a href="httpdisabled://bbs.home.163.com/bbs/sheji/205684769.html">¾ÈÃü°¡£¬ÎÒÕâÒìÐεĿÍÌüµØ°å¸ÃÔõôÑùÆÌ°¡</a></li>
- <li>[<a target="_blank" href="httpdisabled://bbs.home.163.com/list/homeshow.html">×°ÐÞÕбê</a>]<a href="httpdisabled://bbs.home.163.com/bbs/homebbs/205693470.html">Ñོ»é·¿×°ÐÞ£¬×°ÐÞ¹«Ë¾Ç뱨¼Û¸øÎÒ</a></li>
- <li>[<a target="_blank" href="httpdisabled://bbs.home.163.com/list/jjfs.html">·çË®</a>]<a href="httpdisabled://bbs.home.163.com/bbs/jjfs/205670377.html">רҵ·çˮʦÔÚÏßÃâ·ÑΪÄú·ÖÎö»§ÐÍ·çË®</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://home.163.com/special/lovecolor/"><img src="../img4.cache.netease.com/home/2011/4/7/20110407131936bb4ec.png" alt="Ϊ°®ÉÏÉ«»î¶¯Ô²Âú½áÊø" title="Ϊ°®ÉÏÉ«»î¶¯Ô²Âú½áÊø" height="90" width="120" /><cite>Ϊ°®ÉÏÉ«»î¶¯Ô²Âú½áÊø</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://home.163.com/photoview/2OHS0010/1363.html#q=1">ÁÄÕ«·ç ÄÐÖ÷ÈËÉè¼ÆÃ÷Ç帴¹ÅÎÝ</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://home.163.com/photoview/2OHS0010/1362.html#q=1">°×Áì8Íò´òÔì98ƽÃ×¼òÔ¼·ç¸ñ¼Ò</a></li>
- <li><a href="httpdisabled://home.163.com/photoview/2OHS0010/1364.html#q=1">³¬Ô¤ËãÁË 25Íò×°105ƽÃ×ÉÝ»ª¼Ò</a></li>
- <li><a href="httpdisabled://home.163.com/11/0407/22/712Q48HU00104IJF.html">3¿î¶ùͯ·¿ÅäÉ«´ø¸ø±¦±´ºÃÐÄÇé</a></li>
- <li><a href="httpdisabled://home.163.com/11/0407/23/712T8T9G00104IJ9.html">ÑîÃÝ´©Ë¯ÒÂÅÄÐÔ¸ÐÓÕÈ˼ҾÓдÕæ</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li>[<a target="_blank" href="httpdisabled://home.163.com/weiyu/">Èȵã</a>] <a href="httpdisabled://home.163.com/11/0407/19/712FHPOC00104IJT.html">ͬСÇø150Ì×TOTOÂíÍ°¿ªÁÑ ³§¼Ò:·ÇÖÊÁ¿ÎÊÌâ</a></li>
- <li>[<a target="_blank" href="httpdisabled://home.163.com/jiadian/">¼Òµç</a>] <a href="httpdisabled://home.163.com/11/0407/21/712MU91O00104IJI.html">¿Õµ÷ÕǼ۴«ÑÔ³ÉÕæ ±¾ÔÂÖлòÓ­È«ÃæÕǼÛ</a></li>
- <li>[<a target="_blank" href="httpdisabled://home.163.com/jiaju/">¼Ò¾ß</a>] <a href="httpdisabled://home.163.com/11/0407/22/712PNBK000104IJJ.html">ÓºÈÝ»ª¹ó Æß¿îÆø¶È·Ç·²Å·Ê½Ì«×Ó´²ÍƼö</a></li>
- <li>[<a target="_blank" href="httpdisabled://home.163.com/menchuang/">ÃÅ´°</a>] <a href="httpdisabled://home.163.com/11/0407/21/712O3DNS00104IJG.html">Æ­ÄãûÉÌÁ¿ ÏÊΪÈËÖªµÄľÃÅÈý´óÏúÊÛ¹î¼Æ</a></li>
- <li>[<a target="_blank" href="httpdisabled://home.163.com/weiyu/">ÎÀÔ¡</a>] <a href="httpdisabled://home.163.com/11/0407/23/712S4HF400104IJK.html">´òÆÆ´«Í³ÀíÄî ÓÃÂíÈü¿ËÆÌÌù³öʱÉÐìű³¾°</a></li>
- <li>[<a target="_blank" href="httpdisabled://home.163.com/jiafang/">¼Ò·Ä</a>] <a href="httpdisabled://home.163.com/11/0407/22/712OS7O700104IJH.html">¸ø¼Ò´©ÉÏÇåдº×° 3¿î¿¿µæÑÝÒï´ºÈÕçÍ·×</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><span><a target="_blank" href="httpdisabled://bbs.home.163.com/bbs/jiance/203933236.html">°ïÄãÉó×°ÐÞ±¨¼Ûµ¥</a></span> | <a href="httpdisabled://bbs.home.163.com/bbs/sheji/201770537.html">Éè¼ÆʦÔÚÏßÃâ·ÑÌṩ»§ÐÍ·½°¸</a></li>
- <li><span><a target="_blank" href="httpdisabled://home.163.com/special/tujinew/">ͼ¿â</a></span> | <a href="httpdisabled://home.163.com/special/photo/#s=¿ÍÌü&q=1">[¿ÍÌü]</a> <a target="_blank" href="httpdisabled://home.163.com/special/photo/#s=ÎÔÊÒ&q=1">[ÎÔÊÒ]</a> <a target="_blank" href="httpdisabled://home.163.com/special/photo/#s=С»§ÐÍ&q=1">[С»§ÐÍ]</a> <a target="_blank" href="httpdisabled://home.163.com/special/photo/#s=ÌïÔ°&q=1">[ÌïÔ°]</a> <a target="_blank" href="httpdisabled://home.163.com/special/photo/#s=µØÖк£&q=1">[µØÖк£]</a></li>
- </ul>
- </div>
- </div>
- </div>
- <div id="game" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-9 clearfix">
- <span class="tab-u current"><a href="httpdisabled://game.163.com/">ÓÎÏ·</a></span>
- <span class="tab-u"><a href="httpdisabled://game.163.com/photo/">ÃÀͼ</a></span>
- <span class="tab-u"><a href="httpdisabled://s.163.com/">ÐǼÊ2</a></span>
- <span class="tab-u"><a href="httpdisabled://w.163.com/">ħÊÞÊÀ½ç</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://game.163.com/"><img src="../img4.cache.netease.com/game/2011/4/8/2011040811265683661.jpg" alt="»­¼ÒÉ­ÆøÂ¥20ÖÜÄê" title="»­¼ÒÉ­ÆøÂ¥20ÖÜÄê" height="90" width="120" /><cite>»­¼ÒÉ­ÆøÂ¥20ÖÜÄê</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://game.163.com/special/news/obama_game.html">°Â°ÍÂíÓëÃÀ¹úÓÎÏ·µÄÉç»áµØλ</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://game.163.com/11/0408/11/7145QSKP00314K8H.html">ÖйúÓÎÏ·Íæ¼ÒµÄÊ®´ó²»Á¼Ï°¹ß</a></li>
- <li><a href="httpdisabled://game.163.com/11/0408/09/7141LQKA00314K8G.html">75ËêÀÏÄÌÄÌÊÕ·ÏÆ·Çжϻ¥ÁªÍø</a></li>
- <li><a href="httpdisabled://game.163.com/11/0408/09/713VDQE500314K8G.html">×îÖµµÃ¸¶·ÑÏÂÔصÄ30¿îiPadÓÎÏ·</a></li>
- <li><a href="httpdisabled://game.163.com/11/0408/09/7140OAIT00314K8G.html">Ë÷ÄáÍƳöGTÈü³µÔ˶¯ÏµÁзþ×°</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://game.163.com/11/0408/10/7142PQP200314K8F.html">ÎÚ³ľÆëÒ»Ó×½ÌÈýÄ꡶´«Ææ¡·¡°Í桱µô14Íò¹«¿î</a></li>
- <li><a href="httpdisabled://w.163.com/11/0407/15/712281PD00314C3U.html">¹ú·þ·âºÅ´óÁ¦´ò»÷ÍŶӸ±±¾ÆÛÕ©</a> <a target="_blank" href="httpdisabled://w.163.com/11/0407/10/711I56AN00314C3U.html ">ÈýÖÖPVPÍæ¼Ò·ÖÎö</a></li>
- <li><a href="httpdisabled://game.163.com/11/0407/19/712GRGT500314K8H.html">×°»ú£º1ÄêÒÔºóÒ²²»¹ýʱµÄÅ£X»úÆ÷</a> <a target="_blank" href="httpdisabled://game.163.com/11/0407/17/712A7VM000314K95.html">PS3ÍøÂçÔâ¹¥»÷</a></li>
- <li><a href="httpdisabled://game.163.com/11/0408/10/7142145000314K8G.html">ÍæÓÎÏ·¼õÉÙ¾«×ÓÖÂÈË¿ÚϽµ</a> <a target="_blank" href="httpdisabled://game.163.com/11/0408/10/7141U05D00314K8G.html">ÐéÄâÈËÎïÌÆÀÏѼ×îÓÐÇ®</a></li>
- <li><a href="httpdisabled://game.163.com/11/0407/15/71235H5800314K95.html">Ë÷Äá³ÆNGP²»»áÑÓÆÚ</a> <a target="_blank" href="httpdisabled://s.163.com/11/0408/11/71488RKL00314D0E.html">ľ¹ÏÖ®ºóħÊÞÔÙÎÞ¡°Èý¾ÞÍ·¡±</a></li>
- <li><a href="httpdisabled://ka.game.163.com/">[·¢ºÅ]</a> <a target="_blank" href="httpdisabled://ka.game.163.com/ceshihao/xw/ceshi.html">¡¶ÐþÎä¡·ÌåÑé²âÊÔ¼¤»îÂë</a> <a target="_blank" href="httpdisabled://ka.game.163.com/xinshouka/zt2/neice.html">¡¶Õ÷;2¡·¹ó±ö¿¨</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://bbs.game.163.com/"><em class='fB'>ÂÛ̳</em></a> | <a target="_blank" href="httpdisabled://bbs.game.163.com/thread-167638161-1-2.html">ÈéÉñ°æ·¶±ù±ùÆØ˽ÕÕ</a> | <a target="_blank" href="httpdisabled://bbs.game.163.com/thread-167606978-1-3.html">ÃÀÍÈÃûÄ£ÍÑÒÂPKÔ½ÄÏÃÃ</a></li>
- <li><a href="httpdisabled://bbs.game.163.com/"><em class='fB'>Èȵã</em></a> | <a target="_blank" href="httpdisabled://bbs.game.163.com/thread-167619841-1-1.html">ÑîÃݶƨ¹ÉдÕæÁÃÈË</a> | <a target="_blank" href="httpdisabled://bbs.game.163.com/thread-167685377-1-2.html">º«×îÃÀ³µÄ£¾ÞÐØÀ´Ï®</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <ul class="mod-imgList dotline imgList-w160-2 clearfix">
- <li><a href="httpdisabled://game.163.com/photoview/482T0031/19381.html#p=712S98L1482T0031"><img src="../img3.cache.netease.com/game/2011/4/8/20110408100456977e5.jpg" alt="ÃÄÑÛËÖÐØ·çɧÃÀ½¿Äï¹ë·¿×ÔÅÄ" title="ÃÄÑÛËÖÐØ·çɧÃÀ½¿Äï¹ë·¿×ÔÅÄ" height="90" width="160" /></a><p><a href="httpdisabled://game.163.com/photoview/482T0031/19381.html#p=712S98L1482T0031">ÃÄÑÛËÖÐØ·çɧÃÀ½¿Äï¹ë·¿×ÔÅÄ</a></p></li>
- <li><a href="httpdisabled://game.163.com/photoview/43UD0031/19365.html#p=712DL3BB43UD0031"><img src="../img3.cache.netease.com/game/2011/4/8/20110408091923ca1d8.jpg" alt="¡¶½ÖÍ·°ÔÍõ¡·Q°æ½ÇÉ«¶Ô¾ö" title="¡¶½ÖÍ·°ÔÍõ¡·Q°æ½ÇÉ«¶Ô¾ö" height="90" width="160" /></a><p><a href="httpdisabled://game.163.com/photoview/43UD0031/19365.html#p=712DL3BB43UD0031">¡¶½ÖÍ·°ÔÍõ¡·Q°æ½ÇÉ«¶Ô¾ö</a></p></li>
- <li><a href="httpdisabled://game.163.com/photoview/482T0031/19375.html#p=712PC9IB482T0031"><img src="../img4.cache.netease.com/game/2011/4/8/201104081009084803f.jpg" alt="ÃÀ¹úÈËÑÛÖÐ×îÃÀµÄÈÕ±¾ÃÀÅ®" title="ÃÀ¹úÈËÑÛÖÐ×îÃÀµÄÈÕ±¾ÃÀÅ®" height="90" width="160" /></a><p><a href="httpdisabled://game.163.com/photoview/482T0031/19375.html#p=712PC9IB482T0031">ÃÀ¹úÈËÑÛÖÐ×îÃÀµÄÈÕ±¾ÃÀÅ®</a></p></li>
- <li><a href="httpdisabled://game.163.com/photoview/43UD0031/19366.html#p=712DTK3N43UD0031"><img src="../img4.cache.netease.com/game/2011/4/8/201104081007164a116.jpg" alt="ToHeart2СÄÁ°®¼ÑÃÀÉ«ÊÖ°ì" title="ToHeart2СÄÁ°®¼ÑÃÀÉ«ÊÖ°ì" height="90" width="160" /></a><p><a href="httpdisabled://game.163.com/photoview/43UD0031/19366.html#p=712DTK3N43UD0031">ToHeart2СÄÁ°®¼ÑÃÀÉ«ÊÖ°ì</a></p></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://game.163.com/photo/"><em class='fB'>¾«²ÊרÌâ</em></a> | <a target="_blank" href="httpdisabled://game.163.com/special/girls/yxmnchushen.html">½èÓÎÏ·ÉÏλµÄÃÀÅ®</a> | <a target="_blank" href="httpdisabled://game.163.com/special/girls/nvyou.html">ÓëÓÎÏ·ÓÐȾµÄÅ®ÓÅ</a></li>
- <li><a href="httpdisabled://game.163.com/photo/"><em class='fB'>°ËØÔȤͼ</em></a> | <a target="_blank" href="httpdisabled://game.163.com/photoview/43UD0031/18336.html#p=6VBVC0OC43UD0031">»ÎÑÛ´ó°×Íȼ¯½õ</a> | <a target="_blank" href="httpdisabled://game.163.com/photoview/43UD0031/18327.html#p=6VBGSIPC43UD0031">ÓÎÏ·ÖеÄÇéÉ«³¡¾°</a></li>
- <li><a href="httpdisabled://game.163.com/photo/"><em class='fB'>ÓÎÏ·ÃÀÅ®</em></a> | <a target="_blank" href="httpdisabled://game.163.com/photoview/482T0031/19021.html#p=70FD1J8F482T0031">¸É¶¶×ß¹âʧ¿Ø</a> | <a target="_blank" href="httpdisabled://game.163.com/photoview/482T0031/18722.html?1301149813#p=70067SO7482T0031">ÖÜΤͮ³ß¶ÈÔÙÉý¼¶</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://s.163.com/"><img src="../img4.cache.netease.com/game/2011/4/5/2011040502293054a8f.jpg" alt="̨Íæ¼Ò×·ÅõÌ©¹ú¶¹»¨ÃÃ" title="̨Íæ¼Ò×·ÅõÌ©¹ú¶¹»¨ÃÃ" height="90" width="120" /><cite>̨Íæ¼Ò×·ÅõÌ©¹ú¶¹»¨ÃÃ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://s.163.com/">ÐǼÊ2¹«²â½áÊø Ô¿¨¹ºÂòÖ¸ÄÏ</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://s.163.com/11/0408/11/71488RKL00314D0E.html">ľ¹ÏÖ®ºó ħÊÞÔÙÎÞ¡°Èý¾ÞÍ·¡±</a></li>
- <li><a href="httpdisabled://s.163.com/11/0407/23/712S5EH500314D0E.html">GSLÎåÔÂÈüS¼¶·Ö×鹫²¼</a> <a target="_blank" href="httpdisabled://s.163.com/special/gsl/">GSLרÌâ</a></li>
- <li><a href="httpdisabled://s.163.com/11/0406/02/70U4TMRO00314D0E.html">À¶Ìû£ºÐǼÊ2ÔÚÏß³äÖµ·½·¨Ö¸ÄÏ</a></li>
- <li><a href="httpdisabled://s.163.com/11/0406/10/70UV21F200314D0E.html"><ÐǼÊ2>ÕýʽÔËÓª ÌṩÃâ·ÑÊÔÍæ</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://s.163.com/special/00314IL1/sc2zs.html">[¹¥ÂÔ]</a> <a target="_blank" href="httpdisabled://s.163.com/11/0406/15/70VGGIP700314D0E.html">ÐÂÊֱضÁ£ºÎÒ¸ÃÈçºÎ´òÈë¸ü¸ß¼¶±ðÌìÌÝÁªÈü</a></li>
- <li><a href="httpdisabled://s.163.com/special/sc2_videolist/">[ÊÓƵ]</a> <a target="_blank" href="httpdisabled://s.163.com/11/0408/00/7132L16A00314D09.html"><em class=' I_V_'>ÐǼÊ2½Ìѧ:³æ×åÍâË«¿ª¾Ö</em></a> <a target="_blank" href="httpdisabled://s.163.com/11/0408/10/71448F2T00314D09.html">TvZË«±øӪѹÖÆ</a></li>
- <li><a href="httpdisabled://s.163.com/special/sc2_maplist/">[µØͼ]</a> <a target="_blank" href="httpdisabled://s.163.com/11/0407/12/711MMP7L00314D0E.html"><°¬¶ûʳÉñ><ÐDZ¦ÃÔÕó><ÇóÉúÎÞ·>Õ½ÍøÉÏÏß</a></li>
- <li><a href="httpdisabled://s.163.com/special/go4sc2/">[רÌâ]</a> <a target="_blank" href="httpdisabled://s.163.com/11/0408/11/7147LA1200314D09.html"><em class=' I_V_'>Go4SC2ÖйúÇø#21£ºF91¶á¹Ú</em></a> <a target="_blank" href="httpdisabled://s.163.com/11/0408/11/7146GJMP00314D09.html">°ë¾öÈüVOD</a></li>
- <li><a href="httpdisabled://s.163.com/special/00314IL1/sc2events.html">[ÐÂÎÅ]</a> <a target="_blank" href="httpdisabled://s.163.com/11/0407/13/711R0OIJ00314D0E.html">¹ú·þÍ·ÏñµÛ£ºÇàÍ­×é3000+ʤÀû³É¾ÍºÚ°µÖ®Éù</a></li>
- <li><a href="httpdisabled://s.163.com/special/sc2_videolist/">[ÊÓƵ]</a> <a target="_blank" href="httpdisabled://s.163.com/11/0407/00/710EU79900314D09.html"><em class=' I_V_'>JY½â˵:Áú¹·°ü³­ÆÆÉñ×å</em></a> <a target="_blank" href="httpdisabled://s.163.com/11/0407/14/711T9M1N00314D09.html">xiaOt³ÉÍõ֮·2</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://s.163.com/special/sc2_special/"><em class='fB'>ÐǼÊרÌâ</em></a> | <a target="_blank" href="httpdisabled://s.163.com/special/sc2newbie/">ÐǼÊ2ÐÂÊÖרÌâ</a> | <a target="_blank" href="httpdisabled://s.163.com/special/single/">ÐǼÊ2µ¥ÈËÕ½ÒÛרÌâ</a></li>
- <li><a href="httpdisabled://rep.s.163.com/"><em class='fB'>¼ÏñÍƼö</em></a> | <a target="_blank" href="httpdisabled://s.163.com/11/0330/15/70DGET1C00314D06.html">ÐǼÊ2ÿÖܼÏñTOP5</a> | <a target="_blank" href="httpdisabled://rep.s.163.com/Sc2Replay.aspx?ReplayID=4016">¸ÐȾ³æ¿ÕͶÍÀÅ©</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://w.163.com/11/0407/10/711H0GN200314C3U.html"><img src="../img3.cache.netease.com/game/2011/4/8/2011040810253254779.jpg" alt="±©Ñ©¹Ù·½»­ÀȸüÐÂÔ­»­" title="±©Ñ©¹Ù·½»­ÀȸüÐÂÔ­»­" height="90" width="120" /><cite>±©Ñ©¹Ù·½»­ÀȸüÐÂÔ­»­</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://w.163.com/11/0407/15/712281PD00314C3U.html">´ò»÷ÆÛÕ©£º¹ú·þÔÙ·£Êý°ÙÕʺÅ</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://w.163.com/11/0404/10/70PPBQ6200314C3U.html">ESLÖйú¾º¼¼³¡£ºµÚÎå½ì¿ªÊ¼±¨Ãû</a></li>
- <li><a href="httpdisabled://w.163.com/11/0404/10/70POO85E00314C3U.html">Õ½Õ½µÂ´óÄæת»ñESL-Go4WOW¹Ú¾ü</a></li>
- <li><a href="httpdisabled://w.163.com/11/0326/10/702L895300314C3U.html">CTM×îиĶ¯£º¶ÜÅƸ½Ä§50ר¾«</a></li>
- <li><a href="httpdisabled://w.163.com/11/0326/10/702IPQ6900314C3U.html">¸÷Ö°Òµ4T11ÌØЧÊÕÒæÅÅÃû</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://w.163.com/11/0408/11/7145EIFL00314C3U.html">´óÔÖ±ä4.1£º·ÆÀ­Ë¹ÏÖÉñÃضȼٴåׯ</a> <a target="_blank" href="httpdisabled://w.163.com/11/0408/10/7144L1O700314C3U.html">°§º¿¶´Ñ¨½«¼ò»¯</a></li>
- <li><a href="httpdisabled://w.163.com/11/0408/09/7141696E00314C3U.html">DKµ¥Ë¢¿ñÈËÓûµ¥Ìô°ÂÀ­»ù¶û</a> <a target="_blank" href="httpdisabled://w.163.com/11/0408/11/7146BVU100314C3U.html">Èñ²½ÍƳöħÊÞÖ÷ÌâÇòÒÂ</a></li>
- <li><a href="httpdisabled://w.163.com/11/0408/11/7147BMJ300314C3U.html">ÓÎÏ·½Ì»áÎÒµÄÊ®¼þÊÂ</a> <a target="_blank" href="httpdisabled://bbs.game.163.com/thread-167684983-1-1.html">ÐÄÀï½Ç¶È·ÖÎöħÊÞΪºÎÁ÷ÐÐ</a></li>
- <li><a href="httpdisabled://w.163.com/11/0405/17/70T3G1TD00314C3U.html">ħÊÞÄÇЩÄã²»ÖªµÀµÄÊÂ</a> <a target="_blank" href="httpdisabled://bbs.game.163.com/thread-167686243-1-1.html">ÔÙÑ¡Ò»´Î,Ä㻹»áÍæħÊÞÂð£¿</a></li>
- <li><a href="httpdisabled://w.163.com/11/0406/14/70VAR2QQ00314C3U.html">È«ÇòÊ®¼ÑPVPÍæ¼ÒÅÅÃû¼°ÊÓƵ</a> <a target="_blank" href="httpdisabled://w.163.com/11/0407/10/711I56AN00314C3U.html">ÈýÖÖħÊÞPVPÍæ¼Ò·ÖÎö</a></li>
- <li><a href="httpdisabled://w.163.com/11/0407/09/711F0UBC00314C3U.html">ħÊÞ½«¿ÉÔ¶³Ì²ÎÓ빫»áÁÄÌì</a> <a target="_blank" href="httpdisabled://w.163.com/11/0407/09/711E9RP700314C3U.html">̨·þÊ׸ö25¼¶¹«»áµ®Éú</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://w.163.com/special/patch-335/">WLK3.3.5</a>Ø­<a target="_blank" href="httpdisabled://w.163.com/special/patch-335/">ICC¸±±¾È«BOSS¹¥ÂÔÏê½â</a> | <a target="_blank" href="httpdisabled://w.163.com/special/talent/#s">Ì츳ģÄâÆ÷</a></li>
- <li><a href="httpdisabled://w.163.com/special/ctm-cn/"><em class='fB'>´óÔÖ±ä</em></a>Ø­<a target="_blank" href="httpdisabled://w.163.com/10/1207/16/6NAJCKJN00314C3U.html">´óÔÖ±äÁ·¼¶Ö¸ÄÏ</a>Ø­<a target="_blank" href="httpdisabled://w.163.com/special/ctm-cn/">´óÔֱ丱±¾¹¥ÂÔ»ã×Ü</a></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="area-sub">
- <div id="moneySub" class="mod wgt-tab">
- <h2 class="hd clearfix">
- <span class="mod-title"><a href="httpdisabled://money.163.com/blog/">²Æ¾­×¨À¸</a></span>
- </h2>
- <div class="bd">
- <ul class="mod-list sub-list dotline">
- <li class="title"><a href="httpdisabled://gaunzhui01.blog.163.com/blog/static/11604175820113862511825/">³Â±¦´æ£º¶­·ªÈÇÁ˾åŲƸ»Õß</a></li>
- <li><a href="httpdisabled://heyafu67.blog.163.com/blog/static/1073343422011378356242/">ºÎÑǸ££ººÚ»§²»ÈçÎÞ¹ú¼®ÈË</a></li>
- <li><a href="httpdisabled://wavow.blog.163.com/blog/static/5322843201137104410534/">¶Ëºê±ó£ºµÍ̼ÊÇ´¿ºöÓÆ</a></li>
- <li><a href="httpdisabled://xiaochongfan.blog.163.com/blog/static/13056609520113723936387/">·¶Ð¡³å£º×ʱ¾×ªÏò¶þÈýÏß³ÇÊÐ</a></li>
- <li><a href="httpdisabled://sicmonan.blog.163.com/blog/static/137652998201137112349594/">ÕÅÜÔ骣º±ðÌ«Ö¸Íû»õ±ÒÕþ²ß</a></li>
- </ul>
- <ul class="mod-list sub-list">
- <li><a href="httpdisabled://t.163.com/bashusong/status/-4468598182493823262#retweet">°ÍÊïËÉ£ºÅ·Ã˼ÓÏ¢Ã÷ÏÔÌáÇ°ÁË</a></li>
- <li><a href="httpdisabled://t.163.com/zuoshixie/status/6936536041798423727#retweet">л×÷Ê«£ºÖйúË°¸³È«Çò×î¸ßÂð</a></li>
- <li><a href="httpdisabled://t.163.com/dongfan/status/-6533247751173857004">¶­·ª£ºÌ¸ÂÛÇ®²¢²»ÒâζÃÄË×</a></li>
- <li><a href="httpdisabled://blog.163.com/cctv_ds/blog/static/1751641752011382203889/">¶ÔÊÖ£º°Ù¶ÈÎÄ¿âÇÖȨÁËÂð</a></li>
- <li><a href="httpdisabled://t.163.com/mahongtaotao/status/6745596757056097518#retweet">ÂíºéÌΣºéëÔᢶϲúÉú±©Àû</a></li>
- </ul>
- </div>
- </div>
-<div class="gg gg-h180"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=logo190x180&amp;location=3.html" width="190" height="180" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe></div>
- <div id="nie" class="mod">
- <div class="hd clearfix">
- <h2 class="mod-title"><a href="httpdisabled://nie.163.com/">ÍøÒ×ÓÎÏ·</a></h2>
- <span class="mod-entry"><a href="httpdisabled://xyq.163.com/">ÃλÃ</a> <a href="httpdisabled://xy2.163.com/">´ó»°¢ò</a> <a href="httpdisabled://tx2.163.com/">ÌìÏ·¡</a></span>
- </div>
- <div class="bd">
- <div class="mod-imgText imgText-temp-2 dotline clearfix">
- <a href="httpdisabled://qn.163.com/"><img class="imgText-img" src="../qn.163.com/images/qnyh20110411.jpg" alt="¡¶Ù»Å®ÓĻ꡷" title="¡¶Ù»Å®ÓĻ꡷" height="70" width="70" /></a>
- <h3 class="imgText-title"><a href="httpdisabled://qn.163.com/">¡¶Ù»Å®ÓĻ꡷</a></h3>
- <p class="imgText-digest">¼´Ê±ÖÆÐþ»ÃÍøÓθïÐÂ<span class="cDRed"><a href="httpdisabled://qn.163.com/">[Ïêϸ]</a></span></p>
- </div>
- <ul class="mod-list sub-list">
- <li class="title" ><a href="httpdisabled://nie.163.com/news/2011/4/7/440_234177.html" title="ÌìÏ·¡Áã½ç·¢²¼»áÖÜÈÕ¾ÙÐÐ">ÌìÏ·¡Áã½ç·¢²¼»áÖÜÈÕ¾ÙÐÐ</a></li>
- <li ><a href="httpdisabled://qn.163.com/news/2011/3/31/8354_233837.html" title="ٻŮÓÄ»ê4ÔÂ22ÈÕ²»Ï޺ſª²â">ٻŮÓÄ»ê4ÔÂ22ÈÕ²»Ï޺ſª²â</a></li>
- <li ><a href="httpdisabled://csxy.163.com/news/2011/3/30/8533_233741.html" title="´´ÊÀÎ÷ÓÎÇåÃ÷½Ú»î¶¯£º¼ÀÓ¢»ê">´´ÊÀÎ÷ÓÎÇåÃ÷½Ú»î¶¯£º¼ÀÓ¢»ê</a></li>
- <li ><a href="httpdisabled://dt.163.com/2011/syzf/" title="´óÌƺÀÏÀ×ÊÁÏƬ¡¶Ë­ÓëÕù·æ¡·">´óÌƺÀÏÀ×ÊÁÏƬ¡¶Ë­ÓëÕù·æ¡·</a></li>
- <li ><a href="httpdisabled://game.163.com/special/xy2/9years.html" title="¡¶´ó»°Î÷Ó΢ò¡·¾ÅÄê³É¹¦ÔËÓª">¡¶´ó»°Î÷Ó΢ò¡·¾ÅÄê³É¹¦ÔËÓª</a></li>
- <li ><a href="httpdisabled://xy2.163.com/news/2011/3/16/1082_232975.html" title="²Ýľͬ´º--´ó»°2ÇåÃ÷»î¶¯">²Ýľͬ´º--´ó»°2ÇåÃ÷»î¶¯</a></li>
- </ul>
- <p class="entry">
- <span class="cDRed">Íæ¼Ò£º</span><span class="cBlue"><a href="httpdisabled://hi.163.com/user/10037">ÀÏÍ·ÏÉ</a> | <a href="httpdisabled://hi.163.com/user/10015">ÄÝСÄÝ</a></span><br>
- <span class="cDRed">ÂÛ̳£º</span><span class="cBlue"><a href="httpdisabled://zg.netease.com/">Õ½¹ú·çÔÆ</a> | <a href="httpdisabled://tx2.netease.com/">ÌìÏ·¡</a></span>
- </p>
- </div>
- </div>
- </div>
-</div>
-<!-- end -->
-<div class="area">
- <div class="clearfix">
- <div class="area-sub">
- </div>
- <div class="area-main">
- <div class="main-col-9">
- <SCRIPT LANGUAGE="JavaScript">var dovimecount=1;var sinamvadflag0688="";function domvview36413(){var mvimg = new Image();mvimg.src = 'mediav.gif';mvimg.onerror = (mvimg.onloaddisabled=(mvimg.onabort=function(){mvimg = null;}));}function view_mvst36413(){if(typeof(mediav_fini36413)!="number" && dovimecount <60){dovimecount++;setTimeout("view_mvst36413()",50);}else if(typeof(mediav_fini36413)!="number" && dovimecount >=60){sinamvadflag0688=1;domvview36413();document.getElementById('mvdiv_36413').innerHTML="<a href='http://click.mediav.com/c?type=2&db=mediav&pub=118_5273_36442&cus=6_221_7917_11779_11779000&url=http://www.masamaso.com/interface.php?id=103387&url=http://www.masamaso.com?from=r_wy_sy04ztlfdx' target='_blank'><img width='360' height='100' border='' alt='' src='../img1.126.net/channel5/360/360100_110318.jpg'></img></a>";}}view_mvst36413();</SCRIPT><div id="mvdiv_36413" name="mvdiv_36413"><SCRIPT LANGUAGE="JavaScript" src="../show.mediav.com/s@type=1&amp;db=mediav&amp;pub=118_2620_36413&amp;cus=0_0_0_0_0&amp;wh=360x100&amp;btype=1&amp;js=1.html"></SCRIPT></div>
- </div>
- </div>
-</div>
-<!-- trave & blog -->
-<div class="area">
- <div class="area-main">
- <div class="main-col-10">
- <div id="blog" class="mod wgt-tab">
- <div class="tab-hd tab-u-10 clearfix">
- <span class="tab-u current"><a href="httpdisabled://blog.163.com/">²©¿Í</a></span>
- <span class="tab-u"><a href="httpdisabled://blog.163.com/">²Ý¸ù</a></span>
- <span class="tab-u"><a href="httpdisabled://blog.163.com/">¶Áͼ</a></span>
- <span class="tab-u"><a href="httpdisabled://huodong.163.com/">»î¶¯</a></span>
- </div>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://blog.163.com/?blog"><img src="../img2.cache.netease.com/cnews/2011/4/8/20110408125931e0a79.jpg" alt="ŦԼºÃ¶àÓ¦ÕÙÅ®Àɱ»É±" title="ŦԼºÃ¶àÓ¦ÕÙÅ®Àɱ»É±" height="90" width="120" /><cite>ŦԼºÃ¶àÓ¦ÕÙÅ®Àɱ»É±</cite></a>
- </div>
- <h3 class="main-title"><a href="httpdisabled://zuoshixie.blog.163.com/blog/static/12074505220113885244290/?blog">ÈÃÎÒÃǺúÃÏíÊÜ°ËÔªµÄÆûÓÍ°É</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://chenjieren999.blog.163.com/blog/static/18309409020113811227728/?blog">ºÓ±±ºâË®ÖÐÔºÉæÏÓÔì¼Ù°ï¸»ºÀÐÝÆÞ</a></li>
- <li><a href="httpdisabled://zhangxiaozhou-blog.blog.163.com/blog/static/128551850201137930521/?blog">±«²ªµÏÂ×ÊǸöÆßÊ®¶àËêµÄÄ°ÉúÄêÇáÈË</a></li>
- <li><a href="httpdisabled://blog.163.com/xieyong_2011/blog/static/1829532932011377530336/?blog">ÕżÍÖеÄÐÞÑø»¹Ã»ÓÐÍêÈ«µ½¼Ò</a></li>
- <li><a href="httpdisabled://blog.163.com/jinkaiping@yeah/blog/static/131435277201138920477/?blog">Ó¢¹úС»ïÂí¿Ë°ëÄê½á»é85´Î</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://whbsjwcwh.blog.163.com/blog/static/11268102011386431696/?blog">ÎÒÒ»±²×Ó¶¼×¬²»µ½4000Íò</a> <a target="_blank" href="httpdisabled://zhufangqing1968.blog.163.com/blog/static/15074972120113805221196/">"4000Íò½ÌÊÚ"´´°Ë´óÀøÖ¾¸ñÑÔ</a></li>
- <li><a href="httpdisabled://zqguanjianbin.blog.163.com/blog/static/1356647582011385411860/?blog">¶í¹úÍƳö¡°ÐԸз´¸¯¹ÒÀú¡±</a> <a target="_blank" href="httpdisabled://lnsy024110.blog.163.com/blog/static/4139491201137111946665/">ʵÅÄÒÉËÆ´øǹµÄ¿àÐÐÉ®</a></li>
- <li><a href="httpdisabled://gaoweiweiusa.blog.163.com/blog/static/1313159532011351918644/?blog">Öйú±ÈÃÀ¹úÂäºóÕûÕûÒ»°ÙÄꣿ</a> <a target="_blank" href="httpdisabled://blog.163.com/chenwan999@126/blog/static/1305594152011371129432/">Ä«Î÷¸çÈËÔÚÃÀ¹ú¹¤×ʺܵÍ</a></li>
- <li><a href="httpdisabled://beimeigulang.blog.163.com/blog/static/17988801520113834854421/?blog">ɹɹÎÒµÄÉϴ̵¶²½Ç¹¼¯Èº(ͼ)</a> <a target="_blank" href="httpdisabled://huaqiaoliehurenjia.blog.163.com/blog/static/17935603520113724241721/">·ÖÏíÎÒÕä²ØµÄÐÔ¸ÐÑÌǹ(ͼ)</a></li>
- <li><a href="httpdisabled://zzdyc.blog.163.com/blog/static/954980712011367181322/?blog">´´ÊÀÎ÷ÓΣº°×¾§¾§µÄÒ»Éú</a> <a target="_blank" href="httpdisabled://blog.163.com/special/0012rt/xyzw.html">дÕ÷ÎÄÓ®½±</a> <a target="_blank" href="httpdisabled://csxy.163.com/fab/">ÌåÑ顶´´ÊÀÎ÷ÓΡ·</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://feifei6338.blog.163.com/blog/static/16943665420113811108126/?caogen"><img src="../img2.cache.netease.com/cnews/2011/4/8/20110408144428d419d.jpg" alt="°³Ö»ÄÜ×øÔÚ×ÔÐгµÀï¿Þ" title="°³Ö»ÄÜ×øÔÚ×ÔÐгµÀï¿Þ" height="90" width="120" /><cite>°³Ö»ÄÜ×øÔÚ×ÔÐгµÀï¿Þ</cite></a>
- </div>
- <h3 class="main-title"><a href="httpdisabled://blog.163.com/xi_nan@yeah/blog/static/173764699201137931011/?caogen">Ó¢¹ú»ªÈËÉç»áµÄ»Ò°µÃæÁîÈË·¢Ö¸</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://blog.163.com/chenwan999@126/blog/static/1305594152011371129432/?caogen">ÔÚÃÀ¹ú´ò¹¤µÄÄ«Î÷¸ç¹¤È˹¤×ʺܵÍ</a></li>
- <li><a href="httpdisabled://missfaye.fashion.blog.163.com/blog/static/10259226020113894838495/?caogen">70Äê´úµÄ¿íéÜñÓÖ»ØÀ´ÁË(ͼ)</a></li>
- <li><a href="httpdisabled://blog.163.com/xiangqin_good@yeah/blog/static/11811133820113610331622/?caogen">µÂ¹úɽ³Ç£ºÊʺÏÂýÉú»îµÄµØ·½</a></li>
- <li><a href="httpdisabled://crystal3178.blog.163.com/blog/static/14401067620113895714197/?caogen">¿ª¿Ú˵»°Ö®Ç°ÏȵÍÍ·¿´¿´ÄãµÄÉí·Ý</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://hnayhrh.blog.163.com/blog/static/4213388820113784932395/?caogen">´º¼¾ÒªºÈľ¹ÏÖíÌãÌÀ</a> <a target="_blank" href="httpdisabled://maimaidejianguo.blog.163.com/blog/static/126577749201137103515892/">ºÜ¼òµ¥µÄ»¨±ßÏ㳦ÅûÈø</a></li>
- <li><a href="httpdisabled://ssmdsszx.blog.163.com/blog/static/166449346201137112632146/?caogen">ÊÇʲôԭÒòµ¼ÖÂ12ÐÇ×ùÀë»é</a> <a target="_blank" href="httpdisabled://okdj103.blog.163.com/blog/static/140239020113761226563/">±¾ÖÜÊ®¶þÐÇ×ùÔ˳̷ÖÎö</a></li>
- <li><a href="httpdisabled://heiheirage.blog.163.com/blog/static/432978520113724629520/?caogen">ÕâÑùÒ»¸öÓÖÃÈÓÖÇ·µÄÅóÓÑÕæÎÞÄÎ</a> <a target="_blank" href="httpdisabled://dai1209datang.blog.163.com/blog/static/2223546520113695429358/">½²Ò»¸ö¾ÞÀäµÄÀäЦ»°</a></li>
- <li><a href="httpdisabled://chengyuan68.blog.163.com/blog/static/1361893662011387038390/?caogen">°ÍÎ÷ÔÙСµÄµØ·½¶¼ÓÐÒ¹Éú»î</a> <a target="_blank" href="httpdisabled://ratpetty.blog.163.com/blog/static/6929691120113710417754/">×øС·É»ú±»»ú³¤À­×Ų»ÈöÊÖ</a></li>
- <li><a href="httpdisabled://ldupaper.blog.163.com/blog/static/1329149852011321224510/?caogen">һλÊÔ¹ÜÓ¤¶ùÂèÂèµÄѪÀá»éÒöÊ·</a> <a target="_blank" href="httpdisabled://blog.163.com/jinkaiping@yeah/blog/static/13143527720113691836307/">Àϸ¾³¤ÊÙÖ»ÒòÒ»Éú²»×ö°®</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <ul class="mod-imgList imgList-w120 clearfix">
- <li><a href="httpdisabled://picture007.blog.163.com/album/?saitu#m=2&aid=220179338&pid=6825388527"><img src="../img2.cache.netease.com/cnews/2011/4/8/2011040808393075049.jpg" alt="¿´ÃÀ¹úµÄÂäÆÇÆòؤȺ" title="¿´ÃÀ¹úµÄÂäÆÇÆòؤȺ" height="90" width="120" /></a><p><a href="httpdisabled://picture007.blog.163.com/album/?saitu#m=2&aid=220179338&pid=6825388527">¿´ÃÀ¹úµÄÂäÆÇÆòؤȺ</a></p></li>
- <li><a href="httpdisabled://kenglhh.blog.163.com/album/?saitu#m=2&aid=221347549&pid=6874620546"><img src="../img1.cache.netease.com/cnews/2011/4/8/201104080847137e997.jpg" alt="Сº¢Ó붯ÎïºÏÅÄÐÐΪ" title="Сº¢Ó붯ÎïºÏÅÄÐÐΪ" height="90" width="120" /></a><p><a href="httpdisabled://kenglhh.blog.163.com/album/?saitu#m=2&aid=221347549&pid=6874620546">Сº¢Ó붯ÎïºÏÅÄÐÐΪ</a></p></li>
- <li><a href="httpdisabled://blog.163.com/xiongy_l/album/?saitu#m=2&aid=221372151&pid=6875512485"><img src="../img1.cache.netease.com/cnews/2011/4/8/2011040808080199ae7.jpg" alt="а¶ñµÄ´´ÒâÉÌÒµ¹ã¸æ" title="а¶ñµÄ´´ÒâÉÌÒµ¹ã¸æ" height="90" width="120" /></a><p><a href="httpdisabled://blog.163.com/xiongy_l/album/?saitu#m=2&aid=221372151&pid=6875512485">а¶ñµÄ´´ÒâÉÌÒµ¹ã¸æ</a></p></li>
- <li><a href="httpdisabled://picture007.blog.163.com/blog/static/182129446201137115819892/?saitu"><img src="../img2.cache.netease.com/cnews/2011/4/8/201104080828458908d.jpg" alt="ʵÅÄÈ⼦ÍÀÔ×¼Ó¹¤³§" title="ʵÅÄÈ⼦ÍÀÔ×¼Ó¹¤³§" height="90" width="120" /></a><p><a href="httpdisabled://picture007.blog.163.com/blog/static/182129446201137115819892/?saitu">ʵÅÄÈ⼦ÍÀÔ×¼Ó¹¤³§</a></p></li>
- <li><a href="httpdisabled://image007.blog.163.com/album/?saitu#m=2&aid=221358852&pid=6875473251"><img src="../img1.cache.netease.com/cnews/2011/4/8/2011040811445023471.jpg" alt="´óѧÉúÉÏÑÝÄÚÒÂÅɶÔ" title="´óѧÉúÉÏÑÝÄÚÒÂÅɶÔ" height="90" width="120" /></a><p><a href="httpdisabled://image007.blog.163.com/album/?saitu#m=2&aid=221358852&pid=6875473251">´óѧÉúÉÏÑÝÄÚÒÂÅɶÔ</a></p></li>
- <li><a href="httpdisabled://blog.163.com/xiongy_l/album/?saitu#m=2&aid=221344170&pid=6874340532"><img src="../img1.cache.netease.com/cnews/2011/4/8/20110408075741e084c.jpg" alt="ͼÊé¹ÝÄÇЩÀ×ÈË˯×Ë" title="ͼÊé¹ÝÄÇЩÀ×ÈË˯×Ë" height="90" width="120" /></a><p><a href="httpdisabled://blog.163.com/xiongy_l/album/?saitu#m=2&aid=221344170&pid=6874340532">ͼÊé¹ÝÄÇЩÀ×ÈË˯×Ë</a></p></li>
- </ul>
- </div>
- <div class="tab-con">
- <a href="httpdisabled://yxp.163.com/h/action/scty5.html?sss=fromsyehddt&act=yxpty5_20110331_13?id_2010?huodong"><img src="../imgrc.ph.126.net/F4Oc-9fe_HYFRsSk0SRMmA==/4223532025543403580.jpg" alt="Ó¡ÏñÅÉ" title="Ó¡ÏñÅÉ" class="main-bn-blog" height="90" width="370" /></a>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://blog.163.com/ht/38?id_2020?huodong">¡¾Çé¸ÐÃÅÕï¡¿½â´ðÄãµÄÇé¸ÐÀ§ÈÅ</a></li>
- <li><a href="httpdisabled://mhxx.dream.163.com?mail=mhxx_20110316_05?id_2021?huodong">ÃλÃÐÞÏÉзþ»ð±¬¿ªÆô</a></li>
- <li><a href="httpdisabled://yxp.163.com/?sss=fromsyehdwz&act=yxpspring15_20110401_24?id_2022?huodong">¼Ç¼´ºÓκÃʱ¹â£¬ÁìÃâ·Ñ³åӡȯ</a></li>
- <li><a href="httpdisabled://pmxj.wan.163.com/?02?id_2023?huodong">´©Ô½Ê±¿Õ¸°ÉñÖÝ£¬ÒÀ½£ºÀÒûնħͷ.</a></li>
- <li><a href="httpdisabled://yxp.163.com/h/139.html?sss=frombkesywz&act=yxp139_20110324_08?id_2024?huodong">È«ÇòͨÓû§ËÙÀ´ÁìÈ¡9999·ÝÃâ·Ñ³åӡȯ£¡</a></li>
- <li><a href="httpdisabled://fm.163.com/activities/fmzhcd/index.html?act=fmzhcd_20110314_03?id_2025?huodong">ÖÇÄÜ°æÉÁµçÓÊÀ´¸øÄãµÄÖǻ۳äµçÀ²£¬ÌåÑé¸üÓÐitouchËÍ£¡</a></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- <div class="main-col-9">
- <div id="hz" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-9 clearfix">
- <span class="tab-u current"><a href="httpdisabled://blog.163.com/blogger.html">רÀ¸</a></span>
- <span class="tab-u"><a href="httpdisabled://photo.163.com/pp/square/">ÉãÓ°</a></span>
- <span class="tab-u"><a href="httpdisabled://idj.163.com/">ÔÚÏßÒôÀÖ</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://liuyongtw.blog.163.com/blog/static/18040812520113724310499/?zhuanlan"><img src="../img1.cache.netease.com/cnews/2011/4/8/201104080930016f866.jpg" alt="ÁõÜ­£ºÂíÓ¢¾Å¸øÎÒÅõ³¡" title="ÁõÜ­£ºÂíÓ¢¾Å¸øÎÒÅõ³¡" height="90" width="120" /><cite>ÁõÜ­£ºÂíÓ¢¾Å¸øÎÒÅõ³¡</cite></a>
- </div>
- <h3 class="main-title"><a href="httpdisabled://blog.163.com/tianye_1993/blog/static/561294622011368336805/?zhuanlan">ݼ³Ç×Ó£º¹«²Þ¸ÃÓÉË­Ìṩ£¿</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://alahaigui.blog.163.com/blog/static/2639938820113885754537/?zhuanlan">ºúÈÙÈÙ£º½ðӹС˵ÃÀÅ®Èý´ó´ú±í</a></li>
- <li><a href="httpdisabled://cat898-com.blog.163.com/blog/static/12897521620113803224425/?zhuanlan">ÀèÃ÷£º´ÓÁÙÅèµ½ËÀºó¶¼±»ÇÃÖñ¸Ü</a></li>
- <li><a href="httpdisabled://yetanblog.blog.163.com/blog/static/75669740201138093248/?zhuanlan">Ҷ̴£ºÃñ¼ä½ðÈÚÅÝÄ­½Ó½ü±ÀÀ£</a></li>
- <li><a href="httpdisabled://sheng.dalin.blog.163.com/blog/static/127099945201138051951/?zhuanlan">Ê¢´óÁÖ£ºÎï¼Û¼à¹ÜË«Öرê×¼²»Í×</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://blog.163.com/xk_shijieguan/blog/static/13340475320113741028743/?zhuanlan">³ÂÑÔ£ºÈÕ±¾´Ä³ÇÏØÓæÃñµÄ¿àÈÕ×ÓÏÖÔڲŸոտªÊ¼</a></li>
- <li><a href="httpdisabled://zhangjinlai0412.blog.163.com/blog/static/65913120201137101013443/?zhuanlan">ÁùСÁäͯ£ºÉîÉîÃ廳ÌìÖ®½¾×ÓÖܺ£Ó¤ÏÈÉú</a></li>
- <li><a href="httpdisabled://haoyuehan.blog.163.com/blog/static/70742672011389054501/?zhuanlan">º«ºÆÔ£º±«²ª¡¤µÏÂ×ÈÃÈ˸Ð̾ҡ¹ö¾«Éñ¹ââÍòÕÉ</a></li>
- <li><a href="httpdisabled://t.163.com/shishusi/status/1136017994388299708?zhuanlan">[»°Ìâ]ʯÊö˼£ºÄÐŮͬÁäÍËÐÝÖ»»á¼Ó¾ç½×²ãÁѺÛ</a></li>
- <li><a href="httpdisabled://t.163.com/mikesakai/status/8789474217947845724#retweet?zhuanlan">[»°Ìâ]Çű¾Â¡Ôò£ºÈÕ±¾ÒѾ­½øÈëµØÕð»îԾʱÆÚ</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <ul class="mod-imgList imgList-w160 clearfix">
- <li><a href="httpdisabled://photo.163.com/pp/square/?sheying"><img src="../imgrc.ph.126.net/chRhUK9Mxz9gdCzkEUzn5w==/4226346775310512150.jpg" alt="[ÍƼö] ±ðÕëµÄССÊÀ½ç" title="[ÍƼö] ±ðÕëµÄССÊÀ½ç" height="90" width="160" /></a><p><a href="httpdisabled://photo.163.com/pp/square/?sheying">[ÍƼö] ±ðÕëµÄССÊÀ½ç</a></p></li>
- <li><a href="httpdisabled://photo.163.com/pp/zhuanti.html?sheying"><img src="../imgrc.ph.126.net/nSvNUs-5vbkySqbYp-lnLw==/4226628250287222807.jpg" alt="[רÌâ] ÅØÏø½ÌÖ÷ÄãÉ˲»Æð" title="[רÌâ] ÅØÏø½ÌÖ÷ÄãÉ˲»Æð" height="90" width="160" /></a><p><a href="httpdisabled://photo.163.com/pp/zhuanti.html?sheying">[רÌâ] ÅØÏø½ÌÖ÷ÄãÉ˲»Æð</a></p></li>
- <li><a href="httpdisabled://photo.163.com/pp/star/?sheying"><img src="../imgrc.ph.126.net/VfPeCwJ6ufovjjY9ueyUxA==/4224939400426958880.jpg" alt="[ÈËÎï] Éú»î»ýµíËù²úÉúµÄÖ±¾õ" title="[ÈËÎï] Éú»î»ýµíËù²úÉúµÄÖ±¾õ" height="90" width="160" /></a><p><a href="httpdisabled://photo.163.com/pp/star/?sheying">[ÈËÎï] Éú»î»ýµíËù²úÉúµÄ</a></p></li>
- <li><a href="httpdisabled://photo.163.com/pp/fotoshow/14003/?sheying"><img src="../imgrc.ph.126.net/40YCPhfL6uaLg3xA4ISWew==/4227754150194064440.jpg" alt="[Ó°Ïñ] ׯ±ä ¾µÍ·ÀïµÄʯ¼Òׯ" title="[Ó°Ïñ] ׯ±ä ¾µÍ·ÀïµÄʯ¼Òׯ" height="90" width="160" /></a><p><a href="httpdisabled://photo.163.com/pp/fotoshow/14003/?sheying">[Ó°Ïñ] ׯ±ä ¾µÍ·ÀïµÄʯ¼Ò</a></p></li>
- </ul>
- <div class="mod-keyword c-entry clearfix">
- <h3 class="keyword-hd"><a href="httpdisabled://photo.163.com/upgrade/welcome/">¿ªÍ¨ÉãÓ°¿Õ¼ä£¬¼ÓÈëÍøÒ×ÉãÓ°ÉçÇø <span class="code-en">&raquo;</span></a></h3>
- </div>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://idj.163.com/idj/album/42444"><img src="../img1.cache.netease.com/cnews/2011/4/8/2011040815090608fd9.jpg" alt="ÐíáÔ:ËÕ¸ñÀ­Ã»Óе×" title="ÐíáÔ:ËÕ¸ñÀ­Ã»Óе×" height="90" width="120" /><cite>ÐíáÔ:ËÕ¸ñÀ­Ã»Óе×</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://idj.163.com/idj/album.jsp?id=42443"><em class='fB'>²¼À¼ÄÝ¡¶Femme Fatale¡·</em></a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://idj.163.com/idj/album/42438">¼ÍÎÄÞ¥ÐÂר¼­¡¶»»ÈÕÏß¡·</a></li>
- <li><a href="httpdisabled://idj.163.com/idj/album/42435">·¶çâç÷ÐÂר¼­¡¶Love&FanFan¡·</a></li>
- <li><a href="httpdisabled://idj.163.com/idj/album/42428"><em class='cBlack'>ËïÑà×Ë×îÐÂר¼­¡¶ÊÇʱºò¡·</em></a></li>
- <li><a href="httpdisabled://idj.163.com/idj/mv_love.jsp"><em class='cBlack'>רÌâ:ÄÇЩ¹ØÓÚ°®ÇéµÄÁ·Ï°Ìâ</em></a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://idj.163.com/idj/earth.jsp"><em class=' I_M_'>[иè] </em></a> <a target="_blank" href="httpdisabled://idj.163.com/idj/listen.jsp?type=music&id=200441">¶¼Ê²Ã´Ê±ºòÁË-ÕÅ»ÝÃÃ</a> <a target="_blank" href="httpdisabled://idj.163.com/idj/listen.jsp?type=music&id=200751"> ÎÒ¶¼¶®µÃ-Å®ÅóÓÑ</a></li>
- <li><a href="httpdisabled://idj.163.com/idj/mv.jsp"><em class=' I_V_'>[MV]</em></a> <a target="_blank" href="httpdisabled://idj.163.com/idj/mvplay.jsp?vid=6245">ССÂìÒÏ-ÅËçâ°Ø</a> <a target="_blank" href="httpdisabled://idj.163.com/idj/mvplay.jsp?vid=6247"> ÓÞÈ˵Ĺú¶È-ËïÑà×Ë</a></li>
- <li><a href="httpdisabled://idj.163.com/idj/group.jsp">[ÂÛ̳]</a> <a target="_blank" href="httpdisabled://idj.163.com/idj/group_theme_page.jsp?tid=729&gid=68">¶àÊ×½ðÇú±¬ÔÞ»ìÒômv´óÊײ¥</a></li>
- <li><a href="httpdisabled://idj.163.com/idj/earth.jsp">[°ñµ¥]</a> |<a target="_blank" href="httpdisabled://idj.163.com/idj/earth_more.jsp?gdid=254">»ªÓï</a> |<a target="_blank" href="httpdisabled://idj.163.com/idj/earth_more.jsp?gdid=256">Å·ÃÀ</a> |<a target="_blank" href="httpdisabled://idj.163.com/idj/earth_more.jsp?gdid=255">ÈÕº«</a> |<a target="_blank" href="httpdisabled://idj.163.com/idj/earth_more.jsp?gdid=318">¶¯Âþ</a> |<a target="_blank" href="httpdisabled://idj.163.com/idj/earth.jsp">¸ü¶à</a></li>
- <li><a href="httpdisabled://idj.163.com/idj/special_index.jsp">[×ÔÑ¡¼¯]</a> <a target="_blank" href="httpdisabled://idj.163.com/idj/special.jsp?uid=81&tid=2614">˼Éú»î-ÐÂÏÊD</a> <a target="_blank" href="httpdisabled://idj.163.com/idj/special.jsp?uid=232443&tid=8750"> ¸ø×îºÃµÄʱ¹â</a></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="area-sub">
-</div>
-<!-- end -->
-<!-- UGC -->
-<div class="area">
- <div class="area-main">
- <div class="main-col-10">
- <div id="market" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-10 clearfix">
- <span class="tab-u current"><a href="httpdisabled://travel.163.com/">ÂÃÓÎ</a>¡¤<a href="httpdisabled://edu.163.com/">½ÌÓý</a></span>
- <span class="tab-u"><a href="httpdisabled://travel.163.com/">¹úÄÚ¡¤³ö¾³</a></span>
- <span class="tab-u"><a href="httpdisabled://edu.163.com/">¿¼ÊÔ¡¤Áôѧ</a></span>
- <span class="tab-u"><a href="httpdisabled://baby.163.com/">Ç××Ó</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://daxue.163.com/11/0406/12/70V46VIP00913JC5.html"><img src="../img3.cache.netease.com/edu/2011/4/6/20110406220601277f0.jpg" alt="²»ÎªÈËÖªµÄ&quot;×î&quot;×Ö¸ßУ" title="²»ÎªÈËÖªµÄ&quot;×î&quot;×Ö¸ßУ" height="90" width="120" /><cite>²»ÎªÈËÖªµÄ"×î"×Ö¸ßУ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://edu.163.com/">ѧÉú40ËêûÓÐ4000Íò ÎÞÑÕ¼ûµ¼Ê¦</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://edu.163.com/liuxue">½ÌÓý²¿¹«²¼×îÐÂÅú×¼¾³Íâ¸ßУÃûµ¥</a></li>
- <li><a href="httpdisabled://edu.163.com/11/0407/19/712EDPKR00294IJ5.html">̨¸ßУ´ó½ÕÐ2141ÈË Ë½Á¢Ñ§·Ñ2Íò</a></li>
- <li><a href="httpdisabled://edu.163.com/11/0408/13/714E66Q000294IJK.html">°µ·ÃÄÚÄ»£º¹«¿¼ÅàѵʮÌìѧ·Ñ¹ýÍò</a></li>
- <li><a href="httpdisabled://edu.163.com/11/0408/10/7144BG1D00294IJH.html">×éͼ£º"±±Æ¯"½ÖÎèÄÐÌÆÏþº½µÄÒ»Ìì</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://travel.163.com/11/0406/11/70V1TCLP00063KE8.html">4Ô¹úÄÚÈÈÃÅÄ¿µÄµØÍƼö</a> <a target="_blank" href="httpdisabled://travel.163.com/photoview/4CHV0006/1465.html#p=708NVJDI4CHV0006">Çã¼Òµ´²úµÄÓ¡¶ÈÉÝ»ª»éÀñ(ͼ)</a></li>
- <li><a href="httpdisabled://travel.163.com/11/0406/15/70VG176200063JSA.html">±±¾©»¨ÆÚ¸÷´óÉÍ»¨µØÍƼö(ͼ)</a> <a target="_blank" href="httpdisabled://travel.163.com/photoview/4DB90006/1487.html#p=70VS0IQS4DB90006">³©ÓÎÑÇÂíÑ·"¼ÓÀÕ±Èɳ̲"</a></li>
- <li><a href="httpdisabled://travel.163.com/11/0406/10/70UV76E400063KE8.html">¸æ±ð"ʣŮ"6´óÂÃÓÎÊ¥µØ</a> <a target="_blank" href="httpdisabled://travel.163.com/hellocity/">³É¶¼º¼ÖÝÕù¶áÐÝÏгÇÊÐÈËÆøÍõ</a></li>
- <li><a href="httpdisabled://travel.163.com/11/0406/11/70V0H2H600063IO0.html">È«Çò29´ó"ÄÐÈËÌìÌÃ"</a> <a target="_blank" href="httpdisabled://travel.163.com/11/0406/19/70VTRF6F00063KE8.html">·ÇÖÞÇÀ»é:¿´¼ûƯÁÁÅ®È˾ÍÇÀ(ͼ)</a></li>
- <li><a href="httpdisabled://travel.163.com/photoview/17KK0006/1486.html#p=70VT2TKA17KK0006">ÁîÈËÕ¦ÉàµÄÄá²´¶û¿àÐÐÉ®(ͼ)</a> <a target="_blank" href="httpdisabled://travel.163.com/11/0406/16/70VIHAFQ00063KE8.html">̽Ãص¹úµÄºÏ·¨¼ËÔº(ͼ)</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://travel.163.com/photoview/17KK0006/1491.html#p=711HLS7217KK0006"><img src="../img3.cache.netease.com/travel/2011/4/7/2011040719553034b7b.jpg" alt="µØÇòÉÏ×îÏñÍâÐǵĵط½" title="µØÇòÉÏ×îÏñÍâÐǵĵط½" height="90" width="120" /><cite>µØÇòÉÏ×îÏñÍâÐǵĵط½</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://travel.163.com/11/0407/11/711J068700063KE8.html">×îÊÜÍâ¹úÈËϲ»¶µÄÖйú10´ó¾°µã</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://travel.163.com/11/0407/15/7122IB4T00063IO0.html">ÖйúÊ®´ó¡°ÀäÄ®¡±³ÇÊÐÅÅÐаñ(ͼ)</a></li>
- <li><a href="httpdisabled://travel.163.com/photoview/17KK0006/1489.html#p=711EUAOJ17KK0006">¾ø¶ÔÁîÈ˾ªÑ޵ķۺìɫɳ̲(ͼ)</a></li>
- <li><a href="httpdisabled://travel.163.com/11/0407/13/711SQ0DJ00063KE8.html">ÁíÀà·þÎñ ÃÀÅ®Õдý´©»¤Ê¿×°ÓÃÕëͲ</a></li>
- <li><a href="httpdisabled://travel.163.com/11/0407/10/711GEUNS00063KE8.html">Å®ÐÔÎðÈ룡ֻÓÐÄÐÈ˵ÄÏ£À°Ð¡µº(ͼ)</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://travel.163.com/11/0407/12/711NJJHP00063KE8.html">ÎåÒ»³ö¾³ÓμÛÕÇÁ½³É ÀËÂþº£µºÈËÆø×î¸ß</a> <a target="_blank" href="httpdisabled://travel.163.com/11/0407/13/711SF6PT00063KE8.html">´ºÈÕµÇɽȫÍƼö</a></li>
- <li><a href="httpdisabled://travel.163.com/11/0407/12/711NC3I300063KE8.html">ÊÀ½ç10´óµØÀíÆæ¹ÛÁîÈ˾ªÌ¾</a> <a target="_blank" href="httpdisabled://travel.163.com/11/0407/15/71214JK800063IO0.html">È«Çò×îÃÀÀ뵺³©Óι¥ÂÔ(ͼ)</a></li>
- <li><a href="httpdisabled://travel.163.com/11/0407/12/711NC28S00063KE8.html">´ºÈÕÃÀʳÓÕ»ó Æ·½­ÄÏС×ʲÍÌü</a> <a target="_blank" href="httpdisabled://travel.163.com/11/0407/13/711SAO9700063KE8.html">ÂíÀ´Î÷ÑÇÒìÓò·çÇéÓι¥ÂÔ</a></li>
- <li><a href="httpdisabled://travel.163.com/11/0407/10/711HN0GS00063KE8.html">Öйú×îÃÀÎåºþʮɽ</a> <a target="_blank" href="httpdisabled://travel.163.com/11/0407/11/711JQGAM00063KE8.html">ÎåÒ»ÉÍ»¨µØͼ</a> <a target="_blank" href="httpdisabled://travel.163.com/11/0407/14/711TDGE400063KE8.html">ɽÎ÷ƽ˳Ç×Éí¹¥ÂÔ(ͼ)</a></li>
- <li><a href="httpdisabled://travel.163.com/11/0406/17/70VM1JO800063IBJ.html">´ºÈÕÁµÉϵ¥³µÂÃÐÐ(ͼ)</a> <a target="_blank" href="httpdisabled://travel.163.com/11/0406/11/70V0RMIB00063KE8.html">2011Ó¢Â×Çà´ºÓÎ 29¼þ±Ø×öÖ®ÊÂ</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://daxue.163.com/11/0407/18/712BAVEJ00913JC5.html"><img src="../img3.cache.netease.com/edu/2011/4/9/20110409001451f646c.jpg" alt="´óѧÉúÂ鶹ÈÕ׬Êý°ÙÔª" title="´óѧÉúÂ鶹ÈÕ׬Êý°ÙÔª" height="90" width="120" /><cite>´óѧÉúÂ鶹ÈÕ׬Êý°ÙÔª</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://edu.163.com/11/0408/10/7143IOQU00293L7F.html">ÎÄÃ÷¶½²é¶Ó½ûѧÉú"¹«¹²³¡ËùÇ×ÈÈ"</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://edu.163.com/special/kaoyan2011/">¿¼Ñе÷¼ÁÕýÔÚ½øÐÐ ×¥½ôÍøÉϱ¨Ãû</a></li>
- <li><a href="httpdisabled://edu.163.com/11/0407/18/712DJDH400294IJ5.html">±±¾©¸ß¿¼¼Ó·Ö·¶Î§ 5Äê¡°ÊÝÉí¡±5´¦</a></li>
- <li><a href="httpdisabled://daxue.163.com/11/0407/14/711VTQ7600913JC5.html">24¸ö×îÈÝÒ×±»Îó½âµÄ¸ß¿¼×¨Òµ(ͼ)</a></li>
- <li><a href="httpdisabled://edu.163.com/11/0407/17/7129RGOE00294IPN.html">¼ÓÄôóÑô¹âÃûµ¥ ¹«ÎñÔ±Èë¸ßнÐÐÒµ</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://t.163.com/mylovelydog/status/3130838611543801875#retweet">[΢²©]"³©Ñ§"°ÄÖÞ£º°ÄÖ޵ĴóѧÔÊÐí¡°ÄԲС±´æÔÚ</a></li>
- <li><a href="httpdisabled://daxue.163.com/11/0408/16/714OLNEO00913KMA.html">[¾ÍÒµ]´óÈýѧÉúѧУʳÌÿª·¹ÆÌ ¿ªÒµÁ½Ìì½øÕË4000Ôª</a></li>
- <li><a href="httpdisabled://kids.163.com/11/0408/11/7145E9RC002942C4.html">[ÇàÉÙ]µ÷²é£ºÖйú¶ÀÉú×ÓÅ®ÓÐ×ÔÁµÇãÏò Íâ±í¾ö¶¨×Ô×ð</a></li>
- <li><a href="httpdisabled://edu.163.com/11/0406/17/70VNK51500294IIH.html">[Áôѧ]²»¿´²»ÖªµÀ£ºÖйúÁôѧÉú×î°®Ôú¶ÑÊ®´ó¹ú¼Ò</a></li>
- <li><a href="httpdisabled://daxue.163.com/photoview/0HQO0091/198.html#p=71499BOF0HQO0091">[×éͼ]ÄêÇáÈ˵Ä"ÁíÀà¼õѹ"·½Ê½£ºÆ¯¸¡¡¢»³¾É¡¢±§±§×å</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://baby.163.com/special/bbc110408/"><img src="../img4.cache.netease.com/lady/2011/4/7/2011040711484089cba.jpg" alt="͵Åij¬ÊÐÀïµÄСÃÈÅ®" title="͵Åij¬ÊÐÀïµÄСÃÈÅ®" height="90" width="120" /><cite>͵Åij¬ÊÐÀïµÄСÃÈÅ®</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://baby.163.com/special/wennibaqu/">ÂèÂ裬ΪʲôÄãºÍ°Ö°ÖÍíÉÏÓйÖÉù</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://baby.163.com/11/0407/14/7120CI3V00262I29.html">¼ÙÈ红×ÓÓöµ½ÐÔÉ˺¦ ÄãÒªÔõô°ì</a></li>
- <li><a href="httpdisabled://baby.163.com/11/0407/15/71239FNK00262HRQ.html">ÔõÑùÈÃ80ºóС°Éú¡±´úÄÌË®³ä×㣿</a></li>
- <li><a href="httpdisabled://baby.163.com/11/0407/15/7121GN8400262HRG.html">Äк¢Ö®¼äÖÇÁ¦²î¾à´ó Å®º¢Ïà¶Ôƽ¾ù</a></li>
- <li><a href="httpdisabled://baby.163.com/11/0406/14/70VCDM6F00262USS.html">´ó³ß¶ÈÐÔ½ÌÓý»æ±¾¡¶ÎÒ´ÓÄÄÀïÀ´¡·</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://bbs.lady.163.com/list/xybb.html">[ÂÛ̳]</a> <a target="_blank" href="httpdisabled://bbs.lady.163.com/bbs/xybb/205510146.html">´ó¼Ò°ïæ¿´¿´ ÕâÇé¿öÊÇÀ´Ô¾­»¹ÊÇÁ÷²ú</a></li>
- <li><a href="httpdisabled://bbs.lady.163.com/list/hyrj.html">[ÂÛ̳]</a> <a target="_blank" href="httpdisabled://bbs.lady.163.com/bbs/yunzhou18/205253191.html">ÊÖµçͲ̥½Ì ÊÖµçͲ½ÐBB¡°Æ𴲡±Ëû»ØÓ¦</a></li>
- <li><a href="httpdisabled://bbs.lady.163.com/list/mmbb.html">[ÂÛ̳]</a> <a target="_blank" href="httpdisabled://bbs.lady.163.com/bbs/mmbb/205499080.html">¿´µ½ÎҹصçÄÔ ±¦±¦¾¹À´¾ä£º±¦±¦ºÜÂúÒâ</a></li>
- <li><a href="httpdisabled://t.163.com/baby163">[΢²©]</a> <a target="_blank" href="httpdisabled://t.163.com/zhile365/status/3418988806356097742#retweet">³£ËµÐ»Ð»µÄº¢×ÓÇéÉ̸ü¸ß ¸üÀÖÓÚÖúÈË</a></li>
- <li><a href="httpdisabled://baby.163.com/special/bbc11003/"><em class='fB'>3Ô·âÃ汦±¦ÈËÆøͶƱ</em></a> | <a target="_blank" href="httpdisabled://baby.163.com/special/wangchaoge/"><em class='fB'>¹«ÒæÃ÷ÐÇÂèÂ裺Íõ³±¸è</em></a></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- <div class="main-col-9">
- <div id="bbs" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-9 clearfix">
- <span class="tab-u current"><a href="httpdisabled://bbs.163.com/">ÂÛ̳</a></span>
- <span class="tab-u"><a href="httpdisabled://bbs.163.com/photo/">ɹͼ</a></span>
- <span class="mod-entry"><a href="httpdisabled://bbs.163.com/rank/">·çÔÆ°ñ</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://bbs.163.com/"><img src="../img2.cache.netease.com/cnews/2011/4/8/201104080728304dcb2.jpg" alt="ÍøÆØÉîÛÚÇéÉ«Ò¹µêÕÕƬ" title="ÍøÆØÉîÛÚÇéÉ«Ò¹µêÕÕƬ" height="90" width="120" /><cite>ÍøÆØÉîÛÚÇéÉ«Ò¹µêÕÕƬ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5041.html">¡¡ÃÀ¹ú´óѧÄÐÅ®¼¤ÇéÄÚÒÂÅɶÔ</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://bbs.news.163.com/bbs/photo/205486243.html">Ò˱öÏØȺÄÐŹ´ò¸¾Å®¼à¿ØÆعâ</a></li>
- <li><a href="httpdisabled://bbs.news.163.com/bbs/pp/205532782.html">ÆæÎÅ£¡Ô­À´´óÊ÷»¹ÐèÒª´òµõÕë</a></li>
- <li><a href="httpdisabled://bbs.gz.house.163.com/bbs/housegossip/205313202.html">ÅóÓѸÕ×°ÐÞÍêµÄмҽá¹û±­¾ßÁË</a></li>
- <li><a href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5044.html">ó¯òëÂèÂèÉú±¦±¦¹ý³Ì ¶ñÐÄÉ÷Èë</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://bbs.163.com/photo/">[Éç»á]</a> <a target="_blank" href="httpdisabled://bbs.gz.house.163.com/photoview/2ALD0015/5037.html">"×îţ¥·¿"ѹÇÅÏÂ15Äê</a> <a target="_blank" href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5047.html">¡¡ÍµÅĽÖÍ·´óµ¨ÃÍÅ®</a></li>
- <li><a href="httpdisabled://club.auto.163.com/">[Æû³µ]</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_bbtx/205555685.html">Å££¡¹«Îñ³µ¾ÍÃâ·ÑÍ£</a> <a target="_blank" href="httpdisabled://club.auto.163.com/bbs/auto_01m0/205427558.html">¡¡ÓͼÛÉÏÕǺó×îNB³µÌù</a></li>
- <li><a href="httpdisabled://bbs.home.163.com/list/homeshow.html">[¼Ò¾Ó]</a> <a target="_blank" href="httpdisabled://bbs.home.163.com/bbs/sheji/205326250.html">9Íò´òÔìÏç´åʽ±ðÊû</a> <a target="_blank" href="httpdisabled://bbs.home.163.com/bbs/toushu/205484672.html">¡¡¶¬Ìì¸Õ¹ýÂíÍ°¾ÍÁÑÁË</a></li>
- <li><a href="httpdisabled://bbs.163.com/photo/">[ͼ¿â]</a> <a target="_blank" href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5031.html">ÈÃÃÀÅ®Õ𾫵ÄÏû»êÒÕÊõ</a> <a target="_blank" href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5020.html">¡¡Å·ÖÞ¼ËÔºÃâ·Ñ·þÎñ</a></li>
- <li><a href="httpdisabled://t.163.com/">[΢²©]</a> <a target="_blank" href="httpdisabled://t.163.com/zt/bbs/date">´ïÈ˽ÌÄãÀËÂþÔ¼»á¾øÕÐ</a> <a target="_blank" href="httpdisabled://t.163.com/neigehua/status/-5574834336174310123">¡¡ºº¼é×î¶àµÄµØÓò</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <ul class="mod-imgList imgList-w160-2 clearfix">
- <li><a href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5047.html"><img src="../img1.cache.netease.com/cnews/2011/4/8/201104080835397174e.jpg" alt="½Ö±ßżÓö´©×Å´óµ¨ÃÍÅ®" title="½Ö±ßżÓö´©×Å´óµ¨ÃÍÅ®" height="90" width="160" /></a><p><a href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5047.html">½Ö±ßżÓö´©×Å´óµ¨ÃÍÅ®</a></p></li>
- <li><a href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5043.html"><img src="../img2.cache.netease.com/cnews/2011/4/8/20110408082635b6897.jpg" alt="ÍøÆØÉîÛÚÇéÉ«Ò¹µêÕÕƬ" title="ÍøÆØÉîÛÚÇéÉ«Ò¹µêÕÕƬ" height="90" width="160" /></a><p><a href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5043.html">ÍøÆØÉîÛÚÇéÉ«Ò¹µêÕÕƬ</a></p></li>
- <li><a href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5044.html"><img src="../img1.cache.netease.com/cnews/2011/4/8/20110408092834ed61d.jpg" alt="ó¯òëÂèÂèÉú±¦±¦È«¹ý³Ì" title="ó¯òëÂèÂèÉú±¦±¦È«¹ý³Ì" height="90" width="160" /></a><p><a href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5044.html">ó¯òëÂèÂèÉú±¦±¦È«¹ý³Ì</a></p></li>
- <li><a href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5031.html"><img src="../img2.cache.netease.com/cnews/2011/4/8/2011040809433960d68.jpg" alt="µØÌúÀïÕæÊÇÈ˲ű²³ö" title="µØÌúÀïÕæÊÇÈ˲ű²³ö" height="90" width="160" /></a><p><a href="httpdisabled://bbs.news.163.com/photoview/0HMM0015/5031.html">µØÌúÀïÕæÊÇÈ˲ű²³ö</a></p></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="area-sub">
- <div id="recommend" class="mod">
- <div class="hd clearfix">
- <h2 class="mod-title"><a href="httpdisabled://mall.163.com/">ÍøÒ×É̳Ç</a></h2>
-<span class="mod-entry"><a href="httpdisabled://caipiao.163.com/">²ÊƱ</a> | <a href="httpdisabled://tuan.163.com/">ÍŹº</a></span>
- </div>
- <div class="bd" id="neteasy_mall">
-
- <h3 class="neteasy_mall_title">»°·Ñ³äÖµ</h3>
- <form action="httpdisabled://shop.163.com/mobile/tofill.html" target="_blank" id="neteasy_mall_form" method="post">
- ÊÖ»úºÅÂ룺<input type="text" class="neteasy_mall_phone" id="mall_phone" maxlength="13" onpaste="return false" autocomplete="off" name="chargeAccount"/><span id="phone_err" style="display:none"></span><br />
- ¡¡¡¡ÃæÖµ£º<select class="neteasy_mall_value" id="mall_value" name="faceValue">
- <option value="30">30Ôª</option>
- <option value="50">50Ôª</option>
- <option value="100" selected>100Ôª</option>
- <option value="300">300Ôª</option>
- <option value="500">500Ôª</option>
- </select><input type="submit" value="" class="neteasy_mall_submit"/>
- <br />
- ¡¡¡¡<span class="mall_price">¼Û¸ñ£º<strong class="cDRed" id="mall_money">98.7-99.5</strong>Ôª</span>
- </form>
- <div class="dotline"></div>
- <objectdisabled classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="httpdisabled://downloaddisabled.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0" width="170" height="67">
- <param name="movie" value="httpdisabled://img1.126.net/channel1/rollGame0107.swf">
- <param name="quality" value="high">
- <param name="wmode" value="transparent" />
- <embeddisabled src="../img1.126.net/channel1/rollGame0107.swf" wmode="transparent" quality="high" pluginspage="httpdisabled://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="170" height="67"></embed>
- </object>
- <a href="httpdisabled://tuan.163.com/?tag=%E7%BE%8E%E9%A3%9F"><img class="mall_img" src="../img3.126.net/techpro/tuangou/20110218/170-80.jpg" width="170" height="80" alt="ÍøÒ×Íų¤" title="ÍøÒ×Íų¤" /></a>
- </div>
- </div>
- </div>
- </div>
-</div>
-<!-- end -->
-<!-- lady & bbs -->
-<div class="area">
- <div class="area-main">
- <div class="main-col-10">
-<div class="gg gg-h100"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column390x100&amp;location=5.html" width="390" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-</div>
- <div id="lady" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-10 clearfix">
- <span class="tab-u current"><a href="httpdisabled://lady.163.com/">Å®ÈË</a></span>
- <span class="tab-u"><a href="httpdisabled://fashion.163.com/">ʱÉÐ</a></span>
- <span class="tab-u"><a href="httpdisabled://lady.163.com/sense/">Çé¸Ð</a></span>
- <span class="tab-u"><a href="httpdisabled://lady.163.com/beauty/">ÃÀÈÝ</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://lady.163.com/photoview/4CJ80026/10343.html?1302099128#p=70TGMIA34CJ80026"><img src="../img4.cache.netease.com/lady/2011/4/8/20110408224817711dd.jpg" alt="Å®ÐǶ±³×°Æ´Ë­×î÷È»ó" title="Å®ÐǶ±³×°Æ´Ë­×î÷È»ó" height="90" width="120" /><cite>Å®ÐǶ±³×°Æ´Ë­×î÷È»ó</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://lady.163.com/">ÏëµÃµ½ÄÐÈ˵ÄÐÄ ÏÈÕ÷·þËûµÄθ£¿</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://lady.163.com/11/0331/00/70ECI3L600264IJ9.html">´óSÁõ¼ÎÁáʾ·¶ÓÅÑÅÈËÆÞÇÉ×±°ç</a></li>
- <li><a href="httpdisabled://lady.163.com/11/0328/19/708MHB0T00264IJ2.html">ÁÖÎõÀÙÉÁ»é ÀËÂþ·¢ÐÍÓÅÑÅÓָ߹ó</a></li>
- <li><a href="httpdisabled://lady.163.com/11/0329/17/70B2TS0B00264IJ2.html">ÑîÃÝÁÁÏàʱÉÐÒ¹ ºìȹ¾í·¢³¬ÇÀ¾µ</a></li>
- <li><a href="httpdisabled://fashion.163.com/11/0327/18/7063MKU900264J94.html">·¶±ù±ùÊæä¿ Å̵ãÅ®ÐǺì̺³ó̬˲¼ä</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://bbs.lady.163.com/list/lovestory.html">[ÇéÁ÷¸Ð]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0328/11/707SA0IE00264IIU.html">ºÍÀϹ«AAÖÆ·òÆÞ ¸øËûÁ½Ç§°®Ò»»Ø</a></li>
- <li><a href="httpdisabled://bbs.lady.163.com/list/danshenmm.html">[µ¥Å®]</a> <a target="_blank" href="httpdisabled://bbs.lady.163.com/bbs/danshenmm/204638575.html">25Ëê¹Ô¹ÔÅ®Õ÷»é~Äã¸ÒÈ¢ÎÒ¸Ò¼Þ£¡</a></li>
- <li><a href="httpdisabled://bbs.lady.163.com/list/beautify.html">[»¨ÎÑ]</a> <a target="_blank" href="httpdisabled://bbs.lady.163.com/bbs/beautify/205351998.html">´ïÈËСĢ¹½½ÌÄã´òÔìÃÔÈ˵çÑÛ×±</a></li>
- <li><a href="httpdisabled://bbs.lady.163.com/list/poxi.html">[ÆÅϱ]</a> <a target="_blank" href="httpdisabled://bbs.lady.163.com/bbs/poxi/205219505.html">ÀϹ«ÀäÂäÎÒ ËµÅÂÆÅÆÅÐÄÀïÄÑÊÜ </a></li>
- <li><a href="httpdisabled://bbs.lady.163.com/list/fashion.html">[ʱÉÐ]</a> <a target="_blank" href="httpdisabled://bbs.lady.163.com/bbs/fashion/205114172.html">ÿÈÕÒ»´îÅä Ñý¾«Ð¡½ã±¾ÃüÄêÃÀÀö´î </a></li>
- <li><a href="httpdisabled://bbs.lady.163.com/list/lovestory.html">[ÇéÁ÷¸Ð]</a> <a target="_blank" href="httpdisabled://bbs.lady.163.com/bbs/danshenmm/204638575.html">ÄÐÈËÀ뿪ÐÔ°®¾Í»î²»ÏÂÈ¥Âð£¿</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://lady.163.com"><em class='fB'>´óƬÐ㳡</em></a> |<a target="_blank" href="httpdisabled://lady.163.com/photoview/4CJ80026/10239.html?1301902571">·¶±ù±ùµÇ·¨¹úÔÓÖ¾·âÃæ ÃÀÈ˵ãðë±ðÑùåüÃÄ</a></li>
- <li><a href="httpdisabled://lady.163.com/astro/"><em class='fB'>ÍøÒ×ÐÇ×ù</em></a> |<a target="_blank" href="httpdisabled://lady.163.com/special/sense/siyueyunshi.html">2011ËÄÔÂÐÇÔ˴󼯺Ï</a><a target="_blank" href="httpdisabled://lady.163.com/11/0406/00/70TR7PTK00264III.html">Å®Î×µêÐÇ×ù±¾ÖÜÔËÊÆ</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://fashion.163.com/photoview/43AJ0026/10398.html#p=711THJPG43AJ0026"><img src="../img4.cache.netease.com/lady/2011/4/8/20110408014720d3fc0.jpg" alt="͸ÊÓïοձ¡É´ÊÓ¾õÊ¢Ñç" title="͸ÊÓïοձ¡É´ÊÓ¾õÊ¢Ñç" height="90" width="120" /><cite>͸ÊÓïοձ¡É´ÊÓ¾õÊ¢Ñç</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://fashion.163.com/">¿­ÌØĪ˹ÓëÕæÉß ÃÀŮҰÊÞ´´áÛ·å</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://fashion.163.com/photoview/4GJG0026/10400.html#p=711UCHGK4GJG0026">Ó¡»¨É«²Ê´ó±¬Õ¨ ½ÖÅij±ÈËÑÝÒﴺװ</a></li>
- <li><a href="httpdisabled://fashion.163.com/11/0407/14/711VR9L500264K9M.html">СS¿ñ°® ¸ÒºÍºìµ×Ь½Ð°åµÄŮЬ</a></li>
- <li><a href="httpdisabled://fashion.163.com/photoview/43AJ0026/10405.html#p=71259T7P43AJ0026">ÓÐÁõÏè ÌåÓýÃ÷ÐÇЯ¼Ò¾ìÂãÉíÅÄƬ</a></li>
- <li><a href="httpdisabled://fashion.163.com/11/0407/15/7122USDA00264J94.html">BalmainÉè¼ÆʦƤ°£¶û¡¤°Í¶ûÂüÀëÈÎ</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://fashion.163.com/">[´óƬ]</a> <a target="_blank" href="httpdisabled://fashion.163.com/photoview/3QV10026/10411.html#p=712R1EA13QV10026">ÃÔÀëÊæä¿VS¸öÐÔËïÙ³ </a> <a target="_blank" href="httpdisabled://fashion.163.com/photoview/43AJ0026/10396.html#p=711T9O3A43AJ0026">´¿ÕæÓÕ»ó£¡ÄÑ¿¹¾Ü·ÛÄÛ÷ÈÁ¦</a></li>
- <li><a href="httpdisabled://fashion.163.com/attractive/">[´îÅä]</a> <a target="_blank" href="httpdisabled://fashion.163.com/11/0407/17/7129IQEJ002626K1.html">ÈÕϵËØÑÅͨÇÚ×° ÈËÆøUPÃؾ÷</a> <a target="_blank" href="httpdisabled://fashion.163.com/11/0407/13/711SKLGF00264KF8.html">´º¼¾³öÓθöÐÔ´òµ×¿ã </a></li>
- <li><a href="httpdisabled://fashion.163.com/">[ʱ÷Ö]</a> <a target="_blank" href="httpdisabled://fashion.163.com/photoview/43AJ0026/10409.html#p=7128GQKO43AJ0026">ÕâЩ´ºÏĸ߸úЬÃÀµÃ²»Ïñ»°</a> <a target="_blank" href="httpdisabled://fashion.163.com/11/0407/17/7128012O00264J93.html">¸ßµ÷¸´¹Å·þ×°ÓÐÒÕÊõ¸Ð</a></li>
- <li><a href="httpdisabled://fashion.163.com">[´ó³ß¶È]</a> <a target="_blank" href="httpdisabled://fashion.163.com/photoview/43AJ0026/10386.html#p=711II84E43AJ0026">ÖÚÅ®ÐǸ°ÈÕÅļ«ÏÞдÕæ </a> <a target="_blank" href="httpdisabled://fashion.163.com/photoview/43AJ0026/10390.html#p=711LMLAU43AJ0026">Ä£ÌØÑÝÒïºì´½+ÐÔ¸ÐÄÚÒÂ</a></li>
- <li><a href="httpdisabled://koreastyle.163.com/">[º«¹úÕ¾]</a> <a target="_blank" href="httpdisabled://fashion.163.com/photoview/4GJF0026/10406.html#p=7127JKFL4GJF0026">ÒüÏàîçȫзþװдÕæ</a> <a target="_blank" href="httpdisabled://fashion.163.com/photoview/4GJF0026/10407.html#p=7127NDG94GJF0026">ÒüʤÑÅÆ×д´ºÈÕ×àÃùÇú</a></li>
- <li><a href="httpdisabled://fashion.163.com/">[΢²©¿Ø]</a> <a target="_blank" href="httpdisabled://t.163.com/liujianan/status/-9002711272039920505#retweet ">ÄÐÈË×°ÉãӰʦ´òÔìÐÔ¸Ð×°Å®ÀÉ</a> <a target="_blank" href="httpdisabled://t.163.com/lidongtian/status/-6067023179144458606#retweet">ÀÌï×óÓµÓÒ±§</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://fashion.163.com/special/2011chicyg/"><em class='fB'>ÖØ°õ²ß»®</em></a> | <a target="_blank" href="httpdisabled://fashion.163.com/special/2011chicyg/">ÍøÒ×ʱÉÐÆô¶¯¡°Öйú´´Ô족´óÐÍÆ·Åƻ</a></li>
- <li><a href="httpdisabled://fashion.163.com/special/2011chinafashionweek/"><em class='fB'>ʱÉÐÏÈ·æ</em></a> | <a target="_blank" href="httpdisabled://fashion.163.com/special/shuqi1/">Êæä¿£º±»½ÐʣŮ²»ÔÚºõ£¬ºÃ¹ýÓ¹Ë×ÈËÉú</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://lady.163.com/photoview/43A90026/10329.html#p=70L44JAT43A90026"><img src="../img3.cache.netease.com/lady/2011/4/8/20110408082553b8653.jpg" alt="Ã÷ÐÇÏÖÉí½ÌÄãʧÁµÁÆ·¨" title="Ã÷ÐÇÏÖÉí½ÌÄãʧÁµÁÆ·¨" height="90" width="120" /><cite>Ã÷ÐÇÏÖÉí½ÌÄãʧÁµÁÆ·¨</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://lady.163.com/11/0402/19/70LJBHNH002649P6.html">±ðÌ«¿´ÖسÐŵ ÓÐʱËüÖ»ÊÇÒ»ÖÖµ÷Çé</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://lady.163.com/11/0331/12/70FMRUVM00264IIU.html">Ëû´øÎÒÈ¥¼û³õÁµÇéÈË ÎÒ×ÔÐŲ»ÆðÀ´</a></li>
- <li><a href="httpdisabled://lady.163.com/11/0331/12/70FMDBQ600264IIU.html">°®ÉϺÃÓѵÄÇ°ÄÐÓÑ Ëý˵ËûÃÇû·ÖÊÖ</a></li>
- <li><a href="httpdisabled://lady.163.com/11/0331/12/70FLLJKK00264IIU.html">ÅãËûÐÁ¿àƯ²´¶àÄê ËûÈ´ÀÏÏò×ÅËûÂè</a></li>
- <li><a href="httpdisabled://lady.163.com/11/0331/11/70FKMTV000264IIU.html">ÀϹ«ËµËûÓбÜÔÐËùÒÔСÈý²»»á»³º¢×Ó</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://lady.163.com/sense/">[¶à½ÇÁµ]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0406/16/70VIVBLK00264IIU.html">×÷ΪÇéÈË ÎÒÈ´ÓëËûµÄ˾»ú·¢ÉúÁ˹Øϵ</a></li>
- <li><a href="httpdisabled://lady.163.com/sense/">[ÌðÃÛ]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0406/10/70UVV1JV00264IIU.html">¼´Ê¹Ã»ÓÐÔÚ×îÃÀÀöµÄÄ껪Óö¼ûÄã Ò²²»¾õµÃÒź¶</a></li>
- <li><a href="httpdisabled://lady.163.com/sense/">[ÌÖÂÛ]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0406/10/70UVHFF900264IIU.html">Èç¹ûûÓÐÇ® ÎÒÃǵİ®Çéµ½µ×Äܹ»×߶àÔ¶£¿</a></li>
- <li><a href="httpdisabled://lady.163.com/sense/">[ÇóÖú]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0331/12/70FM5AQR00264IIU.html">¾Ý˵Õæ°®ÄãµÄ²»»áºÍÄã¸ãêÓÃÁ ÄÇÎÒ¸ÃÀ뿪Âð</a></li>
- <li><a href="httpdisabled://lady.163.com/sense/">[ÉËÐÄ]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0331/11/70FKVBUP00264IIU.html">ÒòΪ²»ÄÜÉúº¢×Ó×îÖÕ±»ËûÅ×Æú »¹²»¸ø·ÖÊÖ·Ñ</a></li>
- <li><a href="httpdisabled://lady.163.com/astro/">[ÐÇ×ù] </a><a target="_blank" href="httpdisabled://lady.163.com/special/sense/siyueyunshi.html">ËÄÔÂÔËÊƴ󼯺Ï</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0406/18/70VP9DAB00264III.html">AlexÐÇ×ùÒ»ÖÜÔËÊÆ4.6-4.12</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://lady.163.com/sense/"><em class='fB'>ʱÆÀ×÷ÕßȦ</em></a> |<a target="_blank" href="httpdisabled://t.163.com/xiazm/status/204208825049025523#retweet">40ËêÄãÄÜ׬µ½4ǧÍòÂð</a> <a target="_blank" href="httpdisabled://t.163.com/cbyxw/status/2221663630884260824#retweet">ÓͼÛÉϵ÷³Ô²»Ïû</a></li>
- <li><a href="httpdisabled://lady.163.com/sense/"><em class='fB'>Çé¸Ðר¼ÒÍÅ</em></a> |<a target="_blank" href="httpdisabled://t.163.com/woshiyushunshun/status/5810766844942876669">¿´ÖØÄÐÈ˳ö¹ì¾ÍÏñÄÐÈË¿´ÖØ´¦Å®Ò»Ñù»¬»ü</a> <a target="_blank" href="httpdisabled://t.163.com/zhaogeyu/status/1145370794134928600">Áµ°®°Ë´ó½û¼ÉÊØÔò</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://lady.163.com/photoview/4CJ80026/10401.html#p=711UV1DK4CJ80026"><img src="../img3.cache.netease.com/lady/2011/4/7/20110407235235eb565.jpg" alt="·ëÉÜ·åÑîÃÝÐԸгö¾µ" title="·ëÉÜ·åÑîÃÝÐԸгö¾µ" height="90" width="120" /><cite>·ëÉÜ·åÑîÃÝÐԸгö¾µ</cite></a>
-</div>
- <h3 class="main-title"><a href="httpdisabled://lady.163.com/11/0407/21/712MUKQB00264IJ9.html">ٻŮÓÄ»êPK ÁõÒà·Æ¸üÓÐÓù½ã·¶</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://lady.163.com/photoview/4CJ80026/10402.html#p=712014OG4CJ80026">ºÃÀ³ÎëÅ®ÐDZä×±Ðã Ч¹û¿°±ÈPS</a></li>
- <li><a href="httpdisabled://lady.163.com/photoview/4CJ80026/10392.html#p=711S5P4U4CJ80026">ºì±éÑÇÖÞ ÓÀ²»¹ýÆø52¿î±¬ÃÀ·¢ÐÍ</a></li>
- <li><a href="httpdisabled://lady.163.com/11/0407/13/711QCROP00261IDC.html">ºË·øÉäÏ ÈÕϵ·çױƷPKÅ·ÃÀ·¶¶ù</a></li>
- <li><a href="httpdisabled://lady.163.com/11/0407/14/711TA9SO00264IJ3.html">Å®ÐÇÃÀ±³ÃîÕÐ ½ÌÄãתÉíÒ²ÄÜÓÕ»ó</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://lady.163.com/beauty/">[Ã÷ÐÇ]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0407/14/711UD5G300261IDD.html">ÍÑÀëʣٵÄÅ®ÐÇÔìÐÍ</a> <a target="_blank" href="httpdisabled://lady.163.com/photoview/4CJ80026/10408.html#p=7127TLEP4CJ80026">ÌÀΨ0ºÅÉí²Ä³Æ°ÔʱÉÐȦ</a></li>
- <li><a href="httpdisabled://lady.163.com/beauty/">[¼¼ÇÉ]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0407/15/7123O09R00261IDD.html">¾ëÈݲ»½ø°ì¹«ÊÒ 5Ãë»»ÑÕÃîÕÐ</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0407/14/711VU77U00261IDD.html">ѧ»¯À滨װÄÛ×±</a></li>
- <li><a href="httpdisabled://lady.163.com/beauty/">[´óƬ]</a> <a target="_blank" href="httpdisabled://lady.163.com/photoview/4CJ80026/10404.html#p=7122Q5VQ4CJ80026">×¢ÒâÕâ¸ö´ºÌìÒª×ö·ÛºìÅ®ÀÉ</a> <a target="_blank" href="httpdisabled://lady.163.com/photoview/4CJ80026/10383.html#p=710A2AHE4CJ80026">À­¶¡»ÊºóÌÒÉ«÷ÈÓ°</a></li>
- <li><a href="httpdisabled://lady.163.com/beauty/">[»¤·ô]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0407/14/71205P3T00261IDC.html">¾¯Ì軯ױƷµÄɽկ»õ</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0407/15/7120OGQN00261IDC.html">»¤·ôÆ·ÓöÔÁ¿Ð§¹û·­±¶</a></li>
- <li><a href="httpdisabled://lady.163.com/beauty/">[ÃÀ·¢]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0407/16/7124J76Q00261PDG.html">DIYȾ·¢¼¼Êõ±ÈÃÀ·¢Ê¦×¨Òµ</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0407/12/711PFBDR00261PDG.html">»¨¶ä±à·¢ÀËÂþÉý¼¶</a></li>
- <li><a href="httpdisabled://lady.163.com/beauty/">[͵ʦ]</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0407/14/711VOECH00264IJ3.html">ֽƬÈËÅ®ÐǵÄÊÝÉíÐļÆ</a> <a target="_blank" href="httpdisabled://lady.163.com/11/0407/12/711ON0LV00261IDD.html">ÃÀ¼×ÕÀ·Å½ñ´ºµ±ºìÉ«²Ê</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://lady.163.com/special/2010meirongdajiangbanjiang/"><em class='fB'>ÃÀÈÝ´ó½±</em></a> |<a target="_blank" href="httpdisabled://t.163.com/jinyuxi">½ùÓðÎ÷³öϯÉϺ£µÏÊ¿ÄῪ¹¤Àñ</a> <a target="_blank" href="httpdisabled://t.163.com/fenshouzhuang/status/-711319073236628">·ÖÊÖÃÃдÕæ</a></li>
- <li><a href="httpdisabled://t.163.com/zt/lady/weimeiren"><em class='fB'>΢ÃÀÈË</em></a> |<a target="_blank" href="httpdisabled://t.163.com/rogerxiaoxin/status/-2251987904942340332">×¢Ò⣺ë¿×Ô½³¶Ô½´ó</a> <a target="_blank" href="httpdisabled://t.163.com/2951350383">С½ÌÖ÷Ö§ÕУº¹ûËá»»·ô</a></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- <div class="main-col-9">
-<div class="gg gg-h100"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column360x100&amp;location=5.html" width="360" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-</div>
- <div id="book" class="mod wgt-tab">
- <h2 class="tab-hd tab-u-9 clearfix">
- <span class="tab-u current"><a href="httpdisabled://book.163.com/">¶ÁÊé</a></span>
- <span class="tab-u"><a href="httpdisabled://data.book.163.com/">ͼÎÄ</a></span>
- <span class="mod-entry"><a href="httpdisabled://book.163.com/rank/">ͼÊéÅÅÐаñ</a></span>
- </h2>
- <div class="bd tab-bd display-control">
- <div class="tab-con current">
- <div class="imgText-temp-1 dotline clearfix">
- <div class="mod-img main-img">
- <a href="httpdisabled://data.book.163.com/book/section/0000FaLV/0000FaLV70.html?wangshou1"><img src="../img4.cache.netease.com/book/2011/4/8/20110408102221db369.jpg" alt="ÈÕ±¾ºÜºó»Ú·¢¶¯77ʱä" title="ÈÕ±¾ºÜºó»Ú·¢¶¯77ʱä" height="90" width="120" /><cite>ÈÕ±¾ºÜºó»Ú·¢¶¯77ʱä</cite></a>
- </div>
- <h3 class="main-title"><a href="httpdisabled://book.163.com/?wangshou1">»¹Ô­±»Ñýħ»¯µÄ¹úÃñµ³½«Áì</a></h3>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://data.book.163.com/book/section/000BEaSf/000BEaSf1.html?wangshou1">¶«±±ºÚÉç»áÀϴ󣺶çÊÖÖ¸Á¢Íþ</a></li>
- <li><a href="httpdisabled://data.book.163.com/book/home/009200010013/0000LWGF.html?wangshou1">¹«°²¾Ö³¤¾¹ÊÇÄ»ºóºÚ°ïÀÏ´ó</a></li>
- <li><a href="httpdisabled://data.book.163.com/book/section/0000FUKb/0000FUKb8.html?wangshou1">Õâ¸öÄÐÓÑÓеãÀ䣬Ëû˵kissÔà</a></li>
- <li><a href="httpdisabled://data.book.163.com/book/section/0000FFVL/0000FFVL39.html?wangshou1">×îÔçÔ¤ÑÔëÔ󶫳ÉΪÁìÐäµÄÈË</a></li>
- </ul>
- </div>
- <ul class="mod-list main-list">
- <li><a href="httpdisabled://data.book.163.com/index.html?wangshou1">[ÀúÊ·]</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/section/0000FdFQ/0000FdFQ5.html">µËСƽÈçºÎÕÆȨ</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/section/0000FEVC/0000FEVC74.html">ÃÀÏòÈÕ±¾Í¶ÁËÈý¿ÅÔ­×Óµ¯</a></li>
- <li><a href="httpdisabled://data.book.163.com/list/3_009200010013.html?wangshou1">[¹Ù³¡]</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010013/0000fKFb.html">Á½¸öÅ®¿Æ³¤µÄ±ðÑùÈËÉú</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010013/0000fJfP.html">ÎÂÈáÏÝÚå±³ºóµÄ¹Ù³¡</a></li>
- <li><a href="httpdisabled://data.book.163.com/list/2_00920001.html?wangshou1">[¶¼ÊÐ]</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010019/0000UHKZ.html">ɱÈË°¸Òý³öêÓÃÁÇé¸Ð</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010019/0000ZZMH.html">Äа×Áì°®ÉÏÒ¹×Ü»áС½ã</a></li>
- <li><a href="httpdisabled://data.book.163.com/list/2_00920001.html?wangshou1">[Ô­´´]</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010011/0000JMdT.html">±»Àä¿áÕÉ·ò"Çô½û"ÆßÄê</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010010/0000XLDL.html">¹Å´úÅ®¼äµýÊÖÍó¸ß³¬</a></li>
- <li><a href="httpdisabled://data.book.163.com/list/2_00920019.html?wangshou1">[Éç¿Æ]</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/section/000BEaVb/000BEaVb17.html">Ê׸ö³ÐÈϱ»ÖйúÎüÒýµÄ×Üͳ</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200190001/000BEdSA.html">Å®ÈËÄãÀÏÁËÕ¦°ì</a></li>
- <li><a href="httpdisabled://data.book.163.com/list/2_00920009.html?wangshou1">[ͼÎÄ]</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/section/000BELIL/000BELIL24.html?wangshou1">ÁÖ»ÕÒòÓëÁºË¼³É</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/section/0000UGTM/0000UGTM2.html?wangshou1">ëÔó¶«×îºó7Äê</a> <a target="_blank" href="httpdisabled://data.book.163.com/book/section/0000UHHF/0000UHHF0.html?wangshou1">Íõ¹âÃÀÏà²á</a></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://book.163.com/rank/?wangshou1"><em class='fB'>ÈÈÊé</em></a> | <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010014/000BEKcO.html?wangshou1">°Ë·¾üѪսÈÕ¿Ü</a> | <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010013/000BEKYJ.html?wangshou1">¹Ù³¡Ç±¹æÔò</a> | <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010019/000BELMA.html?wangshou1">ºì³¾µßµ¹</a></li>
- <li><a href="httpdisabled://book.163.com/rank/?wangshou1"><em class='fB'>È«±¾</em></a> | <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010013/000BCFHb.html">ÉóÅÐÔÚ¼´</a> | <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010011/000BELMS.html">ÎÒÊÇ»µÅ®Éú</a> | <a target="_blank" href="httpdisabled://data.book.163.com/book/home/009200010013/000BEKaV.html">¸±Ê¡³¤²»°®Å®É«</a></li>
- </ul>
- </div>
- <div class="tab-con">
- <ul class="mod-imgList imgList-w160-2 dotline clearfix">
- <li><a href="httpdisabled://data.book.163.com/book/section/000BDIGW/000BDIGW5.html"><img src="../img3.cache.netease.com/book/2011/4/8/20110408110145beb70.jpg" alt="ÔÚÌì°²ÃÅѧϰµÄÇàÄê" title="ÔÚÌì°²ÃÅѧϰµÄÇàÄê" height="90" width="160" /></a><p><a href="httpdisabled://data.book.163.com/book/section/000BDIGW/000BDIGW5.html">ÔÚÌì°²ÃÅѧϰµÄÇàÄê</a></p></li>
- <li><a href="httpdisabled://data.book.163.com/book/section/000BDBXU/000BDBXU10.html"><img src="../img3.cache.netease.com/book/2011/4/8/20110408105903d5d53.jpg" alt="ÕÅÒÕı¹®ÀþÀÏÕÕƬÆعâ" title="ÕÅÒÕı¹®ÀþÀÏÕÕƬÆعâ" height="90" width="160" /></a><p><a href="httpdisabled://data.book.163.com/book/section/000BDBXU/000BDBXU10.html">ÕÅÒÕı¹®ÀþÀÏÕÕƬÆعâ</a></p></li>
- <li><a href="httpdisabled://data.book.163.com/book/section/000BELIL/000BELIL34.html"><img src="../img3.cache.netease.com/book/2011/4/7/20110407103153df111.jpg" alt="Ãû¼ËÈü½ð»¨½á»éÕÕ" title="Ãû¼ËÈü½ð»¨½á»éÕÕ" height="90" width="160" /></a><p><a href="httpdisabled://data.book.163.com/book/section/000BELIL/000BELIL34.html">Ãû¼ËÈü½ð»¨½á»éÕÕ</a></p></li>
- <li><a href="httpdisabled://data.book.163.com/book/section/000BELBS/000BELBS30.html"><img src="../img3.cache.netease.com/book/2011/4/7/201104071025387042e.jpg" alt="º«¹úÃ÷ÐÇʱÉбضÁ±¦µä" title="º«¹úÃ÷ÐÇʱÉбضÁ±¦µä" height="90" width="160" /></a><p><a href="httpdisabled://data.book.163.com/book/section/000BELBS/000BELBS30.html">º«¹úÃ÷ÐÇʱÉбضÁ±¦µä</a></p></li>
- </ul>
- <ul class="mod-list specialTopic-list">
- <li><a href="httpdisabled://book.163.com/?wangshou2?wangshou1"><em class='fB'>΢²©ÎÄѧ</em></a> | <a target="_blank" href="httpdisabled://t.163.com/zt/book/qingming?wangshou2">ÇåÃ÷½Ú£¬ÓвŵÄÄã¿ìÀ´Ðøд#¶Ï»êÌå</a></li>
- <li><a href="httpdisabled://book.163.com/?wangshou1"><em class='fB'>΢²©Êéµ¥</em></a> | <a target="_blank" href="httpdisabled://t.163.com/zt/book/weishudan03">ÇåÃ÷½ÚÈÃÎÒÃÇÒ»ÆðÀ´¶Á¶Á¡°¸¼¸æÌ塱</a></li>
- <li><a href="httpdisabled://book.163.com/?wangshou1"><em class='fB'>×÷¼Ò¹Ûµã</em></a> | <a target="_blank" href="httpdisabled://t.163.com/haoyuehan/status/-7869073952390510568">º«ºÆÔÂ:°²ÌïÊǸöÇéÉ̲»¸ßµÄÓ×ÖÉÇàÄê</a></li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="area-sub">
-<div class="gg gg-h180"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=logo190x180&amp;location=4.html" width="190" height="180" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe></div>
- <div class="gg gg-h300"><iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=logo190x300&amp;location=2.html" width="190" height="300" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe></div>
- </div>
-</div>
-<!-- end -->
-<div class="area">
-<div class="area-main">
- <div class="main-col-10">
- <iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column390x100&amp;location=6.html" width="390" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-
- </div>
- <div class="main-col-9">
- <iframe src="../g.163.com/r@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=column360x100&amp;location=6.html" width="360" height="100" frameborder="0" border="0" marginwidth="0" marginheight="0" scrolling="no" ></iframe>
-
- </div>
- </div>
- <div class="area-sub">
- <div id="trends" class="mod trends-mod">
- <div class="hd clearfix">
- <h2 class="mod-title"><a href="httpdisabled://gb.corp.163.com/gbnews/General.html">ÍøÒ׶¯Ì¬</a></h2>
- <span class="mod-entry">NTES:52.93 -0.13%
-</span>
- </div>
- <div class="bd">
- <ul class="mod-list trends-list cBlue">
- <li><a href="httpdisabled://corp.163.com/11/0318/11/6VE3M14G00832V3T.html">¡¶ÐǼÊÕù°Ô2¡·3ÔÂ29ÈÕÃâ·Ñ¹«²â</a></li>
- <li><a href="httpdisabled://corp.163.com/11/0304/11/6UA4807T00832V3T.html">å­¹«Òæ»ù½ð»á³ÉÁ¢ ÍøÒ×¾èǧÍò</a></li>
- <li><a href="httpdisabled://corp.163.com/11/0224/07/6TL1O5ML00832V3T.html">ÍøÒ×¹«²¼Ëļ¾¶ÈδÉó¼Æ²ÆÎñÒµ¼¨</a></li>
- </ul>
- </div>
- </div>
- </div>
-</div>
-</div>
-<div class="footer">
- <div class="aboutNetease">
- <ul>
- <li><a href="httpdisabled://corp.163.com/eng/about/overview.html">About NetEase</a>¡¡-¡¡<a href="httpdisabled://gb.corp.163.com/gb/about/overview.html">¹«Ë¾¼ò½é</a>¡¡-¡¡<a href="httpdisabled://gb.corp.163.com/gb/contactus.html">ÁªÏµ·½·¨</a>¡¡-¡¡<a href="httpdisabled://hr.163.com/">ÕÐƸÐÅÏ¢</a>¡¡-¡¡<a href="httpdisabled://help.163.com/">¿Í»§·þÎñ</a>¡¡-¡¡<a href="httpdisabled://gb.corp.163.com/gb/legal.html">Ïà¹Ø·¨ÂÉ</a>¡¡-¡¡<a href="httpdisabled://emarketing.163.com/">ÍøÂçÓªÏú</a>¡¡-¡¡<a href="httpdisabled://sitemap.163.com/">ÍøÕ¾µØͼ</a>¡¡-¡¡<a href="httpdisabled://survey2.163.com/html/userexperience/cover.html">Óû§ÌåÑéÌáÉý¼Æ»®</a></li>
- </ul>
- </div>
-<!-- Ò³½Å -->
- <div class="foot">
- <div class="copyRight">ÍøÒ×¹«Ë¾°æȨËùÓС¡&copy;1997-2011<br />
- <a href="httpdisabled://img3.126.net/163homepage/license_090531.jpg">ICPÖ¤ÔÁB2-20090191</a> <a href="httpdisabled://img3.126.net/163homepage/zzxk09.jpg">ÔöÖµµçÐÅÒµÎñ¾­ÓªÐí¿ÉÖ¤B2-20090058</a> <a href="httpdisabled://img3.126.net/163homepage/cert.jpg">»¥ÁªÍø³ö°æÐí¿ÉÖ¤ÔÁ002ºÅ</a> <a href="httpdisabled://img1.cache.netease.com/cnews/163/img6/xuke.jpg">»¥ÁªÍøÐÂÎÅÐÅÏ¢·þÎñÐí¿ÉÖ¤</a> <a href="httpdisabled://www.gdca.gov.cn/">¹ã¶«Ê¡Í¨ÐŹÜÀí¾Ö</a> <a href="httpdisabled://cimg.163.com/home/2005/8/16/20050816101415d41d8.jpg">¹ú¼ÊÁªÍø±¸°¸</a> <a href="httpdisabled://www.bjjubao.org/index.htm">±±¾©»¥ÁªÍøÎ¥·¨²»Á¼ÐÅÏ¢¾Ù±¨</a><br>
- <a href="httpdisabled://net.china.cn/chinese/index.htm">Î¥·¨²»Á¼ÐÅÏ¢¾Ù±¨ÖÐÐÄ</a>¡¡<a href="httpdisabled://post.news.163.com/msg/jubao.jsp">²»Á¼ÐÅÏ¢¾Ù±¨ÐÅÏä</a>¡¡<a href="httpdisabled://post.news.163.com/msg/zhubian.jsp">ÎÄÃ÷°ìÍø¾Ù±¨µç»°</a>¡¡<a href="httpdisabled://www.netbj.org.cn/">±±¾©ÍøÂçÐÐҵЭ»á</a>¡¡<a href="httpdisabled://img1.126.net/channel1/html/stxkz.JPG">ÊÓÌý½ÚÄ¿ÖÆ×÷Ðí¿ÉÖ¤</a>¡¡<a href="httpdisabled://cimg20.163.com/sports/2008/5/16/20080516153237ce90f.gif">´«²¥Ðí¿ÉÖ¤</a>¡¡<a href="httpdisabled://img4.cache.netease.com/cnews/img10/20101013.jpg">ÎÄÍøÎÄ[2008]080ºÅ</a>¡¡<a href="httpdisabled://img1.126.net/channel1/html/ylzs_0422.pdf">»¥ÁªÍøÒ©Æ·ÐÅÏ¢·þÎñ×ʸñÖ¤Êé</a><br>
- ¾©¹«Íø°²±¸110000000013ºÅ ±±¾©ÍøͨÌṩÍøÂç´ø¿í <br /> <a href="httpdisabled://www.hd315.gov.cn/beian/view.asp?bianhao=0102000102300012"><img src="../img3.126.net/163homepage/biaoshi.gif" alt=""></a> <a href="httpdisabled://www.itrust.org.cn/yz/pjwx.asp?wm=2012043533"><img alt="" src="../img1.cache.netease.com/cnews/netease/wzdzbs.gif"></a> <a href="httpdisabled://www.bj.cyberpolice.cn/index.htm"><img alt="" src="../img3.126.net/163homepage/bj110.gif"></a> </div>
- </div>
-</div>
-</div>
-<script type="text/javascript">
-//<![CDATA[
-//NTES Login Start
-(function () {
- var body = NTES(document.body), doc = NTES(document.documentElement);
- var TIMER = null;
- var P_INFO = NTES.cookie.get("P_INFO");
- var S_INFO = NTES.cookie.get("S_INFO");
- var SELECT_VALUE = NTES.cookie.get("selectValue");
- var CLOSE_NUM = NTES.cookie.get("closeNum");
- SELECT_VALUE = SELECT_VALUE == "" ? -1 : SELECT_VALUE;
- CLOSE_NUM = CLOSE_NUM == "" ? 0 : parseInt(CLOSE_NUM);
- NTES.element.datasetFix = function(name, value) {
- var t = this;
- if (value !== undefined) {
- if (t.dataset){
- t.dataset[name] = value;
- }else{
- t.setAttribute("data-" + name, value);
- };
- t.className = t.className;
- }else{
- if (t.dataset){
- return t.dataset[name];
- }else{
- return t.getAttribute("data-" + name);
- }
- }
- };
-
-
- NTES.element.showed = function() {
- if (NTES.style.getCurrentStyle(this, "display") == "none"){
- return false
- }else{
- return true
- }
- };
-
- NTES.element.show = function() {
- this.addCss("display:block");
- };
-
- NTES.element.hide = function(delay) {
- var t = this;
- TIMER = window.setTimeout(function(){
- t.addCss("display:none");
- }, delay);
- };
-
- NTES.element.toggle = function() {
- var t = this;
- if ( !(this.showed()) ){
- t.show();
- }else{
- t.hide();
- }
- };
-
- //NTES Auto Complete
- var NTESAutoComplete = function( inputElem, nextElem ) {
- var t = this;
- t._inputElem = inputElem;
- t._nextElem = nextElem;
- t._idName = "login_auto_list";
- t._className = "login-auto-list";
- t._domains = ["163.com", "126.com", "vip.126.com", "yeah.net", "188.com", "vip.163.com", "gmail.com", "qq.com", "sina.com", "hotmail.com"];
- t._account = "";
- t._domain = "163.com";
- t.mailType = 0;
- t.buildList();
- t._autoList = NTES("#" + t._idName);
- t._autoListItem = t._autoList.NTES("td");
-
- t._autoListItem.addEvent("mouseover", function() {
- t._autoListItem.removeCss("hover");
- $(this).addCss("hover");
- })
- .addEvent("mouseout", function() {
- $(this).removeCss("hover");
- });
-
- t._inputElem.addEvent("focus", function() {
- if (this.value.trim() != "") t._autoList.show();
- })
- .addEvent("blur", function() {
- if (this.value.trim() != ""){
- t.selectCurrent();
- t._autoList.hide();
- t._nextElem.focus();
- }
- })
- .addEvent("keydown", function(e) {
- switch(e.keyCode) {
- case 38: // up
- e.preventDefault();
- t.moveSelect(-1);
- break;
- case 40: // down
- e.preventDefault();
- t.moveSelect(1);
- break;
- case 9: // tab
- if (t._autoList.showed()){
- t._autoListItem.removeCss("hover");
- };
- e.preventDefault();
- this.blur();
- break;
- case 13: // return
- case 108: // num return
- if( t.selectCurrent() ){
- e.preventDefault();
- this.blur();
- };
- break;
- default:
- break;
- }
- t.refreshAutoList();
- })
- .addEvent("keyup", function(e) {
- t.refreshAutoList();
- });
- };
- NTESAutoComplete.prototype = {
- insertAfter : function(newElem, targetElem) {
- var parentElem = targetElem.parentNode;
- if(parentElem.lastChild == targetElem)
- {
- parentElem.appendChild(newElem);
- }else{
- parentElem.insertBefore(newElem, targetElem);
- }
- },
- isNTESDomain : function(value){
- var t = this;
- var pos = value.indexOf("@");
- var domain = value.substr(pos + 1, value.length);
- for (var i = 0 ; i < t._domains.length; i++){
- if (t._domains[i] == domain) {
- return true;
- }
- };
- return false;
- },
- selectCurrent : function() {
- var t = this;
- var hoverItem = -1;
- for (var i = 0 ; i < t._autoListItem.length; i++){
- if ( $(t._autoListItem[i]).hasClass("hover") ){
- hoverItem = i;
- break;
- }
- };
- if (hoverItem == -1) {
- if (t._inputElem.value.indexOf("@") == -1) {
- t.mailType = t.mailType == 0 ? t.mailType = 1 : t.mailType;
- t.setInputValue(t.mailType);
- }else if( !(t.isNTESDomain(t._inputElem.value)) ){
- t.mailType = 0;
- }
- };
- if (hoverItem > -1) {
- t.mailType = hoverItem + 1;
- t.setInputValue(t.mailType);
- return true;
- } else {
- return false;
- };
- },
- moveSelect : function (step){
- var t = this;
- if (t._inputElem.value.trim() == "") return;
- t.mailType += step;
- if (t.mailType <= 0) {
- t.mailType = t._domains.length;
-
- } else if (t.mailType > t._domains.length) {
- t.mailType = 1;
- }
-
- t._autoListItem.removeCss("hover");
- $(t._autoList.$("td")[t.mailType - 1]).addCss("hover");
- t.selectCurrent();
-
- },
- splitValue : function() {
- var t = this;
- var value = t._inputElem.value;
- var pos = value.indexOf("@");
- var account, domain;
- if (value.trim() != "") {
- if (pos == -1){
- account = value;
- domain = t._domain;
- }else{
- account = value.substr(0, pos);
- domain = value.substr(pos + 1, value.length);
- }
- }else{
- account = "";
- domain = t._domain;
- };
- t.mailType = 0;
- for (var i = 0 ; i < t._domains.length ; i++ ){
- if ( t._domains[i] == domain ) t.mailType = i + 1;
- };
- t._account = account;
- t._domain = domain;
- },
- refreshAutoList : function(silent) {
- var t = this;
- t.splitValue();
- for (var i = 0 ; i < t._autoListItem.length; i ++){
- t._autoListItem[i].firstChild.nodeValue = t._account + "@" + t._domains[i];
- };
- if (t._inputElem.value.trim() == "") {
- t._autoList.hide();
- t.mailType = 0;
- }else if ( silent == undefined ){
- t._autoList.show();
- };
- },
- setInputValue : function(n) {
- if ( n == 0 ) return;
- var t = this;
- t.mailType = n;
- t._inputElem.value = t._autoListItem[n - 1].firstChild.nodeValue;
- t.splitValue();
- },
- buildList : function() {
- var t = this;
- var oTable = document.createElement("table");
- var oTbody = document.createElement("tbody");
- var oThead = document.createElement("thead");
- var oTr = document.createElement("tr");
- var oTd = document.createElement("td");
- var oTh = document.createElement("th");
- t.splitValue();
- oThead = document.createElement("thead");
- oTr = document.createElement("tr");
- oTh = document.createElement("th");
- oTh.innerHTML = "ÇëÑ¡Ôñ»ò¼ÌÐøÊäÈë...";
- oTr.appendChild(oTh);
- oThead.appendChild(oTr);
- oTable.appendChild(oThead);
- for (var i = 0; i < t._domains.length; i++){
- oTr = document.createElement("tr");
- oTd = document.createElement("td");
- oTd.innerHTML = t._account ? t._account + "@" + t._domains[i] : t._domains[i];
- oTr.appendChild(oTd);
- oTbody.appendChild(oTr);
- }
- oTable.appendChild(oTbody);
- oTable.id = t._idName;
- oTable.className = t._className;
- oTable.style.display = "none";
- t.insertAfter(oTable, t._inputElem);
- }
- };
-
- //NTES Login
- var NTESLogin = function( usernameElem, passwordElem ) {
- if (!arguments.length) { return; }
- var t = this;
- t.constructor = arguments.callee;
- t._login = NTES("#NTES_Login");
- t.addTips(t._login);
- t._loginForm = NTES("#login_form");
- t._username = usernameElem;
- t._password = passwordElem;
- t._ursname = t._loginForm.ursname;
- t._submit = NTES($("#login_form input[type=submit]")[0]);
- t._selectInput = NTES("#login_form [name=selected]")[0];
- t._selected = SELECT_VALUE;
- t._selectArea = NTES("#login_select_area");
- t._select = NTES("#login_selected");
- t._selectDefault = t._select.firstChild.nodeValue;
- t._selectMain = NTES("#login_select_main");
- t._selectList = NTES("li", t._selectMain);
- t._loginTipsUsername = NTES("#login_tips_username");
- t._loginTipsPassword = NTES("#login_tips_password");
- t._loginTipsMobile = NTES("#login_tips_mobile");
- t._loginBefore = NTES("#login_before");
- t._loginAfter = NTES("#login_after");
- t._tipsMobileEnable = (CLOSE_NUM < 3) ? true : false;
- t._product = NTES("#product");
- t._autoComplete = new NTESAutoComplete(t._username, t._password);
- t._selectFilter = [
- ["others", [0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0]],
- ["163.com", [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]],
- ["126.com", [0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0]],
- ["vip.126.com", [0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0]],
- ["yeah.net", [0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0]],
- ["188.com", [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1]],
- ["vip.163.com", [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]],
- ["gmail.com", [0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0]],
- ["qq.com", [0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0]],
- ["hotmail.com", [0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0]]
- ];
- t._formRequestArray = [
- "httpdisabledsdisabled://reg.163.com/logins.jsp",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?url=http://entry.mail.163.com/coremail/fcg/ntesdoor2?lightweight=1&",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?type=1&url=http://entry.mail.126.com/cgi/ntesdoor?hid=10010102&lightweight=1&verifycookie=1&language=0&style=-1",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?type=1&url=http://reg.vip.126.com/enterMail.m",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?type=1&url=http://entry.yeah.net/cgi/ntesdoor?lightweight=1&verifycookie=1&style=-1",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?url=http://reg.mail.188.com/servlet/login",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?type=1&url=http://reg.vip.163.com/enterMail.m?language=-1&style=-1&enterVip=true",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?url=http://blog.163.com/passportIn.do?entry=163",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?url=http://photo.163.com/",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?url=http://yuehui.163.com/?keyfrom=163home",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?url=http://bbs.163.com",
- "httpdisabledsdisabled://reg.163.com/logins.jsp?url=http://t.163.com"
- ];
- t._username.addEvent("keydown", function(e) {
- t._loginTipsMobile.hide();
- })
- .addEvent("keyup", function(e) {
- if ( t._selectFilter[t._autoComplete.mailType][1][t.getSelect()] == 1 ){
- t.setSelect("default");
- t._selectList.removeCss("hover");
- }
- })
- .addEvent("blur", function() {
- t._loginTipsUsername.hide();
- t._username.datasetFix("state", "");
- if ( t._selectFilter[t._autoComplete.mailType][1][t.getSelect()] == 1 ){
- t.setSelect("default");
- t._selectList.removeCss("hover");
- }
- t.showTipsMobile();
- }).addEvent("mouseover", function() {
- if ( this.value.trim() != ""){
- t._loginTipsMobile.hide();
- t.showTipsUsername();
- }else{
- t.showTipsMobile();
- }
- }).addEvent("mouseout", function() {
- t._loginTipsUsername.hide();
- if ( !(t._autoComplete._autoList.showed()) ){
- t.showTipsMobile();
- };
- });
- t._password.addEvent("blur", function() {
- t._loginTipsPassword.hide();
- t._password.datasetFix("state", "");
- })
- t._select.addEvent("click", function(e) {
- e.preventDefault();
- t.setSelectList();
- t._selectMain.toggle();
- })
- .addEvent("mouseover", function() {
- if ( t._selectMain.showed() ){
- TIMER && clearTimeout( TIMER );
- t._selectMain.show();
- }})
- .addEvent("mouseout", function() {
- t._selectMain.hide(300);
- });
- t._selectMain.addEvent("mouseover", function() {
- TIMER && clearTimeout( TIMER );
- this.show();
- })
- .addEvent("mouseout", function() {
- this.hide(300);
- });
- t._selectList.addEvent("mouseover", function() {
- t._selectList.removeCss("hover");
- if( !($(this).hasClass("disable")) ){
- $(this).addCss("hover");
- }
- }).addEvent("click", function() {
- if( !($(this).hasClass("disable")) ){
- t.setSelect(t.getSelect());
- t._selectMain.toggle();
- }
- });
- t._loginForm.addEvent("submit", function(e) {
- e.preventDefault();
- t.doSubmit();
- });
- t._loginTipsMobile.NTES("a.login-tips-close").addEvent("click", function(e) {
- e.preventDefault();
- t._tipsMobileEnable = false;
- t._loginTipsMobile.hide();
- NTES.cookie.set("closeNum", CLOSE_NUM + 1 , 30 * 24 * 60);
- });
-
- t.init();
- };
- NTESLogin.prototype = {
- init : function() {
- var t = this;
- var pInfo = P_INFO;
- var sInfo = S_INFO;
- pInfo = pInfo.substr(0, pInfo.indexOf("|"));
- var account = pInfo.substr(0, pInfo.indexOf("@"));
- /@([^*]+)/.test(pInfo);
- var domain = RegExp.$1;
- if ( t._selected > 0 && t._selected < t._selectFilter.length ){
- for ( var i = 0; i < t._selectFilter.length; i++ ){
- if ( t._selectFilter[i][0] == domain ){
- if ( i > 0 && i <= t._selectFilter.length ) t._autoComplete.mailType = i;
- t._selected = i;
- break;
- }
- }
- }
- var mobile = P_INFO.split("|")[6] || "";
- if (pInfo && t._username.value == "") {
- t._username.value = pInfo;
- t._autoComplete.refreshAutoList("silent");
- t._autoComplete._autoList.hide();
- }
- if (pInfo && sInfo) {
- t._loginForm.parentNode.removeChild(t._loginForm);
- t._loginTipsMobile.parentNode.removeChild(t._loginTipsMobile);
- t._loginTipsUsername.parentNode.removeChild(t._loginTipsUsername);
- t._loginTipsPassword.parentNode.removeChild(t._loginTipsPassword);
- t._loginBefore.parentNode.removeChild(t._loginBefore);
- t._loginAfter.show();
- var loginAfterUsername = $("#login_after_username");
- var loginAfterSelect = $("#login_after_select");
- var loginAfterLogout = $("#login_after_logout");
- var links = loginAfterSelect.$("a");
- var linksMail = loginAfterSelect.$("a.select-mail-link");
- if(pInfo.split("@")[0].length <= 12){
- loginAfterUsername.firstChild.nodeValue =loginAfterUsername.firstChild.nodeValue.replace(/pInfo/, pInfo);
- }
- else {
- loginAfterUsername.firstChild.nodeValue =loginAfterUsername.firstChild.nodeValue.replace(/pInfo/, pInfo.substr(0,12)+'...');
- }
- links[0].href =links[0].href.replace(/pInfo/, pInfo);
- links[8].href =links[8].href.replace(/pInfo/, pInfo);
- loginAfterLogout.href =loginAfterLogout.href.replace(/accountName/, account);
-
- if ( t._autoComplete.mailType == 0){
- if ( domain == "popo.163.com" || domain == "gmail.com" || domain == "qq.com" || domain == "hotmail.com"){
- for (var i = 0 ; i < links.length; i++){
- if ( !($(links[i]).hasClass("popo-link")) ) {
- links[i].parentNode.removeChild(links[i]);
- }
- }
- }else{
- for (var i = 0 ; i < links.length; i++){
- if ( !($(links[i]).hasClass("others-link")) ) {
- links[i].parentNode.removeChild(links[i]);
- }
- }
- }
- }else{
- if( domain == "gmail.com" || domain == "qq.com" || domain == "hotmail.com"){
- for (var i = 0 ; i < links.length; i++){
- if ( !($(links[i]).hasClass("popo-link")) ) {
- links[i].parentNode.removeChild(links[i]);
- }
- }
- }else{
- $(linksMail[t._autoComplete.mailType - 1]).addCss("user-link");
- for (var i = 0 ; i < linksMail.length; i++){
- if ( !($(linksMail[i]).hasClass("user-link")) ) {
- linksMail[i].parentNode.removeChild(linksMail[i]);
- }
- }
- }
- };
- loginAfterUsername.addEvent("click", function(e) {
- e.preventDefault();
- loginAfterSelect.toggle();
- })
- .addEvent("mouseover", function() {
- if ( loginAfterSelect.showed() ){
- TIMER && clearTimeout( TIMER );
- loginAfterSelect.show();
- }
- })
- .addEvent("mouseout", function() {
- loginAfterSelect.hide(300);
- })
- loginAfterSelect.addEvent("mouseover", function() {
- TIMER && clearTimeout( TIMER );
- this.show();
- })
- .addEvent("mouseout", function() {
- this.hide(300);
- });
- var pHead = NTES(t._product.$("h2")[0]);
- var pBody = t._product.NTES(".bd");
- var myList = pBody.NTES(" > div.tab-con > ul.product-list > li > span");
- myList.each(function() {
- var link = NTES(this).NTES("a")[0];
- link.href = link.href.replace(/pInfo/, pInfo);
- });
- if ( t._autoComplete.mailType > 0 && domain != "qq.com" && domain != "gmail.com" && domain != "hotmail.com"){
- var myMailLink = loginAfterSelect.$("a.user-link")[0].cloneNode(true);
- var oldMailLink = NTES(myList[0]).$("a")[0];
- myMailLink.className = oldMailLink.className;
- oldMailLink.parentNode.removeChild(oldMailLink);
- myMailLink.innerHTML = t._selectList[t._autoComplete.mailType].innerHTML;
- myList[0].appendChild(myMailLink);
- }
- t._product.addCss("wgt-tab");
- pHead.removeCss("hd");
- pHead.addCss("tab-hd product-tab");
- pHead.NTES(" > span").removeCss("mod-title");
- pHead.NTES(" > span").addCss("tab-u");
- pHead.NTES(" > span.tab-u").removeCss("current");
- pBody.NTES(" > div.tab-con").removeCss("current");
- NTES(pBody.NTES(" > div.tab-con")[1]).addCss("current");
- var oSpan = document.createElement("span");
- oSpan.innerHTML = "ÎÒµÄÍøÒ×";
- oSpan.className = "tab-u current";
- pHead.appendChild(oSpan);
- } else {
- if( mobile && mobile != "&0" ){
- var mobileNum = mobile.substr(0,3) + "*****" + mobile.substr(3,3);
- var closeBtn = t._loginTipsMobile.$("a")[1];
- while (t._loginTipsMobile.firstChild) {
- t._loginTipsMobile.removeChild(t._loginTipsMobile.firstChild);
- }
- var oSpan = document.createElement("span");
- oSpan.innerHTML = "ÓÃÄãµÄÊÖ»úºÅÂë <span style=\"color:green\">" + mobileNum + "</span>" + " ¿ÉÒԵǼ ";
- t._loginTipsMobile.appendChild(oSpan);
- t._loginTipsMobile.appendChild(closeBtn);
- };
-
- if (t._selected == -1) t.setSelect("default", true);
- else{
- t.setSelect( t._selected, true );
- $(t._selectList[t._selected]).addCss("hover");
- }
- if ( t._selected > 0 && t._selected < t._selectFilter.length ) t._autoComplete.mailType = t._selected;
-
- t._username.datasetFix("state", "");
- t._password.datasetFix("state", "");
- t._submit.datasetFix("state", "");
- t.showTipsMobile();
- }
-
- },
- setCursorPosition : function(ctrl, pos){
- if(ctrl.setSelectionRange)
- {
- ctrl.focus();
- ctrl.setSelectionRange(pos,pos);
- }
- else if (ctrl.createTextRange) {
- var range = ctrl.createTextRange();
- range.collapse(true);
- range.moveEnd('character', pos);
- range.moveStart('character', pos);
- range.select();
- }
- },
- setSelectList : function() {
- var t = this;
- t._selectList.removeCss("disable");
- if (t._username.value.trim() != ""){
- for (var i = 0 ; i < t._selectList.length ; i++){
- if (t._selectFilter[t._autoComplete.mailType][1][i] == 1){
- $(t._selectList[i]).addCss("disable");
- }
- }
- }
- },
- getSelect : function() {
- var t = this;
- var hoverItem = 0;
- for (var i = 0 ; i < t._selectList.length; i++){
- if ($(t._selectList[i]).hasClass("hover")){
- hoverItem = i;
- break;
- }
- };
- return hoverItem;
- },
- setSelect : function(n, init) {
- var t = this;
- if ( n == "default"){
- t._select.firstChild.nodeValue = t._selectDefault;
- t._selected = -1;
- return;
- }
- t._select.firstChild.nodeValue = t._selectList[n].firstChild.nodeValue;
- t._selected = n;
- if ( !init && t._username.value.trim() == "" && n > 0 && n < t._selectFilter.length){
- t._username.value = "@" + t._selectFilter[n][0];
- t._autoComplete.refreshAutoList();
- t._autoComplete.mailType = n;
- t.setCursorPosition(t._username, 0);
- }
- },
- showTipsUsername : function() {
- var t = this;
- t._loginTipsUsername.innerHTML = t._username.value;
- t._loginTipsUsername.show();
- },
- showTipsMobile : function() {
- var t = this;
- if ( t._tipsMobileEnable ){
- t._loginTipsMobile.show();
- };
- },
- checkInput : function(){
- var t = this;
- if( t._username.value.trim() === "" ) {
- t._username.datasetFix("state", "error");
- t._username.focus();
- t._loginTipsUsername.innerHTML = "ÇëÊäÈëÕ˺Å";
- t._loginTipsMobile.hide();
- t._loginTipsUsername.show();
- return false;
- };
- if( t._password.value === "" ) {
- t._password.datasetFix("state", "error");
- t._password.focus();
- t._loginTipsPassword.innerHTML = "ÇëÊäÈëÃÜÂë";
- t._loginTipsMobile.hide();
- t._loginTipsPassword.show();
- return false;
- };
- return true;
- },
- doSubmit : function(e) {
- var t = this;
- if( t.checkInput() ) {
- t._loginForm.target = "_blank";
- NTES.cookie.set("selectValue", t._selected, 30 * 24 * 60);
- switch (parseInt(t._selected)) {
- case -1:
- t._username.name = "username";
- t._password.name = "password";
- t._loginForm.target = "_self";
- t._loginForm.action = t._formRequestArray[0];
- break;
- case 0:
- case 1:
- t._username.name = "username";
- t._password.name = "password";
- t._loginForm.action = t._formRequestArray[t._selected];
- break;
- case 4:
- t._username.name = "username";
- t._password.name = "password";
- t._loginForm.action = t._formRequestArray[t._selected];
- break;
- default:
- t._username.name = "username";
- t._password.name = "password";
- t._ursname.name = "username";
- t._ursname.value = t._username.value;
- t._loginForm.action = t._formRequestArray[t._selected];
- break;
- };
- t._loginForm.submit();
- };
- },
- addTips : function(elem) {
- var oSpan = document.createElement("span");
- oSpan.className = "login-tips login-tips-username";
- oSpan.id = "login_tips_username";
- elem.appendChild(oSpan);
- oSpan = document.createElement("span");
- oSpan.className = "login-tips login-tips-password";
- oSpan.id = "login_tips_password";
- elem.appendChild(oSpan);
- oSpan = document.createElement("span");
- oSpan.className = "login-tips";
- oSpan.id = "login_tips_mobile";
- oSpan.innerHTML = "ÊÖ»úºÅÂëÒ²¿ÉÒԵǼ <a class=\"cBlue\" href="httpdisabled://www.163.com/%5C%22http://e.mail.163.com/mobilemail/home.do?from=163home%5C%22">Ãâ·Ñ°ó¶¨</a> <a class=\"login-tips-close\" href="httpdisabled://www.163.com/%5C%22#\"">¡Á</a>";
- elem.appendChild(oSpan);
- }
-
- }
-
- var NTESLoginObj = window.NTESLoginObj = new NTESLogin(NTES("#login_username"), NTES("#login_password"));
-})();
-//NTES Login End
-//widget tab
-(function () {
- var slides = $(".wgt-tab"), slides_gg = $(".wgt-tab-gg"), i, wrapper;
- //alert (slides);
- for (i = slides.length - 1; i >= 0; i--) {
- wrapper = $(slides[i]);
- new NTES.ui.Slide(wrapper.$(".tab-u"), wrapper.$(".tab-con"), "current","mouseover",null, 150);
- }
- for (i = slides_gg.length - 1; i >= 0; i--) {
- wrapper = $(slides_gg[i]);
- new NTES.ui.Slide(wrapper.$(".tab-u"), wrapper.$(".tab-con"), "current","mouseover",null, 150);
- }
-})();
-// ad for random
-(function () {
- var AChange = function (obj) {
- var t = this;
- t.obj = obj ? obj : {};
- var num = t.obj["num"] == "" ? 1 : Math.floor(Math.random()*t.obj["num"]) + 1;
- var url = t.obj["temp"] + num + ".html";
- var content = $(t.obj["content"]);
- NTES.ajax.send(url, "GET", null, {
- onSuccess: function(xhr){
- content.innerHTML = xhr.responseText;
- new NTES.ui.Slide(content.$("span.tab-u"), content.$("div.tab-con"), "current", "mouseover", 5000);
- }
- });
- }
- window.AChange = AChange;
-})();
-function isYdDefault(s){return false}
-function ydInputFocus(e){return false}
-function ydInputBlur(e){}
-function getSearchUrl(inputId, product, keyfrom) {
- var url = "httpdisabled://" + product + ".youdao.com/";
- if (window.RegExp && window.encodeURIComponent) {
- var input = document.getElementById(inputId);
- var query = input.value;
- if (query != "") {
- query = query.replace(/(^link:)|(^inlink:)|(^related:)/,"");
- url = url + "search?q=" + encodeURIComponent(query) + "&keyfrom=" + keyfrom;
- } else {
- url = url + "?keyfrom=" + keyfrom;
- }
- }
- return url;
-}
-function changeProduct(p) {
- var url = getSearchUrl("query", p, "163.index");
- void(url, "_blank");
-}
-//]]>
-</script>
-<script type="text/javascript" src="../img3.126.net/yodaoimages/pack.r091221/scripts/autocomplete.163.165290.js" charset="utf-8"></script>
-<script type="text/javascript">
-//<![CDATA[
-if(typeof(SEvent) != "undefined") {
- var aa;
- if (SEvent.observe) {
- SEvent.observe(window, "loaddisabled", function() {
- aa = new AutoComplete("query", "ydQuery", "aa", true, false, "", true, "httpdisabled://www.youdao.com");
- aa.setSearchServer("httpdisabled://www.youdao.com/search?");
- aa.setLogServer("httpdisabled://www.youdao.com/");
- aa.setKeyFrom("163.index");
- aa.showContent = function(){
- var inputbox = document.getElementById("query");
- var position = SP.cumOffset(inputbox);
- this.sdiv.style.top = position[1] + inputbox.offsetHeight + "px";
- if (this.bName == "IE" && this.bVer == 8) {
- this.sdiv.style.left = (position[0] - 1) + "px";
- } else {
- this.sdiv.style.left = (position[0] + 1) + "px";
- }
- this.sdiv.style.cursor = "default";
- this.sdiv.style.width = (inputbox.offsetWidth + 1) + "px";
- SElement.show(this.sdiv);
- this.vis = true;
- this.curNodeIdx = -1;
- }
- aa.start();
- });
- }
-}
-//yodao keyword weather
-(function () {
- var ydConfig = {
- ipQuery: "httpdisabled://ip.ws.126.net/ipquery",
- dataCity: "httpdisabled://www.163.com/special/0077450P/citycode.html",
- dataUrl: "httpdisabled://www.163.com/inc/163new/youdao/tq_id_",
- cityCode: "",
- cityName: "",
- defaultCity: "±±¾©",
- defaultCode: "54511",
- keywordUrl: "httpdisabled://www.163.com/inc/163new/youdao/hw.html"
- };
- var ydService = {
- getWeather: function(url) {
- var url = ydConfig.dataUrl + url + ".html";
- NTES.ajax.importJs(url, function(){
- if (typeof cityWeather == "undefined") {return false};
- var tpl1 = '<span id="setChange" class="weather-location"><#=cityName#></span><span class="weather-temperature"><a href="httpdisabled://www.youdao.com/search?keyfrom=163.index.weather&q=<#=cityName#>ÌìÆø" title="<#=weatherInfo#> <#=temperature#>"><#=temperature#></a></span>'
- var ele = $("#weatherIcon");
- if (typeof ele.style.maxWidth == "undefined") {
- var tpl2 = '<a title="<#=weatherInfo#> <#=temperature#>" href="httpdisabled://www.youdao.com/search?keyfrom=163.index.weather&q=<#=cityName#>ÌìÆø"><#=weatherInfo#></a>';
- }
- else {
- var tpl2 = '<a title="<#=weatherInfo#> <#=temperature#>" href="httpdisabled://www.youdao.com/search?keyfrom=163.index.weather&q=<#=cityName#>ÌìÆø"><img src="httpdisabled://img3.126.net/yodaoimages/icons/weather2/<#=weatherImg1#>.png" width="65" height="40" alt="<#=weatherInfo#> <#=temperature#>" /></a>';
- }
- $("#weather").innerHTML = NTES.util.parseTpl(tpl1, cityWeather);
- $("#weatherIcon").innerHTML = NTES.util.parseTpl(tpl2, cityWeather);
- $("#wgt_weather").style.visibility = "visible";
- $("#setChange").addEvent("click", function(e){
- $("#ydAreas").style.display = $("#ydAreas").style.display == "block" ? "none" : "block";
- e.preventDefault();
- e.cancelBubble = true;
- if($("#ydAreas").style.display == "block"){
- document.onclick = function(){
- $("#ydAreas").style.display = "none";
- $("#categoryMore").style.display = "none";
- }
- }
- $("#ydAreas").addEvent("click",function(e){
- e.cancelBubble = true;
- });
- });
- }, "gbk");
- if($("#selectProvince option").length == "1"){
- NTES.ajax.importJs(ydConfig.dataCity, function(){
- var sel = $("#selectProvince");
- var opt="";
- var opt_txt = "";
- sel.innerHTML = "<option>ÇëÑ¡Ôñ</option>";
- var len = cityLibrary.length;
- for (var i = 0; i < len; i++) {
- opt = document.createElement("option");
- opt_txt = document.createTextNode(cityLibrary[i][0]);
- opt.appendChild(opt_txt);
- opt.setAttribute("value",cityLibrary[i][0]);
- sel.appendChild(opt);
- }
- sel.disabled = false;
- });
- }
- $("#selectProvince").addEvent("change",function(){
- var name = this.options[this.options.selectedIndex].value;
- var len = cityLibrary.length;
- var i = -1;
- while (++i < len) {
- if (cityLibrary[i][0] == name) {
- var sel = $("#selectCity");
- opt_txt = "";
- sel.innerHTML = "<option>ÇëÑ¡Ôñ</option>";
- var obj = cityLibrary[i][1];
- var tlen = obj.length;
- var result = [];
- for (var j = 0; j < tlen; j++) {
- opt = document.createElement("option");
- opt_txt = document.createTextNode(obj[j][1]);
- opt.appendChild(opt_txt);
- opt.setAttribute("value",obj[j][0]);
- sel.appendChild(opt);
- }
- sel.disabled = false;
- }
- }
- });
- },
- init: function(){
- ydConfig.cityCode = NTES.cookie.get("theCity");
- if ("" == ydConfig.cityCode) {
- NTES.ajax.importJs(ydConfig.ipQuery, function(){
- ydConfig.cityName = "" !== lc ? lc.replace(/[Ê¡ÊÐ]$/, "") : lo.replace(/[Ê¡ÊÐ]$/, "");
- if (!ydConfig.cityName) {
- ydConfig.cityCode = ydConfig.defaultCode;
- NTES.cookie.set("theCity", ydConfig.cityCode, "30d");
- ydService.getWeather(ydConfig.cityCode);
- }
- else {
- NTES.ajax.importJs(ydConfig.dataCity, function(){
- var len = cityLibrary.length;
- for (var i = 0; i < len; i++) {
- if (cityLibrary[i][0] == ydConfig.cityName) {
- ydConfig.cityCode = cityLibrary[i][1][0][0];
- }
- else {
- var len1 = cityLibrary[i][1].length;
- var j = -1;
- while (++j < len1) {
- if (cityLibrary[i][1][j][1] == ydConfig.cityName) {
- ydConfig.cityCode = cityLibrary[i][1][j][0];
- }
- }
- }
- }
- NTES.cookie.set("theCity", ydConfig.cityCode, "30d");
- ydService.getWeather(ydConfig.cityCode);
- }, "gb2312");
- }
- }, "gb2312");
- }
- else {
- ydService.getWeather(ydConfig.cityCode);
- }
- $("#yodaoMore").addEvent("click",function(e){
- $("#categoryMore").style.display = $("#categoryMore").style.display == "block" ? "none" : "block";
- e.cancelBubble = true;
- if($("#categoryMore").style.display == "block"){
- document.onclick = function(){
- $("#categoryMore").style.display = "none";
- $("#ydAreas").style.display = "none";
- }
- }
- });
- $("#yodaoMore").addEvent("click",function(e){
- e.cancelBubble = true;
- });
- $("#closeWeather").addEvent("click", function(e){
- $("#ydAreas").style.display = "none";
- e.preventDefault();
- });
- $("#ydaSubmit").addEvent("click", function(e){
- var province = $("#selectProvince").value;
- var city = $("#selectCity").value;
- if ( city == "") {
- alert("ÇëÑ¡ÔñÏàÓ¦µÄ³ÇÊÐ");
- }
- else {
- NTES.cookie.set("theCity", city, "30d");
- ydService.getWeather(city);
- $("#ydAreas").style.display = "none";
- }
- e.preventDefault();
- });
- //end
- //keywords
- NTES.ajax.importJs(ydConfig.keywordUrl, function(){
- var len = keywords.length;
- var tpl = '<a href="httpdisabled://www.163.com/%3C#=url#>"><#=text#></a>';
- var keyword1 = [], keyword2 = [], keyword3 = [];
- for (var i = 0; i < len; i++) {
- if (i < 3) {
- keyword1.push(NTES.util.parseTpl(tpl, keywords[i]));
- }
- else if (i < 6){
- keyword2.push(NTES.util.parseTpl(tpl, keywords[i]))
- }
- else if (i < 9){
- keyword3.push(NTES.util.parseTpl(tpl, keywords[i]))
- }
- }
- $("#ydHotKeys").innerHTML = keyword1.join(" ");
- $("#ydHotKeys").style.visibility = "visible";
- result = [];
- var flag = 1;
- setInterval(function(){
- if (flag == 1) {
- $("#ydHotKeys").innerHTML = keyword1.join(" ");
- flag = 2;
- }
- else if (flag == 2) {
- $("#ydHotKeys").innerHTML = keyword2.join(" ");
- flag = 3;
- }
- else if (flag == 3){
- $("#ydHotKeys").innerHTML = keyword3.join(" ");
- flag = 1;
- }
- }, 8000);
- }, "gbk");
- }
- };ydService.init();
- })();
-//house ip check
-(function(){
- var HouseConfig = {
- ip: "httpdisabled://ip.ws.126.net/ipquery",
- textHouse: "·¿²ú",
- textBuy: "Âò·¿",
- city: [{
- name: "¹ãÖÝ",
- url1: "httpdisabled://gz.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/gz/",
- src1: "/special/00774IHD/house_gz_01.html",
- src2: "/special/00774IHD/house_gz_02.html"
- }, {
- name: "·ðɽ",
- url1: "httpdisabled://fs.house.163.com/",
- url2: "httpdisabled://house.163.com/",
- src1: "/special/00774IHD/house_fs_01.html",
- src2: "/special/00774IHD/house_gz_02.html"
- }, {
- name: "Ö麣",
- url1: "httpdisabled://zh.house.163.com/",
- url2: "httpdisabled://house.163.com/",
- src1: "/special/00774IHD/house_zh_01.html",
- src2: "/special/00774IHD/house_gz_02.html"
- }, {
- name: "°ÄÃÅ",
- url1: "httpdisabled://zh.house.163.com/",
- url2: "httpdisabled://house.163.com/",
- src1: "/special/00774IHD/house_zh_01.html",
- src2: "/special/00774IHD/house_gz_02.html"
- }, {
- name: "ÉîÛÚ",
- url1: "httpdisabled://sz.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/sz/",
- src1: "/special/00774IHD/house_sz_01.html",
- src2: "/special/00774IHD/house_sz_02.html"
- }, {
- name: "ÕØÇì",
- url1: "httpdisabled://zq.house.163.com/",
- url2: "httpdisabled://house.163.com/",
- src1: "/special/00774IHD/house_zq_01.html",
- src2: "/special/00774IHD/house_gz_02.html"
- }, {
- name: "ºÏ·Ê",
- url1: "httpdisabled://hf.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/hf/search/0-0-0-0-0-0-0-0-1.html",
- src1: "/special/00774IHD/house_hf_01.html",
- src2: "/special/00774IHD/house_hf_02.html"
- }, {
- name: "±±¾©",
- url1: "httpdisabled://bj.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/bj/",
- src1: "/special/00774IHD/house_bj_01.html",
- src2: "/special/00774IHD/house_bj_02.html"
- }, {
- name: "º£¿Ú",
- url1: "httpdisabled://hn.house.163.com/",
- url2: "httpdisabled://house.163.com/",
- src1: "/special/00774IHD/house_hn_01.html",
- src2: "/special/00774IHD/house_gz_02.html"
- }, {
- name: "ÈýÑÇ",
- url1: "httpdisabled://hn.house.163.com/",
- url2: "httpdisabled://house.163.com/",
- src1: "/special/00774IHD/house_hn_01.html",
- src2: "/special/00774IHD/house_gz_02.html"
- }, {
- name: "Ö£ÖÝ",
- url1: "httpdisabled://zz.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/zz/search/0-0-0-0-0-0-0-0-1.html",
- src1: "/special/00774IHD/house_zz_01.html",
- src2: "/special/00774IHD/house_zz_02.html"
- }, {
- name: "Î人",
- url1: "httpdisabled://wh.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/wh/search/0-0-0-0-0-0-0-0-1.html",
- src1: "/special/00774IHD/house_wh_01.html",
- src2: "/special/00774IHD/house_wh_02.html"
- }, {
- name: "Î÷°²",
- url1: "httpdisabled://xa.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/xa/search/0-0-0-0-0-0-0-0-1.html",
- src1: "/special/00774IHD/house_xa_01.html",
- src2: "/special/00774IHD/house_xa_02.html"
- }, {
- name: "ÉϺ£",
- url1: "httpdisabled://sh.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/sh/",
- src1: "/special/00774IHD/house_sh_01.html",
- src2: "/special/00774IHD/house_sh_02.html"
- }, {
- name: "Ìì½ò",
- url1: "httpdisabled://tj.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/tj/search/0-0-0-0-0-0-0-0-1.html",
- src1: "/special/00774IHD/house_tj_01.html",
- src2: "/special/00774IHD/house_tj_02.html"
- }, {
- name: "ÖØÇì",
- url1: "httpdisabled://cq.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/cq/search/0-0-0-0-0-0-0-0-1.html",
- src1: "/special/00774IHD/house_cq_01.html",
- src2: "/special/00774IHD/house_cq_02.html"
- }, {
- name: "º¼ÖÝ",
- url1: "httpdisabled://hz.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/hz/search/0-0-0-0-0-0-0-0-1.html",
- src1: "/special/00774IHD/house_hz_01.html",
- src2: "/special/00774IHD/house_hz_02.html"
- }, {
- name: "ÉòÑô",
- url1: "httpdisabled://sy.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/sy/search/0-0-0-0-0-0-0-0-1.html",
- src1: "/special/00774IHD/house_sy_01.html",
- src2: "/special/00774IHD/house_sy_02.html"
- }, {
- name: "´óÁ¬",
- url1: "httpdisabled://dl.house.163.com/",
- url2: "httpdisabled://dl.house.163.com/more/index4-1.shtml",
- src1: "/special/00774IHD/house_dl_01.html",
- src2: "/special/00774IHD/house_dl_02.html"
- }, {
- name: "ÄϾ©",
- url1: "httpdisabled://nj.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/nj/search/0-0-0-0-0-0-0-0-1.html",
- src1: "/special/00774IHD/house_nj_01.html",
- src2: "/special/00774IHD/house_nj_02.html"
- }, {
- name: "ËÕÖÝ",
- url1: "httpdisabled://suzhou.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/suzhou/search/0-0-0-0-0-0-0-0-1.html",
- src1: "/special/00774IHD/house_suzhou_01.html",
- src2: "/special/00774IHD/house_suzhou_02.html"
- }],
- defaultCity: {//ĬÈÏΪ¹ãÖÝ
- name: "¹ãÖÝ",
- url1: "httpdisabled://gz.house.163.com/",
- url2: "httpdisabled://xf.house.163.com/gz/",
- src1: "/special/00774IHD/house_gz_01.html",
- src2: "/special/00774IHD/house_gz_02.html"
- }
- }
- NTES.ajax.importJs(HouseConfig.ip, function(){
-
- var len = HouseConfig.city.length;
- var locName = "", buyName = HouseConfig.textBuy, locNameUrl = "", buyNameUrl = "", loaddisabledCon1 = "", loaddisabledCon2 = "";
- var i = -1;
- while (++i < len) {
- if (localAddress.city.indexOf(HouseConfig.city[i].name) != -1 || localAddress.province.indexOf(HouseConfig.city[i].name) != -1) {
- locName = HouseConfig.city[i].name + HouseConfig.textHouse;
- locNameUrl = HouseConfig.city[i].url1;
- buyNameUrl = HouseConfig.city[i].url2;
- loaddisabledCon1 = HouseConfig.city[i].src1;
- loaddisabledCon2 = HouseConfig.city[i].src2;
- }
- }
- if (locName == "" && locNameUrl == "") {
- locName = HouseConfig.defaultCity.name + HouseConfig.textHouse;
- locNameUrl = HouseConfig.defaultCity.url1;
- buyNameUrl = HouseConfig.defaultCity.url2;
- loaddisabledCon1 = HouseConfig.defaultCity.src1;
- loaddisabledCon2 = HouseConfig.defaultCity.src2;
- }
- var tab_1 = NTES("#house .tab-u a")[0];
- var tab_2 = NTES("#house .tab-u a")[1];
- tab_1.innerHTML = locName;
- tab_1.href = locNameUrl;
- tab_2.innerHTML = buyName;
- tab_2.href = buyNameUrl;
-
- NTES.ajax.send(loaddisabledCon1, "GET", null, {
- onSuccess: function(xhr){
- $("#house div.tab-con")[0].innerHTML = xhr.responseText;
- }
- });
- NTES.ajax.send(loaddisabledCon2, "GET", null, {
- onSuccess: function(xhr){
- $("#house div.tab-con")[1].innerHTML = xhr.responseText;
- }
- });
-
- });
-})();
-//end
-//shop.163.com
-var Mall = {};
-Mall.gId = function(id){return document.getElementById(id)};
-Mall.checkPhone = function(num){
- if(/^13\d{9}$/.test(num)||(/^15[0-35-9]\d{8}$/.test(num))||(/^18\d{9}$/.test(num))){return true};return false;
-} ;
-Mall.init = function(){
- this.issubmit = true;
- var rep = /[^\d]/;
- Mall.gId("mall_phone").onkeyup = function(){this.value = this.value.replace(rep,"");};
- Mall.gId("mall_phone").onblur = function(){
- if(!Mall.checkPhone(this.value)){
- this.style.borderColor = "#DC3A3B";Mall.issubmit = false;Mall.gId("phone_err").style.display = "";
- }
- else{this.style.borderColor = "#86A2BD";Mall.issubmit = true;Mall.gId("phone_err").style.display = "none";}
- };
- var arr = ["29.55-30.15","49.35-49.9","98.7-99.7","296.1-300.3","493.5-498"];
- Mall.gId("mall_value").onchange = function(){
- Mall.gId("mall_money").innerHTML = arr[this.selectedIndex];
- };
-
- Mall.gId("neteasy_mall_form").onsubmit = function(){
- Mall.gId("mall_phone").onblur();
- if(!Mall.issubmit){return false;}
- };
-};
-Mall.init();
-//update news
-(function(){
- var UpdateNews = function(option) {
- var t = this;
- t.option = option ? option : {};
- var nowTime = "2011-04-09 05:51:01"
- t.nowTime = nowTime.split(" ")[1].substring(0,2);
- if (NTES.cookie.get(t.option["cookieName"]) == "") {
- var cookieStr = [];
- cookieStr.push("00");
- }
- else{
- var cookieStr = NTES.cookie.get(t.option["cookieName"]).split("|");
- cookieStr.shift();
- }
- cookieStr.push(t.nowTime);
- NTES.cookie.set(t.option["cookieName"], cookieStr.join("|"), "1d");
- if (cookieStr[0] > cookieStr[1]) {
- cookieStr[0] = 0;
- }
- else if (cookieStr[0] == cookieStr[1]) {
- NTES(t.option["infoSelect"]).attr("innerHTML",t.option["infotxt1"]);
- NTES(t.option["btnSelect"]).attr("innerHTML",t.option["btntxt1"]);
- return false;
- }
- var aElements = NTES("a[data-t-h]"), newElements = [];
- for (var i = 0; i < aElements.length; i++) {
- var tmp = aElements[i].getAttribute("data-t-h");
- if( cookieStr[0] <= tmp && tmp <= cookieStr[1])
- newElements.push(aElements[i]);
- }
- t.closeUpdate(cookieStr, newElements);
- if(newElements.length != "0"){
- NTES(t.option["btnSelect"]).style.visibility="visible";
- NTES(t.option["btnSelect"]).addEvent("click", function() {
- if (t.option["btntxt1"] == this.innerHTML) {
- t.showUpdate(cookieStr, newElements);
- }
- else {
- t.closeUpdate(cookieStr, newElements);
- }
- });
- }
- };
- UpdateNews.prototype = {
- showUpdate: function(cookieStr, newElements) {
- if(newElements.length != "0"){
- var t = this;
- NTES.each(newElements, function(){NTES.style.addCss(this,"new")});
- NTES(t.option["infoSelect"]).attr("innerHTML",t.option["infotxt2"]);
- NTES(t.option["btnSelect"]).attr("innerHTML",t.option["btntxt2"]);
- NTES(t.option["btnSelect"]).style.visibility = "visible";
- }
- },
- closeUpdate: function(cookieStr, newElements) {
- var t = this;
- var str;
- if(newElements.length == "0"){return false;};
- if(cookieStr[0] == "00" ){
- str = t.option["infotxt3"];
- }
- else{
- str = t.option["infotxt4"];
- }
- str = str.replace("NEWNUM",newElements.length);
- NTES.each(newElements, function(){NTES.style.removeCss(this,"new")});
- NTES(t.option["infoSelect"]).attr('innerHTML', str);
- NTES(t.option["btnSelect"]).attr("innerHTML",t.option["btntxt1"]);
- }
- }
- window.UpdateNews = UpdateNews;
-})();
-NTES.ready( function(){
- var updateNews = new UpdateNews({
- cookieName: "updateRange",
- infoSelect: "#updateInfo",
- btnSelect: "#updateBtn",
- infotxt1: '´ÓÄúÉϴηÃÎʵ½ÏÖÔÚ¸üР<span class="fB cDRed">0</span> Ìõ×ÊѶ',
- infotxt2: "ÓÐÏ»®ÏßÌáʾΪ×îÐÂ×ÊѶ",
- infotxt3: '´Ó0µãµ½ÏÖÔÚ¸üР<span class="fB cDRed">NEWNUM</span> Ìõ×ÊѶ',
- infotxt4: '´ÓÄúÉϴηÃÎʵ½ÏÖÔÚ¸üР<span class="fB cDRed">NEWNUM</span> Ìõ×ÊѶ',
- btntxt1: "ÏÔʾ",
- btntxt2: "¹Ø±Õ"
- });
-});
-//]]>
-</script>
-<div id="ssid1"></div>
-<!-- È«ÆÁÊÕËõ begin -->
-<!-- <script type="text/javascript" src="httpdisabled://popme.163.com/js/nadScreenFloat2011_1.js"></script>
-<script type="text/javascript">//<![CDATA[
-function shownad(){
- new nadScreenFloat("httpdisabled://img1.126.net/channel5/009396/audi750550_110401.jpg",{
- type : "image",
- href : "httpdisabled://g.163.com/a?CID=6678&Values=1009526041&Redirect=http://as.kejet.com/afaclick?u/MDE3MDU1NjUyQUU3MkIy/o/MENGOURGRDlCRUNEN0E3/m/MzlGQTEwMTAzNDVBNDQ1?http://www.audi.cn/cn/brand/zh/financial_products/financial/finance_A3.html",
- playFunc : function(){
- //document.getElementById("nad2234Home").parentNode.style.visibility= "visible";
- }
- });
-}
-var timeOut = setTimeout("shownad()",1);
-</script> -->
-<!-- È«ÆÁÊÕËõ end -->
-<!-- 2010Ê×Ò³ÂÖÌæ¶ÔÁª -->
-<script>
- var sydl=0;
- var coupletTop = 120;
- var rdmdl=Math.floor(Math.random()*3)+1;
-if(rdmdl==1)
-{
- var coupletLeftUrl = 'http://img1.126.net/channel4/008972/mai20300la_0325.swf';
- var coupletRightUrl = 'http://img1.126.net/channel4/008972/mai20300ra_0325.swf';
- var coupletLeftUrlb = 'http://img1.126.net/channel5/008981/mai110300l_110407.swf';
- var coupletRightUrlb = 'http://img1.126.net/channel5/008981/mai110300r_110407.swf';
- var sydl=1;
-}
-if(rdmdl==2)
-{
- var coupletLeftUrl = 'http://img1.126.net/channel5/008981/mbb20300l_110331.swf';
- var coupletRightUrl = 'http://img1.126.net/channel5/008981/mbb20300r_110331.swf';
- var coupletLeftUrlb = 'http://img1.126.net/channel5/008981/mbb110300l_110331.swf';
- var coupletRightUrlb = 'http://img1.126.net/channel5/008981/mbb110300r_110331.swf';
- var sydl=1;
-}
-if(rdmdl==3)
-{
- var coupletLeftUrl = 'http://img1.126.net/channel5/008981/bl20300l_110331.swf';
- var coupletRightUrl = 'http://img1.126.net/channel5/008981/bl20300r_110331.swf';
- var coupletLeftUrlb = 'http://img1.126.net/channel5/008981/bl110300l_110331.swf';
- var coupletRightUrlb = 'http://img1.126.net/channel5/008981/bl110300r_110331.swf';
- var sydl=1;
-}
-if(sydl==1)
-{
-void('<scr'+'ipt type="text/javascript" src="httpdisabled://img1.126.net/channel7/js/duilian_2011n.js"></scr'+'ipt>');
-}
-</script>
-<!-- 2010Ê×Ò³ÂÖÌæ¶ÔÁª -->
-<SCRIPT LANGUAGE="JavaScript1.1" SRC="../pro.163.com/js.ng/site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=flash&amp;location=1"></SCRIPT>
-<SCRIPT LANGUAGE="JavaScript1.1" SRC="../g.163.com/jr@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=popup&amp;location=1"></SCRIPT>
-<img src='../adgeo.163.com/ad_cookies' width="0" height="0">
-<!-- ¸¡²ã -->
-<!-- µ×²¿µ¯´° -->
-<SCRIPT LANGUAGE="JavaScript1.1" SRC="../g.163.com/jr@site=netease&amp;affiliate=homepage&amp;cat=homepage&amp;type=adend&amp;location=1"></SCRIPT>
-<!-- START WRating v1.0 -->
-<script type="text/javascript" src="../163.wrating.com/a1.js">
-</script>
-<script type="text/javascript">
-var vjAcc="860010-0503010000";
-var wrUrl="httpdisabled://163.wrating.com/";
-vjTrack("");
-</script>
-<noscript><img src="../163.wrating.com/a.gif@a=&amp;c=860010-0503010000" width="1" height="1"/></noscript>
-<!-- END WRating v1.0 -->
-<!-- START NetEase Devilfish 2006 -->
-<script src="../analytics.163.com/ntes.js" type="text/javascript"></script>
-<script type="text/javascript">
-_ntes_nacc = "www";
-neteaseTracker();
-neteaseClickStat();
-</script>
-<!-- END NetEase Devilfish 2006 -->
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/www.163.com/mediav.gif b/mobile/android/tests/browser/chrome/tp5/163.com/www.163.com/mediav.gif
deleted file mode 100755
index 0f6336351..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/www.163.com/mediav.gif
+++ /dev/null
@@ -1,8 +0,0 @@
-<html><head><meta http-equiv="cache-control" content="no-cache"></head><body>
-<SCRIPT LANGUAGE="Javascript">
-mvas_43392=36442;mv_acquire=1;mv_bid=43392;
-mvcu_43392='http://show.mediav.com/c?type=2&db=mediav&impid=FW9XAHo9veWj&pub=118_5273_36442&cus=189_1757_19945_43392_0&ref=&url=http://a1410.oadz.com/link/C/1410/522442/.-WeASW6LJ46VaLGFhf4K8Gv7lo_/p021/185/http://www.yksuit.com/?aid=483719';
-</SCRIPT>
-
-<SCRIPT>eval('mediav_fini'+mvas_43392+'=1');var mediav_fini2010010688=1;</SCRIPT>
-<iframe style="display:none" src="http://material.mediav.com/ckmap.htm#prefix=http://audit.wrating.com/a.gif&a=1&c=860010-3000005801&mvck=0O7psfuGKe_9FwVoR1AeWU=="></iframe> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/163.com/zjs.ipinyou.com/2011032517331513260_2342_190180.js b/mobile/android/tests/browser/chrome/tp5/163.com/zjs.ipinyou.com/2011032517331513260_2342_190180.js
deleted file mode 100755
index 7526f6978..000000000
--- a/mobile/android/tests/browser/chrome/tp5/163.com/zjs.ipinyou.com/2011032517331513260_2342_190180.js
+++ /dev/null
@@ -1 +0,0 @@
-window.onerror=function(){return true};var toprefer="m_ZJSTAT";var parentlocation="";var parentrefer="m_ZJSTAT";var selflocation=window.location;var selfrefer=document.referrer;var realrefer="";var reallocation="";var hourvisitnum=1;var realvisitnum=1;var nowdate=new Date();var clientcolor="";if (navigator.appName=="Netscape"){clientcolor=screen.pixelDepth;}else {clientcolor=screen.colorDepth;}hourvisitnum=document.cookie.match(new RegExp("(^| )m_ZJSTAT_PAGES=([^;]*)(;|$)"));hourvisitnum=(hourvisitnum==null)?1: (parseInt(unescape((hourvisitnum)[2]))+1);var currentdate =new Date();currentdate.setTime(currentdate.getTime()+60*60*1000);document.cookie="m_ZJSTAT_PAGES="+hourvisitnum+ ";path=/;expires="+currentdate.toGMTString();realvisitnum=document.cookie.match(new RegExp("(^| )m_ZJSTAT_TIMES=([^;]*)(;|$)"));if(realvisitnum==null){realvisitnum=1;}else{ realvisitnum=parseInt(unescape((realvisitnum)[2])); realvisitnum=(hourvisitnum==1)?(realvisitnum+1):(realvisitnum);}currentdate.setTime(currentdate.getTime()+365*24*60*60*1000);document.cookie="m_ZJSTAT_TIMES="+realvisitnum+";path=/;expires="+currentdate.toGMTString();realrefer=selfrefer;if(parentrefer!=="m_ZJSTAT"){realrefer=parentrefer;}if(toprefer!=="m_ZJSTAT"){realrefer=toprefer;} reallocation=parentlocation;try{lainframe}catch(e){reallocation=selflocation;}void('<iframe target="_blank" src="httpdisabled://www.ipinyou.com/collect.jsp?mediaId=13472&stationId=13260&adPlaceId=2342&collectCode=2342&collectCodeType=2&hourVisitNum='+hourvisitnum+'&realVisitNum='+realvisitnum+'&zone='+(0-nowdate.getTimezoneOffset()/60)+'&screenColor='+clientcolor+'&screen='+screen.width+','+screen.height+'&referUrl='+escape(realrefer)+'&url='+escape(reallocation)+'" width="190" height="180" frameborder="0" scrolling="no" marginwidth="0" marginheight="0"></iframe>'); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/README b/mobile/android/tests/browser/chrome/tp5/README
deleted file mode 100644
index c733fb4c0..000000000
--- a/mobile/android/tests/browser/chrome/tp5/README
+++ /dev/null
@@ -1 +0,0 @@
-This directory contains pages and other resources downloaded from the web for the purpose of testing against pages from the real world. Pages are copied from the Talos tp5 data -- see https://wiki.mozilla.org/Buildbot/Talos/Tests#tp5. These files are not made available under an open source license.
diff --git a/mobile/android/tests/browser/chrome/tp5/baidu.com/c.baidu.com/c.gif@t=0&q=mozilla&p=0&pn=1.html b/mobile/android/tests/browser/chrome/tp5/baidu.com/c.baidu.com/c.gif@t=0&q=mozilla&p=0&pn=1.html
deleted file mode 100755
index e69de29bb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/baidu.com/c.baidu.com/c.gif@t=0&q=mozilla&p=0&pn=1.html
+++ /dev/null
diff --git a/mobile/android/tests/browser/chrome/tp5/baidu.com/open.baidu.com/stat/image/Icon_Aladdin.gif b/mobile/android/tests/browser/chrome/tp5/baidu.com/open.baidu.com/stat/image/Icon_Aladdin.gif
deleted file mode 100755
index 6e1d27f89..000000000
--- a/mobile/android/tests/browser/chrome/tp5/baidu.com/open.baidu.com/stat/image/Icon_Aladdin.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/aladdin/img/table/bg.gif b/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/aladdin/img/table/bg.gif
deleted file mode 100755
index dd7f76048..000000000
--- a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/aladdin/img/table/bg.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/arr.gif b/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/arr.gif
deleted file mode 100755
index c466d496b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/arr.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/baidu_jgylogo1.gif b/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/baidu_jgylogo1.gif
deleted file mode 100755
index e1d5d3714..000000000
--- a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/baidu_jgylogo1.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/i2.png b/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/i2.png
deleted file mode 100755
index 85b8e9683..000000000
--- a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/img/i2.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/js/bdsug.js@v=1.0.3.0 b/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/js/bdsug.js@v=1.0.3.0
deleted file mode 100755
index dab5c2a40..000000000
--- a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/js/bdsug.js@v=1.0.3.0
+++ /dev/null
@@ -1 +0,0 @@
-(function(){var M=navigator.userAgent.indexOf("MSIE")!=-1&&!window.opera;var V=(document.compatMode=="BackCompat");function I(C){return document.getElementById(C)}function K(C){return document.createElement(C)}function S(C){return String(C).replace(new RegExp("(^[\\s\\t\\xa0\\u3000]+)|([\\u3000\\xa0\\s\\t]+\x24)","g"),"")}function U(C){return String(C).replace(new RegExp("[\\s\\t\\xa0\\u3000]","g"),"")}function P(G,X,C){if(M){G.attachEvent("on"+X,(function(Y){return function(){C.call(Y)}})(G))}else{G.addEventListener(X,C,false)}}function N(C){if(M){C.returnValue=false}else{C.preventDefault()}}function R(X){if(M){var G=document.createStyleSheet();G.cssText=X}else{var C=document.createElement("style");C.type="text/css";C.appendChild(document.createTextNode(X));document.getElementsByTagName("HEAD")[0].appendChild(C)}}function H(G){var X=document.forms[0];for(var Y in G){if(G[Y]==undefined){if(I("bdsug_ipt_"+Y)){X.removeChild(I("bdsug_ipt_"+Y))}}else{if(!O(Y)){X.appendChild(C(Y,G[Y]))}else{O(Y).value=G[Y]}}}function C(Z,b){var a=K("INPUT");a.type="hidden";a.name=Z;a.id="bdsug_ipt_"+Z;a.value=b;return a}}function O(Y){var X=document.forms[0];var G=false;var C=X.getElementsByTagName("INPUT");for(var Z=0;Z<C.length;Z++){if(Y==C[Z].getAttribute("name")){G=C[Z];return G}else{G=false}}}function L(G){var X=document.forms[0];for(var C in G){if(C=="f"){if(O("f")){if(O("f").id=="bdsug_ipt_f"){X.removeChild(I("bdsug_ipt_f"))}else{O("f").value="8"}}}else{if(I("bdsug_ipt_"+C)){X.removeChild(I("bdsug_ipt_"+C))}}}}var A=0;if(typeof window.bdsug!="object"||window.bdsug==null){window.bdsug={}}bdsug.sug={};bdsug.sugkeywatcher={};var J=(function(){function C(b){var Z=this.__MSG_QS__;if(!Z[b]){Z[b]=[]}for(var a=1,X=arguments.length,Y;a<X;a++){Z[b].push(arguments[a])}}function G(Y){var Z=this.__MSG_QS__[Y.type];if(Z==null){return }for(var a=0,X=Z.length;a<X;a++){Z[a].rm(Y)}}return{ini:function(X){X.__MSG_QS__={};X.on=C;X.dm=G;return X}}})();var F=(function(){var X=I("kw");var f;var i=0;var C=0;var d="";var Y="";var c;var k=false;var a=true;var h;function Z(){if(a){A=new Date().getTime();F.dm({type:"start"});a=false}}function e(o){if(a){A=new Date().getTime();F.dm({type:"start"});a=false}o=o||window.event;if(o.keyCode==9||o.keyCode==27){F.dm({type:"hide_div"})}if(o.keyCode==13){N(o);F.dm({type:"key_enter"})}if(o.keyCode==86&&o.ctrlKey){H({n:2})}if(f.style.display!="none"){if(o.keyCode==38){N(o);F.dm({type:"key_up"})}if(o.keyCode==40){F.dm({type:"key_down"})}}else{if(o.keyCode==38||o.keyCode==40){F.dm({type:"need_data",wd:X.value})}}}function l(){var o=X.value;if(o==d&&o!=""&&o!=Y&&o!=c){if(C==0){C=setTimeout(function(){F.dm({type:"need_data",wd:o})},100)}}else{clearTimeout(C);C=0;d=o;if(o==""){F.dm({type:"hide_div"})}if(Y!=X.value){Y=""}}}function m(){i=setInterval(l,10)}function g(){clearInterval(i)}function j(){if(k){window.event.cancelBubble=true;window.event.returnValue=false;k=false}}function b(o){X.blur();X.setAttribute("autocomplete",o);X.focus()}function G(o){var o=o||window.event;if(o.keyCode==13){N(o)}}X.setAttribute("autocomplete","off");var n=false;bdsug.sugkeywatcher.on=function(){if(!n){if(M){X.attachEvent("onkeydown",e)}else{X.addEventListener("keydown",e,false)}n=true}};bdsug.sugkeywatcher.off=function(){if(n){if(M){X.detachEvent("onkeydown",e)}else{X.removeEventListener("keydown",e,false)}n=false}};bdsug.sugkeywatcher.on();P(X,"mousedown",Z);P(X,"beforedeactivate",j);if(window.opera){P(X,"keypress",G)}return J.ini({rm:function(o){switch(o.type){case"div_ready":f=o.sdiv;Y=X.value;m();break;case"clk_submit":g();X.blur();X.value=o.wd;break;case"ent_submit":g();X.blur();break;case"key_select":c=o.selected;break;case"close":g();b("on");break;case"mousedown_tr":if(navigator.userAgent.toLowerCase().indexOf("webkit")!=-1){g();setTimeout(m,2000)}k=true;break}}})})();var W=(function(){var h;var a=I("kw");var l;var d=-1;var C;var m;var o;function n(){var r=l.rows;for(var q=0;q<r.length;q++){r[q].className="ml"}}function e(){if(typeof (l)!="undefined"&&l!=null&&h.style.display!="none"){var r=l.rows;for(var q=0;q<r.length;q++){if(r[q].className=="mo"){return[q,r[q].cells[0].innerHTML]}}}return[-1,""]}function i(){if(M){o.style.display="none"}h.style.display="none"}function G(){n();this.className="mo"}function b(q){W.dm({type:"mousedown_tr"});if(!M){q.stopPropagation();q.preventDefault();return false}}function c(q){var r=q;return function(){var s=C[r];i();W.dm({type:"clk_submit",oq:I("kw").value,wd:s,rsp:r})}}function f(q){q=q||window.event;N(q);W.dm({type:"close"});i();(new Image()).src="httpdisabled://sclick.baidu.com/w.gif?fm=suggestion&title=%B9%D8%B1%D5&t="+new Date().getTime()}function X(){var q=[a.offsetWidth,a.offsetHeight];h.style.width=((M&&V)?q[0]:q[0]-2)+"px";h.style.top=((M&&V)?q[1]:q[1]-1)+"px";h.style.display="block";if(M){o.style.top=((M&&V)?q[1]:q[1]-1)+"px";o.style.width=((M&&V)?q[0]:q[0]-2)+"px"}}function Y(r,q){if(r&&q){var s=S(r);if(q.indexOf(s)==0){q=p(q,s)}else{if(q.indexOf(U(r))==0){s=U(r);q=p(q,s)}else{}}}q=q.replace("&","&amp;");return q}function p(q,s){var t="<span>"+s+"</span>";var u=s.length;var r="<b>"+q.substring(u)+"</b>";return(t+r)}function j(){l=K("TABLE");l.id="st";l.cellSpacing=0;l.cellPadding=2;var s=K("tbody");l.appendChild(s);for(var t=0,u=C.length;t<u;t++){var r=s.insertRow(-1);P(r,"mouseover",G);P(r,"mouseout",n);P(r,"mousedown",b);P(r,"click",c(t));var q=r.insertCell(-1);q.innerHTML=Y(m,C[t])}h.innerHTML="";h.appendChild(l);X();if(M){o.style.display="block";o.style.left=0+"px";o.style.top=a.offsetHeight+"px";o.style.width=a.offsetWidth+"px";o.style.height=h.offsetHeight-10+"px"}}function Z(){d=e()[0];if(d==-1){W.dm({type:"submit"})}else{W.dm({type:"ent_submit",oq:m,wd:e()[1],rsp:d})}}function k(){d=e()[0];n();if(d==0){W.dm({type:"key_select",selected:""});I("kw").value=m;d--;L({oq:m,sug:C[d],n:1,rsp:d,f:3,rsv_sug:rsv_sug})}else{if(d==-1){d=C.length}d--;var q=l.rows[d];q.className="mo";W.dm({type:"key_select",selected:C[d]});I("kw").value=C[d];H({oq:m,sug:C[d],n:1,rsp:d,f:3,rsv_sug:rsv_sug})}}function g(){d=e()[0];n();if(d==C.length-1){W.dm({type:"key_select",selected:""});I("kw").value=m;d=-1;L({oq:m,sug:C[d],n:1,rsp:d,f:3,rsv_sug:rsv_sug})}else{d++;var q=l.rows[d];q.className="mo";W.dm({type:"key_select",selected:C[d]});I("kw").value=C[d];H({oq:m,sug:C[d],n:1,rsp:d,f:3,rsv_sug:rsv_sug})}}return J.ini({rm:function(q){switch(q.type){case"div_ready":h=q.sdiv;o=q.frm;break;case"give_data":m=q.data.q;C=q.data.s;rsv_sug=q.data.t;if(C.length!=0){j()}else{i()}break;case"key_enter":Z();break;case"key_up":k();break;case"key_down":g();break;case"hide_div":i();break;case"mousedown_other":i();break;case"window_blur":i();break;case"need_resize":X();break}}})})();var T=(function(){var C=document.forms[0];function G(){if(I("bdsug_ipt_sug")){if(I("bdsug_ipt_sug").value==S(I("kw").value)){L({n:1,sug:1})}else{L({f:1})}}}P(C,"submit",G);function X(){G();C.submit()}function Y(Z){H(Z);L({sug:1,n:1});C.submit()}return J.ini({rm:function(Z){switch(Z.type){case"clk_submit":case"ent_submit":Y({oq:Z.oq,rsp:Z.rsp,f:3,sugT:(new Date().getTime()-A),rsv_sug:rsv_sug});break;case"submit":X();break}}})})();var B=(function(){var G={};function X(C){if(typeof G[C]=="undefined"){B.dm({type:"request_data",wd:C})}else{B.dm({type:"give_data",data:G[C]})}}function Y(C){G[C.q]=C;B.dm({type:"give_data",data:G[C.q]})}return J.ini({rm:function(C){switch(C.type){case"response_data":Y(C.data);break;case"need_data":X(C.wd);break}}})})();var Q=(function(){var C;var X;function G(Y){Q.dm({type:"need_cookie"});if(C){document.body.removeChild(C)}C=K("SCRIPT");C.src="httpdisabled://suggestion.baidu.com/su?wd="+encodeURIComponent(Y)+"&p="+X+"&cb=window.bdsug.sug&t="+(new Date()).getTime();C.charset="gb2312";document.body.appendChild(C)}return J.ini({rm:function(Y){switch(Y.type){case"request_data":G(Y.wd);break;case"give_cookie":var Z=Y.sug;if(Z>0){Z=3}X=Z;break}}})})();bdsug.sug=function(C){bdsug.dm({type:"response_data",data:C})};bdsug.initSug=function(){bdsug.dm({type:"init"})};J.ini(bdsug);var E=(function(){function C(){if(navigator.cookieEnabled){document.cookie="su=0; domain=www.baidu.com"}}function G(){var X=(navigator.cookieEnabled&&/sug=(\d)/.test(document.cookie)?RegExp.$1:3);E.dm({type:"give_cookie",sug:X})}return J.ini({rm:function(X){switch(X.type){case"close":C();break;case"need_cookie":G();break}}})})();var D=(function(){var Z=I("kw");var C;var c=document.forms[0];var Y;function a(){if(C.offsetWidth!=0&&Z.offsetWidth!=C.offsetWidth){D.dm({type:"need_resize"})}}function d(){C=K("DIV");C.id="sd_"+new Date().getTime();C.style.display="none";c.appendChild(C);if(M){Y=K("IFRAME");Y.style.display="none";Y.style.position="absolute";C.parentNode.insertBefore(Y,C)}}function b(e){e=e||window.event;var f=e.target||e.srcElement;if(f==Z){return }while(f=f.parentNode){if(f==C){return }}D.dm({type:"mousedown_other"})}function X(){D.dm({type:"window_blur"})}function G(){var f="#"+C.id;var e=[];D.dm({type:"div_ready",sdiv:C,frm:Y});setInterval(a,100);P(document,"mousedown",b);P(window,"blur",X);e.push(f+"{border:1px solid #817F82;position:absolute;top:28px;left:0}");e.push(f+" table{width:100%;background:#fff;cursor:default}");e.push(f+" td{font:14px verdana;line-height:20px;text-indent:6px}");e.push(f+" td b{color:#333}");e.push(f+" .mo{background-color:#E2EAFF}");e.push(f+" .ml{background-color:#fff}");R(e.join(""))}bdsug.sug.initial=G;return J.ini({rm:function(e){switch(e.type){case"start":G();break;case"init":d();break}}})})();F.on("need_data",B);F.on("close_div",W);F.on("key_enter",W);F.on("key_up",W);F.on("key_down",W);F.on("hide_div",W);F.on("start",D);B.on("request_data",Q);B.on("give_data",W);bdsug.on("response_data",B);bdsug.on("init",D);W.on("clk_submit",F,T);W.on("ent_submit",F,T);W.on("submit",T);W.on("key_select",F);W.on("close",F,E);W.on("mousedown_tr",F);D.on("mousedown_other",W);D.on("need_resize",W);D.on("div_ready",F,W);D.on("window_blur",W);Q.on("need_cookie",E);E.on("give_cookie",Q);window.bdsug.initSug()})(); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/s@wd=mozilla.html b/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/s@wd=mozilla.html
deleted file mode 100755
index 1c0734368..000000000
--- a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/s@wd=mozilla.html
+++ /dev/null
@@ -1,123 +0,0 @@
-<!DOCTYPE html><!--STATUS OK--><html><head>
-<meta http-equiv="X-UA-Compatible" content="IE=7">
-<meta http-equiv="content-type" content="text/html;charset=gb2312">
-<title>°Ù¶ÈËÑË÷_mozilla </title>
-<style>body{color:#000;background:#fff;padding:7px 0 0;margin:0;position:relative}body,th,td,.p1,.p2{font-family:arial}p,form,ul,li,h3{margin:0;padding:0;list-style:none}input{padding-top:0;padding-bottom:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}table,img{border:0}td{font-size:9pt;line-height:18px}em{font-style:normal;color:#cc0000}a em{text-decoration:underline}.m,a.m{color:#666}a.m:visited{color:#606}.g,a.g{color:#008000}.c{color:#77c}.f14{font-size:14px}.f10{font-size:10.5pt}.f16{font-size:16px}#u,#head,#tool,#search,#foot{font-size:12px}.p1{line-height:120%;margin-left:-12pt}.p2{width:100%;line-height:120%;margin-left:-12pt}#out{_margin-left:880px;_zoom:1}#in{_position:relative;_float:left;_margin-left:-880px}#wrapper{min-width:880px;_zoom:1}#u{white-space:nowrap;position:absolute;right:10px;top:6px;_top:0;z-index:210}#u_m{color:#00c;cursor:pointer}#u_ms{text-decoration:underline}#u_m_tip{position:absolute;right:40px;top:24px;_top:26px;z-index:210;border:1px solid #9a99ff;display:none;background:#fff;overflow:hidden;width:100px}#u_m_tip a{display:block;line-height:22px;color:#0001cf;padding:0 10px;font-size:12px;text-decoration:none;border-bottom:1px solid #e6e6e6;width:100%}#u_m_tip a:hover{background:#d9e1f6}#u_m_tip a.last{border-bottom:0}#head{padding-left:15px}.fm{clear:both;position:relative;z-index:9}.nv{height:45px;position:relative;z-index:200}.nv .logo{float:left;margin-right:20px}.nv .tab{float:left;padding:20px 0 0;line-height:18px}.nv a,.nv b,.btn,#page,#more{font-size:14px}.nv a{color:#0000cc}.i{width:536px;*width:519px;height:32px;*height:20px;padding:3px 7px;padding-top:7px\9;font:16px arial;background:url(img/i2.png) no-repeat;border:1px solid #b6b6b6;border-color:#7b7b7b #b6b6b6 #b6b6b6 #7b7b7b;vertical-align:top;margin-right:5px}.btn{width:95px;height:32px;padding:0;padding-top:2px\9;border:0;background:#ddd url(img/i2.png) 0 -35px;cursor:pointer}.btn_h{background-position:-100px -35px}.btn_wr{width:97px;height:34px;display:inline-block;background:url(img/i2.png) no-repeat -202px bottom;_padding-top:1px;*position:relative}.seth{margin-left:22px;display:none;display:inline\9}.seth a{color:#00c}#tb_mr{color:#00c;cursor:pointer;position:relative;z-index:200}#tb_mr b{font-weight:normal;text-decoration:underline}#tb_mr small{font-size:11px}#more{width:58px;height:100px;border:1px solid #9A99FF;background:#fff;position:absolute;z-index:200;left:452px;top:45px;*top:46px;overflow:hidden;display:none;outline:none}#more a{width:53px;height:25%;line-height:24px;display:block;padding:0 0 0 7px;color:#0001CF;text-decoration:none}#more a span{font-family:"ËÎÌå"}#more a:hover{background:#D9E1F6}#more div{height:1px;overflow:hidden;background:#ccf;margin:0 3px}#page{padding:0 0 0 18px;white-space:nowrap}#page{word-spacing:4px}#page .n{font-size:16px}#rs{width:100%;background:#eff2fa;padding:8px 0;margin:20px 0 0}#rs td{width:5%}#rs th{font-size:14px;font-weight:normal;line-height:19px;white-space:nowrap;text-align:left;vertical-align:top}#rs .tt{font-weight:bold;padding:0 10px 0 23px}.to{font-size:16px;line-height:24px;padding:0 0 0 58px;margin:20px 0 0}#search{padding:35px 0 16px 18px}#search .btn_wr{vertical-align:middle}#foot{height:20px;line-height:20px;color:#77c;background:#e6e6e6;text-align:center}#foot span{color:#666}.f{line-height:115%;*line-height:120%;font-size:100%;width:33.7em;padding-left:15px;word-break:break-all;word-wrap:break-word}.h{margin-left:8px;width:100%}.r{word-break:break-all;cursor:hand;width:238px}.t{font-weight:normal;font-size:medium}.pl{padding-left:3px;height:8px;padding-right:2px;font-size:14px}.mo,a.mo:link,a.mo:visited{color:#666;font-size:100%;line-height:10px}.htb{margin-bottom:5px}.jc a{color:#cc0000}a font[size="3"] font, font[size="3"] a font{text-decoration:underline}div.blog,div.bbs{color:#707070;padding-top:3px}.result{width:34em;table-layout:fixed}.nums{font-size:12px;color:#999}.tools{width:220px;position:absolute;top:10px}#mHolder{width:62px;position:relative;top:-18px;margin-left:9px;margin-right:-12px;display:none}#mCon{position:absolute;right:7px;top:3px;*top:6px;cursor:pointer;padding:0 18px 0 0;line-height:normal;background:url(img/arr.gif) no-repeat right center}#mCon span{color:#00c;cursor:default;display:block;padding-top:3px}#mCon .hw{text-decoration:underline;cursor:pointer}#mMenu{width:56px;border:1px solid #9a99ff;position:absolute;right:7px;top:28px;display:none;background:#fff}#mMenu a{width:100%;height:100%;color:#00c;display:block;line-height:22px;text-indent:6px;text-decoration:none}#mMenu a:hover{background:#d9e1f6}#mMenu .ln{height:1px;background:#ccf;overflow:hidden;margin:2px;font-size:1px;line-height:1px}.op_LAMP{background:url("..void.baidu.com/stat/image/Icon_Aladdin.gif") no-repeat 0 2px;color:#77C;display:inline-block;font-size:13px;height:12px;*height:14px;width:16px;text-decoration:none;zoom:1;}
-.EC_mr15{margin-left:15px}.pd15{padding-left:15px}.favurl{background-repeat:no-repeat;background-position:0 1px;padding-left:20px;}</style>
-
-<script>var name,location,navigate,bdQid="e0156d2700181a32",al_arr=[];var selfOpen = void;eval("void = selfOpen;");function G(id){return document.getElementById(id);}function h(obj){obj.style.behavior='url(#default#homepage)';obj.setHomePage('http://www.baidu.com');var img=window["BD_PS_C"+(new Date()).getTime()]=new Image();img.src="httpdisabled://sclick.baidu.com/w.gif?fm=hp&tn=baidu&t="+new Date().getTime();}function al_c(A){while(A.tagName!="TABLE"){A=A.parentNode;}return A.getAttribute("id");}function al_c2(n,c){while(c--){while((n=n.parentNode).tagName!="TABLE");};return n.getAttribute("id");}function c(q){var p = window.document.location.href, sQ = '', sV = '', mu='', img = window["BD_PS_C" + (new Date()).getTime()] = new Image();for (v in q) {switch (v) {case "title":sV = encodeURIComponent(q[v].replace(/<[^<>]+>/g, ""));break;case "url":sV = escape(q[v]);break;default:sV = q[v];}sQ += v + "=" + sV + "&";}try{if (("p2" in q)&&G(q["p1"]).getAttribute("mu") && q["fm"]!="pl") {mu= "mu=" + escape(G(q["p1"]).getAttribute("mu"));}}catch(e){};img.src = "httpdisabled://sclick.baidu.com/w.gif?q=mozilla&" + sQ + mu + "&cid=0&qid=e0156d2700181a32&t="+new Date().getTime()+"&path="+p;return true;}window["bdUser"]=null;window["login_success"]=[];</script>
-</head>
-<body link="#0000cc">
-<div id="out"><div id="in"><div id="wrapper">
-<p id="u"><a href="httpdisabled://www.baidu.com/gaoji/preferences.html" onmousedown="return user_c({'fm':'set','tab':'setting','url':this.href})">ËÑË÷ÉèÖÃ</a>&nbsp;|&nbsp;<a id="lb" href="httpdisabled://passport.baidu.com/?login&tpl=mn" onclick="return false;" onmousedown="return user_c({'fm':'set','tab':'login','url':this.href})">µÇ¼</a></p>
-<div id="head"><div class="nv"><a href="httpdisabled://www.baidu.com/" class="logo"><img src="img/baidu_jgylogo1.gif" width="117" height="38" border="0" alt="µ½°Ù¶ÈÊ×Ò³"></a><div class="tab"><a href="httpdisabled://news.baidu.com/ns?cl=2&rn=20&tn=news&word=mozilla" onmousedown="return c({'fm':'tab','tab':'news'})">ÐÂÎÅ</a>¡¡<b>ÍøÒ³</b>¡¡<a href="httpdisabled://tieba.baidu.com/f?kw=mozilla&fr=wwwt" onmousedown="return c({'fm':'tab','tab':'tieba'})">Ìù°É</a>¡¡<a href="httpdisabled://zhidao.baidu.com/q?ct=17&pn=0&tn=ikaslist&rn=10&word=mozilla&fr=wwwt" onmousedown="return c({'fm':'tab','tab':'zhidao'})">ÖªµÀ</a>¡¡<a href="httpdisabled://mp3.baidu.com/m?tn=baidump3&ct=134217728&lm=-1&word=mozilla" onmousedown="return c({'fm':'tab','tab':'mp3'})">MP3</a>¡¡<a href="httpdisabled://image.baidu.com/i?tn=baiduimage&ct=201326592&lm=-1&cl=2&word=mozilla" onmousedown="return c({'fm':'tab','tab':'pic'})">ͼƬ</a>¡¡<a href="httpdisabled://video.baidu.com/v?ct=301989888&rn=20&pn=0&db=0&s=25&word=mozilla" onmousedown="return c({'fm':'tab','tab':'video'})">ÊÓƵ</a>¡¡<a href="httpdisabled://map.baidu.com/m?word=mozilla&fr=ps01000" onmousedown="return c({'fm':'tab','tab':'map'})">µØͼ</a>¡¡<span id="tb_mr" onmousedown="return c({'fm':'tab','tab':'tbmore'});"><b>¸ü¶à</b><small>¨‹</small></span></div><div id="more"><a href="httpdisabled://baike.baidu.com/searchword/?word=mozilla&pic=1" onmousedown="return c({'fm':'tab','tab':'baike'})">°Ù¿Æ</a><a href="httpdisabled://wenku.baidu.com/search?word=mozilla&lm=0&od=0" onmousedown="return c({'fm':'tab','tab':'wenku'})">ÎÄ¿â</a><a href="httpdisabled://dict.baidu.com/s?wd=mozilla" onmousedown="return c({'fm':'tab','tab':'dict'})">´Êµä</a><div></div><a href="httpdisabled://www.baidu.com/more/" onmousedown="return c({'fm':'tab','tab':'more'})">¸ü¶à<span>&gt;&gt;</span></a></div></div><form name="f" action="httpdisabled://www.baidu.com/s" class="fm"><input type="hidden" name="bs" value="mozilla"><input type="hidden" name="f" value="8"><input name="wd" id="kw" class="i" value="mozilla" maxlength="100"><span class="btn_wr"><input type="submit" id="su" value="°Ù¶ÈÒ»ÏÂ" class="btn" onmousedown="this.className='btn btn_h'" onmouseout="this.className='btn'"></span><span class="tools"><span id="mHolder"><div id="mCon"><span>ÊäÈë·¨</span></div><ul id="mMenu"><li><a href="s@wd=mozilla.html#" name="ime_hw">ÊÖд</a></li><li><a href="s@wd=mozilla.html#" name="ime_py">Æ´Òô</a></li><li class="ln"></li><li><a href="s@wd=mozilla.html#" name="ime_cl">¹Ø±Õ</a></li></ul></span><span class="seth"><a href="s@wd=mozilla.html#" onClick="h(this)">°Ñ°Ù¶ÈÉèΪÖ÷Ò³</a></span>
-</span></form></div><br>
-
-<table width="30%" border="0" cellpadding="0" cellspacing="0" align="right"><tr>
-<td align="left" style="padding-right:10px">
-<div style="border-left:1px solid #e1e1e1;padding-left:10px;word-break:break-all;word-wrap:break-word;">
-
-
-
-
-
-<style type="text/css">
-.r.ec_bdtg{ width:238px;}
-.ec_bdtg .fsblock{padding:0;word-break:normal;font-family:arial}
-.ec_bdtg .fsblock a{text-decoration:none;}
-.ec_bdtg .title a{ text-decoration:underline; margin:0; padding:0; cursor:pointer;}
-</style>
-<div class="r ec_bdtg">
-<div class="fsblock">
-
- <div class="title"><a href="httpdisabled://www.baidu.com/adrc.php?t=000a00c00f7Ul0D0SOY00FTFK60U6GqP0000000000000000wp6s7s.THdVULGGUAk90A3qmh7GuZR0T1d-njDdPhfzP10snH6kmHnz0ZRq0ADquZCkIAc1TZKBwL9Cih4PrNGRfg9rN7GoHyGWIYdDwHwPNYNlHy-pI7bzUAVfN77lHdwWnDqRmvduNjK3yZGKUywZnj-2U-uYR7PpIhPVp1-PRdGlu7I2IhPVp1-2UbF4mNfsnfK-5y9YIZ0lQzq-QhF9pywdQhPEUitOThNhugcqnH0z0APzm1Y1nWTdn6" target="_blank"><font size="3" style="_font-size:8pt;">&#9654</font><font size="3">À´°Ù¶ÈÍƹãÄúµÄ²úÆ·</font></a></div>
- <a href="httpdisabled://www.baidu.com/adrc.php?t=000a00c00f7Ul0D0SOY00FTFK60U6GqP0000000000000000wp6s7s.THdVULGGUAk90A3qmh7GuZR0T1d-njDdPhfzP10snH6kmHnz0ZRq0ADquZCkIAc1TZKBwL9Cih4PrNGRfg9rN7GoHyGWIYdDwHwPNYNlHy-pI7bzUAVfN77lHdwWnDqRmvduNjK3yZGKUywZnj-2U-uYR7PpIhPVp1-PRdGlu7I2IhPVp1-2UbF4mNfsnfK-5y9YIZ0lQzq-QhF9pywdQhPEUitOThNhugcqnH0z0APzm1Y1nWTdn6" target="_blank"><font color="#000" size="-1">×ÉѯÈÈÏߣº400-800-8888</font><br/>
- <font color="#008000" size="-1">e.baidu.com</font></a>
-
-</div>
-</div>
-<br />
-
-
-
-</div>
-<br>
-</td></tr></table>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<table cellpadding="0" cellspacing="0" class="result" id="1" mu="httpdisabled://baike.baidu.com/view/393243.htm"><tr><td class="f"><h3 class="t"><a target="_blank" href="httpdisabled://baike.baidu.com/view/393243.htm" onmousedown="return c({'fm':'albk','title':this.innerHTML,'url':this.href,'p1':al_c(this)});"><em>mozilla</em>_°Ù¶È°Ù¿Æ</a></h3><font size="-1"><em>Mozilla</em>»ù½ð»á¼ò³Æ<em>Mozilla</em>(ËõдMF»òMoFo£¬ÈçͼΪ<em>Mozilla</em> »ù½ð»áµÄ×¢²á±êʶ)£¬ÊÇΪ֧³ÖºÍÁìµ¼¿ªÔ´µÄ<em>Mozilla</em>ÏîÄ¿¶øÉèÁ¢µÄÒ»¸ö·ÇÓªÀû×éÖ¯¡£¸Ã×éÖ¯Öƶ¨...<font color="#666666">¹²19´Î±à¼­</font><br/><a target="_blank" href="httpdisabled://baike.baidu.com/view/393243.htm#1" onmousedown="return c({'fm':'albk','title':this.innerHTML,'url':this.href,'p1':al_c(this),'p2':'1'});">·¢Õ¹¼òÊ·</a> - <a target="_blank" href="httpdisabled://baike.baidu.com/view/393243.htm#2" onmousedown="return c({'fm':'albk','title':this.innerHTML,'url':this.href,'p1':al_c(this),'p2':'2'});">Ãû×ÖÀ´Àú</a> - <a target="_blank" href="httpdisabled://baike.baidu.com/view/393243.htm#3" onmousedown="return c({'fm':'albk','title':this.innerHTML,'url':this.href,'p1':al_c(this),'p2':'3'});">ͼ±êÀ´Ô´</a> - <a target="_blank" href="httpdisabled://baike.baidu.com/view/393243.htm#4" onmousedown="return c({'fm':'albk','title':this.innerHTML,'url':this.href,'p1':al_c(this),'p2':'4'});">³õÆڳɾÍ</a> <br/><font color="#008000">baike.baidu.com/view/393243.htm 2010-12-26</font></font></td></tr></table><br>
-<table cellpadding="0" cellspacing="0" class="result" id="2"><tr><td class=f><h3 class="t"><a onmousedown="return c({'fm':'as','F':'779317EA','F1':'9D73F1E4','F2':'4CA63E6B','F3':'54E5243F','T':'1302299163','title':this.innerHTML,'url':this.href,'p1':2,'y':'FB6977FE'})" href="httpdisabled://www.mozilla.org/products/firefox/" target="_blank">ıÖÇÍøÂ磬»ðºüä¯ÀÀÆ÷ÖйúΨһ¹Ù·½ÍøÕ¾ | <em>Mozilla</em>, Firefox, and ...</a></h3><font size=-1> [10-13] <em>Mozilla</em>¶­Ê³¤Ã×Çжû³ÆδÀ´ä¯ÀÀÆ÷»áÊÇÕûºÏƽ̨ [09-26] ÊÀ½çÈí¼þ×ÔÓÉÈÕ »ðºüÉçÇøÔÙÏÆ¿ªÔ´Èȳ± [09-08] »ðºü¹È¸èÁªÊÖ·¢²¼¡°W3Help¡±ÍøÕ¾ ÖÂÁ¦´Ù½øW3C...<br><span class="g">www.<b>mozilla</b>.org/products/firefox/ 2010-12-18 </span> - <a href="httpdisabled://cache.baidu.com/c?m=9f65cb4a8c8507ed4fece763105392230e54f73c619f8b4b21878448e4391b145a24a3e67165414292d8283c41f81d01a0ed22376a4376b8c495c01183e5c1&p=8b2a931d84d805ff57ed972c1349&user=baidu&fm=sc&query=mozilla&qid=e0156d2700181a32&p1=2" target="_blank" class="m">°Ù¶È¿ìÕÕ</a><br></font></td></tr></table><br>
-<table cellpadding="0" cellspacing="0" id="3" mu="httpdisabled://soft.baidu.com/softwaresearch/s?tn=software&rn=10&wd=mozilla"><style>.op_table01_content table{margin-top:4px;}.op_table01_content th{text-align:left;white-space:nowrap;background:url("aladdin/img/table/bg.gif") repeat-x 0 -37px;font-weight:normal;height:26px;line-height:26px;font-size:13px;}.op_table02_content td a{text-decoration:none;}.op_table01_content td{white-space:nowrap;height:33px;font-size:14px;border-bottom:#eee 1px solid;}.op_software table{width:98%;}.op_software td{padding-right:14px;}</style><script>function jI(D){var C=D;var B=0;while(C=C.parentNode){B=parseInt(C.getAttribute("id"));if(B>0){break}}var A=C.getElementsByTagName("a");for(var B=0;B<A.length;B++){if(D==A[B]){return B}}return A.length-1}function _aMC(C){var B=C,A=-1;while(B=B.parentNode){A=parseInt(B.getAttribute("id"));if(A>0){return A}}};</script><tr><td class=f> <a onmousedown="return c({'fm':'alop','title':this.innerHTML,'url':this.href,'p1':_aMC(this)})" href="httpdisabled://soft.baidu.com/softwaresearch/s?tn=software&rn=10&wd=mozilla" target="_blank"><font size="3"><em>mozilla</em>_Ïà¹ØÏÂÔØÐÅÏ¢123Ìõ_°Ù¶ÈÈí¼þËÑË÷</font></a><br> <div class="op_table01_content op_software"> <table cellspacing="0" class="op_software_tb"><tr><th style="border-left:0;">Èí¼þÃû³Æ</th><th class="op_software_size">Èí¼þ´óС</th><th class="op_software_src">À´Ô´</th></tr> <tr><td> <a target="_blank" onmousedown="return c({'fm':'alop','title':this.innerHTML,'url':this.href,'p1':_aMC(this),'p2':jI(this)})" href="httpdisabled://www.newhua.com/soft/3600.htm" ><em>Mozilla</em> Firefox 4.0 ¼òÌå°æ</a></td><td class="op_software_size"> 11.85 M </td><td class="op_software_src"> »ª¾üÈí¼þÔ° </td></tr> <tr><td> <a target="_blank" onmousedown="return c({'fm':'alop','title':this.innerHTML,'url':this.href,'p1':_aMC(this),'p2':jI(this)})" href="httpdisabled://www.skycn.com/soft/16613.html" ><em>Mozilla</em> Thunderbird 2.0.0.23 ¼òÌåÖÐÎÄ°æ</a></td><td class="op_software_size"> 6.34 M </td><td class="op_software_src"> Ìì¿ÕÈí¼þÕ¾ </td></tr> <tr><td> <a target="_blank" onmousedown="return c({'fm':'alop','title':this.innerHTML,'url':this.href,'p1':_aMC(this),'p2':jI(this)})" href="httpdisabled://dl.pconline.com.cn/html_2/1/104/id=49635&pn=0.html" ><em>Mozilla</em> Firefox 4 ¼òÌåÖÐÎÄÕýʽ°æ</a></td><td class="op_software_size"> 11.85 M </td><td class="op_software_src"> ̫ƽÑóÏÂÔØ </td></tr> <tr><td> <a target="_blank" onmousedown="return c({'fm':'alop','title':this.innerHTML,'url':this.href,'p1':_aMC(this),'p2':jI(this)})" href="httpdisabled://www.duote.com/soft/9276.html" ><em>Mozilla</em> Firefox Plus(FoxPlus) V3.0.2.1 ¼ò...</a></td><td class="op_software_size"> 9.96 M </td><td class="op_software_src"> ¶àÌØÈí¼þÕ¾ </td></tr> <tr><td> <a target="_blank" onmousedown="return c({'fm':'alop','title':this.innerHTML,'url':this.href,'p1':_aMC(this),'p2':jI(this)})" href="httpdisabled://www.crsky.com/soft/9196.html" ><em>Mozilla</em> SeaMonkey v2.0.13 for Windows</a></td><td class="op_software_size"> 10.15 M </td><td class="op_software_src"> ·Ç·²Èí¼þÕ¾ </td></tr> </table> <div style="padding:4px 0 2px;"><a onmousedown="return c({'fm':'alop','title':this.innerHTML,'url':this.href,'p1':_aMC(this),'p2':jI(this)})" style="color:#7777CC;font-size:12px;" href="httpdisabled://soft.baidu.com/softwaresearch/s?tn=software&rn=10&wd=mozilla" target="_blank">²é¿´È«²¿123Ìõ½á¹û<span style="font-family:simsun">&gt;&gt;</span></a></div><font size=-1 color=#008000>soft.baidu.com/softwaresearch/s?tn=software&r... 2011-4-9</font></div> </div></td></tr></table><br><table cellpadding="0" cellspacing="0" class="result" id="4"><tr><td class=f><h3 class="t"><a onmousedown="return c({'fm':'as','F':'771317EA','F1':'9D73F4E4','F2':'4CA63E6B','F3':'54E5243F','T':'1302299163','title':this.innerHTML,'url':this.href,'p1':4,'y':'F2E77FDE'})" href="httpdisabled://www.mozilla.com/firefox/" target="_blank">ıÖÇÍøÂ磬»ðºüä¯ÀÀÆ÷ÖйúΨһ¹Ù·½ÍøÕ¾ | <em>Mozilla</em>, Firefox, and ...</a></h3><font size=-1> [10-13] <em>Mozilla</em>¶­Ê³¤Ã×Çжû³ÆδÀ´ä¯ÀÀÆ÷»áÊÇÕûºÏƽ̨ [09-26] ÊÀ½çÈí¼þ... [01-22] Firefox»ðºüä¯ÀÀÆ÷3.6Õýʽ·¢²¼£¬ÊÓƵ½éÉÜÐÂÌØÐÔ£¡ [01-06] »ðºü...<br><span class="g">www.<b>mozilla</b>.com/firefox/ 2010-12-26 </span> - <a href="httpdisabled://cache.baidu.com/c?m=9d78d513d99c1ce703b3ca2d19519738160ec6257ec0d16662c9d60dd6735b36183babe0797c4313d3b22d3a5eb21d07aaa7622f7d1e&p=9e759a41d6b119b406f3c7710b5f&user=baidu&fm=sc&query=mozilla&qid=e0156d2700181a32&p1=4" target="_blank" class="m">°Ù¶È¿ìÕÕ</a><br></font></td></tr></table><br>
-<table cellpadding="0" cellspacing="0" class="result" id="5"><tr><td class=f><h3 class="t"><a onmousedown="return c({'fm':'as','F':'779317EA','F1':'9D33F1E4','F2':'4CA67D6B','F3':'54E5243F','T':'1302299163','title':this.innerHTML,'url':this.href,'p1':5,'y':'9E0BBBDE'})" href="httpdisabled://www.mozilla.com/" target="_blank">ıÖÇÍøÂç »ðºüä¯ÀÀÆ÷ÖйúΨһ¹Ù·½ÍøÕ¾ | <em>Mozilla</em>, Firefox, and C...</a></h3><font size=-1> »ðºüÉçÇøÊÇıÖÇÍøÂ繫˾´î½¨µÄΪÓû§·þÎñµÄÉçÇø¡£Ä±ÖÇÍøÂç²»ÊÇ´«Í³ÒâÒåÉϵÄÈí¼þ¹«Ë¾£¬ËûÊÇÖÂÁ¦ÓÚ¹¹½¨×ÔÓÉ¡¢¿ª·Å»¥ÁªÍø¼°²úÆ·µÄÈ«ÇòÉçÇø£¬ÎªÄú´òÔìȫеÄÍøÂçä¯ÀÀÆ÷¡ª...<br><span class="g">www.<b>mozilla</b>.com/ 2011-4-6 </span> - <a href="httpdisabled://cache.baidu.com/c?m=9d78d513d99c1ce703b3ca2d19519738160ec6257ec0d16662c9d60dd6735b36183babe0797c4313d3b22d3a5eb2&p=9a63c00485cc41ec08e2966053&user=baidu&fm=sc&query=mozilla&qid=e0156d2700181a32&p1=5" target="_blank" class="m">°Ù¶È¿ìÕÕ</a><br></font></td></tr></table><br>
-<table cellpadding="0" cellspacing="0" class="result" id="6"><tr><td class=f><h3 class="t"><a onmousedown="return c({'fm':'as','F':'779717EA','F1':'9D73F1E4','F2':'4CA67D6B','F3':'54E5243F','T':'1302299163','title':this.innerHTML,'url':this.href,'p1':6,'y':'4C376A76'})" href="httpdisabled://www.mozilla.org.cn/" target="_blank">ıÖÇÍøÂç »ðºüä¯ÀÀÆ÷ÖйúΨһ¹Ù·½ÍøÕ¾ | <em>Mozilla</em>, Firefox, and C...</a></h3><font size=-1> »ðºüÉçÇøÊÇıÖÇÍøÂ繫˾´î½¨µÄΪÓû§·þÎñµÄÉçÇø¡£Ä±ÖÇÍøÂç²»ÊÇ´«Í³ÒâÒåÉϵÄÈí¼þ¹«Ë¾£¬ËûÊÇÖÂÁ¦ÓÚ¹¹½¨×ÔÓÉ¡¢¿ª·Å»¥ÁªÍø¼°²úÆ·µÄÈ«ÇòÉçÇø£¬ÎªÄú´òÔìȫеÄÍøÂçä¯ÀÀÆ÷¡ª...<br><span class="g">www.<b>mozilla</b>.org.cn/ 2011-4-7 </span> - <a href="httpdisabled://cache.baidu.com/c?m=9d78d513d99c1ce703b3ca2d19519738160ec6257ec0d16662c9d60dd6735b36183babe0797c4313d3b2212754b8492bbbac2b&p=8b2a950ec58011a05eead3371347&user=baidu&fm=sc&query=mozilla&qid=e0156d2700181a32&p1=6" target="_blank" class="m">°Ù¶È¿ìÕÕ</a><br></font></td></tr></table><br>
-<table cellpadding="0" cellspacing="0" class="result" id="7"><tr><td class=f><h3 class="t"><a onmousedown="return c({'fm':'as','F':'779717EA','F1':'9D73F1E4','F2':'4CA63E6B','F3':'54E5243F','T':'1302299163','title':this.innerHTML,'url':this.href,'p1':7,'y':'39D7CAFF'})" href="httpdisabled://www.mozilla.org/firefox/" target="_blank">ıÖÇÍøÂç »ðºüä¯ÀÀÆ÷ÖйúΨһ¹Ù·½ÍøÕ¾ | <em>Mozilla</em>, Firefox, and C...</a></h3><font size=-1> ¹ØÓÚ<em>Mozilla</em> ·¨ÂÉÉùÃ÷ »ðºü²©¿ÍFirefox screenshot »ðºüä¯ÀÀÆ÷ Firefox »ðºüfirefox Ãâ·ÑÏÂÔØ 4.0 ¼òÌåÖÐÎÄ Windows &gt;&gt;ÆäËüϵͳ/ÓïÑÔ°æ±¾ÏÂÔØ &gt;&gt;ÌÚѶÏÂÔØ &gt;&gt;ÐÂÀË...<br><span class="g">www.<b>mozilla</b>.org/firefox/ 2011-3-24 </span> - <a href="httpdisabled://cache.baidu.com/c?m=9f65cb4a8c8507ed4fece763105392230e54f73c619f8b4b21878448e4391b145a32b8fb70764d4eced1393a41f94603b7b86d2c6950&p=c9769a4286cc4ab11ca7c66856&user=baidu&fm=sc&query=mozilla&qid=e0156d2700181a32&p1=7" target="_blank" class="m">°Ù¶È¿ìÕÕ</a><br></font></td></tr></table><br>
-<table cellpadding="0" cellspacing="0" class="result" id="8"><tr><td class=f><h3 class="t"><a onmousedown="return c({'fm':'as','F':'779717EA','F1':'9D43F1E4','F2':'4CA65EEA','F3':'54E5243F','T':'1302299163','title':this.innerHTML,'url':this.href,'p1':8,'y':'8B8DFDEE'})" href="httpdisabled://addons.mozilla.org/" target="_blank">ÄãÒ¡¹ö¸ÐлÄúʹÓÃfirefoxä¯ÀÀÆ÷³¢ÊÔ¸½¼Ó×é¼þ</a></h3><font size=-1> <span class="g">addons.<b>mozilla</b>.org/ 2011-4-6 </span> - <a href="httpdisabled://cache.baidu.com/c?m=9d78d513d99c1ce703b3ca2d19519738160ec6257ec0d16662c9c01ec5390700506694e47a6a4b5a8d966b6776f20909f7&p=8f72c64ad3871cfa08e297744e42&user=baidu&fm=sc&query=mozilla&qid=e0156d2700181a32&p1=8" target="_blank" class="m">°Ù¶È¿ìÕÕ</a><br></font></td></tr></table><br>
-<table cellpadding="0" cellspacing="0" id="9" mu="httpdisabled://news.baidu.com/ns?cl=2&rn=20&tn=news&word=mozilla&ct=1&fr=ala0"><tr><td class="f" style="padding-bottom:3px;"><font size="3"><a href="httpdisabled://news.baidu.com/ns?cl=2&rn=20&tn=news&word=mozilla&ct=1&fr=ala0" target="_blank" onmousedown="return c({'fm':'alns','title':this.innerHTML,'url':this.href,'p1':al_c(this)});"><em>mozilla</em>µÄÏà¹ØÐÂÎÅ</a></font></td></tr><tr><td class="f"><p style="margin:0;padding:0;margin-left:1em;"><font size="-1"><a href="httpdisabled://tech.hexun.com/2011-04-08/128582384.html " target="_blank" onmousedown="return c({'fm':'alns','title':this.innerHTML,'url':this.href,'p1':al_c(this),'p2':1});"><em>mozilla</em>·ÏßͼÆعâ!»ðºü5/6·¼×ÙÕ§ÏÖ</a> <font color="#008000">ºÍѶÍø</font>&nbsp;<font color="#666666">13Сʱǰ</font><br><em>Mozilla</em>¹«Ë¾ÈÕÇ°½øÒ»²½·Å³öÁËÆäFirefox»ðºüϵÁÐä¯ÀÀÆ÷²úÆ·µÄ¿ª·¢Ä£ÐÍ¡£´ÓÒѾ­Ð¹Â¶µÄ»ðºü²úƷ·ÏßͼÀ´¿´,½ô¸úÔÚ»ðºü4ä¯ÀÀÆ÷Ö®ºóµÄ»ðºü5Ô¤¼Æ½«ÓÚ201...</font><br><font size="-1"><a href="httpdisabled://www.cnbeta.com/articles/139492.htm " target="_blank" onmousedown="return c({'fm':'alns','title':this.innerHTML,'url':this.href,'p1':al_c(this),'p2':2});"><em>mozilla</em>:firefox 5½«ÔÚ6ÔÂ21ÈÕµ½À´ °æ±¾6ÔÚ8ÔÂ18ÈÕ</a> <font color="#008000">cnBeta</font>&nbsp;<font color="#666666">21Сʱǰ</font></font><br><font size="-1"><a href="httpdisabled://tech.hexun.com/2011-04-07/128550959.html " target="_blank" onmousedown="return c({'fm':'alns','title':this.innerHTML,'url':this.href,'p1':al_c(this),'p2':3});">²»ÏëÃðÍö!<em>mozilla</em>³ÜÈèǽ¼à¶½»ðºü²å¼þ</a> <font color="#008000">ºÍѶÍø</font>&nbsp;<font color="#666666">1ÌìÇ°</font></font><br></p></td></tr>
-</table><br><table cellpadding="0" cellspacing="0" class="result" id="10"><tr><td class=f><h3 class="t"><a onmousedown="return c({'fm':'as','F':'779717EA','F1':'9D73F3E4','F2':'4CA6BE6B','F3':'54E5243F','T':'1302299163','title':this.innerHTML,'url':this.href,'p1':10,'y':'DFFFFFD7'})" href="httpdisabled://www.newhua.com/soft/1349.htm" target="_blank"><em>Mozilla</em> Firefox 4.0 Beta 12 ¼òÌå°æ ÏÂÔØ - »ª¾üÈí¼þÔ° - ÍøÂ繤...</a></h3><font size=-1> <em>Mozilla</em> Firefox 4.0 Beta 12 ¼òÌå°æ [ÏÂÔصØÖ·] Èí¼þÀà±ð£º¹úÍâÈí¼þ/Ö÷Ò³ä¯ÀÀ Èí¼þÊÚȨ£ºÃâ·Ñ°æ ÔËÐл·¾³£ºWinxp/vista/win7/2000/2003 ¸üÐÂʱ¼ä£º2011-2-26...<br><span class="g">www.newhua.com/soft/1349.htm 2011-2-26 </span> - <a href="httpdisabled://cache.baidu.com/c?m=9d78d513d99c1ce703b3ca2d19519738160ec6257ec0d16662c9d60dd6735b361b31a6e160710704a49421381cee1408aced3573310837b7ec92ce15&p=aa7dc64ad0af06b105bd9b7842&user=baidu&fm=sc&query=mozilla&qid=e0156d2700181a32&p1=10" target="_blank" class="m">°Ù¶È¿ìÕÕ</a><br></font></td></tr></table><br>
-
-
-
-
-
-
-
-
-
-
-<script></script>
-<br clear=all>
-
-<p id="page"><span>1</span> <a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;pn=10&amp;usm=2">[2]</a> <a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;pn=20&amp;usm=2">[3]</a> <a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;pn=30&amp;usm=2">[4]</a> <a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;pn=40&amp;usm=2">[5]</a> <a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;pn=50&amp;usm=2">[6]</a> <a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;pn=60&amp;usm=2">[7]</a> <a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;pn=70&amp;usm=2">[8]</a> <a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;pn=80&amp;usm=2">[9]</a> <a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;pn=90&amp;usm=2">[10]</a> <a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;pn=10&amp;usm=2" class="n">ÏÂÒ»Ò³</a> <span class="nums" style="margin-left:120px">ÕÒµ½Ïà¹Ø½á¹ûÔ¼11,900,000¸ö</span></p>
-
-
-
-
-
-
-
-
-<div id="rs"><table cellpadding="0"><tr><th rowspan="2" class="tt">Ïà¹ØËÑË÷</th><th><a href="httpdisabled://www.baidu.com/s?wd=mozilla%20firefox&amp;rsp=0&amp;oq=mozilla&amp;f=1&amp;rsv_ers=xdt0">mozilla firefox</a>
-</th><td></td><th><a href="httpdisabled://www.baidu.com/s?wd=mozilla%204.0&amp;rsp=1&amp;oq=mozilla&amp;f=1&amp;rsv_ers=xdt0">mozilla 4.0</a>
-</th><td></td><th><a href="httpdisabled://www.baidu.com/s?wd=mozilla%20sunbird&amp;rsp=2&amp;oq=mozilla&amp;f=1&amp;rsv_ers=xdt0">mozilla sunbird</a>
-</th><td></td><th><a href="httpdisabled://www.baidu.com/s?wd=mozilla%BB%F9%BD%F0%BB%E1&amp;rsp=3&amp;oq=mozilla&amp;f=1&amp;rsv_ers=xdt0">mozilla»ù½ð»á</a>
-</th><td></td><th><a href="httpdisabled://www.baidu.com/s?wd=mozilla%D0%FB%D1%D4&amp;rsp=4&amp;oq=mozilla&amp;f=1&amp;rsv_ers=xdt0">mozillaÐûÑÔ</a>
-</th></tr><tr><th><a href="httpdisabled://www.baidu.com/s?wd=mozilla.org&amp;rsp=5&amp;oq=mozilla&amp;f=1&amp;rsv_ers=xdt0">mozilla.org</a>
-</th><td></td><th><a href="httpdisabled://www.baidu.com/s?wd=mozilla%20%C2%DB%CC%B3&amp;rsp=6&amp;oq=mozilla&amp;f=1&amp;rsv_ers=xdt0">mozilla ÂÛ̳</a>
-</th><td></td><th><a href="httpdisabled://www.baidu.com/s?wd=mozilla%CA%C7%CA%B2%C3%B4&amp;rsp=7&amp;oq=mozilla&amp;f=1&amp;rsv_ers=xdt0">mozillaÊÇʲô</a>
-</th><td></td><th><a href="httpdisabled://www.baidu.com/s?wd=mozilla.com&amp;rsp=8&amp;oq=mozilla&amp;f=1&amp;rsv_ers=xdt0">mozilla.com</a>
-</th><td></td><th><a href="httpdisabled://www.baidu.com/s?wd=mozilla%20%B9%D9%CD%F8&amp;rsp=9&amp;oq=mozilla&amp;f=1&amp;rsv_ers=xdt0">mozilla ¹ÙÍø</a>
-</th></tr></table></div>
-
-<div id="search"><form name="f2" action="httpdisabled://www.baidu.com/s" ><input type="hidden" name="bs" value="mozilla"><input type="hidden" name="f" value="8"><input name="wd" class="i" value="mozilla" maxlength="100"><span class="btn_wr"><input type="submit" value="°Ù¶ÈÒ»ÏÂ" class="btn" onmouseout="this.className='btn'" onmousedown="this.className='btn btn_h'"></span>&nbsp;&nbsp;&nbsp;<a href="httpdisabled://www.baidu.com/s?wd=mozilla&amp;tn=baidufir" onmousedown="return c({'almid':'fir','stl':'link'})">½á¹ûÖÐÕÒ</a>&nbsp;&nbsp;&nbsp;<a href="httpdisabled://www.baidu.com/search/jiqiao.html" target="_blank" onmousedown="return c({'fm':'behb','tab':'help','url':this.href,'title':this.innerHTML})">°ïÖú</a>&nbsp;&nbsp;&nbsp;<a href="httpdisabled://www.baidu.com/search/jubao.html" target="_blank" onmousedown="return c({'fm':'behb','tab':'jubao','url':this.href,'title':this.innerHTML})">¾Ù±¨</a>&nbsp;&nbsp;&nbsp;<a href="httpdisabled://www.baidu.com/gaoji/advanced.html" onclick='location.href=this.href+"?q="+encodeURIComponent(document.f.kw.value);return false;' onmousedown="return c({'fm':'behb','tab':'gaoji','url':this.href,'title':this.innerHTML})">¸ß¼¶ËÑË÷</a></form></div>
-
-
-<div id="foot">&copy;2011 Baidu <span>´ËÄÚÈÝϵ°Ù¶È¸ù¾ÝÄúµÄÖ¸Áî×Ô¶¯ËÑË÷µÄ½á¹û£¬²»´ú±í°Ù¶ÈÔ޳ɱ»ËÑË÷ÍøÕ¾µÄÄÚÈÝ»òÁ¢³¡</span></div>
-</div></div></div>
-<img src="../c.baidu.com/c.gif@t=0&amp;q=mozilla&amp;p=0&amp;pn=1.html" style="display:none">
-</body>
-
-<script>for(ai in al_arr){al_arr[ai]()};c({'fm':'se','T':'1302299163','y':'FFDFDFEF'});if(navigator.cookieEnabled && !/sug?=0/.test(document.cookie)){void('<script src="js/bdsug.js@v=1.0.3.0"><\/script>')};</script>
-<script>window.onunloaddisabled=function(){};window.onloaddisabled=function(){document.forms[0].reset();document.forms[document.forms.length-1].reset()};function addEV(C,B,A){if(window.attachEvent){C.attachEvent("on"+B,A)}else{if(window.addEventListener){C.addEventListener(B,A,false)}}}addEV(document,"click",function(E){var E=E||window.event;var A=E.target||E.srcElement;var D=window.event?E.button:E.which;var C=G("tb_mr"),B=G("more");while(A&&A!=document.body&&A.tagName.toLowerCase()!="html"){if(A==C){break}A=A.parentNode}if(A!=C){B.style.display="none"}else{if(D<2){B.style.display=B.style.display=="block"?"none":"block"}}});var bdimeHW={};var imeTar="kw";var ime_t1=(new Date()).getTime();(function(){var d=navigator,Y=document,j=window,e=d.userAgent.indexOf("MSIE")!=-1;var c=G("mCon"),f=G("mMenu");var q=["ÊäÈë·¨","ÊÖд","Æ´Òô"],r=["cl","hw","py"],m=["","httpdisabled://www.baidu.com/hw/hwInput_1.1.js","httpdisabled://www.baidu.com/olime/bdime.js"],o=[0,0,0];var l=d.cookieEnabled;if(l&&/\bbdime=(\d)/.test(Y.cookie)){W(r[RegExp["\x241"]],false)}var n=f.getElementsByTagName("a");for(var b=0;b<n.length;b++){n[b].onclick=Z}if(e){var g=[];var h=c.getElementsByTagName("*");for(var b=0;b<h.length;b++){g.push(h[b])}g.push(c);var h=f.getElementsByTagName("*");for(var b=0;b<h.length;b++){g.push(h[b])}g.push(f);for(var b=0;b<g.length;b++){g[b].setAttribute("unselectable","on")}}else{try{var i=k.value.length;k.selectionStart=i;k.selectionEnd=i;bdimeHW.hasF=1}catch(a){}}function Z(){ime_t1=(new Date()).getTime();var A=this.name.split("_")[1];if(j.bdime){bdime.control.closeIme()}W(A,true);return false}function W(B,A){var C=0;if(B==r[1]){C=1;G("mHolder").style.display="inline-block";c.innerHTML='<span id="imeS" class="hw">'+q[1]+"</span>";if(e){G("imeS").setAttribute("unselectable","on")}function D(){if(!o[1]){if(Y.selection&&Y.activeElement.id&&Y.activeElement.id=="kw"){bdimeHW.hasF=1}bdimeHW.input=imeTar;bdimeHW.submit="su";X(m[1]);setTimeout(function(){if(bdsug){bdsug.sug.initial()}},1000);o[1]=1}else{bdimeHW.reloaddisabled(A)}}if(A){D()}else{addEV(G("imeS"),"click",D)}}else{if(B==r[2]){C=2;G("mHolder").style.display="inline-block";c.innerHTML="<span>"+q[2]+"</span>";if(!o[2]){X(m[2]);o[2]=1}else{if(j.bdime){bdime.voidIme()}}}else{c.innerHTML="<span>"+q[0]+"</span>"}}if(A&&l){var E=new Date();E.setTime(E.getTime()+365*24*3600*1000);Y.cookie="bdime="+C+";domain=baidu.com;path=/;expires="+E.toGMTString()}}function X(A){if(A){var B=Y.createElement("script");B.src=A;Y.getElementsByTagName("head")[0].appendChild(B)}}function p(B){var B=B||window.event;var A=B.target||B.srcElement;f.style.display=A.id=="mCon"&&f.style.display!="block"?"block":"none"}addEV(Y,"click",p)})();</script>
-<script src="user/js/u.js"></script>
-
-
-</html><!--afa2eb9a8e2636eb--> \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/user/js/u.js b/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/user/js/u.js
deleted file mode 100755
index 8c9ae6086..000000000
--- a/mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/user/js/u.js
+++ /dev/null
@@ -1 +0,0 @@
-function user_c(F){var G=encodeURIComponent(window.document.location.href),E="",D="",A="",B="",C=window["BD_PS_C"+(new Date()).getTime()]=new Image();for(v in F){switch(v){case"title":A=encodeURIComponent(F[v].replace(/<[^<>]+>/g,""));break;case"url":A=encodeURIComponent(F[v]);break;default:A=F[v]}E+=v+"="+A+"&"}B="&mu="+G;C.src="httpdisabled://nsclick.baidu.com/v.gif?pid=201&pj=psuser&"+E+"path="+G+"&wd="+D+"&t="+new Date().getTime();return true}var const_callback_list="login_success";var bdu=(function(){var I="passport.baidu.com";var D=navigator.userAgent.indexOf("MSIE")!=-1&&!window.opera;if(!window[const_callback_list]){window[const_callback_list]=[]}function O(C){return document.getElementById(C)}function A(Q,C,P){var G=document.createElement(Q);if(C){G.id=C}if(P){G.className=P}return G}function H(P,G,C,Q){if(D){P.attachEvent("on"+G,C)}else{P.addEventListener(G,C,!Q)}}function M(P,G,C){if(D){P.detachEvent("on"+G,C)}else{P.removeEventListener(G,C,true)}}function N(C){C=C||window.event;C.stopPropagation?C.stopPropagation():(C.cancelBubble=true)}function B(P,Q,C){if(C!=undefined){P.style[Q]=C}else{if(P.style[Q]){return P.style[Q]}else{if(P.currentStyle){return P.currentStyle[Q]}else{if(document.defaultView&&document.defaultView.getComputedStyle){Q=Q.replace(/([A-Z])/g,"-\u00241").toLowerCase();var G=document.defaultView.getComputedStyle(P,"");return G&&G.getPropertyValue(Q)||""}}}}}function F(G){if(D){var P=document.createStyleSheet();P.cssText=G}else{var C=document.createElement("style");C.type="text/css";C.appendChild(document.createTextNode(G));document.getElementsByTagName("HEAD")[0].appendChild(C)}}(function(){try{var G=[".bd_dialog{border:2px solid #a8b9eb;background:#dae4ff;color:#333;overflow:hidden}",".bd_dialog_handle{width:100%;height:30px;overflow:hidden;background:url(/user/img/bg1.gif) repeat-x;cursor:move;-moz-user-select:none}",".bd_dialog_title{line-height:24px;font-size:14px;font-weight:bold;float:left;overflow:hidden;margin:3px 10px}",".bd_dialog_close{width:19px;height:19px;float:right;background:url(/user/img/close.gif);overflow:hidden;margin:6px;cursor:pointer}",".bd_dialog_main{width:auto;height:auto;margin:5px;border:1px solid #c3cff2;overflow:hidden;background:#FFF}",".bd_tab{margin:20px 20px 10px 20px}",".bd_tab_btns{overflow:hidden;height:28px;padding-left:10px;background:url(/user/img/p.gif) repeat-x bottom;text-align:center}",".bd_tab_conts{margin-top:15px}",".bd_tab_btn{overflow:hidden;float:left;cursor:pointer;font-size:14px;font-weight:bold;width:76px;margin-left:6px;line-height:28px;background:url(/user/img/bb.gif);color:#00c;text-decoration:underline}",".bd_tab_btn_s{overflow:hidden;float:left;cursor:pointer;font-size:14px;font-weight:bold;width:76px;margin-left:6px;line-height:28px;background:url(/user/img/bs.gif)}",".bd_tab_cont{display:none;height:auto}",".bd_tab_cont_s{display:block}","#login_div{font-size:14px}","#login_div u{text-decoration:none;font-size:13px;color:#f00;display:inline-block;height:auto}","#login_msg_div{overflow:hidden;height:18px}","#login_cap{margin-left:20px}","#login_msg_div{margin-left:20px}","#login_tb_div{margin-left:20px}","#login_tb td{padding:4px 4px 4px 0;vertical-align:middle;font-size:14px;line-height:normal}","#login_tb td.lb{width:60px}","#login_tb input.lt{padding:1px;line-height:18px;height:24px;*height:18px;width:170px}","#login_tb input.v{padding:1px;line-height:18px;height:24px;*height:18px}","#login_tb label{font-size:13px}","#login_tb .c9{font-size:13px;color:#999}","#login_check{line-height:130%}","#login_v_tr{display:none}","#login_v_img{border:1px solid #000}","#login_tb a.la{font-size:13px;*margin-bottom:4px;color:#03c;display:inline-block;line-height:30px;vertical-align:middle}","#login_submit{width:78px;height:28px;font-size:14px}","#login_line{background:#d9e1f7;overflow:hidden;height:1px;width:auto;margin:20px 0}","#login_sug{width:100%;line-height:40px;font-weight:bold;text-align:center}","#login_u_msg{width:40px}","#login_p_msg{width:40px}"];F(G.join(""))}catch(C){}})();function L(){var R=O("u");var G=O("lb");var C=[{text:"ËÑË÷ÉèÖÃ",url:"httpdisabled://www.baidu.com/gaoji/preferences.html",tab:"setting"},{text:"ÎÒµÄÓ¦ÓÃÖÐÐÄ",url:"httpdisabled://app.baidu.com/store/mine",tab:"myapp"}];var Q=0;if(R&&G){H(G,"click",function(){switch(Q){case 0:break;case 1:bdlogin.box.show();break}})}function P(){Q=1;T()}function S(U,V){R.innerHTML="<a target=_blank href=http://passport.baidu.com onmousedown=\"return user_c({'fm':'set','tab':'username','url':this.href})\"><b>"+U+"</b></a>&nbsp;|&nbsp;<span id=\"u_m\" onmousedown=\"return user_c({'fm':'set','tab':'more','url':this.href})\"><span id=\"u_ms\">ÉèÖÃ</span><small>¨‹</small></span>&nbsp;|&nbsp;<a href=http://passport.baidu.com/?logout&tpl=mn onmousedown=\"return user_c({'fm':'set','tab':'logout','url':this.href})\">Í˳ö</a>";setTimeout(function(){T()},10)}function T(){var X=O("u_m");if(X){var Y=A("div","u_m_tip");var W=[];for(var V=0,U=C.length;V<U;V++){var Z=C[V];W.push("<a "+((V==U-1)?"class='last'":"")+" href='"+Z.url+"' target='_self' onmousedown=\"return user_c({'fm':'set','tab':'"+Z.tab+"','url':this.href})\">"+Z.text+"</a>")}Y.innerHTML=W.join("");document.body.appendChild(Y);H(Y,"click",N,true);H(X,"click",function(a){Y.style.display="block";N(a)},true);H(document,"click",function(){Y.style.display="none"},true)}}return{login:S,notifyReady:P}}function E(P){var U=A("div");var V=[];var R=[];var C=0;function W(){Q()}function Q(){var d=P.cssPrefix;var f=P.tabs;var a=P.selectIndex;C=a;U.innerHTML="";U.className=d;V=[];R=[];var e=A("div");e.className=d+"_btns";var Y=A("div");Y.className=d+"_conts";for(var Z=0,b=f.length;Z<b;Z++){var g=f[Z];var X=A("span");var h=A("div");if(Z==a){X.loaddisabled=true;if(g.loaddisabled){g.loaddisabled.call(window)}X.className=d+"_btn_s";h.className=d+"_cont_s"}else{X.loaddisabled=false;X.className=d+"_btn";h.className=d+"_cont"}X.innerHTML=g.label;h.appendChild(g.domNode);H(X,"click",(function(c){return function(){T(c)}})(Z));V.push(X);R.push(h);e.appendChild(X);Y.appendChild(h)}U.appendChild(e);U.appendChild(Y)}function S(X,Y){for(i=0,len=V.length;i<len;i++){V[i].className=Y+"_btn";R[i].className=Y+"_cont"}V[X].className=Y+"_btn_s";R[X].className=Y+"_cont_s"}function T(Y){var a=V[Y];var Z=P.tabs[Y].loaddisabled;var X=P.tabs[Y].click;C=Y;if(!a.loaddisabled){a.loaddisabled=true;if(Z){Z.call(window)}}S(Y,P.cssPrefix);if(X){X.call(window)}}function G(){return C}W();return{getIndex:G,show:T,domNode:U}}function K(G){var r=window,z=document.body,x=document.documentElement;var V=A("span");var p=G.width||395,w=G.height||400;var c,a,e,j,f=8;var P=null;function s(){C()}function g(){z.appendChild(V);if(G.loaddisabled){G.loaddisabled.call(window)}T(true)}function q(b){try{z.removeChild(V)}catch(d){}if(!b&&P){try{P.call(window,0)}catch(d){}P=null}}function T(b){if(V.sbIE6){V.sbIE6.redraw()}if(b&&V.msk){V.msk.redraw()}if(V.dlg){V.dlg.redraw()}if(V.shd){V.shd.redraw()}}function X(b,d){p=b;w=d;if(V.dlg){V.dlg.resize(b,d)}if(V.shd){V.shd.resize(b,d)}}function C(){V.innerHTML="";if(D){V.sbIE6=o();V.appendChild(V.sbIE6)}if(G.mask){V.msk=W();V.appendChild(V.msk)}V.dlg=R("µÇ¼");V.appendChild(V.dlg);if(G.shadow){V.shd=t();V.appendChild(V.shd)}H(r,"resize",function(){T(true)})}function U(d){d=r.event||d;var b=AA(d.clientX-c,0,e);var AB=AA(d.clientY-a,0,j);B(V.dlg,"left",b+"px");B(V.dlg,"top",AB+"px");if(V.shd){B(V.shd,"left",b+f+"px");B(V.shd,"top",AB+f+"px")}}function u(){M(z,"mousemove",U);M(z,"mouseup",u);if(V.dlg.releaseCapture){V.dlg.releaseCapture()}if(r.releaseEvents){r.releaseEvents(Event.MOUSEMOVE|Event.MOUSEUP)}}function S(){if(G.ready){G.ready.call(window)}}function W(){var b=Q();var d=n("#333",40,b);d.redraw=function(){var AB=Q(true);l(d,AB);setTimeout(function(){var AC=Q();l(d,AC)},0)};return d}function o(){var b=Q();var d=A("iframe");B(d,"position","absolute");B(d,"top",b.y+"px");B(d,"left",b.x+"px");B(d,"zIndex",10000);B(d,"opacity",1/100);B(d,"filter","alpha(opacity=1)");B(d,"width",b.w+"px");B(d,"height",b.h+"px");d.redraw=function(){var AB=Q(true);B(d,"width",AB.w+"px");B(d,"height",AB.h+"px");setTimeout(function(){var AC=Q();B(d,"width",AC.w+"px");B(d,"height",AC.h+"px")},0)};return d}function Q(d){var b=d?k():Y();b.x=0;b.y=0;b.z=10001;return b}function t(){var b=n("#333",20,Z());b.redraw=function(){var d=Z();l(b,d)};b.resize=y;return b}function R(AF){var d=n("",100,Z(true));d.className="bd_dialog";var AC=A("div");AC.className="bd_dialog_handle";var AD=A("span");AD.className="bd_dialog_title";AD.innerHTML=AF;AC.appendChild(AD);var AB=A("span");AB.className="bd_dialog_close";H(AB,"click",function(){user_c({fm:"set",tab:"close",url:"httpdisabled://passport.baidu.com/"});q()});AC.appendChild(AB);var AE=A("span");B(AE,"clear","both");AC.appendChild(AE);if(G.drag){H(AC,"mousedown",function(AG){AG=r.event||AG;var AH=Y();c=AG.clientX-d.offsetLeft;a=AG.clientY-d.offsetTop;e=AH.w-d.clientWidth-f;j=AH.h-d.clientHeight-f;H(z,"mousemove",U);H(z,"mouseup",u);H(r,"scroll",u);if(d.setCapture){d.setCapture()}else{H(r,"mouseup",u)}if(r.captureEvents){r.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP)}})}var b=A("div");b.className="bd_dialog_main";if(G.domNode){b.appendChild(G.domNode)}d.caption=function(AG){if(AG){AD.innerHTML=AG}return AD.innerHTML};d.clear=function(){b.innerHTML=""};d.redraw=function(){var AG=Z(true);l(d,AG)};d.resize=y;d.appendChild(AC);d.appendChild(b);return d}function n(d,AB,b){var AC=A("div");B(AC,"position","absolute");B(AC,"top",b.y+"px");B(AC,"left",b.x+"px");B(AC,"zIndex",b.z);B(AC,"backgroundColor",d);B(AC,"opacity",AB/100);B(AC,"filter","alpha(opacity="+AB+")");B(AC,"width",b.w+"px");B(AC,"height",b.h+"px");return AC}function y(d,AC){var AE=Y();maxX=AE.w-d-f;maxY=AE.h-AC-f;var AB=d-parseInt(B(this,"width"));var AD=AC-parseInt(B(this,"height"));var b=AA(parseInt(B(this,"left"))-AB/2,0,maxX);var AF=AA(parseInt(B(this,"top"))-AD/2,0,maxY);B(this,"top",AF+"px");B(this,"left",b+"px");B(this,"width",d+"px");B(this,"height",AC+"px")}function l(d,b){B(d,"top",b.y+"px");B(d,"left",b.x+"px");B(d,"width",b.w+"px");B(d,"height",b.h+"px")}function Z(AB){var b=k();var d=AB?0:f;return{z:AB?10005:10002,x:AA((b.w-p)/2,0)+d+b.l,y:AA((b.h-w)/2,0)+d+b.t,w:p,h:w}}function AA(d,AB,b){if(b){d=d>b?b:d}return d>=AB?d:AB}function Y(d){var AB=Math.max(z.scrollHeight,x.scrollHeight);var b=Math.max(z.scrollWidth,x.scrollWidth);if(x&&x.clientWidth){AB=Math.max(x.clientHeight,AB);b=Math.max(x.clientWidth,b)}else{AB=Math.max(z.clientHeight,AB);b=Math.max(z.clientWidth,b)}return{h:AB,w:b}}function k(){var b,d;if(x&&x.clientWidth){b=x.clientWidth;d=x.clientHeight}else{b=z.clientWidth;d=z.clientHeight}return{w:b,h:d,t:Math.max(z.scrollTop,x.scrollTop),l:Math.max(z.scrollLeft,x.scrollLeft)}}function m(b){if(V.dlg){V.dlg.caption(b)}}function h(b){P=b}s();return{resize:X,setCloseCallback:h,caption:m,ready:S,show:g,close:q,domNode:V}}function J(Q){var AG="httpdisabledsdisabled://"+I+"/";var n=Q.prefix||"login";var AI=Q.callbackName||"baiduLoginReply";var a=Q.jump||"";var Y=Q.showVerifyCode;var k=Q.hideVerifyCode;var R=Q.success;var g=null;var d=false;var X=false;var AB=A("div",n+"_div");var p,j,w,h,b,AD,q,AH,T,r,m,U,z,y,o;var G={0:"µÇ¼³É¹¦",1:"Óû§Ãû¸ñʽ´íÎó",2:"Óû§²»´æÔÚ",3:"",4:"µÇ¼ÃÜÂë´íÎó",5:"½ñÈյǼ´ÎÊý¹ý¶à¡£",6:"ÑéÖ¤Â벻ƥÅä",7:"µÇ¼ʱ·¢Éúδ֪´íÎó£¬ÇëÖØеǼ¡£",8:"µÇ¼ʱ·¢Éúδ֪´íÎó£¬ÇëÖØеǼ¡£",16:"¶Ô²»Æð£¬ÄúÏÖÔÚÎÞ·¨µÇ¼¡£",20:"´ËÕʺÅÒѵǼÈËÊý¹ý¶à¡£",256:"",257:"ÇëÊäÈëÑéÖ¤Âë","default":"µÇ¼ʱ·¢Éúδ֪´íÎó£¬ÇëÖØеǼ¡£"};function P(){AB.innerHTML=Z()}function Z(){var AJ="<div id="+n+"_cap>"+Q.caption+"</div><div id="+n+"_msg_div><u id="+n+"_msg></u></div><div id="+n+"_tb_div><form method=post id="+n+"_fm action="+AG+"api/?login target=login_Hide_Frame><table id="+n+"_tb cellpadding=0 cellspacing=0><tr><td class=lb>Óû§Ãû£º<td><input class=lt type=text id="+n+"_u><td><u id="+n+"_u_msg></u><tr><td>ÃÜ¡¡Â룺<td><input class=lt type=password id="+n+"_p><td><u id="+n+"_p_msg></u><tr id="+n+"_v_tr><td >ÑéÖ¤Â룺<td colspan=2 valign=middle><input id="+n+"_v class=v type=text size=4> <img align=middle id="+n+"_v_img src='about:blank'> <a id="+n+"_v_re class=la href=# >¿´²»Ç壿</a><tr><td><td id="+n+"_check><input style='margin-left:-1px;*margin-left:-3px' type=checkbox id="+n+"_mem value='on' checked> <label for="+n+"_mem>¼ÇסÎҵĵǼ״̬</label><br><span class=c9>ÔÚ¹«ÓõçÄÔÉÏÇëÎð¹´Ñ¡</span><td><tr><td><td colspan=2><input type=submit id="+n+"_submit value=µÇ¼> <a id="+n+"_getpass class=la href=# target=_blank>Íü¼ÇÃÜÂë</a><input type=hidden id="+n+"_token><input type=hidden id="+n+"_tpl><input type=hidden id="+n+"_time><input type=hidden name=callback value="+AI+"><input type=hidden name=staticpage value="+a+"></table></form></div><div id="+n+"_line></div><div id="+n+"_sug>"+Q.footer+"</div><iframe style='display:none' src='about:blank' id=login_Hide_Frame name=login_Hide_Frame></iframe>";return AJ}function x(){P()}function f(){p=O(n+"_msg");j=O(n+"_u_msg");w=O(n+"_p_msg");h=O(n+"_u");AD=O(n+"_p");q=O(n+"_v");T=O(n+"_v_img");AH=O(n+"_v_tr");loginValiRe=O(n+"_v_re");b=O(n+"_mem");r=O(n+"_getpass");m=O(n+"_submit");U=O(n+"_fm");z=O(n+"_token");y=O(n+"_tpl");o=O(n+"_time");H(U,"submit",(function(){return function(AJ){if(!AC()){AE(AJ);return false}else{m.disabled=true;return true}}})());H(loginValiRe,"click",function(AJ){s();AE(AJ);return false});H(h,"blur",function(){var AJ=A("script");AJ.src=AG+"?logcheck&username="+encodeURIComponent(h.value)+"&callback=bdlogin.login.ucheck&tpl=mn&t="+(new Date()).getTime();document.body.appendChild(AJ);return true})}function u(AJ){if(!X){switch(AJ){case"0":W(false);d=false;break;case"1":W(true);d=true;break}}}function AF(){var AK=(new Date()).getTime();var AJ=O("bd_login_script");if(AJ){document.body.removeChild(AJ)}var AL=A("script","bd_login_script");if(h){AL.src=AG+"?apilogin&callback=bdlogin.login.ready&tpl=mn&username="+h.value+"&tt="+AK}else{AL.src=AG+"?apilogin&callback=bdlogin.login.ready&tpl=mn&tt="+AK}document.body.appendChild(AL)}function V(AJ){f();if("0"==AJ.error_no){r.href=AJ.more_ext.ext1_url;r.innerHTML=AJ.more_ext.ext1_name;l(AJ.param_in,AJ.param_out);window[AI]=e}}function AE(AJ){if(AJ&&AJ.preventDefault){AJ.preventDefault()}else{window.event.returnValue=false}}function AC(){if(""==C(h.value)){S(null,"ÇëÊäÈëÓû§Ãû",null,null,true);return false}if(""==C(AD.value)){S(null,null,"ÇëÊäÈëÃÜÂë",null,true);return false}if(d&&""==C(q.value)){S("ÇëÊäÈëÑéÖ¤Âë",null,null,null,true);return false}return true}function l(AJ,AK){h.name=AJ.param1_name;h.value=AJ.param1_value;AD.name=AJ.param2_name;AD.value=AJ.param2_value;b.name=AJ.param5_name;q.name=AJ.param4_name;q.value="";s();if("1"==AJ.param4_value){W(true);d=true;X=true}else{W(false);d=false;X=false}z.name=AK.param1_name;z.value=AK.param1_contex;y.name=AK.param2_name;y.value=AK.param2_contex;o.name=AK.param3_name;o.value=AK.param3_contex;if(""==h.value){h.focus()}else{AD.focus()}}function s(){var AJ="httpdisabledsdisabled://"+I+"/?verifypic&t="+(new Date()).getTime();T.src=AJ}function W(AJ){if(D){AH.style.display=AJ?"block":"none"}else{AH.style.display=AJ?"table-row":"none"}if(AJ&&Y){Y.call(window)}if(!AJ&&k){k.call(window)}}function e(AK,AL){m.disabled=false;switch(AK){case"0":var AJ=decodeURIComponent(AL.un);c(1,AJ);break;case"1":S(null,G[AK]);break;case"2":S(null,G[AK]);break;case"4":S(null,null,G[AK]);break;case"5":S(G[AK]);break;case"6":S(G[AK]);break;case"7":S(G[AK]);break;case"8":S(G[AK]);break;case"16":S(G[AK]);break;case"20":S(G[AK]);break;case"257":S(G[AK]);break;default:S()}}function c(AK,AJ){if(R){R.call(window,AK,AJ)}if(g){g.call(window,AK,AJ);g=null}}function S(AM,AN,AK,AL,AJ){if(AN||AK){B(h,"width","128px");B(AD,"width","128px");B(j,"width","100px");B(w,"width","100px")}else{B(h,"width","170px");B(AD,"width","170px");B(j,"width","40px");B(w,"width","40px")}p.innerHTML=AM?AM:"";j.innerHTML=AN?AN:"";w.innerHTML=AK?AK:"";if(AN){h.focus()}if(AK){AD.focus()}if(d&&AL){q.focus()}if(!AJ){AF()}}function AA(){return d||X}function t(AJ){g=AJ}function C(AJ){AJ=AJ.replace(/(\u3000+)|(\u3000+)/g,"");AJ=AJ.replace(/( +)|( +)/g,"");return AJ}x();return{domNode:AB,verify:AA,loaddisabled:AF,ready:V,ucheck:u,setCallback:t,success:c}}return{Bar:L,Tab:E,Dialog:K,Login:J}})();var bdlogin=[];bdlogin.bar=bdu.Bar();var lParams={prefix:"login",callbackName:"bdLoginReply",jump:"httpdisabled://www.baidu.com/user/j.html",caption:"°Ù¶È×¢²áÓû§ÇëÖ±½ÓµÇ¼",footer:"ûÓаٶÈÕʺţ¿<a href='javascript:showRegTab()'>Á¢¼´×¢²á°Ù¶ÈÕʺÅ</a>",success:function(E,B){if(E==1){user_c({fm:"set",tab:"loginOK",url:"httpdisabled://passport.baidu.com/login"})}else{if(E==2){user_c({fm:"set",tab:"regOK",url:"httpdisabled://passport.baidu.com/reg"})}}bdlogin.box.close(true);for(var C=0,A=window[const_callback_list].length;C<A;C++){var D=window[const_callback_list][C];try{D.call(window,E,B,null)}catch(F){}}window.bdUser=B},showVerifyCode:function(){if(bdlogin.tab.getIndex()==0){bdlogin.box.resize(395,436)}},hideVerifyCode:function(){if(bdlogin.tab.getIndex()==0){bdlogin.box.resize(395,386)}}};bdlogin.login=bdu.Login(lParams);window[const_callback_list].push(function(C,A,B){bdlogin.bar.login(A)});window.regSuccess=function(A){bdlogin.login.success(2,A)};window.showRegTab=function(){if(bdlogin.tab){bdlogin.tab.show(1)}};var regDiv=document.createElement("DIV");var tabParams={tabs:[{label:"µÇ¼",domNode:bdlogin.login.domNode,click:function(){setTimeout(function(){if(bdlogin.login.verify()){bdlogin.box.resize(395,436)}else{bdlogin.box.resize(395,386)}bdlogin.box.caption("µÇ¼")},30)},loaddisabled:function(){}},{label:"×¢²á",domNode:regDiv,click:function(){bdlogin.box.resize(570,510);bdlogin.box.caption("×¢²á")},loaddisabled:function(){regDiv.innerHTML="<iframe src=/user/reg.html frameborder=0 scrolling=no width=515 height=390 style='border:0;margin:0;padding:0'></iframe>"}}],selectIndex:0,cssPrefix:"bd_tab"};bdlogin.tab=bdu.Tab(tabParams);var dParams={domNode:bdlogin.tab.domNode,width:395,height:400,mask:true,shadow:true,drag:true,ready:function(){bdlogin.bar.notifyReady()},loaddisabled:function(){bdlogin.tab.show(0);bdlogin.login.loaddisabled()}};bdlogin.box=bdu.Dialog(dParams);bdlogin.login.setCallback(function(){});bdlogin.box.ready();window._invoke_login=function(B){if(B){try{bdlogin.login.setCallback(B);bdlogin.box.setCloseCallback(B)}catch(A){return false}}bdlogin.box.show();return true}; \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/b.scorecardresearch.com/b2@c1=2&c2=6035051&c3=&c4=www.bbc.co.uk%2Fnews%2F&c5=&c6=&c15=&cv=1.3&cj=1.html b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/b.scorecardresearch.com/b2@c1=2&c2=6035051&c3=&c4=www.bbc.co.uk%2Fnews%2F&c5=&c6=&c15=&cv=1.3&cj=1.html
deleted file mode 100755
index e69de29bb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/b.scorecardresearch.com/b2@c1=2&c2=6035051&c3=&c4=www.bbc.co.uk%2Fnews%2F&c5=&c6=&c15=&cv=1.3&cj=1.html
+++ /dev/null
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/bbc.112.2o7.net/b/ss/bbcwglobalprod/1/H.21--NS/0@AQB=1&pccr=true&AQE=1 b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/bbc.112.2o7.net/b/ss/bbcwglobalprod/1/H.21--NS/0@AQB=1&pccr=true&AQE=1
deleted file mode 100755
index f4a2493a1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/bbc.112.2o7.net/b/ss/bbcwglobalprod/1/H.21--NS/0@AQB=1&pccr=true&AQE=1
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/edge.quantserve.com/quant.js b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/edge.quantserve.com/quant.js
deleted file mode 100755
index 2e74eb3e1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/edge.quantserve.com/quant.js
+++ /dev/null
@@ -1,28 +0,0 @@
-if(!__qc){var __qc={qcdst:function(){if(__qc.qctzoff(0)!=__qc.qctzoff(6))return 1;return 0;},qctzoff:function(m){var d1=new Date(2000,m,1,0,0,0,0);var t=d1.toGMTString();var d3=new Date(t.substring(0,t.lastIndexOf(" ")-1));return d1-d3;},qceuc:function(s){if(typeof(encodeURIComponent)=='function'){return encodeURIComponent(s);}
-else{return escape(s);}},qcrnd:function(){return Math.round(Math.random()*2147483647);},qcgc:function(n){var v='';var c=document.cookie;if(!c)return v;var i=c.indexOf(n+"=");var len=i+n.length+1;if(i>-1){var end=c.indexOf(";",len);if(end<0)end=c.length;v=c.substring(len,end);}
-return v;},qcdomain:function(){var d=document.domain;if(d.substring(0,4)=="www.")d=d.substring(4,d.length);var a=d.split(".");var len=a.length;if(len<3)return d;var e=a[len-1];if(e.length<3)return d;d=a[len-2]+"."+a[len-1];return d;},qhash2:function(h,s){for(var i=0;i<s.length;i++){h^=s.charCodeAt(i);h+=(h<<1)+(h<<4)+(h<<7)+(h<<8)+(h<<24);}
-return h;},qhash:function(s){var h1=0x811c9dc5,h2=0xc9dc5118;var hash1=__qc.qhash2(h1,s);var hash2=__qc.qhash2(h2,s);return(Math.round(Math.abs(hash1*hash2)/65536)).toString(16);},sd:["4dcfa7079941","127fdf7967f31","588ab9292a3f","32f92b0727e5","22f9aa38dfd3","a4abfe8f3e04","18b66bc1325c","958e70ea2f28","bdbf0cb4bbb","65118a0d557","40a1d9db1864","18ae3d985046","3b26460f55d"],qcsc:function(){var s="";var d=__qc.qcdomain();if(__qc.qad==1)return";fpan=u;fpa=";var qh=__qc.qhash(d);for(var i=0;i<__qc.sd.length;i++){if(__qc.sd[i]==qh)return";fpan=u;fpa=";}
-var u=document;var a=__qc.qcgc("__qca");if(a.length>0){s+=";fpan=0;fpa="+a;}
-else{var da=new Date();a='P0-'+__qc.qcrnd()+'-'+da.getTime();u.cookie="__qca="+a+"; expires=Sun, 18 Jan 2038 00:00:00 GMT; path=/; domain="+d;a=__qc.qcgc("__qca");if(a.length>0){s+=";fpan=1;fpa="+a;}
-else{s+=";fpan=u;fpa=";}}
-return s;},qcdc:function(n){document.cookie=n+"=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/; domain="+__qc.qcdomain();},qpxloaddisabled:function(img){if(img&&typeof(img.width)=="number"&&img.width==3){__qc.qcdc("__qca");}},qcp:function(p,myqo){var s='',a=null;var media='webpage',event='loaddisabled';if(myqo!=null){for(var k in myqo){if(typeof(k)!='string'){continue;}
-if(typeof(myqo[k])!='string'){continue;}
-if(k=='qacct'){a=myqo[k];continue;}
-s+=';'+k+p+'='+__qc.qceuc(myqo[k]);if(k=='media'){media=myqo[k];}
-if(k=='event'){event=myqo[k];}}}
-if(typeof a!="string"){if((typeof _qacct=="undefined")||(_qacct.length==0))return'';a=_qacct;}
-if(media=='webpage'&&event=='loaddisabled'){for(var i=0;i<__qc.qpixelsent.length;i++){if(__qc.qpixelsent[i]==a)return'';}
-__qc.qpixelsent.push(a);}
-if(media=='ad'){__qc.qad=1;}
-s=';a'+p+'='+a+s;return s;},qcesc:function(s){return s.replace(/\./g,'%2E').replace(/,/g,'%2C');},qcd:function(o){return(typeof(o)!="undefined"&&o!=null);},qcogl:function(){var m=document.getElementsByTagName('meta');var o='';for(var i=0;i<m.length;i++){if(o.length>=1000)return o;if(__qc.qcd(m[i])&&__qc.qcd(m[i].attributes)&&__qc.qcd(m[i].attributes.property)&&__qc.qcd(m[i].attributes.property.value)&&__qc.qcd(m[i].content)){var p=m[i].attributes.property.value;var c=m[i].content;if(p.length>3&&p.substring(0,3)=='og:'){if(o.length>0)o+=',';var l=(c.length>80)?80:c.length;o+=__qc.qcesc(p.substring(3,p.length))+'.'+__qc.qcesc(c.substring(0,l));}}}
-return __qc.qceuc(o);},firepixel:function(qoptions){var e=(typeof(encodeURIComponent)=='function')?"n":"s";var r=__qc.qcrnd();var sr='',qo='',qm='',url='',ref='',je='u',ns='1';var qocount=0;__qc.qad=0;if(typeof __qc.qpixelsent=="undefined"){__qc.qpixelsent=new Array();}
-if(typeof qoptions!="undefined"&&qoptions!=null){__qc.qopts=qoptions;for(var k in __qc.qopts){if(typeof(__qc.qopts[k])=='string'){qo=__qc.qcp("",__qc.qopts);break;}else if(typeof(__qc.qopts[k])=='object'&&__qc.qopts[k]!=null){++qocount;qo+=__qc.qcp("."+qocount,__qc.qopts[k]);}}}else if(typeof _qacct=="string"){qo=__qc.qcp("",null);}
-if(qo.length==0)return;var ce=(navigator.cookieEnabled)?"1":"0";if(typeof navigator.javaEnabled!='undefined')je=(navigator.javaEnabled())?"1":"0";if(typeof _qmeta!="undefined"&&_qmeta!=null){qm=';m='+__qc.qceuc(_qmeta);_qmeta=null;}
-if(self.screen){sr=screen.width+"x"+screen.height+"x"+screen.colorDepth;}
-var d=new Date();var dst=__qc.qcdst();var qs='http';if(window.location.protocol=='https:'){qs+='s';}
-qs="../../pixel.quantserve.com";var fp=__qc.qcsc();if(window.location&&window.location.href)url=__qc.qceuc(window.location.href);if(window.document&&window.document.referrer)ref=__qc.qceuc(window.document.referrer);if(self==top)ns='0';var ogl=__qc.qcogl();var img=new Image();img.alt="";img.src=qs+'/pixel/r.html';img.onloaddisabled=function(){__qc.qpxloaddisabled(img);}},quantserve:function(){if(typeof _qevents=='undefined'){_qevents=[];}
-if(typeof _qoptions!="undefined"&&_qoptions!=null){__qc.firepixel(_qoptions);_qoptions=null;}else if(!_qevents.length&&typeof _qacct!="undefined"){__qc.firepixel(null);}
-if(!__qc.evts){for(var k in _qevents){__qc.firepixel(_qevents[k]);}
-_qevents={push:function(){var a=arguments;for(var i=0;i<a.length;i++){__qc.firepixel(a[i]);}}};__qc.evts=1;}}};}
-function quantserve(){__qc.quantserve();}
-quantserve();
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/js.revsci.net/gateway/gw.js@csid=J08781 b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/js.revsci.net/gateway/gw.js@csid=J08781
deleted file mode 100755
index a82317b0b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/js.revsci.net/gateway/gw.js@csid=J08781
+++ /dev/null
@@ -1,4 +0,0 @@
-//Vermont-12.4.0-1133
-var rsi_now= new Date();
-var rsi_csid= 'J08781';if(typeof(csids)=="undefined"){var csids=[rsi_csid];}else{csids.push(rsi_csid);};function rsiClient(Da){this._rsiaa=Da;this._rsiba=1;this._rsica=1;this._rsida=0;this._rsiea=0;this._rsifa=0;this._rsiga="1003161";this._rsiha="pix04.revsci.net";this._rsiia="js";this._rsija="b";this._rsika="3";this._rsila=3;this._rsima=1;this._rsina=new Array();this._rsioa=0;this._rsipa=null;this._rsiqa=null;this._rsira=null;this._rsisa=null;this._rsita=null;this._rsiua=null;this._rsiva=0;this.DM_cat=function(Ea){this._rsipa=Ea;};this.DM_name=function(Fa){this._rsiqa=Fa;};this.DM_keywords=function(st){this._rsira=st;};this.DM_event=function(Ga){this._rsisa=Ga;};this.DM_addToLoc=function(n,v){this._rsita=_rsiwa(this._rsita,n,v);};this.DM_addEncToLoc=function(n,v){this.DM_addToLoc(_rsixa(n),_rsixa(v));};this.DM_setLoc=function(u){this._rsita=u;};this.rsi_c=function(Da){this._rsiaa=Da;};this.rsi_ral=function(Ha){this._rsiba=Ha;};this.rsi_riu=function(Ia){this._rsica=Ia;};this.rsi_tiu=function(Ja){this._rsida=Ja;};this.rsi_m=function(Ka){this._rsiea=Ka;};this.rsi_dw=function(La){this._rsifa=La;};this.rsi_s=function(Ma){this._rsiha=Ma;};this.rsi_t=function(Na){this._rsiia=Na;};this.rsi_en=function(Oa){this._rsija=Oa;};this.rsi_cn=function(Pa){this._rsika=Pa;};this.rsi_us=function(Qa){this._rsila=Qa;};this.rsi_ra=function(ra){this._rsima=ra;};this.DM_tag=function(){var Ra;if(this._rsioa==0||this._rsiea==1){if(typeof(DM_prepClient)=="function"){DM_prepClient(this._rsiaa,this);}var Sa=this._rsiya();if(this._rsiia=="gif"){Ra=new Image(2,3);Ra.src=Sa;this._rsina[this._rsina.length]=Ra;}else if(this._rsiia=="js"){if(this._rsifa==1){void("<script language=\"JavaScript\" type=\"text/javascript\" src=\""+Sa+"\"><"+"/script>");}else{var Ta=document.createElement("script");Ta.language="JavaScript";Ta.type="text/javascript";Ta.src=Sa;if(document.body==null){document.getElementsByTagName("head")[0].appendChild(Ta);}else{document.body.insertBefore(Ta,document.body.firstChild);}Ra=Ta;}}this._rsioa=1;}this.rsi_r();return Ra;};this._rsiya=function(){var Ua="";this.DM_addEncToLoc("_rsiL",this._rsiva);Ua="DM_LOC="+_rsixa(this._rsita);if(this._rsipa){Ua+="&DM_CAT="+_rsixa(this._rsipa);}if(this._rsisa){Ua+="&DM_EVT="+_rsixa(this._rsisa);}if(this._rsira){Ua+="&DM_KYW="+_rsixa(this._rsira);}if(this._rsica==1&&this._rsiua){Ua+="&DM_REF="+_rsixa(this._rsiua);}if(this._rsida==1){Ua+="&DM_TIT="+_rsixa(document.title);}if(this._rsiqa){Ua+="&DM_NAM="+_rsixa(this._rsiqa);}Ua+="&DM_EOM=1";var Va="httpdisabled"+(location.protocol=="httpdisabledsdisabled:"?"s":"")+"://";var Wa="/"+this._rsiaa+"/"+this._rsija+this._rsika+"/0/"+this._rsila+"/"+this._rsiga+"/";var Xa=Math.floor(Math.random()*1000000000)+"."+this._rsiia;var Ya=Va+this._rsiha+Wa+Xa+"?D="+_rsixa(Ua)+"&C="+_rsixa(csids);var Za=Ya.length;if(Za>=2000){if(Ya.charAt(1998)=='%'){Ya=Ya.substr(0,1998);}else if(Ya.charAt(1999)=='%'){Ya=Ya.substr(0,1999);}else{Ya=Ya.substr(0,2000);}if(Ya.charAt(Ya.length-3)=='%'&&Ya.charAt(Ya.length-2)=='2'&&Ya.charAt(Ya.length-1)=='5'){Ya=Ya.substr(0,Ya.length-3);}}return Ya;};this.rsi_r=function(){var $a;var ab;var bb=0;var cb=0;if(this._rsiba==1){var db=window;while(true){try{$a=db.document.location;ab=db.document.referrer;bb=cb;}catch(notAllowed){}if(db==window.top||db==db.parent){break;}db=db.parent;cb++;}}else{$a=window.document.location;ab=window.document.referrer;}this._rsiva=cb-bb;this._rsiua=this._rsima?_rsiza(ab.toString()):ab.toString();if(this._rsiva==0){this._rsita=(this._rsima)?_rsiza($a.href):$a.href;}else{this._rsita=this._rsiua;}this._rsipa=null;this._rsiqa=null;this._rsira=null;this._rsisa=null;};this.rsi_r();}var _rsixa;if(typeof(encodeURIComponent)=="function"){_rsixa=encodeURIComponent;}else{var _rsiAa=new RegExp("[\x00-\x20]|[\x22-\x26]|[\x2B-\x2C]|\x2F|[\x3A-\x40]|[\x5B-\x5E]|\x60|[\x7B-\x7D]|[\x7F-\uFFFF]","g");_rsixa=function(v){return v.toString().replace(_rsiAa,_rsiBa);}}function _rsiwa(u,n,v){return u+(u.indexOf("?")==-1?"?":"&")+n+"="+v;}function _rsiza(u){var i=u.indexOf('#');return(i>=0)?u.substr(0,i):u;}function _rsiCa(i){var eb=i.toString(16).toUpperCase();return eb.length<2?"0"+eb:eb;}function _rsiBa(c){var i=c.charCodeAt(0);if(isNaN(i))return "";if(i<128)return "%"+_rsiCa(i);if(i<2048)return "%"+_rsiCa(0xC0+(i>>6))+"%"+_rsiCa(0x80+(i&0x3F));if(i<65536)return "%"+_rsiCa(0xE0+(i>>12))+"%"+_rsiCa(0x80+(i>>6&0x3F))+"%"+_rsiCa(0x80+(i&0x3F));return "%"+_rsiCa(0xF0+(i>>18))+"%"+_rsiCa(0x80+(i>>12&0x3F))+"%"+_rsiCa(0x80+(i>>6&0x3F))+"%"+_rsiCa(0x80+(i&0x3F));}window[rsi_csid]=new rsiClient(rsi_csid);
-function DM_cat(aa){window[rsi_csid].DM_cat(aa);}function DM_name(ba){window[rsi_csid].DM_name(ba);}function DM_keywords(kw){window[rsi_csid].DM_keywords(kw);}function DM_event(ca){window[rsi_csid].DM_event(ca);}function DM_addToLoc(n,v){window[rsi_csid].DM_addToLoc(n,v);}function DM_addEncToLoc(n,v){window[rsi_csid].DM_addEncToLoc(n,v);}function DM_setLoc(u){window[rsi_csid].DM_setLoc(u);}function DM_tag(){window[rsi_csid].DM_tag();}
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbc.co.uk/js/app/av/emp/1_1_3_0_0_426652_426614_1/config.sjson@edition=us&site=news&section=%2FFrontpage b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbc.co.uk/js/app/av/emp/1_1_3_0_0_426652_426614_1/config.sjson@edition=us&site=news&section=%2FFrontpage
deleted file mode 100755
index 2794be925..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbc.co.uk/js/app/av/emp/1_1_3_0_0_426652_426614_1/config.sjson@edition=us&site=news&section=%2FFrontpage
+++ /dev/null
@@ -1,195 +0,0 @@
-/**
- * namespace Holds at least 1 config JSON object
- */
-bbc.fmtj.page.empConfig = {};
-
-/**
- * The base configuration applied to all
- * EMPs embedded on Journalism sites.
- *
- */
-bbc.fmtj.page.empConfig.base = {
-
- /**
- * Related to the EMP such as size,
- * location etc.
- *
- */
- player : {
- /** the height of the transport controls in the EMP */
- toolbarPadding: 0,
- uxHighlightColour: '0xff0000',
-
- /**
- * The footer that appears when the EMP voided in a
- * popout window.
- */
- popoutFooterHeight : {
- /** height of the audio footer */
- audio: 32,
- /** height of the video footer */
- video: 77
- },
-
- /* Used to feed the embeddedMedia.Player required version */
- requiredVersion: "9.0.115"
-
- },
-
- /** Supported audio player sizes. The size keys must match those output by CPS */
- audio : {
- /** the 'small' size */
- small : { width: 226, height: 115 },
- /** the larger size */
- full : { width: 512, height: 115 }
- },
-
- /**
- * Supported video player sizes
- * TODO: Are these used
- */
- video : {
- /* should be named sizes? */
- /* these may not be used...*/
- standard : { width: 448, height: 252 },
- popout : { width: 512, height: 323 }
- },
-
- /**
- * Message text for users that do not have the
- * correct version of Flash to embed the EMP
- */
- noFlashMessage : {
- heading : "Cannot play media.",
- bodyText : "You do not have the correct version of the flash player. ",
- linkText : "Downloaddisabled the correct version",
- linkUrl : "httpdisabled://www.adobe.com/shockwave/downloaddisabled/downloaddisabled.cgi?P1_Prod_Version=ShockwaveFlash"
- },
-
- /**
- * The templates to be used with the noFlashMessage.
- */
- noFlashTemplate : {
- audio: '<div class="audioImage"></div><div class="warning"><p><strong>{heading}</strong>{bodyText} <a href="{linkUrl}">{linkText}</a></p></div>',
- video: '<img class="holding" src="{holding}" width="{width}" height="{height}"><div class="warning"><p><strong>{heading}</strong>{bodyText} <a href="{linkUrl}">{linkText}</a></p></div>'
- },
-
- /**
- * The URL of the config XML file for configuring the EMP
- * see http://newsimg.bbc.co.uk/player/emp/1_1_3_0_0_426652_426614_1/
- */
- configUrl: "httpdisabled://news.bbc.co.uk/player/emp/1_1_3_0_0_426652_426614_1/config/default.xml",
-
- /**
- The settings to be converted into keys such as config_settings_KEY = VALUE
- and passed to emp.set(key, value)
-
- example settings: {
- language: "default"
- }
-
- =>
-
- emp.set( "config_settings_language", "default" );
-
- see http://newsimg.bbc.co.uk/player/emp/1_1_3_0_0_426652_426614_1/docs/guides/configurationSettings.html
- */
- settings: {
- /** Language to use for EMP interface */
- language: "default",
- skin:"silver"
- },
-
- /**
- Same behaviour as settings object above but used to configure
- any EMP plugins:
-
- examples plugins: {
- fmtjLiveStats: {
- pageType: "eav7"
- }
- }
-
- =>
-
- emp.set( "config_plugins_fmtjLivestats_pageType", eav7" )
-
- see http://newsimg.bbc.co.uk/player/emp/1_1_3_0_0_426652_426614_1/docs/guides/plugins.html
-
- TODO what do we do about livestats tracking for developer usage??
- */
- plugins: {
- /** Livestats plugin parameters are supplied by CPS */
- fmtjLiveStats: {}
- },
-
- // TODO: Add quova geoip logic here to stop appearing when inside the uk
-
- /**
- * Options for configuring adverts
- * when EMP is viewed internationally.
- */
- ads: {
- /**
- * Configuration for companion ad format
- */
- companion: {
- /** Dimensions of the companion */
- size: "300x60",
-
- /** Type of companion */
- type: "adi",
-
- /**
- * Prefix for the id of the companion banner if automatically created
- * by this embed code (for example if embedded by a developer)
- */
- idPrefix: "bbccom_companion_",
-
- /**
- * Template for the companion banner dom id
- */
- template: '<div class="bbccom_visibility_hidden" id="{id}"><div class="bbccom_companion_text">Advertisement</div>'
-
- /**
- * name suppress {boolean}
- * When true and a developer is embedding then no companion will
- * be created. Make sure that you also stop the EMP showing a
- * pre-roll advert by calling:
- * emp.set( "config_settings_suppressItemKind", "advert" );
- */
- }
- }
-};
-
-
-
- /*
- * Begin panorama config
- */
-
-
- /*
- * Begin welsh config
- */
-
-
- /*
- * Begin F1 config
- */
-
-
- /*
- * Begin weather config
- */
-
-
- /*
- * Register EMP
- */
- bbc.fmtj.queue.register({namespace:"bbc.fmtj.av.emp",method:"loaddisabled",scripts: {foot: [ "/js/app/av/emp/1_1_3_0_0_426652_426614_1/emp.js" ]}});
-
-/*
-* DemocracyLive and Childrens do not have a site_to_serve variable
-* So there is currently no way to configure them.
-*/
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/css/screen/shared/19_58/3pt_ads.css b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/css/screen/shared/19_58/3pt_ads.css
deleted file mode 100755
index e5de0645a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/css/screen/shared/19_58/3pt_ads.css
+++ /dev/null
@@ -1 +0,0 @@
-body#travel .bbccom_wallpaper #blq-container-inner{overflow:visible;}#bbccom_slot_wallpaper_left{height:600px;left:-310px;position:absolute;top:-40px;width:300px;}#bbccom_slot_wallpaper_right{height:600px;position:absolute;right:-310px;top:-40px;width:300px;}#blq-pre-mast{z-index:9999;}.bbccom_display_none{display:none!important;}.bbccom_visibility_hidden{height:60px;visibility:hidden;}.bbccom_text,.bbccom_text a,.bbccom_text a:hover,.bbccom_text a:active,.bbccom_text a:visited,.lhs .bbccom_text a:link,.lhs .bbccom_text a:visited,.lhs .bbccom_text a:active,.lhs .bbccom_text a:hover,.lhs #bbccom_button .bbccom_text a,.lhs #bbccom_button .bbccom_text a:hover,#bbccom_sponsor_section_text,.bbccom_sponsor_text,.photo_gallery #bbccom_sponsor_section_text,#blq-main .bbccom_companion_text,#blq-main .bbccom_companion_text a,#bbccom_mpu a,#bbccom_mpu_high a,#bbccom_leaderboard a,#galothercontentbox .bbccom_text a:link,#navigation .bbccom_text a:link,#secondary-content .bbccom_text a:link,#secondary-content .bbccom_text a:visited,#secondary-content .bbccom_text a:active,#secondary-content .bbccom_text a:hover,#secondary-content .bbccom_text a:focus,#travel #bbccom_sponsor_section_text,#bbccom_sponsor_section_news,#blq-main .bbccom_adsense h3 a{color:#505050;font:bold 10px/23px helvetica,arial,sans-serif!important;letter-spacing:0!important;text-transform:uppercase;background-color:transparent;}#travel .bbccom_adsense h4 a,#travel .bbccom_adsense h4 p a{color:#000;font:bold 13px/13px arial,helvetica,sans-serif!important;text-transform:none;}#travel #blq-main .bbccom_adsense p{color:#505050;}#travel #blq-main .bbccom_adsense p a{color:#78b200;text-transform:none;}#bbccom_sponsor_section_text,#bbccom_module_special-reports .bbccom_text,#bbccom_leaderboard_container .bbccom_text a,#bbccom_module_programme-breakout .bbccom_text,#bbccom_module_hyper-promotional-content .bbccom_text,.news #header-wrapper #bbccom_sponsor_section .bbccom_text{color:#fff;text-decoration:none;}.bbccom_text{text-align:right;}.bbccom_text,#bbccom_module_range-most-popular_text{text-align:right;}.bbccom_sponsor .bbccom_text{padding-right:3px;display:inline;}.adimg{border-style:none;}.news .bbccom-advert{margin-top:-1px;}.bbccom_slot_mpu .more-galleries li.last-child{display:none;}.news .partner_buttons_2cols{padding:10px 23px 0;width:288px;}.news #bbccom_partner_button1{width:334px;}.news .bbccom_adsense,.blogs .bbccom_adsense{background-color:#fff;border:1px solid #999;}.news #blq-main .bbccom_adsense h3 a,.news #blq-main .bbccom_adsense p,.blogs #blq-main .bbccom_adsense h3 a,.blogs #blq-main .bbccom_adsense p{color:#505050;}.news #blq-main .bbccom_adsense a,.blogs #blq-main .bbccom_adsense a{color:#174f82;}#travel #bbccom_leaderboard,#travel #bbccom_mpu,#travel #bbccom_button,#travel #bbccom_promo_feature_1{background-color:#e8e8e8;}#travel .gallery #bbccom_leaderboard,#travel .gallery #bbccom_mpu,#travel .gallery #bbccom_button,#travel .gallery #bbccom_promo_feature_1{background-color:#212121;}#travel .gallery .bbccom_text a{color:#878787;}#travel #bbccom_leaderboard{line-height:1;padding:0 8px 8px;}#travel #bbccom_mpu{margin-bottom:20px;padding:0 8px;text-align:center;}.bbccom_slot_mpu336 #promo-content #bbccom_mpu{padding:0;}#travel.bbccom_slot_mpu336 #bbccom_mpu{width:336px;}.bbccom_slot_xxl .feature #promo-content div{margin:0 auto;}#travel #bbccom_button{line-height:1;padding:0 8px 8px;}#travel #bbccom_button a{display:inline-block;line-height:1;}#travel #bbccom_sponsor_section{bottom:22px;top:auto;right:0;}#travel #promo-content .bbccom_text{padding-right:8px;}#travel .promo_feature{line-height:1;margin-bottom:24px;width:336px;}#travel #blq-main .bbccom_adsense{background-color:#e8e8e8;}#travel #blq-main .bbccom_adsense h3{border-bottom:1px solid #ABABAB;margin:0 8px;padding:0;text-align:right;}#travel #bbccom_adsense_mpu{margin-top:0;}#bbccom_leaderboard{width:728px;padding:0 2px;margin:0 auto;}#bbccom_leaderboard_container{background-color:#484848;}#bbccom_leaderboard_container #bbccom_leaderboard{padding-bottom:8px;}.bbccom_slot_leaderboard970 #bbccom_leaderboard,.bbccom_slot_leaderboard97066 #bbccom_leaderboard,.bbccom_slot_leaderboard97090 #bbccom_leaderboard{height:auto;padding:0 3px;width:auto;}.bbccom_slot_leaderboard970 #blq-main #bbccom_leaderboard,.bbccom_slot_leaderboard97066 #blq-main #bbccom_leaderboard,.bbccom_slot_leaderboard97090 #blq-main #bbccom_leaderboard{padding:0 3px;}#bbccom_button .bbccom_text{text-align:right;}#bbccom_button{border:0 none;float:left;padding:0 0 8px 20px;width:120px;}.lhs #bbccom_button a:link,.lhs #bbccom_button a:visited,.lhs #bbccom_button a:active{padding:0;}#blq-main .companion_v4{height:60px;padding-top:10px;width:auto;}#blq-main .bbccom_companion{height:84px;margin:auto;overflow:hidden;width:300px;}#blq-main .bbccom_companion div{float:right;height:auto;padding:0;}#blq-main .companion_v4 div.bbccom_companion_text{width:auto;}#story-body .companion_v4{padding-bottom:10px;}.videoInStoryA .bbccom_visibility_show,.videoInStoryB .bbccom_visibility_show{height:auto;margin-top:8px;}#blq-main .companion_parent{background-color:#D5D5D5;height:auto;margin-top:-3px;padding-bottom:10px;text-align:center;}#blq-main .companion_parent .bbccom_companion_text{display:block;float:none;height:auto;margin:0 auto;padding:0;text-align:right;width:300px;}#blq-main .companion_parent .bbccom_companion_text a{background-image:none;float:none;padding:0;}#blq-main .companion_parent div{height:60px;}#blq-main .companion_parent div.bbccom_companion_text{height:24px;}#bbccom_sponsor_section{background:none;height:31px;position:absolute;right:85px;text-align:right;top:27px;width:auto;}.sportbanner #bbccom_sponsor_section{padding:0 28px 0 0;right:-11px;top:-2px;}.sportbanner #bbccom_sponsor_section_text{float:left;margin-top:15px;}.wodban #bbccom_sponsor_section{padding:0 13px 0 0;right:0;top:-3px;}#bbccom_sponsor_section div{background:none;display:inline-block;float:none;margin:0;padding:0;}#bbccom_sponsor_section_text{width:130px;}#bbccom_sponsor_section_image,#bbccom_sponsor_section_image a{width:96px;}#bbccom_sponsor_section_image{padding-left:10px;}.banner #bbccom_sponsor_section div{height:auto;}.news #header-wrapper #bbccom_sponsor_section{left:auto;right:0;top:15px;width:205px;}.news #header-wrapper #bbccom_sponsor_section .bbccom_text{float:left;line-height:38px!important;}.bbccom_sponsor{height:31px;}#bbccom_sponsor_section_news{float:left;margin:0 0 0 10px;}#bbccom_sponsor_section_news p{float:left;margin:20px 5px 0 0;}#bbccom_sponsor_section_news img{display:block;}.news .photo-gallery #bbccom_sponsor_section{left:auto;right:0;top:42px;}.news .photo-gallery #bbccom_sponsor_section .bbccom_text{float:left;padding-top:3px;}.news .photo-gallery #bbccom_sponsor_section a{margin-left:3px;}#socialBookMarks iframe{border:none;}#bbccom_module_page-bookmark-links{height:31px;position:absolute;right:0;text-align:right;top:-10px;width:230px;}.story-related{margin:0 0 24px!important;}#bbccom_module_hyper-promotional-content{background:#D1700E;border-top:1px solid #fff;padding:8px;text-align:right;margin-top:0;}.bbccom_slot_module_special-reports .special-reports .top-report{padding-bottom:4em;}.bbccom_slot_module_special-reports .more-special-reports{display:none;}#bbccom_module_special-reports{text-align:right;min-height:1px;padding:8px 8px 5px 0;position:absolute;bottom:0;right:0;width:100%;z-index:1;}#bbccom_storyprintsponsorship{overflow:auto;border:1px solid #eee;float:right;margin:9px 0 29px 0;width:251px;padding:4px 0;}#bbccom_storyprintsponsorship p{float:left;font-size:.8em;padding:6px 0 6px 6px;text-transform:uppercase;margin-right:10px;}#bbccom_storyprintsponsorship div{height:31px;}#bbccom_storyprintsponsorship a{background-image:none;margin:0;padding:0;}#bbccom_storyprintsponsorship .bbccom_text{display:none;}#bbccom_module_most-popular,#bbccom_module_programme-breakout,#bbccom_module_range-most-popular,#bbccom_module_most-popular-category{clear:both;height:31px;overflow:hidden;padding-top:8px;position:relative;text-align:right;}.bbccom_slot_xxl #bbccom_module_programme-breakout{float:right;padding-bottom:8px;width:336px;}.bbccom_slot_xxl li.no-image #bbccom_module_programme-breakout{right:auto;bottom:auto;position:relative;width:auto;}#bbccom_module_market-data-include{background:#ededed;border-top:1px solid #fff;margin:-16px 0 16px 0;padding:8px 8px 8px 0;text-align:right;}#main-content .story-actions{float:left;width:468px;}#bbccom_mpu,#bbccom_mpu_high{border:0;margin:0 auto;width:300px;}.news #bbccom_mpu{margin:-8px auto 13px;}.news .media-asset #bbccom_mpu{margin-top:0;}.news #bbccom_mpu_high{margin:-6px auto 13px;}.news #bbccom_mpu img,.news #bbccom_mpu_high img{margin-bottom:-6px;}.wgreylinebottom #bbccom_mpu{margin:-14px auto 11px;}td #bbccom_mpu{margin-bottom:16px;}.blq_hp #bbccom_mpu{margin:0;}#galothercontentbox #bbccom_mpu{margin-top:-12px;}.bbccom_slot_xxl #bbccom_mpu,.bbccom_slot_xxl #bbccom_mpu_high{width:468px;margin-left:15px;}.bbccom_slot_mpu336 #bbccom_mpu,.bbccom_slot_mpu336 #bbccom_mpu_high{width:auto;}.bbccom_slot_mpu_skyscraper #bbccom_mpu,.bbccom_slot_mpu_skyscraper #bbccom_mpu_high{height:644px;width:160px;}.mpu_v4{margin:0 0 20px 3px;}#bbccom_adsense_mpu,#secondary-content #bbccom_adsense_mpu{margin-top:10px;}#secondary-content #bbccom_mpu,#secondary-content #bbccom_mpu div,#secondary-content #bbccom_mpu_high,#secondary-content #bbccom_mpu_high div,#secondary-content #bbccom_adsense_mpu,#secondary-content #bbccom_adsense_mpu div{border-bottom:none;}#secondary-content #bbccom_mpu,#secondary-content #bbccom_mpu div,#secondary-content #bbccom_mpu_high,#secondary-content #bbccom_mpu_high div{border-bottom:none;padding-bottom:0;width:300px;}#bbccom_skyscraper{position:absolute;border:0;width:160px;height:600px;text-align:center;}.skyscraper_v4{top:156px;left:1000px;}.skyscraper_v3_5{top:104px;left:815px;}.skyscraper_v3{top:256px;left:770px;}#bbccom_bottom{height:71px;width:470px;}.bottom_v3,.bottom_v3_5{margin:0 0 0 215px;padding:8px 0;}#bbccom_adsense_mpu,#bbccom_adsense_middle{display:inline-block;font-family:arial,sans-serif;}.bbccom_adsense{background-color:#EDF3F3;}#bbccom_adsense_mpu{margin-bottom:10px;}#bbccom_adsense_middle{margin-bottom:20px;width:466px;}#main-content #bbccom_adsense_middle{margin-bottom:20px;margin-top:22px;}.bbccom_adsense h3,.bbccom_adsense h4{font-size:14px;}#blq-main .bbccom_adsense h3{padding:6px;}#blq-main .bbccom_adsense li{background-image:none;padding:6px;}#blq-main .bbccom_adsense h3 a{background-image:none;padding:0;color:#555;font-weight:bold;}#blq-main .bbccom_adsense a{border-bottom:none;color:#006;}#blq-main .bbccom_adsense p{color:#000;font-size:13px;margin:0;padding:0;}#blq-main .bbccom_adsense p a{font-weight:normal;}#blq-main .adsense_mpu_weather_top{margin-top:0;}.adsense_mpu_weather{background-color:#fff;width:296px;}.layout-block-a .bbccom_adsense{width:462px;}.layout-block-a #bbccom_adsense_mpu{margin-top:0;}#secondary-content .adsense_mpu li{background-image:none;}#bbccom_partner_button1{border:1px solid #EAEAEA;float:left;margin:8px 0 16px 0;padding-top:10px;position:relative;}#bbccom_partner_button1 a{display:inline-block;height:30px;margin-left:31px;padding-bottom:10px;width:120px;}#bbccom_partner_button1 .partner_buttons_4cols a{margin-left:27px;}#bbccom_partner_button1 .bbccom_text{position:absolute;right:0;top:-26px;}.bbccom_slot_xxl #bbccom_partner_button1{width:494px;}.sportbanner{position:relative;}#bbccom_bottom_adlabel{color:#bbb;}#bbccom_leaderboard table,#bbccom_leaderboard tr,#bbccom_leaderboard td,#bbccom_leaderboard th{margin:0;padding:0;}.bbccom_slot_sponsor_section div.cg-2010-section{background:url("../../../../sol/shared/img/v4/commonwealth_games_2010/cg_bbccom_banner_sprite2.png") no-repeat scroll 160px 0 transparent;}.cg-2010-section .sportbanner #bbccom_sponsor_section{padding:0 16px 0 0;right:0;}.cg-2010-section #bbccom_sponsor_section_text{color:#000;float:left;margin-top:15px;}.bbccom_slot_sponsor_section a#rss-alternative{margin-right:340px;}.bbccom_slot_sponsor_section #fixturesLink{background-image:none;float:left;line-height:1.3em;margin-left:10px;}.bbccom_slot_sponsor_section .world-cup-2010-section .athleticsbg{margin-top:65px;}.world-cup-2010-section #bbccom_mpu{margin-bottom:20px;}.bbccom_slot_sponsor_section .world-cup-2010-section .contentwrapper,.bbccom_slot_sponsor_section .world-cup-2010-section .contentwrapperwide{padding:32px 0 0 0;}.world-cup-2010-section #bbccom_sponsor_section{color:#505050;left:auto;line-height:55px;right:14px;top:118px;width:230px;}.world-cup-2010-section #bbccom_sponsor_section div{float:left;line-height:53px;}.world-cup-2010-section #bbccom_sponsor_section a{left:0;position:relative;top:0;width:100px;}.bbccom_slot_mpu div.f1-winter-olympics-2010 #bbccom_mpu{padding-bottom:29px;}div.f1-winter-olympics-2010 #bbccom_sponsor_section{left:531px;top:21px;width:260px;}div.f1-winter-olympics-2010 #bbccom_sponsor_section div{float:left;}div.f1-winter-olympics-2010 #bbccom_sponsor_section_text{padding-top:6px;}div.f1-winter-olympics-2010 #bbccom_sponsor_section_image{position:relative;width:100px;}div.f1-winter-olympics-2010 .sportbanner div #bbccom_sponsor_section_image a{left:0;top:0;width:100px;}.embedvideo .latestinfo p{margin-top:388px;}.i #bbccom_leaderboard_adlabel{color:#fff;}#ad,#ad .container{background:transparent;}div.contentBlock a.headerSponsor{display:block;font-size:.667em;font-weight:normal;height:30px;padding:5px 5px 5px 40px;background-color:#EFEDED;}div.contentBlock a.headerSponsor img{float:left;}div.contentBlock a.headerSponsor span{float:left;line-height:26px;margin-right:5px;}.moduleAdvertContent{height:31px;padding:6px 10px;cursor:default;}.moduleAdvertContent a,.moduleAdvertContent a img{float:left;}div.bbccom_module_adlabel{color:#666;float:left;font-size:.8em;margin:6px 10px 0 0;width:180px;}#bbccom_halfbanner{border-top:1px solid #DBDBDB;text-align:center;}div.bbccom_halfbanner_adlabel{color:#666;font-size:.8em;margin:6px 10px 0 0;text-align:center;width:300px;}.bbccom_halfbanner_image{padding:5px 0 10px 0;}#international .colB{min-height:250px;height:auto;padding-top:0;}.blq-js #international.bbccom_slot_mpu .colB{height:auto;padding-top:7px;}.blq-js #international.bbcdotcomAdvertsResetMpu .colB{padding-top:0;height:250px;}.blq-js .bbccom_slot_mpu .colE{margin-top:0!important;}.blq-js #international.bbcdotcomAdvertsResetMpu .colE{margin-top:-250px;}.advert{margin-left:2px;}.news .advert{margin:0 0 -2px 2px;}.front-page .advert{margin:0 0 3px 2px;}.bbcdotcomAdvertsResetMpu #bbccom_mpu{display:none;}.skylightTheme #bbccom_leaderboard_container{background-color:#1778B3;}.doveTheme #bbccom_leaderboard_container{background-color:#5B688F;}.tealTheme #bbccom_leaderboard_container{background-color:#2383A3;}.aquaTheme #bbccom_leaderboard_container{background-color:#158979;}.greenTheme #bbccom_leaderboard_container{background-color:#5D891B;}.violetTheme #bbccom_leaderboard_container{background-color:#6A5789;}.purpleTheme #bbccom_leaderboard_container{background-color:#823892;}.pinkTheme #bbccom_leaderboard_container{background-color:#9D1767;}.oliveTheme #bbccom_leaderboard_container{background-color:#7C7854;}.suedeTheme #bbccom_leaderboard_container{background-color:#695C4A;}.redTheme #bbccom_leaderboard_container{background-color:#9E2C1D;}.orangeTheme #bbccom_leaderboard_container{background-color:#C55F16;}.blackTheme #bbccom_leaderboard_container{background-color:#3F3F3F;}.module h2 a.headerSponsor{position:absolute;right:30px;top:0;width:auto;}.module h2 a.headerSponsor{display:block;font-size:.667em;font-weight:normal;height:30px;margin:5px 0 0;}.module h2 a.headerSponsor span{float:left;line-height:26px;margin-right:5px;}.module h2 a.headerSponsor img{float:left;}.blogs #bbccom_mpu,.blogs #bbccom_partner_button1,.blogs #bbccom_adsense_mpu{float:left;}.blogs #bbccom_partner_button1{margin:14px 0;}.blogs #bbccom_mpu{margin-bottom:14px;}#bbccom_leaderboard_adlabel.bbccom_text a,.blogs #content #bbccom_mpu_adlabel a{color:#666;}.blogs .adsense_mpu{font-size:1em;}.blogs #content .adsensetitle a:link{color:#555;}.blogs #content .adsenselabel a:link{font-size:1.1em;}.blogs #content .adsenselabel a:link,.blogs #content .adsenseurl a:link{color:#006;}.blogs #content .adsensead span{line-height:1.4em;}.blogs #bbccom_sponsor_section{width:auto;top:20px;}.blogs #bbccom_sponsor_section_text{width:auto;font-size:.8em;line-height:31px;}.blogs #bbccom_sponsor_section_image{width:auto;}.blogs #bbccom_sponsor_section_text,.blogs #bbccom_sponsor_section_image{float:left;margin-left:10px;}#blq-weather-header #bbccom_sponsor_section{top:-2px;right:14px;display:block;}#blq-weather-header #bbccom_sponsor_section div{display:block;}#blq-weather-header #bbccom_sponsor_section_text{text-align:right;}#blq-weather-header #bbccom_sponsor_section_image{width:auto;}.bbccom_slot_interstitial #blq-acc,.bbccom_slot_interstitial #blq-mast{display:none!important;}.bbccom_slot_interstitial{overflow:hidden;}.bbccom_slot_interstitial_300x600 #bbccom_int{width:300px;}#bbccom_int_container{width:100%;text-align:center;height:5000px;left:0;position:absolute;top:-40px;z-index:10000;}#bbccom_int_outer{top:0;z-index:9999;background:url('../../../../../www.bbc.co.uk/bbc.com/images/interstitial/header.gif') #ddd no-repeat;height:100%!important;height:4000px;}#bbccom_int_inner{width:976px;}#bbccom_int_head{text-align:right;padding:70px 10px 0 0;}#bbccom_int_link{font-family:arial,sans-serif;color:black;font-size:.8em;font-weight:bold;text-decoration:none;cursor:pointer;background:url('../../../../../www.bbc.co.uk/bbc.com/images/interstitial/arrow.gif') transparent right center no-repeat;padding-right:14px;}#bbccom_int{margin:0 auto;padding-top:20px;width:640px;}#travel #bbccom_int_outer{background:url('../../../../../www.bbc.co.uk/bbc.com/images/interstitial/header_travel.gif') #ddd no-repeat;}.blq_hp .pulse-pop{top:103px;}.bbccom_slot_leaderboard .pulse-pop{top:232px;}.bbccom_slot_leaderboard97066 .pulse-pop{top:200px;}.bbccom_slot_leaderboard97090 .pulse-pop{top:224px;}.news #blq-pre-mast .pulse-pop{left:700px;top:300px;}.centerbody #blq-pre-mast .pulse-pop{left:700px;top:300px;}.blq-js #international .colB{padding-top:0;height:280px;}.blq-js #international .colE{margin-top:-280px;}#blq-main .front-page .bbccom_companion{display:none;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/img/1_0_1/cream/hi/news/news-blocks.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/img/1_0_1/cream/hi/news/news-blocks.gif
deleted file mode 100755
index 33d693a4a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/img/1_0_1/cream/hi/news/news-blocks.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/app/bbccom/19_52/s_code.js b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/app/bbccom/19_52/s_code.js
deleted file mode 100755
index ea521da8d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/app/bbccom/19_52/s_code.js
+++ /dev/null
@@ -1,1091 +0,0 @@
-/* SiteCatalyst code version: H.22.1.
-Copyright 1996-2010 Adobe, Inc. All Rights Reserved
-More info available at http://www.omniture.com */
-
-/*
-Version: 1.7.3
- */
-//var s_account = "bbcwglobaldev"
-var s_account = "bbcwglobalprod"
-var s=s_gi(s_account)
-/************************** CONFIG SECTION **************************/
-/* You may add or alter any code config here. */
-s.charSet="ISO-8859-1"
-/* Conversion Config */
-s.currencyCode="USD"
-/* Link Tracking Config */
-s.trackDownloaddisabledLinks=true
-s.trackExternalLinks=true
-s.trackInlineStats=true
-s.linkDownloaddisabledFileTypes="exe,zip,wav,mp3,mov,mpg,avi,wmv,doc,pdf,xls"
-s.linkInternalFilters="javascript:,bbc.com,bbc.co.uk"
-s.linkLeaveQueryString=false
-s.linkTrackVars="None"
-s.linkTrackEvents="None"
-
-/* Time Parting Config */
-s.dstStart = "3/28/2010";
-s.dstEnd = "10/31/2010";
-s.currentYear = Set_Year();
-
-/* Channel Manager Configuration */
-s._extraSearchEngines=""
-s._channelDomain = "Facebook|facebook.com>Twitter|twitter.com>YouTube|youtube.com>LinkedIn|linkedin.com>MySpace|myspace.com>Other Social Media|digg.com,flickr.com,stumbleupon.com,del.icio.us,reddit.com,metacafe.com,technorati.com"
-s._channelParameter = ""
-s._channelPattern = ""
-
-/* Hierarchy Section Rules */
-var thisURL = document.URL;
-var h1 = "";
-var h2 = "";
-var h3 = "";
-var h4 = "";
-var br = "<br>";
-var url = "";
-var hArray;
-var hLength;
-var newUrl = "";
-var contentIdMatch;
-//string sequence starting with a - or _, followed by 7 - 8 digits, followed by a non digit or EOL
-var reStandardContentId = new RegExp("([0-9]{7,8})([^0-9]|$)");
-var reNewsContentId = new RegExp("(-)([0-9]{7,8})([^0-9]|$)");
-
-s.usePlugins = true
-function s_doPlugins(s) {
- /* Add calls to plugins here */
-
- /* Custom Page Views event */
- s.events = s.apl(s.events, "event2", ",", 1);
-
-
- /* Hierarchy Section Rules */
-
- evaluateUrl(thisURL);
-
- s.channel = s.prop6;
-
- /* Meta tag capture */
- if (document.getElementsByName) {
-
- //Page Name variable
- s.pageName = document.title.replace(/ - /g, ' | ').toLowerCase();
- s.eVar2 = s.pageName;
-
- s.hier1 = document.title.replace(/ - /g, '|');
- if ("undefined" != typeof BBC) {
- s.hier2 = BBC.adverts.getSectionPath();
- } else {
- sectionPath = window.location.pathname.replace('2/hi', 'news'); // Flip news
- sectionPath = sectionPath.replace('sport2/hi', 'sport'); // Flip sport
- sectionPath = sectionPath.replace(/\/+[0-9]*.([a-z])*$/g, ''); // Remove / from the end of the link
- s.hier2 = sectionPath.substring(1);
- }
-
-
- //Site Section for channel now set above
-// var metaArray = document.getElementsByName('CPS_SITE_NAME');
-// for (var i = 0; i < metaArray.length; i++) {
-// s.channel = metaArray[i].content;
-// }
-
-
- //prop3
- var metaArray = document.getElementsByName('Headline');
- for (var i = 0; i < metaArray.length; i++) {
- s.prop3 = metaArray[i].content;
- s.eVar3 = s.prop3;
- }
-
- //prop4
- var metaArray = document.getElementsByName('CPS_ID');
- for (var i = 0; i < metaArray.length; i++) {
- s.prop4 = metaArray[i].content;
- s.eVar4 = s.prop4;
- }
-
- //prop5
- var metaArray = document.getElementsByName('contentFlavor');
- for (var i = 0; i < metaArray.length; i++) {
- s.prop5 = metaArray[i].content.toUpperCase();
- s.eVar5 = s.prop5;
- }
-
-
- //prop10
- var metaArray = document.getElementsByName('OriginalPublicationDate');
- for (var i = 0; i < metaArray.length; i++) {
- s.prop10 = metaArray[i].content;
- s.eVar10 = s.prop10;
- }
-
- //prop14
- //var metaArray = document.getElementsByName('CPS_AUDIENCE');
- //for (var i = 0; i < metaArray.length; i++) {
- // s.prop14 = metaArray[i].content;
- // s.eVar14 = s.prop14;
- //}
-
- //prop15
- var metaArray = document.getElementsByName('IFS_URL');
- for (var i = 0; i < metaArray.length; i++) {
- s.prop15 = metaArray[i].content;
- s.eVar15 = s.prop15;
- }
- }
-
- if ("undefined" != typeof bbc &&
- "undefined" != typeof bbc.fmtj &&
- "undefined" != typeof bbc.fmtj.page ) {
- s.prop32 = bbc.fmtj.page.adKeyword;
- s.eVar32 = s.prop32;
- }
-
- if ("undefined" != typeof bbcdotcom &&
- "undefined" != typeof bbcdotcom.stats ) {
-
- if ('yes' == bbcdotcom.stats.adEnabled) {
- s.prop57 = "yes";
- s.eVar57 = s.prop57;
- } else {
- s.prop57 = "no";
- s.eVar57 = s.prop57;
- }
- // TODO: Remove the if statement and set prop14 once a fix for
- // https://jira.dev.bbc.co.uk/browse/BBCCOM-490 is live.
- if('homepage' != h1) {
- s.prop14 = bbcdotcom.stats.audience;
- s.eVar14 = s.prop14;
- }
- s.prop31 = bbcdotcom.stats.contentType;
- s.eVar31 = s.prop31;
- }
-
- //s.prop31 = "standard - html"
- //s.eVar31 = "standard - html"
- //s.prop31 = "Normal Web"
-
- /* Visitor Information */
- //Visitor Number
- s.prop12 = s.getVisitNum();
-
- //Days Since Last Visit
- s.prop13 = s.getDaysSinceLastVisit();
- s.eVar13 = s.prop13;
-
- //Page Refresh Variable
- s.prop17 = s.trackRefresh(s.pageName, 'tr_pr1');
-
- //Track New and Repeat Visitors
- s.prop18 = s.getNewRepeat();
- if (s.pageName && s.prop18 == 'New') s.prop19 = s.pageName;
- if (s.pageName && s.prop18 == 'Repeat') s.prop20 = s.pageName;
-
- //Set Time Parting Variables
- s_hour = s.getTimeParting('h', '0');
- s_day = s.getTimeParting('d', '0');
- s_timepart = s_day + "|" + s_hour;
- s.prop11 = s_timepart.toLowerCase();
- if (s.visEvent) s.eVar11 = s.prop11;
-
- /* Campaign Config */
- //The Campaign variable
- //s.campaign = s.getQueryParam('cmpid');
- //s.eVar1 = s.crossVisitParticipation(s.campaign, 's_cpm', '90', '5', '>', 'purchase');
-
- s.campaign = s.getQueryParam('ocid');
- s.campaign = s.getValOnce(s.campaign,'s_campaign',0);
-
- /* Plugin: channelManager v2.2 */
- s.channelManager('cmp,cmpid,cid,rss,ocid,OCID', ':', 's_cm', '0');
-
- if (s._channel == "Natural Search") {
- s._channel = "Organic";
- s._campaign = s._partner + "-" + s._channel + "-" + s._keywords.toLowerCase();
- }
- if (s._channel == "Referrers") {
- s._channel = "Other Referrers";
- s._campaign = s._channel + "-" + s._referringDomain;
- }
-
- s.eVar43 = s._referrer
- s.eVar44 = s._referringDomain
- s.eVar45 = s._keywords
- s.eVar46 = s._partner
- s.eVar47 = s._channel
-
- //Referrer - Search Term Stacking
- s.eVar48 = s.crossVisitParticipation(s._keywords, 's_ev48', '30', '5', '>', 'event2', 1);
-
- //Referrer - Channel Stacking
- s.eVar49 = s.crossVisitParticipation(s._channel, 's_ev49', '30', '5', '>');
-
-
-}
-s.doPlugins = s_doPlugins
-
-function Set_Year() {
- var now = new Date();
- var year = now.getYear();
- if (year < 1900) {
- year = year + 1900;
- }
- return year;
-}
-
-/*********************** PLUGINS SECTION ****************************/
-
-function evaluateUrl(siteUrl) {
-
- h1 = "";
- h2 = "";
- h3 = "";
- h4 = "";
- url = "";
- hArray = null;
- hLength = null;
- newUrl = "";
- contentIdMatch = null;
-
- url = siteUrl;
-
- url = url.toLowerCase();
- url = url.replace(/^\s*(.*?)\s*$/,"$1");
-
- //if last character is / then remove
- url = url.replace(/\/$/g,'');
-
- //remove protocol in url
- newUrl = url.replace(/^(http|https):\/\//g,"");
-
- //remove uk- in url if there is another section
- //i.e. http://www.bbc.co.uk/news/uk-politics-11754656
- if(3 <= newUrl.split('-').length) {
- newUrl = newUrl.replace(/uk-/,"");
- }
-
- //replace a number document with article, mainly for v3 stories
- newUrl = newUrl.replace(/\/[0-9]{7}.stm/,"/articles");
-
- // strip default.stm
- newUrl = newUrl.replace(/\/default.stm/g,'');
-
- //split the url
- hArray = newUrl.split("\/");
- hLength = hArray.length;
-
- if (hLength >= 2) {
-
- siteSection = hArray[1];
-
- switch(siteSection){
- case 'news': news(); break;
- case 'sport': sport(); break;
- case 'sport2': sport(); break;
- case 'weather': weather(); break;
- case 'travel': travel(); break;
- case 'blogs': blogs(); break;
- case 'radio': radio(); break;
- //default:void("no siteSection found" + br);break;
- }
- }
-
- //Handle home page
- if (hLength == 1) {
- h1 = 'homepage';
- }
-
- if ("undefined" != typeof h1 && '' != h1) {
- s.prop6 = h1;
- s.eVar6 = s.prop6;
- s.channel = s.prop6;
- }
- if ("undefined" != typeof h2 && '' != h2) {
- s.prop7 = h2;
- s.eVar7 = s.prop7;
- }
- if ("undefined" != typeof h3 && '' != h3) {
- s.prop8 = h3;
- s.eVar8 = s.prop8;
- }
- if ("undefined" != typeof h4 && '' != h4) {
- s.prop9 = h4;
- s.eVar9 = s.prop9;
- }
-
- //***
- //END of Main section
- //***
-}
-
-function news (){
-
- h1 = hArray[1];
-
- contentIdMatch = reNewsContentId.test(newUrl)
- if (!contentIdMatch) {
- if (hLength >= 3) {
- h2 = h1 + ">" + hArray[2];
- if (hLength >= 4) {
- h3 = h2 + ">" + hArray[3];
- }
- }
- }
- else {
- if (hLength >= 2) {
-
- //change all \d{7} and \d{8} to 'articles'
- var lastFwdSlash = newUrl.lastIndexOf("/");
- var lastValue = newUrl.substr(lastFwdSlash + 1);
-
- lastValue = lastValue.replace(/([0-9]{8})/,"articles");
- lastValue = lastValue.replace(/([0-9]{7})/,"articles");
-
- var firstDash = lastValue.indexOf("-");
-
- if (firstDash > 0){
-
- h2 = h1 + ">" + lastValue.substring(0,firstDash);
- h3 = h2 + ">" + lastValue.substr(firstDash + 1);
-
- } else {
-
- h2 = h1 + ">" + lastValue;
-
- }
-
- }
-
- }
-}
-
-function sport() {
-
- var newUrlSport = "";
-
- //Keep the original value (eg Sport2),
- h1 = hArray[1].replace(/sport2/g,'sport');
-
- contentIdMatch = reStandardContentId.test(newUrl);
-
- if (!contentIdMatch) {
-
- newUrl = newUrl.replace(/sport2/g,'sport');
- newUrlSport = newUrl.replace(/\/hi\//g,'\/');
- hArray = newUrlSport.split("\/");
- hLength = hArray.length;
-
- if (hLength >= 3) {
-
- //Use the new value of h1 eg sport not sport2
- h2 = hArray[1] + ">" + hArray[2];
- if (hLength >= 4) {
- h3 = h2 + ">" + hArray[3];
-
- newUrlSport = newUrlSport.replace(/\/m\//g,'\/');
- hArray = newUrlSport.split("\/");
- hLength = hArray.length;
-
- if (hLength >= 5) {
- h4 = h3 + ">" + hArray[4];
- }
- }
- }
-
- } else {
-
- var posHi = hArray.indexOf('hi');
-
- if (posHi > 0 && (hLength >= (posHi + 1) )) {
- h2 = h1 + ">" + hArray[posHi + 1];
- }
- if (posHi > 0 && (hLength >= (posHi + 2) )) {
- h3 = h2 + ">" + hArray[posHi + 2];
- }
- var posM = hArray.indexOf('m');
- if (posM > 0 && (hLength >= (posM + 1) )) {
- h4 = h3 + ">" + hArray[posM + 1];
- }
- }
-}
-
-function weather() {
-
- h1 = hArray[1];
-
- newUrl = newUrl.replace(/\/hi\//g,'\/');
- hArray = newUrl.split("\/");
- hLength = hArray.length;
-
- if (hLength >= 3) {
- h2 = h1 + ">" + hArray[2];
- contentIdMatch = reStandardContentId.test(newUrl);
- if (!contentIdMatch) {
- if (hLength >= 4) {
- h3 = h2 + ">" + hArray[3];
- }
- } else {
- h3 = h2 + ">" + 'articles';
- }
- }
-}
-
-function travel () {
- h1 = hArray[1];
- if (hLength >= 3) {
- h2 = h1 + ">" + hArray[2];
- contentIdMatch = reStandardContentId.test(newUrl);
- if (!contentIdMatch) {
- if (hLength >= 4) {
- h3 = h2 + ">" + hArray[3];
- }
- }
- else {
- h3 = h2 + ">" + 'articles';
- }
- }
-}
-
-function blogs() {
-
- newUrl = newUrl.replace(/\.shtml/g,'\/');
- hArray = newUrl.split("\/");
- hLength = hArray.length;
-
- h1 = hArray[1];
-
- if (hLength >= 3) {
- h2 = h1 + ">" + hArray[2];
- if (hLength >= 4) {
- h3 = h2 + ">" + hArray[3];
- if (hLength >= 5) {
- h4 = h3 + ">" + hArray[4];
- }
- }
- }
-}
-
-function radio() {
- h1 = hArray[1];
-}
-
-
-/*********************************************************************
-* Function p_fo(x,y): Ensures the plugin code is fired only on the
-* first call of do_plugins
-* Returns:
-* - 1 if first instance on firing
-* - 0 if not first instance on firing
-*********************************************************************/
-s.p_fo = new Function("n", ""
-+ "var s=this;if(!s.__fo){s.__fo=new Object;}if(!s.__fo[n]){s.__fo[n]="
-+ "new Object;return 1;}else {return 0;}");
-
-/*
-* Plugin: getValOnce 0.2 - get a value once per session or number of days
-*/
-s.getValOnce = new Function("v", "c", "e", ""
-+ "var s=this,k=s.c_r(c),a=new Date;e=e?e:0;if(v){a.setTime(a.getTime("
-+ ")+e*86400000);s.c_w(c,v,e?a:0);}return v==k?'':v");
-
-/*
-* Plugin Utility: apl v1.1
-*/
-s.apl = new Function("l", "v", "d", "u", ""
-+ "var s=this,m=0;if(!l)l='';if(u){var i,n,a=s.split(l,d);for(i=0;i<a."
-+ "length;i++){n=a[i];m=m||(u==1?(n==v):(n.toLowerCase()==v.toLowerCas"
-+ "e()));}}if(!m)l=l?l+d+v:v;return l");
-
-/*
-* Utility Function: split v1.5 - split a string (JS 1.0 compatible)
-*/
-s.split = new Function("l", "d", ""
-+ "var i,x=0,a=new Array;while(l){i=l.indexOf(d);i=i>-1?i:l.length;a[x"
-+ "++]=l.substring(0,i);l=l.substring(i+d.length);}return a");
-
-/* Utility Function: p_c */
-s.p_c = new Function("v", "c", ""
-+ "var x=v.indexOf('=');return c.toLowerCase()==v.substring(0,x<0?v.le"
-+ "ngth:x).toLowerCase()?v:0");
-
-/*
-* s.join: 1.0 - s.join(v,p)
-*
-* v - Array (may also be array of array)
-* p - formatting parameters (front, back, delim, wrap)
-*
-*/
-s.join = new Function("v", "p", ""
-+ "var s = this;var f,b,d,w;if(p){f=p.front?p.front:'';b=p.back?p.back"
-+ ":'';d=p.delim?p.delim:'';w=p.wrap?p.wrap:'';}var str='';for(var x=0"
-+ ";x<v.length;x++){if(typeof(v[x])=='object' )str+=s.join( v[x],p);el"
-+ "se str+=w+v[x]+w;if(x<v.length-1)str+=d;}return f+str+b;");
-
-/*
-* Plugin Utility: Replace v1.0
-*/
-s.repl = new Function("x", "o", "n", ""
-+ "var i=x.indexOf(o),l=n.length;while(x&&i>=0){x=x.substring(0,i)+n+x."
-+ "substring(i+o.length);i=x.indexOf(o,i+l)}return x");
-
-/*
-* Plugin - trackRefresh v1.1 (requires split utility function)
-*/
-s.trackRefresh = new Function("v", "c", ""
-+ "var s=this,a,t=new Date,x;t.setTime(t.getTime()+1800000);if(!s.c_r("
-+ "c)){s.c_w(c,v,t);return v}else{x=unescape(s.c_r(c));if(x==v){x+='~["
-+ "1]';s.c_w(c,x,0);return x}else{a=s.split(x,'~[');if(a[0]==v){i=pars"
-+ "eInt(a[1])+1;x=a[0]+'~['+i+']';s.c_w(c,x,0);return x}else{s.c_w(c,v"
-+ ",0);return v}}}");
-
-/*
-* Plugin: Visit Number By Month 2.0 - Return the user visit number
-*/
-s.getVisitNum = new Function(""
-+ "var s=this,e=new Date(),cval,cvisit,ct=e.getTime(),c='s_vnum',c2='s"
-+ "_invisit';e.setTime(ct+30*24*60*60*1000);cval=s.c_r(c);if(cval){var"
-+ " i=cval.indexOf('&vn='),str=cval.substring(i+4,cval.length),k;}cvis"
-+ "it=s.c_r(c2);if(cvisit){if(str){e.setTime(ct+30*60*1000);s.c_w(c2,'"
-+ "true',e);return str;}else return 'unknown visit number';}else{if(st"
-+ "r){str++;k=cval.substring(0,i);e.setTime(k);s.c_w(c,k+'&vn='+str,e)"
-+ ";e.setTime(ct+30*60*1000);s.c_w(c2,'true',e);return str;}else{s.c_w"
-+ "(c,ct+30*24*60*60*1000+'&vn=1',e);e.setTime(ct+30*60*1000);s.c_w(c2"
-+ ",'true',e);return 1;}}"
-);
-
-/*
-* Plugin: getTimeToComplete 0.4 - return the time from start to stop
-*/
-s.getTimeToComplete = new Function("v", "cn", "e", ""
-+ "var s=this,d=new Date,x=d,k;if(!s.ttcr){e=e?e:0;if(v=='start'||v=='"
-+ "stop')s.ttcr=1;x.setTime(x.getTime()+e*86400000);if(v=='start'){s.c"
-+ "_w(cn,d.getTime(),e?x:0);return '';}if(v=='stop'){k=s.c_r(cn);if(!s"
-+ ".c_w(cn,'',d)||!k)return '';v=(d.getTime()-k)/1000;var td=86400,th="
-+ "3600,tm=60,r=5,u,un;if(v>td){u=td;un='days';}else if(v>th){u=th;un="
-+ "'hours';}else if(v>tm){r=2;u=tm;un='minutes';}else{r=.2;u=1;un='sec"
-+ "onds';}v=v*r/u;return (Math.round(v)/r)+' '+un;}}return '';");
-
-/*
-* Plugin: Days since last Visit 1.1.H - capture time from last visit
-*/
-s.getDaysSinceLastVisit = new Function("c", ""
-+ "var s=this,e=new Date(),es=new Date(),cval,cval_s,cval_ss,ct=e.getT"
-+ "ime(),day=24*60*60*1000,f1,f2,f3,f4,f5;e.setTime(ct+3*365*day);es.s"
-+ "etTime(ct+30*60*1000);f0='Cookies Not Supported';f1='First Visit';f"
-+ "2='More than 30 days';f3='More than 7 days';f4='Less than 7 days';f"
-+ "5='Less than 1 day';cval=s.c_r(c);if(cval.length==0){s.c_w(c,ct,e);"
-+ "s.c_w(c+'_s',f1,es);}else{var d=ct-cval;if(d>30*60*1000){if(d>30*da"
-+ "y){s.c_w(c,ct,e);s.c_w(c+'_s',f2,es);}else if(d<30*day+1 && d>7*day"
-+ "){s.c_w(c,ct,e);s.c_w(c+'_s',f3,es);}else if(d<7*day+1 && d>day){s."
-+ "c_w(c,ct,e);s.c_w(c+'_s',f4,es);}else if(d<day+1){s.c_w(c,ct,e);s.c"
-+ "_w(c+'_s',f5,es);}}else{s.c_w(c,ct,e);cval_ss=s.c_r(c+'_s');s.c_w(c"
-+ "+'_s',cval_ss,es);}}cval_s=s.c_r(c+'_s');if(cval_s.length==0) retur"
-+ "n f0;else if(cval_s!=f1&&cval_s!=f2&&cval_s!=f3&&cval_s!=f4&&cval_s"
-+ "!=f5) return '';else return cval_s;");
-
-/*
-* Plugin: getNewRepeat 1.0 - Return whether user is new or repeat
-*/
-s.getNewRepeat = new Function(""
-+ "var s=this,e=new Date(),cval,ct=e.getTime(),y=e.getYear();e.setTime"
-+ "(ct+30*24*60*60*1000);cval=s.c_r('s_nr');if(cval.length==0){s.c_w("
-+ "'s_nr',ct,e);return 'New';}if(cval.length!=0&&ct-cval<30*60*1000){s"
-+ ".c_w('s_nr',ct,e);return 'New';}if(cval<1123916400001){e.setTime(cv"
-+ "al+30*24*60*60*1000);s.c_w('s_nr',ct,e);return 'Repeat';}else retur"
-+ "n 'Repeat';");
-
-/*
-* Plugin: getTimeParting 2.0 - Set timeparting values based on time zone
-*/
-s.getTimeParting = new Function("t", "z", ""
-+ "var s=this,cy;dc=new Date('1/1/2000');"
-+ "if(dc.getDay()!=6||dc.getMonth()!=0){return'Data Not Available'}"
-+ "else{;z=parseFloat(z);var dsts=new Date(s.dstStart);"
-+ "var dste=new Date(s.dstEnd);fl=dste;cd=new Date();if(cd>dsts&&cd<fl)"
-+ "{z=z+1}else{z=z};utc=cd.getTime()+(cd.getTimezoneOffset()*60000);"
-+ "tz=new Date(utc + (3600000*z));thisy=tz.getFullYear();"
-+ "var days=['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday',"
-+ "'Saturday'];if(thisy!=s.currentYear){return'Data Not Available'}else{;"
-+ "thish=tz.getHours();thismin=tz.getMinutes();thisd=tz.getDay();"
-+ "var dow=days[thisd];var ap='AM';var dt='Weekday';var mint='00';"
-+ "if(thismin>30){mint='30'}if(thish>=12){ap='PM';thish=thish-12};"
-+ "if (thish==0){thish=12};if(thisd==6||thisd==0){dt='Weekend'};"
-+ "var timestring=thish+':'+mint+ap;if(t=='h'){return timestring}"
-+ "if(t=='d'){return dow};if(t=='w'){return dt}}};");
-
-/*
-* Plugin: getQueryParam 2.3
-*/
-s.getQueryParam = new Function("p", "d", "u", ""
-+ "var s=this,v='',i,t;d=d?d:'';u=u?u:(s.pageURL?s.pageURL:s.wd.locati"
-+ "on);if(u=='f')u=s.gtfs().location;while(p){i=p.indexOf(',');i=i<0?p"
-+ ".length:i;t=s.p_gpv(p.substring(0,i),u+'');if(t){t=t.indexOf('#')>-"
-+ "1?t.substring(0,t.indexOf('#')):t;}if(t)v+=v?d+t:t;p=p.substring(i="
-+ "=p.length?i:i+1)}return v");
-s.p_gpv = new Function("k", "u", ""
-+ "var s=this,v='',i=u.indexOf('?'),q;if(k&&i>-1){q=u.substring(i+1);v"
-+ "=s.pt(q,'&','p_gvf',k)}return v");
-s.p_gvf = new Function("t", "k", ""
-+ "if(t){var s=this,i=t.indexOf('='),p=i<0?t:t.substring(0,i),v=i<0?'T"
-+ "rue':t.substring(i+1);if(p.toLowerCase()==k.toLowerCase())return s."
-+ "epa(v)}return ''");
-
-/*
-* channelManager v2.2 - Tracking External Traffic
-*/
-s.channelManager = new Function("a", "b", "c", "V", ""
-+ "var s=this,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,t,u,v,w,x,y,z,A,B,C,D,E,F,"
-+ "G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,W,X,Y;g=s.referrer?s.referrer:documen"
-+ "t.referrer;g=g.toLowerCase();if(!g){h='1'}i=g.indexOf('?')>-1?g.ind"
-+ "exOf('?'):g.length;j=g.substring(0,i);k=s.linkInternalFilters.toLow"
-+ "erCase();k=s.split(k,',');l=k.length;for(m=0;m<l;m++){n=j.indexOf(k"
-+ "[m])==-1?'':g;if(n)o=n}if(!o&&!h){p=g;q=g.indexOf('//')>-1?g.indexO"
-+ "f('//')+2:0;r=g.indexOf('/',q)>-1?g.indexOf('/',q):i;t=g.substring("
-+ "q,r);t=t.toLowerCase();u=t;P='Referrers';v=s.seList+'>'+s._extraSea"
-+ "rchEngines;if(V=='1'){j=s.repl(j,'oogle','%');j=s.repl(j,'ahoo','^'"
-+ ");g=s.repl(g,'as_q','*');}A=s.split(v,'>');B=A.length;for(C=0;C<B;C"
-+ "++){D=A[C];D=s.split(D,'|');E=s.split(D[0],',');F=E.length;for(G=0;"
-+ "G<F;G++){H=j.indexOf(E[G]);if(H>-1){I=s.split(D[1],',');J=I.length;"
-+ "for(K=0;K<J;K++){L=s.getQueryParam(I[K],'',g);if(L){L=L.toLowerCase"
-+ "();M=L;if(D[2]){u=D[2];N=D[2]}else{N=t}if(V=='1'){N=s.repl(N,'#',' "
-+ "- ');g=s.repl(g,'*','as_q');N=s.repl(N,'^','ahoo');N=s.repl(N,'%','"
-+ "oogle');}}}}}}}O=s.getQueryParam(a,b);if(O){u=O;if(M){P='Paid Searc"
-+ "h'}else{P='Paid Non-Search';}}if(!O&&M){u=N;P='Natural Search'}f=s."
-+ "_channelDomain;if(f){k=s.split(f,'>');l=k.length;for(m=0;m<l;m++){Q"
-+ "=s.split(k[m],'|');R=s.split(Q[1],',');S=R.length;for(T=0;T<S;T++){"
-+ "W=j.indexOf(R[T]);if(W>-1)P=Q[0]}}}d=s._channelParameter;if(d){k=s."
-+ "split(d,'>');l=k.length;for(m=0;m<l;m++){Q=s.split(k[m],'|');R=s.sp"
-+ "lit(Q[1],',');S=R.length;for(T=0;T<S;T++){U=s.getQueryParam(R[T]);i"
-+ "f(U)P=Q[0]}}}e=s._channelPattern;if(e){k=s.split(e,'>');l=k.length;"
-+ "for(m=0;m<l;m++){Q=s.split(k[m],'|');R=s.split(Q[1],',');S=R.length"
-+ ";for(T=0;T<S;T++){X=O.indexOf(R[T]);if(X==0)P=Q[0]}}}if(h=='1'&&!O)"
-+ "{u=P=t=p='Direct Load'}T=M+u+t;U=c?'c':'c_m';if(c!='0'){T=s.getValO"
-+ "nce(T,U,0);}if(T)M=M?M:'n/a';s._referrer=T&&p?p:'';s._referringDoma"
-+ "in=T&&t?t:'';s._partner=T&&N?N:'';s._campaignID=T&&O?O:'';s._campai"
-+ "gn=T&&u?u:'';s._keywords=T&&M?M:'';s._channel=T&&P?P:'';");
-/* Top 130 - Grouped
-s.seList="altavista.co,altavista.de|q,r|AltaVista>.aol.,suche.aolsvc"
-+".de|q,query|AOL>ask.jp,ask.co|q,ask|Ask>www.baidu.com|wd|Baidu>daum"
-+".net,search.daum.net|q|Daum>google.,googlesyndication.com|q,as_q|Go"
-+"ogle>icqit.com|q|icq>bing.com|q|Microsoft Bing>myway.com|searchfor|"
-+"MyWay.com>naver.com,search.naver.com|query|Naver>netscape.com|query"
-+",search|Netscape Search>reference.com|q|Reference.com>seznam|w|Sezn"
-+"am.cz>abcsok.no|q|Startsiden>tiscali.it,www.tiscali.co.uk|key,query"
-+"|Tiscali>virgilio.it|qs|Virgilio>yahoo.com,yahoo.co.jp|p,va|Yahoo!>"
-+"yandex|text|Yandex.ru>search.cnn.com|query|CNN Web Search>search.ea"
-+"rthlink.net|q|Earthlink Search>search.comcast.net|q|Comcast Search>"
-+"search.rr.com|qs|RoadRunner Search>optimum.net|q|Optimum Search";*/
-/* Top 130 */
-s.seList = "altavista.co|q,r|AltaVista>aol.co.uk,search.aol.co.uk|query"
-+ "|AOL - United Kingdom>search.aol.com,search.aol.ca|query,q|AOL.com "
-+ "Search>ask.com,ask.co.uk|ask,q|Ask Jeeves>www.baidu.com|wd|Baidu>da"
-+ "um.net,search.daum.net|q|Daum>google.co,googlesyndication.com|q,as_"
-+ "q|Google>google.com.ar|q,as_q|Google - Argentina>google.com.au|q,as"
-+ "_q|Google - Australia>google.at|q,as_q|Google - Austria>google.com."
-+ "bh|q,as_q|Google - Bahrain>google.com.bd|q,as_q|Google - Bangladesh"
-+ ">google.be|q,as_q|Google - Belgium>google.com.bo|q,as_q|Google - Bo"
-+ "livia>google.ba|q,as_q|Google - Bosnia-Hercegovina>google.com.br|q,"
-+ "as_q|Google - Brasil>google.bg|q,as_q|Google - Bulgaria>google.ca|q"
-+ ",as_q|Google - Canada>google.cl|q,as_q|Google - Chile>google.cn|q,a"
-+ "s_q|Google - China>google.com.co|q,as_q|Google - Colombia>google.co"
-+ ".cr|q,as_q|Google - Costa Rica>google.hr|q,as_q|Google - Croatia>go"
-+ "ogle.cz|q,as_q|Google - Czech Republic>google.dk|q,as_q|Google - De"
-+ "nmark>google.com.do|q,as_q|Google - Dominican Republic>google.com.e"
-+ "c|q,as_q|Google - Ecuador>google.com.eg|q,as_q|Google - Egypt>googl"
-+ "e.com.sv|q,as_q|Google - El Salvador>google.ee|q,as_q|Google - Esto"
-+ "nia>google.fi|q,as_q|Google - Finland>google.fr|q,as_q|Google - Fra"
-+ "nce>google.de|q,as_q|Google - Germany>google.gr|q,as_q|Google - Gre"
-+ "ece>google.com.gt|q,as_q|Google - Guatemala>google.hn|q,as_q|Google"
-+ " - Honduras>google.com.hk|q,as_q|Google - Hong Kong>google.hu|q,as_"
-+ "q|Google - Hungary>google.co.in|q,as_q|Google - India>google.co.id|"
-+ "q,as_q|Google - Indonesia>google.ie|q,as_q|Google - Ireland>google."
-+ "is|q,as_q|Google - Island>google.co.il|q,as_q|Google - Israel>googl"
-+ "e.it|q,as_q|Google - Italy>google.com.jm|q,as_q|Google - Jamaica>go"
-+ "ogle.co.jp|q,as_q|Google - Japan>google.jo|q,as_q|Google - Jordan>g"
-+ "oogle.co.ke|q,as_q|Google - Kenya>google.co.kr|q,as_q|Google - Kore"
-+ "a>google.lv|q,as_q|Google - Latvia>google.lt|q,as_q|Google - Lithua"
-+ "nia>google.com.my|q,as_q|Google - Malaysia>google.com.mt|q,as_q|Goo"
-+ "gle - Malta>google.mu|q,as_q|Google - Mauritius>google.com.mx|q,as_"
-+ "q|Google - Mexico>google.co.ma|q,as_q|Google - Morocco>google.nl|q,"
-+ "as_q|Google - Netherlands>google.co.nz|q,as_q|Google - New Zealand>"
-+ "google.com.ni|q,as_q|Google - Nicaragua>google.com.ng|q,as_q|Google"
-+ " - Nigeria>google.no|q,as_q|Google - Norway>google.com.pk|q,as_q|Go"
-+ "ogle - Pakistan>google.com.py|q,as_q|Google - Paraguay>google.com.p"
-+ "e|q,as_q|Google - Peru>google.com.ph|q,as_q|Google - Philippines>go"
-+ "ogle.pl|q,as_q|Google - Poland>google.pt|q,as_q|Google - Portugal>g"
-+ "oogle.com.pr|q,as_q|Google - Puerto Rico>google.com.qa|q,as_q|Googl"
-+ "e - Qatar>google.ro|q,as_q|Google - Romania>google.ru|q,as_q|Google"
-+ " - Russia>google.st|q,as_q|Google - Sao Tome and Principe>google.co"
-+ "m.sa|q,as_q|Google - Saudi Arabia>google.com.sg|q,as_q|Google - Sin"
-+ "gapore>google.sk|q,as_q|Google - Slovakia>google.si|q,as_q|Google -"
-+ " Slovenia>google.co.za|q,as_q|Google - South Africa>google.es|q,as_"
-+ "q|Google - Spain>google.lk|q,as_q|Google - Sri Lanka>google.se|q,as"
-+ "_q|Google - Sweden>google.ch|q,as_q|Google - Switzerland>google.com"
-+ ".tw|q,as_q|Google - Taiwan>google.co.th|q,as_q|Google - Thailand>go"
-+ "ogle.bs|q,as_q|Google - The Bahamas>google.tt|q,as_q|Google - Trini"
-+ "dad and Tobago>google.com.tr|q,as_q|Google - Turkey>google.com.ua|q"
-+ ",as_q|Google - Ukraine>google.ae|q,as_q|Google - United Arab Emirat"
-+ "es>google.co.uk|q,as_q|Google - United Kingdom>google.com.uy|q,as_q"
-+ "|Google - Uruguay>google.co.ve|q,as_q|Google - Venezuela>google.com"
-+ ".vn|q,as_q|Google - Viet Nam>google.co.vi|q,as_q|Google - Virgin Is"
-+ "lands>icqit.com|q|icq>bing.com|q|Microsoft Bing>myway.com|searchfor"
-+ "|MyWay.com>naver.com,search.naver.com|query|Naver>netscape.com|quer"
-+ "y,search|Netscape Search>reference.com|q|Reference.com>seznam|w|Sez"
-+ "nam.cz>abcsok.no|q|Startsiden>tiscali.it|key|Tiscali>virgilio.it|qs"
-+ "|Virgilio>yahoo.com,search.yahoo.com|p|Yahoo!>ar.yahoo.com,ar.searc"
-+ "h.yahoo.com|p|Yahoo! - Argentina>au.yahoo.com,au.search.yahoo.com|p"
-+ "|Yahoo! - Australia>ca.yahoo.com,ca.search.yahoo.com|p|Yahoo! - Can"
-+ "ada>fr.yahoo.com,fr.search.yahoo.com|p|Yahoo! - France>de.yahoo.com"
-+ ",de.search.yahoo.com|p|Yahoo! - Germany>hk.yahoo.com,hk.search.yaho"
-+ "o.com|p|Yahoo! - Hong Kong>in.yahoo.com,in.search.yahoo.com|p|Yahoo"
-+ "! - India>yahoo.co.jp,search.yahoo.co.jp|p,va|Yahoo! - Japan>kr.yah"
-+ "oo.com,kr.search.yahoo.com|p|Yahoo! - Korea>mx.yahoo.com,mx.search."
-+ "yahoo.com|p|Yahoo! - Mexico>ph.yahoo.com,ph.search.yahoo.com|p|Yaho"
-+ "o! - Philippines>sg.yahoo.com,sg.search.yahoo.com|p|Yahoo! - Singap"
-+ "ore>es.yahoo.com,es.search.yahoo.com|p|Yahoo! - Spain>telemundo.yah"
-+ "oo.com,espanol.search.yahoo.com|p|Yahoo! - Spanish (US : Telemundo)"
-+ ">tw.yahoo.com,tw.search.yahoo.com|p|Yahoo! - Taiwan>uk.yahoo.com,uk"
-+ ".search.yahoo.com|p|Yahoo! - UK and Ireland>yandex|text|Yandex.ru>s"
-+ "earch.cnn.com|query|CNN Web Search>search.earthlink.net|q|Earthlink"
-+ " Search>search.comcast.net|q|Comcast Search>search.rr.com|qs|RoadRu"
-+ "nner Search>optimum.net|q|Optimum Search";
-
-/*
-* Plug-in: crossVisitParticipation v1.6 - stacks values from
-* specified variable in cookie and returns value
-*/
-s.crossVisitParticipation = new Function("v", "cn", "ex", "ct", "dl", "ev", "dv", ""
-+ "var s=this,ce;if(typeof(dv)==='undefined')dv=0;if(s.events&&ev){var"
-+ " ay=s.split(ev,',');var ea=s.split(s.events,',');for(var u=0;u<ay.l"
-+ "ength;u++){for(var x=0;x<ea.length;x++){if(ay[u]==ea[x]){ce=1;}}}}i"
-+ "f(!v||v==''){if(ce){s.c_w(cn,'');return'';}else return'';}v=escape("
-+ "v);var arry=new Array(),a=new Array(),c=s.c_r(cn),g=0,h=new Array()"
-+ ";if(c&&c!='')arry=eval(c);var e=new Date();e.setFullYear(e.getFullY"
-+ "ear()+5);if(dv==0&&arry.length>0&&arry[arry.length-1][0]==v)arry[ar"
-+ "ry.length-1]=[v,new Date().getTime()];else arry[arry.length]=[v,new"
-+ " Date().getTime()];var start=arry.length-ct<0?0:arry.length-ct;var "
-+ "td=new Date();for(var x=start;x<arry.length;x++){var diff=Math.roun"
-+ "d((td.getTime()-arry[x][1])/86400000);if(diff<ex){h[g]=unescape(arr"
-+ "y[x][0]);a[g]=[arry[x][0],arry[x][1]];g++;}}var data=s.join(a,{deli"
-+ "m:',',front:'[',back:']',wrap:\"'\"});s.c_w(cn,data,e);var r=s.join"
-+ "(h,{delim:dl});if(ce)s.c_w(cn,'');return r;");
-
-
-/* Configure Modules and Plugins */
-
-s.loaddisabledModule("Media")
-s.Media.autoTrack = false
-s.Media.playerName = "EMP"
-s.Media.trackVars = "eVar21,events,eVar22,eVar23,eVar24";
-
-s.Media.trackWhilePlaying=true;
-s.Media.trackMilestones="25,50,75";
-
-// Set up variables to fake ad request
-s.playUndefinedMovie = 0;
-s.stopUndefinedMovie = 0;
-
-// Used to make sure each videos events are only tracked once
-s.eventsTracked = {};
-s.liveStreamTracked = false;
-
-s.Media.monitor = function (s, obj) {//Use this code with either JavaScript or Flash.
- // eVar1 = Media Name
- // event3 = Movie Starts
- // event4 = Ad Plays
- // event5 = Ad Stops
- // event6 = Content Plays
- // event7 = Content Stops
- // event8 = Movie Ends
-
- if (obj.mediaEvent == "adPlay" && !s.eventsTracked[obj.mediaName].event4) { //Executes when the video voids.
- s.Media.trackVars = "eVar21,events,eVar22,eVar23,eVar24";
- s.Media.trackEvents = "event4";
- s.events="event4";
- s.Media.track(obj.mediaName);
- s.eventsTracked[obj.mediaName].event4 = true;
- } else if (obj.mediaEvent == "adStop" && !s.eventsTracked[obj.mediaName].event5) { //Executes when the video ad stops.
- s.Media.trackVars = "eVar21,events,eVar22,eVar23,eVar24";
- s.Media.trackEvents = "event5";
- s.events="event5";
- s.Media.track(obj.mediaName);
- s.eventsTracked[obj.mediaName].event5 = true;
- } else if (obj.mediaEvent == "contentPlay" && !s.eventsTracked[obj.mediaName].event6) { //Executes when the voids.
- s.Media.trackVars = "eVar21,events,eVar22,eVar23,eVar24";
- s.Media.trackEvents = "event6";
- s.events="event6";
- s.Media.track(obj.mediaName);
- s.eventsTracked[obj.mediaName].event6 = true;
- } else if (obj.mediaEvent == "contentStop" && !s.eventsTracked[obj.mediaName].event7) { //Executes when the video stops.
- s.Media.trackVars = "eVar21,events,eVar22,eVar23,eVar24";
- s.Media.trackEvents = "event7";
- s.events="event7";
- s.Media.track(obj.mediaName);
- s.eventsTracked[obj.mediaName].event7 = true;
- } else if (obj.mediaEvent == "movieEnd" && !s.eventsTracked[obj.mediaName].event8) { //Executes when the playlist ends.
- s.Media.trackVars = "eVar21,events,eVar22,eVar23,eVar24";
- s.Media.trackEvents = "event8";
- s.events="event8";
- s.Media.track(obj.mediaName);
- s.eventsTracked[obj.mediaName].event8 = true;
- }
-};
-
-function setProperties (obj){
- s.prop21 = obj.mediaName;
- s.prop22 = obj.mediaType;
- s.prop23 = obj.mediaId;
- s.prop24 = obj.adId;
- s.eVar21 = s.prop21;
- s.eVar22= s.prop22;
- s.eVar23= s.prop23;
- s.eVar24= s.prop24;
-}
-
-/*
- * Faking the ad if three undefined movieTypes played with this method
- */
-function playStopAd(obj) {
- // Faking the adPlay for EMP 10.17
- // monitor is used to fire events
- obj.mediaEvent = 'adPlay';
- s.Media.monitor(s, obj);
- // Faking the adStop for EMP 10.17
- // monitor is used to fire events
- obj.mediaEvent = 'adStop';
- s.Media.monitor(s, obj);
-}
-
-function startMovie(obj) {
-
- setProperties(obj);
-
- // This videos tracked obj
- if ('undefined' == typeof(s.eventsTracked[obj.mediaName])) {
- s.eventsTracked[obj.mediaName] = {
- event3: false,
- event4: false,
- event5: false,
- event6: false,
- event7: false,
- event8: false
- };
- }
-
- if (!s.eventsTracked[obj.mediaName].event3) { //Executes when the playlist starts.
- s.Media.trackVars = "eVar21,events,eVar22,eVar23,eVar24";
- s.Media.trackEvents = "event3";
- s.events="event3";
- s.void(obj.mediaName, obj.mediaLength, obj.mediaPlayerName);
- s.eventsTracked[obj.mediaName].event3 = true;
- }
-
-
- //s.Media.monitor(s, obj);
- // Removing this for the moment as there is always at least a one second ad
- /*
- // 1st playUndefinedMovie - We called play but passed to AS3
- // 2nd playUndefinedMovie - We called play on ident
- // 1st stopUndefinedMovie - We called stop on ident
- if(2 == s.playUndefinedMovie && 1 == s.stopUndefinedMovie) {
- playStopAd(obj);
- }
- */
-
-}
-
-function playMovie(obj) {
- // Not used for live streams
- if('programme' == obj.mediaType && -1 !== obj.mediaLength) {
- obj.mediaEvent = 'contentPlay';
- setProperties(obj);
- s.Media.play(obj.mediaName, obj.mediaOffset);
- s.Media.monitor(s, obj);
- }
-}
-
-function stopMovie(obj) {
- if(undefined == obj.mediaType || 'undefined' == obj.mediaType || '' == obj.mediaType) {
- s.stopUndefinedMovie += 1;
- } else if('programme' == obj.mediaType) {
- obj.mediaEvent = 'contentStop';
- setProperties(obj);
- s.Media.stop(obj.mediaName, obj.mediaOffset);
- s.Media.monitor(s, obj);
- }
-}
-
-function endMovie(obj) {
- obj.mediaEvent = 'movieEnd';
- setProperties(obj);
- s.Media.monitor(s, obj);
- s.Media.close(obj.mediaName);
-}
-
-/* WARNING: Changing any of the below variables will cause drastic
-changes to how your visitor data is collected. Changes should only be
-made when instructed to do so by your account manager.*/
-s.trackingServer="bbc.112.2o7.net"
-
-/****************************** MODULES *****************************/
-/* Module: Media */
-s.m_Media_c="var m=s.m_i('Media');m.cn=function(n){var m=this;return m.s.rep(m.s.rep(m.s.rep(n,\"\\n\",''),\"\\r\",''),'--**--','')};void=function(n,l,p,b){var m=this,i=new Object,tm=new Date,a='',"
-+"x;n=m.cn(n);l=parseInt(l);if(!l)l=1;if(n&&p){if(!m.l)m.l=new Object;if(m.l[n])m.close(n);if(b&&b.id)a=b.id;for (x in m.l)if(m.l[x]&&m.l[x].a==a)m.close(m.l[x].n);i.n=n;i.l=l;i.p=m.cn(p);i.a=a;i.t=0"
-+";i.ts=0;i.s=Math.floor(tm.getTime()/1000);i.lx=0;i.lt=i.s;i.lo=0;i.e='';i.to=-1;m.l[n]=i}};m.close=function(n){this.e(n,0,-1)};m.play=function(n,o){var m=this,i;i=m.e(n,1,o);i.m=new Function('var m"
-+"=s_c_il['+m._in+'],i;if(m.l){i=m.l[\"'+m.s.rep(i.n,'\"','\\\\\"')+'\"];if(i){if(i.lx==1)m.e(i.n,3,-1);i.mt=setTimeout(i.m,5000)}}');i.m()};m.stop=function(n,o){this.e(n,2,o)};m.track=function(n){va"
-+"r m=this;if (m.trackWhilePlaying) {m.e(n,4,-1)}};m.e=function(n,x,o){var m=this,i,tm=new Date,ts=Math.floor(tm.getTime()/1000),ti=m.trackSeconds,tp=m.trackMilestones,z=new Array,j,d='--**--',t=1,b,"
-+"v=m.trackVars,e=m.trackEvents,pe='media',pev3,w=new Object,vo=new Object;n=m.cn(n);i=n&&m.l&&m.l[n]?m.l[n]:0;if(i){w.name=n;w.length=i.l;w.playerName=i.p;if(i.to<0)w.event=\"OPEN\";else w.event=(x="
-+"=1?\"PLAY\":(x==2?\"STOP\":(x==3?\"MONITOR\":\"CLOSE\")));voidTime=new Date();voidTime.setTime(i.s*1000);if(x>2||(x!=i.lx&&(x!=2||i.lx==1))) {b=\"Media.\"+name;pev3 = m.s.ape(i.n)+d+i.l+d+m.s.a"
-+"pe(i.p)+d;if(x){if(o<0&&i.lt>0){o=(ts-i.lt)+i.lo;o=o<i.l?o:i.l-1}o=Math.floor(o);if(x>=2&&i.lo<o){i.t+=o-i.lo;i.ts+=o-i.lo;}if(x<=2){i.e+=(x==1?'S':'E')+o;i.lx=x;}else if(i.lx!=1)m.e(n,1,o);i.lt=ts"
-+";i.lo=o;pev3+=i.t+d+i.s+d+(m.trackWhilePlaying&&i.to>=0?'L'+i.to:'')+i.e+(x!=2?(m.trackWhilePlaying?'L':'E')+o:'');if(m.trackWhilePlaying){b=0;pe='m_o';if(x!=4){w.offset=o;w.percent=((w.offset+1)/w"
-+".length)*100;w.percent=w.percent>100?100:Math.floor(w.percent);w.timePlayed=i.t;if(m.monitor)m.monitor(m.s,w)}if(i.to<0)pe='m_s';else if(x==4)pe='m_i';else{t=0;v=e='None';ti=ti?parseInt(ti):0;z=tp?"
-+"m.s.sp(tp,','):0;if(ti&&i.ts>=ti)t=1;else if(z){if(o<i.to)i.to=o;else{for(j=0;j<z.length;j++){ti=z[j]?parseInt(z[j]):0;if(ti&&((i.to+1)/i.l<ti/100)&&((o+1)/i.l>=ti/100)){t=1;j=z.length}}}}}}}else{m"
-+".e(n,2,-1);if(m.trackWhilePlaying){w.offset=i.lo;w.percent=((w.offset+1)/w.length)*100;w.percent=w.percent>100?100:Math.floor(w.percent);w.timePlayed=i.t;if(m.monitor)m.monitor(m.s,w)}m.l[n]=0;if(i"
-+".e){pev3+=i.t+d+i.s+d+(m.trackWhilePlaying&&i.to>=0?'L'+i.to:'')+i.e;if(m.trackWhilePlaying){v=e='None';pe='m_o'}else{t=0;m.s.fbr(b)}}else t=0;b=0}if(t){vo.linkTrackVars=v;vo.linkTrackEvents=e;vo.p"
-+"e=pe;vo.pev3=pev3;m.s.t(vo,b);if(m.trackWhilePlaying){i.ts=0;i.to=o;i.e=''}}}}return i};m.ae=function(n,l,p,x,o,b){if(n&&p){var m=this;if(!m.l||!m.l[n])void(n,l,p,b);m.e(n,x,o)}};m.a=function(o,t"
-+"){var m=this,i=o.id?o.id:o.name,n=o.name,p=0,v,c,c1,c2,xc=m.s.h,x,e,f1,f2='s_media_'+m._in+'_oc',f3='s_media_'+m._in+'_t',f4='s_media_'+m._in+'_s',f5='s_media_'+m._in+'_l',f6='s_media_'+m._in+'_m',"
-+"f7='s_media_'+m._in+'_c',tcf,w;if(!i){if(!m.c)m.c=0;i='s_media_'+m._in+'_'+m.c;m.c++}if(!o.id)o.id=i;if(!o.name)o.name=n=i;if(!m.ol)m.ol=new Object;if(m.ol[i])return;m.ol[i]=o;if(!xc)xc=m.s.b;tcf=n"
-+"ew Function('o','var e,p=0;try{if(o.versionInfo&&o.currentMedia&&o.controls)p=1}catch(e){p=0}return p');p=tcf(o);if(!p){tcf=new Function('o','var e,p=0,t;try{t=o.GetQuickTimeVersion();if(t)p=2}catc"
-+"h(e){p=0}return p');p=tcf(o);if(!p){tcf=new Function('o','var e,p=0,t;try{t=o.GetVersionInfo();if(t)p=3}catch(e){p=0}return p');p=tcf(o)}}v=\"var m=s_c_il[\"+m._in+\"],o=m.ol['\"+i+\"']\";if(p==1){"
-+"p='Windows Media Player '+o.versionInfo;c1=v+',n,p,l,x=-1,cm,c,mn;if(o){cm=o.currentMedia;c=o.controls;if(cm&&c){mn=cm.name?cm.name:c.URL;l=cm.duration;p=c.currentPosition;n=o.playState;if(n){if(n="
-+"=8)x=0;if(n==3)x=1;if(n==1||n==2||n==4||n==5||n==6)x=2;}';c2='if(x>=0)m.ae(mn,l,\"'+p+'\",x,x!=2?p:-1,o)}}';c=c1+c2;if(m.s.isie&&xc){x=m.s.d.createElement('script');x.language='jscript';x.type='tex"
-+"t/javascript';x.htmlFor=i;x.event='PlayStateChange(NewState)';x.defer=true;x.text=c;xc.appendChild(x);o[f6]=new Function(c1+'if(n==3){x=3;'+c2+'}setTimeout(o.'+f6+',5000)');o[f6]()}}if(p==2){p='Qui"
-+"ckTime Player '+(o.GetIsQuickTimeRegistered()?'Pro ':'')+o.GetQuickTimeVersion();f1=f2;c=v+',n,x,t,l,p,p2,mn;if(o){mn=o.GetMovieName()?o.GetMovieName():o.GetURL();n=o.GetRate();t=o.GetTimeScale();l"
-+"=o.GetDuration()/t;p=o.GetTime()/t;p2=o.'+f5+';if(n!=o.'+f4+'||p<p2||p-p2>5){x=2;if(n!=0)x=1;else if(p>=l)x=0;if(p<p2||p-p2>5)m.ae(mn,l,\"'+p+'\",2,p2,o);m.ae(mn,l,\"'+p+'\",x,x!=2?p:-1,o)}if(n>0&&"
-+"o.'+f7+'>=10){m.ae(mn,l,\"'+p+'\",3,p,o);o.'+f7+'=0}o.'+f7+'++;o.'+f4+'=n;o.'+f5+'=p;setTimeout(\"'+v+';o.'+f2+'(0,0)\",500)}';o[f1]=new Function('a','b',c);o[f4]=-1;o[f7]=0;o[f1](0,0)}if(p==3){p='"
-+"RealPlayer '+o.GetVersionInfo();f1=n+'_OnPlayStateChange';c1=v+',n,x=-1,l,p,mn;if(o){mn=o.GetTitle()?o.GetTitle():o.GetSource();n=o.GetPlayState();l=o.GetLength()/1000;p=o.GetPosition()/1000;if(n!="
-+"o.'+f4+'){if(n==3)x=1;if(n==0||n==2||n==4||n==5)x=2;if(n==0&&(p>=l||p==0))x=0;if(x>=0)m.ae(mn,l,\"'+p+'\",x,x!=2?p:-1,o)}if(n==3&&(o.'+f7+'>=10||!o.'+f3+')){m.ae(mn,l,\"'+p+'\",3,p,o);o.'+f7+'=0}o."
-+"'+f7+'++;o.'+f4+'=n;';c2='if(o.'+f2+')o.'+f2+'(o,n)}';if(m.s.wd[f1])o[f2]=m.s.wd[f1];m.s.wd[f1]=new Function('a','b',c1+c2);o[f1]=new Function('a','b',c1+'setTimeout(\"'+v+';o.'+f1+'(0,0)\",o.'+f3+"
-+"'?500:5000);'+c2);o[f4]=-1;if(m.s.isie)o[f3]=1;o[f7]=0;o[f1](0,0)}};m.as=new Function('e','var m=s_c_il['+m._in+'],l,n;if(m.autoTrack&&m.s.d.getElementsByTagName){l=m.s.d.getElementsByTagName(m.s.i"
-+"sie?\"OBJECT\":\"EMBED\");if(l)for(n=0;n<l.length;n++)m.a(l[n]);}');if(s.wd.attachEvent)s.wd.attachEvent('onloaddisabled',m.as);else if(s.wd.addEventListener)s.wd.addEventListener('loaddisabled',m.as,false)";
-s.m_i("Media");
-
-
-/************* DO NOT ALTER ANYTHING BELOW THIS LINE ! **************/
-var s_code='',s_objectID;function s_gi(un,pg,ss){var c="s._c='s_c';s.wd=window;if(!s.wd.s_c_in){s.wd.s_c_il=new Array;s.wd.s_c_in=0;}s._il=s.wd.s_c_il;s._in=s.wd.s_c_in;s._il[s._in]=s;s.wd.s_c_in++;s"
-+".an=s_an;s.cls=function(x,c){var i,y='';if(!c)c=this.an;for(i=0;i<x.length;i++){n=x.substring(i,i+1);if(c.indexOf(n)>=0)y+=n}return y};s.fl=function(x,l){return x?(''+x).substring(0,l):x};s.co=func"
-+"tion(o){if(!o)return o;var n=new Object,x;for(x in o)if(x.indexOf('select')<0&&x.indexOf('filter')<0)n[x]=o[x];return n};s.num=function(x){x=''+x;for(var p=0;p<x.length;p++)if(('0123456789').indexO"
-+"f(x.substring(p,p+1))<0)return 0;return 1};s.rep=s_rep;s.sp=s_sp;s.jn=s_jn;s.ape=function(x){var s=this,h='0123456789ABCDEF',i,c=s.charSet,n,l,e,y='';c=c?c.toUpperCase():'';if(x){x=''+x;if(s.em==3)"
-+"return encodeURIComponent(x);else if(c=='AUTO'&&('').charCodeAt){for(i=0;i<x.length;i++){c=x.substring(i,i+1);n=x.charCodeAt(i);if(n>127){l=0;e='';while(n||l<4){e=h.substring(n%16,n%16+1)+e;n=(n-n%"
-+"16)/16;l++}y+='%u'+e}else if(c=='+')y+='%2B';else y+=escape(c)}return y}else{x=s.rep(escape(''+x),'+','%2B');if(c&&s.em==1&&x.indexOf('%u')<0&&x.indexOf('%U')<0){i=x.indexOf('%');while(i>=0){i++;if"
-+"(h.substring(8).indexOf(x.substring(i,i+1).toUpperCase())>=0)return x.substring(0,i)+'u00'+x.substring(i);i=x.indexOf('%',i)}}}}return x};s.epa=function(x){var s=this;if(x){x=''+x;return s.em==3?de"
-+"codeURIComponent(x):unescape(s.rep(x,'+',' '))}return x};s.pt=function(x,d,f,a){var s=this,t=x,z=0,y,r;while(t){y=t.indexOf(d);y=y<0?t.length:y;t=t.substring(0,y);r=s[f](t,a);if(r)return r;z+=y+d.l"
-+"ength;t=x.substring(z,x.length);t=z<x.length?t:''}return ''};s.isf=function(t,a){var c=a.indexOf(':');if(c>=0)a=a.substring(0,c);if(t.substring(0,2)=='s_')t=t.substring(2);return (t!=''&&t==a)};s.f"
-+"sf=function(t,a){var s=this;if(s.pt(a,',','isf',t))s.fsg+=(s.fsg!=''?',':'')+t;return 0};s.fs=function(x,f){var s=this;s.fsg='';s.pt(x,',','fsf',f);return s.fsg};s.si=function(){var s=this,i,k,v,c="
-+"s_gi+'var s=s_gi(\"'+s.oun+'\");s.sa(\"'+s.un+'\");';for(i=0;i<s.va_g.length;i++){k=s.va_g[i];v=s[k];if(v!=undefined){if(typeof(v)=='string')c+='s.'+k+'=\"'+s_fe(v)+'\";';else c+='s.'+k+'='+v+';'}}"
-+"c+=\"s.lnk=s.eo=s.linkName=s.linkType=s.wd.s_objectID=s.ppu=s.pe=s.pev1=s.pev2=s.pev3='';\";return c};s.c_d='';s.c_gdf=function(t,a){var s=this;if(!s.num(t))return 1;return 0};s.c_gd=function(){var"
-+" s=this,d=s.wd.location.hostname,n=s.fpCookieDomainPeriods,p;if(!n)n=s.cookieDomainPeriods;if(d&&!s.c_d){n=n?parseInt(n):2;n=n>2?n:2;p=d.lastIndexOf('.');if(p>=0){while(p>=0&&n>1){p=d.lastIndexOf('"
-+".',p-1);n--}s.c_d=p>0&&s.pt(d,'.','c_gdf',0)?d.substring(p):d}}return s.c_d};s.c_r=function(k){var s=this;k=s.ape(k);var c=' '+s.d.cookie,i=c.indexOf(' '+k+'='),e=i<0?i:c.indexOf(';',i),v=i<0?'':s."
-+"epa(c.substring(i+2+k.length,e<0?c.length:e));return v!='[[B]]'?v:''};s.c_w=function(k,v,e){var s=this,d=s.c_gd(),l=s.cookieLifetime,t;v=''+v;l=l?(''+l).toUpperCase():'';if(e&&l!='SESSION'&&l!='NON"
-+"E'){t=(v!=''?parseInt(l?l:0):-60);if(t){e=new Date;e.setTime(e.getTime()+(t*1000))}}if(k&&l!='NONE'){s.d.cookie=k+'='+s.ape(v!=''?v:'[[B]]')+'; path=/;'+(e&&l!='SESSION'?' expires='+e.toGMTString()"
-+"+';':'')+(d?' domain='+d+';':'');return s.c_r(k)==v}return 0};s.eh=function(o,e,r,f){var s=this,b='s_'+e+'_'+s._in,n=-1,l,i,x;if(!s.ehl)s.ehl=new Array;l=s.ehl;for(i=0;i<l.length&&n<0;i++){if(l[i]."
-+"o==o&&l[i].e==e)n=i}if(n<0){n=i;l[n]=new Object}x=l[n];x.o=o;x.e=e;f=r?x.b:f;if(r||f){x.b=r?0:o[e];x.o[e]=f}if(x.b){x.o[b]=x.b;return b}return 0};s.cet=function(f,a,t,o,b){var s=this,r,tcf;if(s.apv"
-+">=5&&(!s.isopera||s.apv>=7)){tcf=new Function('s','f','a','t','var e,r;try{r=s[f](a)}catch(e){r=s[t](e)}return r');r=tcf(s,f,a,t)}else{if(s.ismac&&s.u.indexOf('MSIE 4')>=0)r=s[b](a);else{s.eh(s.wd,"
-+"'onerror',0,o);r=s[f](a);s.eh(s.wd,'onerror',1)}}return r};s.gtfset=function(e){var s=this;return s.tfs};s.gtfsoe=new Function('e','var s=s_c_il['+s._in+'],c;s.eh(window,\"onerror\",1);s.etfs=1;c=s"
-+".t();if(c)s.void(c);s.etfs=0;return true');s.gtfsfb=function(a){return window};s.gtfsf=function(w){var s=this,p=w.parent,l=w.location;s.tfs=w;if(p&&p.location!=l&&p.location.host==l.host){s.tfs="
-+"p;return s.gtfsf(s.tfs)}return s.tfs};s.gtfs=function(){var s=this;if(!s.tfs){s.tfs=s.wd;if(!s.etfs)s.tfs=s.cet('gtfsf',s.tfs,'gtfset',s.gtfsoe,'gtfsfb')}return s.tfs};s.mrq=function(u){var s=this,"
-+"l=s.rl[u],n,r;s.rl[u]=0;if(l)for(n=0;n<l.length;n++){r=l[n];s.mr(0,0,r.r,0,r.t,r.u)}};s.br=function(id,rs){var s=this;if(s.disableBufferedRequests||!s.c_w('s_br',rs))s.brl=rs};s.flushBufferedReques"
-+"ts=function(){this.fbr(0)};s.fbr=function(id){var s=this,br=s.c_r('s_br');if(!br)br=s.brl;if(br){if(!s.disableBufferedRequests)s.c_w('s_br','');s.mr(0,0,br)}s.brl=0};s.mr=function(sess,q,rs,id,ta,u"
-+"){var s=this,dc=s.dc,t1=s.trackingServer,t2=s.trackingServerSecure,tb=s.trackingServerBase,p='.sc',ns=s.visitorNamespace,un=s.cls(u?u:(ns?ns:s.fun)),r=new Object,l,imn='s_i_'+(un),im,b,e;if(!rs){if"
-+"(t1){if(t2&&s.ssl)t1=t2}else{if(!tb)tb='2o7.net';if(dc)dc=(''+dc).toLowerCase();else dc='d1';if(tb=='2o7.net'){if(dc=='d1')dc='112';else if(dc=='d2')dc='122';p=''}t1=un+'.'+dc+'.'+p+tb}rs='http'+(s"
-+".ssl?'s':'')+'://'+t1+'/b/ss/'+s.un+'/'+(s.mobile?'5.1':'1')+'/H.22.1/'+sess+'?AQB=1&ndh=1'+(q?q:'')+'&AQE=1';if(s.isie&&!s.ismac)rs=s.fl(rs,2047);if(id){s.br(id,rs);return}}if(s.d.images&&s.apv>=3"
-+"&&(!s.isopera||s.apv>=7)&&(s.ns6<0||s.apv>=6.1)){if(!s.rc)s.rc=new Object;if(!s.rc[un]){s.rc[un]=1;if(!s.rl)s.rl=new Object;s.rl[un]=new Array;setTimeout('if(window.s_c_il)window.s_c_il['+s._in+']."
-+"mrq(\"'+un+'\")',750)}else{l=s.rl[un];if(l){r.t=ta;r.u=un;r.r=rs;l[l.length]=r;return ''}imn+='_'+s.rc[un];s.rc[un]++}im=s.wd[imn];if(!im)im=s.wd[imn]=new Image;im.s_l=0;im.onloaddisabled=new Function('e',"
-+"'this.s_l=1;var wd=window,s;if(wd.s_c_il){s=wd.s_c_il['+s._in+'];s.mrq(\"'+un+'\");s.nrs--;if(!s.nrs)s.m_m(\"rr\")}');if(!s.nrs){s.nrs=1;s.m_m('rs')}else s.nrs++;im.src=rs;if((!ta||ta=='_self'||ta="
-+"='_top'||(s.wd.name&&ta==s.wd.name))&&rs.indexOf('&pe=')>=0){b=e=new Date;while(!im.s_l&&e.getTime()-b.getTime()<500)e=new Date}return ''}return '<im'+'g sr'+'c=\"'+rs+'\" width=1 height=1 border=0"
-+" alt=\"\">'};s.gg=function(v){var s=this;if(!s.wd['s_'+v])s.wd['s_'+v]='';return s.wd['s_'+v]};s.glf=function(t,a){if(t.substring(0,2)=='s_')t=t.substring(2);var s=this,v=s.gg(t);if(v)s[t]=v};s.gl="
-+"function(v){var s=this;if(s.pg)s.pt(v,',','glf',0)};s.rf=function(x){var s=this,y,i,j,h,l,a,b='',c='',t;if(x){y=''+x;i=y.indexOf('?');if(i>0){a=y.substring(i+1);y=y.substring(0,i);h=y.toLowerCase()"
-+";i=0;if(h.substring(0,7)=='http://')i+=7;else if(h.substring(0,8)=='https://')i+=8;h=h.substring(i);i=h.indexOf(\"/\");if(i>0){h=h.substring(0,i);if(h.indexOf('google')>=0){a=s.sp(a,'&');if(a.lengt"
-+"h>1){l=',q,ie,start,search_key,word,kw,cd,';for(j=0;j<a.length;j++){t=a[j];i=t.indexOf('=');if(i>0&&l.indexOf(','+t.substring(0,i)+',')>=0)b+=(b?'&':'')+t;else c+=(c?'&':'')+t}if(b&&c){y+='?'+b+'&'"
-+"+c;if(''+x!=y)x=y}}}}}}return x};s.hav=function(){var s=this,qs='',fv=s.linkTrackVars,fe=s.linkTrackEvents,mn,i;if(s.pe){mn=s.pe.substring(0,1).toUpperCase()+s.pe.substring(1);if(s[mn]){fv=s[mn].tr"
-+"ackVars;fe=s[mn].trackEvents}}fv=fv?fv+','+s.vl_l+','+s.vl_l2:'';for(i=0;i<s.va_t.length;i++){var k=s.va_t[i],v=s[k],b=k.substring(0,4),x=k.substring(4),n=parseInt(x),q=k;if(v&&k!='linkName'&&k!='l"
-+"inkType'){if(s.pe||s.lnk||s.eo){if(fv&&(','+fv+',').indexOf(','+k+',')<0)v='';if(k=='events'&&fe)v=s.fs(v,fe)}if(v){if(k=='dynamicVariablePrefix')q='D';else if(k=='visitorID')q='vid';else if(k=='pa"
-+"geURL'){q='g';v=s.fl(v,255)}else if(k=='referrer'){q='r';v=s.fl(s.rf(v),255)}else if(k=='vmk'||k=='visitorMigrationKey')q='vmt';else if(k=='visitorMigrationServer'){q='vmf';if(s.ssl&&s.visitorMigra"
-+"tionServerSecure)v=''}else if(k=='visitorMigrationServerSecure'){q='vmf';if(!s.ssl&&s.visitorMigrationServer)v=''}else if(k=='charSet'){q='ce';if(v.toUpperCase()=='AUTO')v='ISO8859-1';else if(s.em="
-+"=2||s.em==3)v='UTF-8'}else if(k=='visitorNamespace')q='ns';else if(k=='cookieDomainPeriods')q='cdp';else if(k=='cookieLifetime')q='cl';else if(k=='variableProvider')q='vvp';else if(k=='currencyCode"
-+"')q='cc';else if(k=='channel')q='ch';else if(k=='transactionID')q='xact';else if(k=='campaign')q='v0';else if(k=='resolution')q='s';else if(k=='colorDepth')q='c';else if(k=='javascriptVersion')q='j"
-+"';else if(k=='javaEnabled')q='v';else if(k=='cookiesEnabled')q='k';else if(k=='browserWidth')q='bw';else if(k=='browserHeight')q='bh';else if(k=='connectionType')q='ct';else if(k=='homepage')q='hp'"
-+";else if(k=='plugins')q='p';else if(s.num(x)){if(b=='prop')q='c'+n;else if(b=='eVar')q='v'+n;else if(b=='list')q='l'+n;else if(b=='hier'){q='h'+n;v=s.fl(v,255)}}if(v)qs+='&'+q+'='+(k.substring(0,3)"
-+"!='pev'?s.ape(v):v)}}}return qs};s.ltdf=function(t,h){t=t?t.toLowerCase():'';h=h?h.toLowerCase():'';var qi=h.indexOf('?');h=qi>=0?h.substring(0,qi):h;if(t&&h.substring(h.length-(t.length+1))=='.'+t"
-+")return 1;return 0};s.ltef=function(t,h){t=t?t.toLowerCase():'';h=h?h.toLowerCase():'';if(t&&h.indexOf(t)>=0)return 1;return 0};s.lt=function(h){var s=this,lft=s.linkDownloaddisabledFileTypes,lef=s.linkExt"
-+"ernalFilters,lif=s.linkInternalFilters;lif=lif?lif:s.wd.location.hostname;h=h.toLowerCase();if(s.trackDownloaddisabledLinks&&lft&&s.pt(lft,',','ltdf',h))return 'd';if(s.trackExternalLinks&&h.substring(0,1)"
-+"!='#'&&(lef||lif)&&(!lef||s.pt(lef,',','ltef',h))&&(!lif||!s.pt(lif,',','ltef',h)))return 'e';return ''};s.lc=new Function('e','var s=s_c_il['+s._in+'],b=s.eh(this,\"onclick\");s.lnk=s.co(this);s.t"
-+"();s.lnk=0;if(b)return this[b](e);return true');s.bc=new Function('e','var s=s_c_il['+s._in+'],f,tcf;if(s.d&&s.d.all&&s.d.all.cppXYctnr)return;s.eo=e.srcElement?e.srcElement:e.target;tcf=new Functi"
-+"on(\"s\",\"var e;try{if(s.eo&&(s.eo.tagName||s.eo.parentElement||s.eo.parentNode))s.t()}catch(e){}\");tcf(s);s.eo=0');s.oh=function(o){var s=this,l=s.wd.location,h=o.href?o.href:'',i,j,k,p;i=h.inde"
-+"xOf(':');j=h.indexOf('?');k=h.indexOf('/');if(h&&(i<0||(j>=0&&i>j)||(k>=0&&i>k))){p=o.protocol&&o.protocol.length>1?o.protocol:(l.protocol?l.protocol:'');i=l.pathname.lastIndexOf('/');h=(p?p+'//':'"
-+"')+(o.host?o.host:(l.host?l.host:''))+(h.substring(0,1)!='/'?l.pathname.substring(0,i<0?0:i)+'/':'')+h}return h};s.ot=function(o){var t=o.tagName;t=t&&t.toUpperCase?t.toUpperCase():'';if(t=='SHAPE'"
-+")t='';if(t){if((t=='INPUT'||t=='BUTTON')&&o.type&&o.type.toUpperCase)t=o.type.toUpperCase();else if(!t&&o.href)t='A';}return t};s.oid=function(o){var s=this,t=s.ot(o),p,c,n='',x=0;if(t&&!o.s_oid){p"
-+"=o.protocol;c=o.onclick;if(o.href&&(t=='A'||t=='AREA')&&(!c||!p||p.toLowerCase().indexOf('javascript')<0))n=s.oh(o);else if(c){n=s.rep(s.rep(s.rep(s.rep(''+c,\"\\r\",''),\"\\n\",''),\"\\t\",''),' '"
-+",'');x=2}else if(t=='INPUT'||t=='SUBMIT'){if(o.value)n=o.value;else if(o.innerText)n=o.innerText;else if(o.textContent)n=o.textContent;x=3}else if(o.src&&t=='IMAGE')n=o.src;if(n){o.s_oid=s.fl(n,100"
-+");o.s_oidt=x}}return o.s_oid};s.rqf=function(t,un){var s=this,e=t.indexOf('='),u=e>=0?t.substring(0,e):'',q=e>=0?s.epa(t.substring(e+1)):'';if(u&&q&&(','+u+',').indexOf(','+un+',')>=0){if(u!=s.un&&"
-+"s.un.indexOf(',')>=0)q='&u='+u+q+'&u=0';return q}return ''};s.rq=function(un){if(!un)un=this.un;var s=this,c=un.indexOf(','),v=s.c_r('s_sq'),q='';if(c<0)return s.pt(v,'&','rqf',un);return s.pt(un,'"
-+",','rq',0)};s.sqp=function(t,a){var s=this,e=t.indexOf('='),q=e<0?'':s.epa(t.substring(e+1));s.sqq[q]='';if(e>=0)s.pt(t.substring(0,e),',','sqs',q);return 0};s.sqs=function(un,q){var s=this;s.squ[u"
-+"n]=q;return 0};s.sq=function(q){var s=this,k='s_sq',v=s.c_r(k),x,c=0;s.sqq=new Object;s.squ=new Object;s.sqq[q]='';s.pt(v,'&','sqp',0);s.pt(s.un,',','sqs',q);v='';for(x in s.squ)if(x&&(!Object||!Ob"
-+"ject.prototype||!Object.prototype[x]))s.sqq[s.squ[x]]+=(s.sqq[s.squ[x]]?',':'')+x;for(x in s.sqq)if(x&&(!Object||!Object.prototype||!Object.prototype[x])&&s.sqq[x]&&(x==q||c<2)){v+=(v?'&':'')+s.sqq"
-+"[x]+'='+s.ape(x);c++}return s.c_w(k,v,0)};s.wdl=new Function('e','var s=s_c_il['+s._in+'],r=true,b=s.eh(s.wd,\"onloaddisabled\"),i,o,oc;if(b)r=this[b](e);for(i=0;i<s.d.links.length;i++){o=s.d.links[i];oc=o"
-+".onclick?\"\"+o.onclick:\"\";if((oc.indexOf(\"s_gs(\")<0||oc.indexOf(\".s_oc(\")>=0)&&oc.indexOf(\".tl(\")<0)s.eh(o,\"onclick\",0,s.lc);}return r');s.wds=function(){var s=this;if(s.apv>3&&(!s.isie|"
-+"|!s.ismac||s.apv>=5)){if(s.b&&s.b.attachEvent)s.b.attachEvent('onclick',s.bc);else if(s.b&&s.b.addEventListener)s.b.addEventListener('click',s.bc,false);else s.eh(s.wd,'onloaddisabled',0,s.wdl)}};s.vs=func"
-+"tion(x){var s=this,v=s.visitorSampling,g=s.visitorSamplingGroup,k='s_vsn_'+s.un+(g?'_'+g:''),n=s.c_r(k),e=new Date,y=e.getYear();e.setYear(y+10+(y<1900?1900:0));if(v){v*=100;if(!n){if(!s.c_w(k,x,e)"
-+")return 0;n=x}if(n%10000>v)return 0}return 1};s.dyasmf=function(t,m){if(t&&m&&m.indexOf(t)>=0)return 1;return 0};s.dyasf=function(t,m){var s=this,i=t?t.indexOf('='):-1,n,x;if(i>=0&&m){var n=t.subst"
-+"ring(0,i),x=t.substring(i+1);if(s.pt(x,',','dyasmf',m))return n}return 0};s.uns=function(){var s=this,x=s.dynamicAccountSelection,l=s.dynamicAccountList,m=s.dynamicAccountMatch,n,i;s.un=s.un.toLowe"
-+"rCase();if(x&&l){if(!m)m=s.wd.location.host;if(!m.toLowerCase)m=''+m;l=l.toLowerCase();m=m.toLowerCase();n=s.pt(l,';','dyasf',m);if(n)s.un=n}i=s.un.indexOf(',');s.fun=i<0?s.un:s.un.substring(0,i)};"
-+"s.sa=function(un){var s=this;s.un=un;if(!s.oun)s.oun=un;else if((','+s.oun+',').indexOf(','+un+',')<0)s.oun+=','+un;s.uns()};s.m_i=function(n,a){var s=this,m,f=n.substring(0,1),r,l,i;if(!s.m_l)s.m_"
-+"l=new Object;if(!s.m_nl)s.m_nl=new Array;m=s.m_l[n];if(!a&&m&&m._e&&!m._i)s.m_a(n);if(!m){m=new Object,m._c='s_m';m._in=s.wd.s_c_in;m._il=s._il;m._il[m._in]=m;s.wd.s_c_in++;m.s=s;m._n=n;m._l=new Ar"
-+"ray('_c','_in','_il','_i','_e','_d','_dl','s','n','_r','_g','_g1','_t','_t1','_x','_x1','_rs','_rr','_l');s.m_l[n]=m;s.m_nl[s.m_nl.length]=n}else if(m._r&&!m._m){r=m._r;r._m=m;l=m._l;for(i=0;i<l.le"
-+"ngth;i++)if(m[l[i]])r[l[i]]=m[l[i]];r._il[r._in]=r;m=s.m_l[n]=r}if(f==f.toUpperCase())s[n]=m;return m};s.m_a=new Function('n','g','e','if(!g)g=\"m_\"+n;var s=s_c_il['+s._in+'],c=s[g+\"_c\"],m,x,f=0"
-+";if(!c)c=s.wd[\"s_\"+g+\"_c\"];if(c&&s_d)s[g]=new Function(\"s\",s_ft(s_d(c)));x=s[g];if(!x)x=s.wd[\\'s_\\'+g];if(!x)x=s.wd[g];m=s.m_i(n,1);if(x&&(!m._i||g!=\"m_\"+n)){m._i=f=1;if((\"\"+x).indexOf("
-+"\"function\")>=0)x(s);else s.m_m(\"x\",n,x,e)}m=s.m_i(n,1);if(m._dl)m._dl=m._d=0;s.dlt();return f');s.m_m=function(t,n,d,e){t='_'+t;var s=this,i,x,m,f='_'+t,r=0,u;if(s.m_l&&s.m_nl)for(i=0;i<s.m_nl."
-+"length;i++){x=s.m_nl[i];if(!n||x==n){m=s.m_i(x);u=m[t];if(u){if((''+u).indexOf('function')>=0){if(d&&e)u=m[t](d,e);else if(d)u=m[t](d);else u=m[t]()}}if(u)r=1;u=m[t+1];if(u&&!m[f]){if((''+u).indexO"
-+"f('function')>=0){if(d&&e)u=m[t+1](d,e);else if(d)u=m[t+1](d);else u=m[t+1]()}}m[f]=1;if(u)r=1}}return r};s.m_ll=function(){var s=this,g=s.m_dl,i,o;if(g)for(i=0;i<g.length;i++){o=g[i];if(o)s.loaddisabledMo"
-+"dule(o.n,o.u,o.d,o.l,o.e,1);g[i]=0}};s.loaddisabledModule=function(n,u,d,l,e,ln){var s=this,m=0,i,g,o=0,f1,f2,c=s.h?s.h:s.b,b,tcf;if(n){i=n.indexOf(':');if(i>=0){g=n.substring(i+1);n=n.substring(0,i)}else "
-+"g=\"m_\"+n;m=s.m_i(n)}if((l||(n&&!s.m_a(n,g)))&&u&&s.d&&c&&s.d.createElement){if(d){m._d=1;m._dl=1}if(ln){if(s.ssl)u=s.rep(u,'http:','https:');i='s_s:'+s._in+':'+n+':'+g;b='var s=s_c_il['+s._in+'],"
-+"o=s.d.getElementById(\"'+i+'\");if(s&&o){if(!o.l&&s.wd.'+g+'){o.l=1;if(o.i)clearTimeout(o.i);o.i=0;s.m_a(\"'+n+'\",\"'+g+'\"'+(e?',\"'+e+'\"':'')+')}';f2=b+'o.c++;if(!s.maxDelay)s.maxDelay=250;if(!"
-+"o.l&&o.c<(s.maxDelay*2)/100)o.i=setTimeout(o.f2,100)}';f1=new Function('e',b+'}');tcf=new Function('s','c','i','u','f1','f2','var e,o=0;try{o=s.d.createElement(\"script\");if(o){o.type=\"text/javas"
-+"cript\";'+(n?'o.id=i;o.defer=true;o.onloaddisabled=o.onreadystatechange=f1;o.f2=f2;o.l=0;':'')+'o.src=u;c.appendChild(o);'+(n?'o.c=0;o.i=setTimeout(f2,100)':'')+'}}catch(e){o=0}return o');o=tcf(s,c,i,u,f1,"
-+"f2)}else{o=new Object;o.n=n+':'+g;o.u=u;o.d=d;o.l=l;o.e=e;g=s.m_dl;if(!g)g=s.m_dl=new Array;i=0;while(i<g.length&&g[i])i++;g[i]=o}}else if(n){m=s.m_i(n);m._e=1}return m};s.vo1=function(t,a){if(a[t]"
-+"||a['!'+t])this[t]=a[t]};s.vo2=function(t,a){if(!a[t]){a[t]=this[t];if(!a[t])a['!'+t]=1}};s.dlt=new Function('var s=s_c_il['+s._in+'],d=new Date,i,vo,f=0;if(s.dll)for(i=0;i<s.dll.length;i++){vo=s.d"
-+"ll[i];if(vo){if(!s.m_m(\"d\")||d.getTime()-vo._t>=s.maxDelay){s.dll[i]=0;s.t(vo)}else f=1}}if(s.dli)clearTimeout(s.dli);s.dli=0;if(f){if(!s.dli)s.dli=setTimeout(s.dlt,s.maxDelay)}else s.dll=0');s.d"
-+"l=function(vo){var s=this,d=new Date;if(!vo)vo=new Object;s.pt(s.vl_g,',','vo2',vo);vo._t=d.getTime();if(!s.dll)s.dll=new Array;s.dll[s.dll.length]=vo;if(!s.maxDelay)s.maxDelay=250;s.dlt()};s.t=fun"
-+"ction(vo,id){var s=this,trk=1,tm=new Date,sed=Math&&Math.random?Math.floor(Math.random()*10000000000000):tm.getTime(),sess='s'+Math.floor(tm.getTime()/10800000)%10+sed,y=tm.getYear(),vt=tm.getDate("
-+")+'/'+tm.getMonth()+'/'+(y<1900?y+1900:y)+' '+tm.getHours()+':'+tm.getMinutes()+':'+tm.getSeconds()+' '+tm.getDay()+' '+tm.getTimezoneOffset(),tcf,tfs=s.gtfs(),ta=-1,q='',qs='',code='',vb=new Objec"
-+"t;s.gl(s.vl_g);s.uns();s.m_ll();if(!s.td){var tl=tfs.location,a,o,i,x='',c='',v='',p='',bw='',bh='',j='1.0',k=s.c_w('s_cc','true',0)?'Y':'N',hp='',ct='',pn=0,ps;if(String&&String.prototype){j='1.1'"
-+";if(j.match){j='1.2';if(tm.setUTCDate){j='1.3';if(s.isie&&s.ismac&&s.apv>=5)j='1.4';if(pn.toPrecision){j='1.5';a=new Array;if(a.forEach){j='1.6';i=0;o=new Object;tcf=new Function('o','var e,i=0;try"
-+"{i=new Iterator(o)}catch(e){}return i');i=tcf(o);if(i&&i.next)j='1.7'}}}}}if(s.apv>=4)x=screen.width+'x'+screen.height;if(s.isns||s.isopera){if(s.apv>=3){v=s.n.javaEnabled()?'Y':'N';if(s.apv>=4){c="
-+"screen.pixelDepth;bw=s.wd.innerWidth;bh=s.wd.innerHeight}}s.pl=s.n.plugins}else if(s.isie){if(s.apv>=4){v=s.n.javaEnabled()?'Y':'N';c=screen.colorDepth;if(s.apv>=5){bw=s.d.documentElement.offsetWid"
-+"th;bh=s.d.documentElement.offsetHeight;if(!s.ismac&&s.b){tcf=new Function('s','tl','var e,hp=0;try{s.b.addBehavior(\"#default#homePage\");hp=s.b.isHomePage(tl)?\"Y\":\"N\"}catch(e){}return hp');hp="
-+"tcf(s,tl);tcf=new Function('s','var e,ct=0;try{s.b.addBehavior(\"#default#clientCaps\");ct=s.b.connectionType}catch(e){}return ct');ct=tcf(s)}}}else r=''}if(s.pl)while(pn<s.pl.length&&pn<30){ps=s.f"
-+"l(s.pl[pn].name,100)+';';if(p.indexOf(ps)<0)p+=ps;pn++}s.resolution=x;s.colorDepth=c;s.javascriptVersion=j;s.javaEnabled=v;s.cookiesEnabled=k;s.browserWidth=bw;s.browserHeight=bh;s.connectionType=c"
-+"t;s.homepage=hp;s.plugins=p;s.td=1}if(vo){s.pt(s.vl_g,',','vo2',vb);s.pt(s.vl_g,',','vo1',vo)}if((vo&&vo._t)||!s.m_m('d')){if(s.usePlugins)s.doPlugins(s);var l=s.wd.location,r=tfs.document.referrer"
-+";if(!s.pageURL)s.pageURL=l.href?l.href:l;if(!s.referrer&&!s._1_referrer){s.referrer=r;s._1_referrer=1}s.m_m('g');if(s.lnk||s.eo){var o=s.eo?s.eo:s.lnk;if(!o)return '';var p=s.pageName,w=1,t=s.ot(o)"
-+",n=s.oid(o),x=o.s_oidt,h,l,i,oc;if(s.eo&&o==s.eo){while(o&&!n&&t!='BODY'){o=o.parentElement?o.parentElement:o.parentNode;if(!o)return '';t=s.ot(o);n=s.oid(o);x=o.s_oidt}oc=o.onclick?''+o.onclick:''"
-+";if((oc.indexOf(\"s_gs(\")>=0&&oc.indexOf(\".s_oc(\")<0)||oc.indexOf(\".tl(\")>=0)return ''}if(n)ta=o.target;h=s.oh(o);i=h.indexOf('?');h=s.linkLeaveQueryString||i<0?h:h.substring(0,i);l=s.linkName"
-+";t=s.linkType?s.linkType.toLowerCase():s.lt(h);if(t&&(h||l))q+='&pe=lnk_'+(t=='d'||t=='e'?s.ape(t):'o')+(h?'&pev1='+s.ape(h):'')+(l?'&pev2='+s.ape(l):'');else trk=0;if(s.trackInlineStats){if(!p){p="
-+"s.pageURL;w=0}t=s.ot(o);i=o.sourceIndex;if(s.gg('objectID')){n=s.gg('objectID');x=1;i=1}if(p&&n&&t)qs='&pid='+s.ape(s.fl(p,255))+(w?'&pidt='+w:'')+'&oid='+s.ape(s.fl(n,100))+(x?'&oidt='+x:'')+'&ot="
-+"'+s.ape(t)+(i?'&oi='+i:'')}}if(!trk&&!qs)return '';s.sampled=s.vs(sed);if(trk){if(s.sampled)code=s.mr(sess,(vt?'&t='+s.ape(vt):'')+s.hav()+q+(qs?qs:s.rq()),0,id,ta);qs='';s.m_m('t');if(s.p_r)s.p_r("
-+");s.referrer=''}s.sq(qs);}else{s.dl(vo);}if(vo)s.pt(s.vl_g,',','vo1',vb);s.lnk=s.eo=s.linkName=s.linkType=s.wd.s_objectID=s.ppu=s.pe=s.pev1=s.pev2=s.pev3='';if(s.pg)s.wd.s_lnk=s.wd.s_eo=s.wd.s_link"
-+"Name=s.wd.s_linkType='';if(!id&&!s.tc){s.tc=1;s.flushBufferedRequests()}return code};s.tl=function(o,t,n,vo){var s=this;s.lnk=s.co(o);s.linkType=t;s.linkName=n;s.t(vo)};if(pg){s.wd.s_co=function(o)"
-+"{var s=s_gi(\"_\",1,1);return s.co(o)};s.wd.s_gs=function(un){var s=s_gi(un,1,1);return s.t()};s.wd.s_dc=function(un){var s=s_gi(un,1);return s.t()}}s.ssl=(s.wd.location.protocol.toLowerCase().inde"
-+"xOf('https')>=0);s.d=document;s.b=s.d.body;if(s.d.getElementsByTagName){s.h=s.d.getElementsByTagName('HEAD');if(s.h)s.h=s.h[0]}s.n=navigator;s.u=s.n.userAgent;s.ns6=s.u.indexOf('Netscape6/');var ap"
-+"n=s.n.appName,v=s.n.appVersion,ie=v.indexOf('MSIE '),o=s.u.indexOf('Opera '),i;if(v.indexOf('Opera')>=0||o>0)apn='Opera';s.isie=(apn=='Microsoft Internet Explorer');s.isns=(apn=='Netscape');s.isope"
-+"ra=(apn=='Opera');s.ismac=(s.u.indexOf('Mac')>=0);if(o>0)s.apv=parseFloat(s.u.substring(o+6));else if(ie>0){s.apv=parseInt(i=v.substring(ie+5));if(s.apv>3)s.apv=parseFloat(i)}else if(s.ns6>0)s.apv="
-+"parseFloat(s.u.substring(s.ns6+10));else s.apv=parseFloat(v);s.em=0;if(s.em.toPrecision)s.em=3;else if(String.fromCharCode){i=escape(String.fromCharCode(256)).toUpperCase();s.em=(i=='%C4%80'?2:(i=="
-+"'%U0100'?1:0))}s.sa(un);s.vl_l='dynamicVariablePrefix,visitorID,vmk,visitorMigrationKey,visitorMigrationServer,visitorMigrationServerSecure,ppu,charSet,visitorNamespace,cookieDomainPeriods,cookieLi"
-+"fetime,pageName,pageURL,referrer,currencyCode';s.va_l=s.sp(s.vl_l,',');s.vl_t=s.vl_l+',variableProvider,channel,server,pageType,transactionID,purchaseID,campaign,state,zip,events,products,linkName,"
-+"linkType';for(var n=1;n<76;n++)s.vl_t+=',prop'+n+',eVar'+n+',hier'+n+',list'+n;s.vl_l2=',tnt,pe,pev1,pev2,pev3,resolution,colorDepth,javascriptVersion,javaEnabled,cookiesEnabled,browserWidth,browse"
-+"rHeight,connectionType,homepage,plugins';s.vl_t+=s.vl_l2;s.va_t=s.sp(s.vl_t,',');s.vl_g=s.vl_t+',trackingServer,trackingServerSecure,trackingServerBase,fpCookieDomainPeriods,disableBufferedRequests"
-+",mobile,visitorSampling,visitorSamplingGroup,dynamicAccountSelection,dynamicAccountList,dynamicAccountMatch,trackDownloaddisabledLinks,trackExternalLinks,trackInlineStats,linkLeaveQueryString,linkDownloaddisabledF"
-+"ileTypes,linkExternalFilters,linkInternalFilters,linkTrackVars,linkTrackEvents,linkNames,lnk,eo,_1_referrer';s.va_g=s.sp(s.vl_g,',');s.pg=pg;s.gl(s.vl_g);if(!ss)s.wds()",
-w=window,l=w.s_c_il,n=navigator,u=n.userAgent,v=n.appVersion,e=v.indexOf('MSIE '),m=u.indexOf('Netscape6/'),a,i,s;if(un){un=un.toLowerCase();if(l)for(i=0;i<l.length;i++){s=l[i];if(!s._c||s._c=='s_c'){if(s.oun==un)return s;else if(s.fs&&s.sa&&s.fs(s.oun,un)){s.sa(un);return s}}}}w.s_an='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
-w.s_sp=new Function("x","d","var a=new Array,i=0,j;if(x){if(x.split)a=x.split(d);else if(!d)for(i=0;i<x.length;i++)a[a.length]=x.substring(i,i+1);else while(i>=0){j=x.indexOf(d,i);a[a.length]=x.subst"
-+"ring(i,j<0?x.length:j);i=j;if(i>=0)i+=d.length}}return a");
-w.s_jn=new Function("a","d","var x='',i,j=a.length;if(a&&j>0){x=a[0];if(j>1){if(a.join)x=a.join(d);else for(i=1;i<j;i++)x+=d+a[i]}}return x");
-w.s_rep=new Function("x","o","n","return s_jn(s_sp(x,o),n)");
-w.s_d=new Function("x","var t='`^@$#',l=s_an,l2=new Object,x2,d,b=0,k,i=x.lastIndexOf('~~'),j,v,w;if(i>0){d=x.substring(0,i);x=x.substring(i+2);l=s_sp(l,'');for(i=0;i<62;i++)l2[l[i]]=i;t=s_sp(t,'');d"
-+"=s_sp(d,'~');i=0;while(i<5){v=0;if(x.indexOf(t[i])>=0) {x2=s_sp(x,t[i]);for(j=1;j<x2.length;j++){k=x2[j].substring(0,1);w=t[i]+k;if(k!=' '){v=1;w=d[b+l2[k]]}x2[j]=w+x2[j].substring(1)}}if(v)x=s_jn("
-+"x2,'');else{w=t[i]+' ';if(x.indexOf(w)>=0)x=s_rep(x,w,t[i]);i++;b+=62}}}return x");
-w.s_fe=new Function("c","return s_rep(s_rep(s_rep(c,'\\\\','\\\\\\\\'),'\"','\\\\\"'),\"\\n\",\"\\\\n\")");
-w.s_fa=new Function("f","var s=f.indexOf('(')+1,e=f.indexOf(')'),a='',c;while(s>=0&&s<e){c=f.substring(s,s+1);if(c==',')a+='\",\"';else if((\"\\n\\r\\t \").indexOf(c)<0)a+=c;s++}return a?'\"'+a+'\"':"
-+"a");
-w.s_ft=new Function("c","c+='';var s,e,o,a,d,q,f,h,x;s=c.indexOf('=function(');while(s>=0){s++;d=1;q='';x=0;f=c.substring(s);a=s_fa(f);e=o=c.indexOf('{',s);e++;while(d>0){h=c.substring(e,e+1);if(q){i"
-+"f(h==q&&!x)q='';if(h=='\\\\')x=x?0:1;else x=0}else{if(h=='\"'||h==\"'\")q=h;if(h=='{')d++;if(h=='}')d--}if(d>0)e++}c=c.substring(0,s)+'new Function('+(a?a+',':'')+'\"'+s_fe(c.substring(o+1,e))+'\")"
-+"'+c.substring(e+1);s=c.indexOf('=function(')}return c;");
-c=s_d(c);if(e>0){a=parseInt(i=v.substring(e+5));if(a>3)a=parseFloat(i)}else if(m>0)a=parseFloat(u.substring(m+10));else a=parseFloat(v);if(a>=5&&v.indexOf('Opera')<0&&u.indexOf('Opera')<0){w.s_c=new Function("un","pg","ss","var s=this;"+c);return new s_c(un,pg,ss)}else s=new Function("un","pg","ss","var s=new Object;"+s_ft(c)+";return s");return s(un,pg,ss)} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/app/bbccom/19_61/bbccom.js b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/app/bbccom/19_61/bbccom.js
deleted file mode 100755
index 6c702097a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/app/bbccom/19_61/bbccom.js
+++ /dev/null
@@ -1 +0,0 @@
-gloaddisableder.loaddisabled(["glow","1","glow.dom","glow.anim","glow.events","glow.embed"],{onLoad:function(A){BBC.adverts=function(){var AM="undefined",s="keyValues",AY="slots",u="ads",P=0,l="",p="/",K=";",Ak="=",Ae="bbccom_display_none",Ac='<script type="text/javascript" src="',AA='"><\/script>',J="/",AB=".js",U="location",x="domain",Aj=false,Y="zoneVersion",V="zoneOverride",AX="zoneReferrer",AE="yes",Ag="no",z="bbccom_",Q="&ord=",T="httpdisabled://ad.doubleclick.net/adj/",D="httpdisabled://ad.doubleclick.net/ad/",C="httpdisabled://ad.doubleclick.net/jump/",r="httpdisabled://ad.doubleclick.net/adi/",h="httpdisabled://ad.doubleclick.net/adx/",AC="httpdisabled://ad.doubleclick.net/pfadx/bbccom.live.site.news/;tile=6;sz=512x288;dcgzip=0",AT="httpdisabled://ad.doubleclick.net/pfadx/",Ad=";slot=",B=";sz=",AG=";tile=",Ah=";dcopt=ist",k=";ord=",i="?",X="bbccom_slot_",AW=undefined,o="disable-wide-advert",AR={newsonline:"/2/hi",bbc_news:"/2/hi",refresh:"/news"},F={news:{old:"/2/hi",refresh:"/news"},sport:{old:"/sport2/hi",refresh:"/sport"},real_cities:{old:"/2/hi",refresh:"/news"}},AP='<div class="bbccom_text"><a href="httpdisabled://faq.external.bbc.co.uk/questions/bbc_online/adverts_general">Advertisement</a></div>',Aa={leaderboard:{size:"728x90,970x66,970x90"},skyscraper:{size:"120x600,160x600"},bottom:{size:"468x60"},mpu:{photo_gallery:"300x250",size:"300x250,300x600",medium_size:"160x600,300x250,300x600,336x700,336x850,336x280",wide_size:"160x600,300x250,300x600,336x700,336x850,336x280,468x648"},button:{size:"120x240"},wallpaper:{size:"1x1"},video:{size:"1x1"},companion:{size:"512x288"},storyprintsponsorship:{size:"88x31"},halfbanner:{size:"234x60"},printableversionsponsorship:{size:"120x60,215x60"},sponsor_1:{size:"88x31"},sponsor_2:{size:"88x31"},sponsor_3:{size:"88x31"},sponsor_4:{size:"88x31"},sponsor_section:{size:"88x31"},sponsor_section_news:{size:"88x31"},partner_button1:{size:"120x30"},partner_button2:{size:"120x30"},partner_button3:{size:"120x30"},partner_button4:{size:"120x30"},partner_button5:{size:"120x30"},partner_button6:{size:"120x30"},partner_button7:{size:"120x30"},partner_button8:{size:"120x30"},adsense_middle:{size:""},adsense_mpu:{size:""},promo_feature:{size:"336x224"},sponsor:{size:"88x31"},module:{size:"88x31"},"module_page-bookmark-links-top":{size:"205x31"},rectangle300x100:{size:"300x100"},not_found:{size:""}};var a,t=l,AJ={},AL={},v=14,E=false,I=false,Al=undefined,AH="4",m=["_v4","_v3_5","_v3"],AK=false,S="",AV="",e="",f="",w="",c=[],AF=[{key:"airline",rules:[{match:[/air|plane|flight|jet|aviation/g,/ash|bomb|crash|dead|detonat|disaster|disrupt|fire|injur|kill|package|passenger|crew|score|strand|strike|volcan|wreck/g],value:"!e"}]}],AO={mpu:{def:"mpu",720:"",160:"mpu_skyscraper",468:"xxl",336:"mpu336"},leaderboard:{def:"leaderboard",300:"",970:"leaderboard970"}};while(v--){t+=(Math.floor(Math.random()*10))}var Af=function(An){var Ao=[];var Am=0;if(AL.keyValues){for(var Ap in AL.keyValues){Ao[Am]=K;Ao[Am+1]=Ap;Ao[Am+2]=Ak;Ao[Am+3]=AL.keyValues[Ap];Am+=4}}if(AL.domValues){for(var As in AL.domValues){var Aq=A.dom.get(AL.domValues[As]);if("undefined"!==typeof (Aq[0])){Ao[Am]=K;Ao[Am+1]=As;Ao[Am+2]=Ak;Ao[Am+3]=escape(Aq[0].innerHTML.split(" ").join("_"));Am+=4}}}if(An){for(var Ar in An){Ao[Am]=K;Ao[Am+1]=Ar;Ao[Am+2]=Ak;Ao[Am+3]=An[Ar];Am+=4}}if(O()&&"undefined"!==bbc.fmtj.page.assetType){Ao[Am]=K;Ao[Am+1]="asset_type";Ao[Am+2]=Ak;Ao[Am+3]=bbc.fmtj.page.assetType;Am+=4}return Ao.join(l)};var q=function(){P++;return P};var d=function(At,An,Aq,Ao){if(typeof (Ao)=="undefined"||AJ[Ao]!==Ag){var As=q();var Ar=g(At);if(Ar==""){return""}if(Aq=="standardUri"){return[D,AL.site,p,AL.zone,Ad,At,B,Ar,Af(An),L(),N(),f,AG,As,k,t,i].join(l)}if(Aq=="iframe"){if(Ar.indexOf(",")!==-1){Ar=Ar.slice(0,Ar.indexOf(","))}var Ap=Ar.slice(0,Ar.indexOf("x"));var Am=Ar.slice(Ar.indexOf("x")+1);return['<iframe width="',Ap,'" height="',Am,'" frameborder="0" scrolling="no" src="',r,AL.site,p,AL.zone,Ad,At,B,Ar,Af(An),L(),N(),f,AG,As,k,t,i,'"></iframe>'].join(l)}if(At=="companion"){return[AT,AL.site,p,AL.zone,Ad,At,B,Ar,Af(An),L(),N(),f,AG,1].join(l)}if(At=="wallpaper"){}return[Ac,T,AL.site,p,AL.zone,Ad,At,B,Ar,Af(An),L(),N(),f,AG,As,W(At),k,t,i,AA].join(l)}else{return"<!-- bbccom: dependent slot closed -->"}};var W=function(Am){return Am=="leaderboard"?Ah:""};var AN=function(An,Am){AJ[An]=Ag;A.dom.get("#"+z+An).addClass(Ae);if(Am&&An=="mpu"){An="mpu_high";AN(An)}};var y=function(){var An=AJ[V]===true?AJ[Y]:J+AJ[Y]+AB;var Am=[Ac,An,AA].join(l);void(Am)};var g=function(An){if(!AL.slotSize||(typeof (AL.slotSize[An])=="undefined")){var Am=Z(An);if(E&&typeof (Am[bbc.fmtj.page.assetType])!="undefined"){return Am[bbc.fmtj.page.assetType]}else{if((I||E)&&Ai().hasClass(o)&&typeof (Am.medium_size)!="undefined"){return Am.medium_size}else{if((I||E)&&typeof (Am.wide_size)!="undefined"){return Am.wide_size}}}return Am.size}else{return AL.slotSize[An]}};var AZ=function(){if(O()&&"cream"==bbc.fmtj.page.siteVersion){E=true}};var j=function(){if(document.getElementsByName("CPS_ASSET_TYPE").length!=0){return true}return false};var O=function(){var Am=G(["CPS_ASSET_TYPE"]);if("undefined"!=typeof (bbc)&&"undefined"!=typeof (bbc.fmtj)&&"undefined"!=typeof (bbc.fmtj.page)&&"(none)"!=bbc.fmtj.page.sectionPath&&null!=bbc.fmtj.page.sectionPath){return true}return false};var R=function(){var Am=G(["CPS_ASSET_TYPE"]);return Am.CPS_ASSET_TYPE=="fix"?true:false};var AU=function(){var Ao=[];var An=window.location.pathname.replace(/^\/*/,"").replace(/\/*$/,"").split("/");for(var Am in An){if(An[Am].search(".stm")==-1){Ao.push(An[Am])}}return Ao};var AD=function(){var Am=G(["CPS_SECTION_PATH"]);return Am.CPS_SECTION_PATH.replace(/^\/*/,"").replace(/\/*$/,"").split("/")};var b=function(){if(S.length==0){if(O()&&!R()){var Ao=("index"!==bbc.fmtj.page.assetType&&"-"!==bbc.fmtj.page.storyId&&null!==bbc.fmtj.page.storyId)?bbc.fmtj.page.storyId:"default.stm";var An=("/"!==bbc.fmtj.page.sectionPath)?bbc.fmtj.page.sectionPath.toLowerCase().replace(/ /g,"_"):"";var Am="/"+bbc.fmtj.page.siteToServe;for(siteToServe in F){if(siteToServe==bbc.fmtj.page.siteToServe){Am=F[bbc.fmtj.page.siteToServe].old;continue}}S=Am+An+"/"+Ao}else{if(j()){var Ap=G(["CPS_ID","CPS_SITE_NAME","CPS_SECTION_PATH","CPS_ASSET_TYPE"]);var Am=("undefined"!=AR[Ap.CPS_SITE_NAME])?AR[Ap.CPS_SITE_NAME]:"";var Ao=("IDX"!==Ap.CPS_ASSET_TYPE)?Ap.CPS_ID:"default.stm";var An=Ap.CPS_SECTION_PATH.replace("frontpage","");S=(""!==An&&"/"!==An)?Am+"/"+An+"/"+Ao:Am}else{S=AJ[U]}}}return S};var G=function(Am){var An={};for(key in Am){if(document.getElementsByName(Am[key]).length!=0&&document.getElementsByName(Am[key])[0].getAttribute("content")!==null){An[Am[key]]=document.getElementsByName(Am[key])[0].getAttribute("content").toLowerCase().replace(/ /g,"_")}}return An};var H=function(){var Am=G(["ad_keyword","Slug"]);if(Am.ad_keyword){e=K+"keyword="+Am.ad_keyword}else{if(Am.Slug){e=K+"keyword="+Am.Slug}}};var N=function(){return e};var M=function(){for(var Am in AF){for(var Ar in AF[Am].rules){var Ap=-1;var Aq=AF[Am].rules[Ar].match.length-1;for(var An=0;An<=Aq;An++){if(AF[Am].rules[Ar].match[An].test(AV)){Ap++}else{return }}if(Ap==Aq){if("!e"==AF[Am].rules[Ar].value){c[AF[Am].key]="!e="+AF[Am].key}else{c[AF[Am].key]=AF[Am].key+"=yes"}}}}for(var Ao in c){w+=";"+c[Ao]}};var AS=function(){var Am=/[?|&]zone=preview&uid=([0-9a-fxA-FX]{26})/.test(window.location.search);if(Am){f=";uid="+RegExp.$1;if("3pt_zone_file"==AJ[Y]){AJ[Y]="preview"}else{AJ[Y]+="_preview"}A.ready(function(){var An=A.dom.get("a").filter(function(Ao){return(this.href&&this.href.indexOf("#")!=1&&this.href.indexOf("bbc.co")!=-1)});A.events.addListener(An,"click",n)})}};var n=function(Ao){Ao.stopPropagation();var Am=Ao.attachedTo.href;var An="zone=preview&"+f.split(";")[1];if(Am.indexOf("?")==-1){Am+="?"+An}else{if(Am.indexOf("#")!=-1){Am=Am.substring(0,Am.indexOf("#"))+"&"+An+Am.substring(Am.indexOf("#"))}else{Am+="&"+An}}window.location=Am;return false};var L=function(){return w};var AQ=function(Am){for(var An in Am){AJ[An]=Am[An]}};var Ai=function(){if(AW==undefined){AW=A.dom.get("body")}return AW};var Z=function(Am){if(typeof (Aa[Am])!="undefined"){return Aa[Am]}else{if(Am.indexOf("_")!==-1){return Aa[Am.slice(0,Am.lastIndexOf("_"))]}else{AJ[Am]=Ag;return Aa.not_found}}};var Ab=function(Am){BBC.adverts.addBodyClass("slot_interstitial");BBC.adverts.addBodyClass("slot_interstitial_"+Am);document.getElementById("bbccom_int_container").className="";A.ready(function(){A.events.addListener("#bbccom_int_link","click",BBC.adverts.closeInterstitial);setTimeout(AI,7000)})};var AI=function(){A.dom.get("body").removeClass("bbccom_slot_interstitial");document.getElementById("bbccom_int_container").className="bbccom_display_none"};return{init:function(An){AQ(An);var Am=G(["Headline","Description"]);AV=Am.Headline+" "+Am.Description;M();AS();H();AZ();y()},setAutoAdRefresh:function(){var Am=A.dom.get("#bbccom_mpu");if(0<Am.length){}Am=A.dom.get("#bbccom_leaderboard");if(0<Am.length){}setTimeout("BBC.adverts.setAutoAdRefresh()",10000)},setGvl3:function(Am){I=Am},setAdsBlocked:function(Am){Aj=Am},getConfig:function(Am){return AJ[Am]},getZoneData:function(){return AL},getAdvertTag:function(Ap,Am,Ao,An){return d(Ap,Am,Ao,An)},getMetaData:function(Am){var Aq,Ar,Ap={};for(var Ao=0;Ao<Am.length;Ao++){if((Aq=window[z+Am[Ao]])){for(var An in Aq){Ar=escape(Aq[An].replace(/\s+/g,""));if(Ar.length>0&&Ar.length<=64){Ap[Am[Ao]+"_"+An]=Ar}}}}return Ap},getSectionPath:function(){S=S.replace(F.news.old,F.news.refresh);S=S.replace(F.sport.old,F.sport.refresh);return S.substring(1).replace(/\/[0-9]*$/,"")},setZone:function(Am){var Ao=b();var An=AJ[x];var Ap=AJ[AX];var Aq={keyValues:{},slots:{}};var Ar=function(Av,Ax){for(var At in Ax.data){if(At===s){for(var Au in Ax.data.keyValues){Aq.keyValues[Au]=Ax.data.keyValues[Au]}}else{if(At==AY){for(var Aw in Ax.data.slots){Aq.slots[Aw]=Ax.data.slots[Aw]}}else{Aq[At]=Ax.data[At]}}}if(Ax.zones){var As=Ax.zones.length;while(As--){if(Ao.indexOf(Av+Ax.zones[As].uri)!==-1){return Ar(Av+Ax.zones[As].uri,Ax.zones[As])}}}return Aq};if(An.indexOf(".external.")!==-1){Ao="/"+An+Ao}else{if(An.indexOf("bbcearth.com")!==-1){Ao="/"+An+Ao}else{if((Ao=="/")||Ao.indexOf("/wwhomepage/")!==-1||Ao.indexOf("/wwhomepageus/")!==-1||Ao.indexOf("/wwhomepageinternational/")!==-1||Ao.indexOf("/internationalhomepage/")!==-1){Ao="/home/"}}}AL=Am.process(Ar(l,Am.zones),An,Ao,Ap)}void:function(Ao,An,Am){if(Aj===false&&AL.ads){if((!AL.slots||(AL.slots[Ao]!=false))&&AJ[Ao]!==Ag){AJ[Ao]=AE;if(typeof (Am)=="object"){Am.is_module="true"}Ai().addClass(X+Ao);if(An||typeof (An)=="undefined"){void(AP+d(Ao,Am))}else{void(d(Ao,Am))}}else{AN(Ao)}}else{AN(Ao)}},checkWrite:function(Am){if(Aj===false&&AL.ads){if((!AL.slots||(AL.slots[Am]!=false))&&AJ[Am]!==Ag){AJ[Am]=AE;return true}else{AN(Am)}return false}else{AN(Am)}return false}voidAttr:function(An,Am){if(Aj===false&&AL.ads){if(!AL.styles||(typeof (AL.styles[Am])=="undefined")){return false}return AL.styles[Am][An]}return false},hasStyles:function(){if(!AL.styles||(typeof (AL.styles)=="undefined")){return false}return true},show:function(Aq,Ao,An){if(a!==undefined){a();a=undefined}if(AJ[Aq]===AE){if(AK&&Al===AH){An=Aq+m[0]}else{if(AK&&Al!==AH){An=Aq+m[1]}else{An=Aq+m[2]}}var Ap;if(Ao==undefined){Ap=z+Aq}else{Ap=Ao}if(document.getElementById(Ap)!==null&&"undefined"!=document.getElementById(Ap)){if("bbccom_visibility_show"!=document.getElementById(Ap).className){document.getElementById(Ap).className=document.getElementById(Ap).className.replace(Ae,"")+" "+An}else{document.getElementById(Ap).className=document.getElementById(Ap).className+" "+An}}var Am=Aq.match(/^module_([a-z]+)$/);if(Am&&document.getElementById(z+Ap)!=null){document.getElementById(z+Ap).className="bbccom_module"}return true}return false},close:function(An){AJ[An]=Ag;Ai().removeClass(X+An);var Am;switch(An){case"leaderboard":Am="bbcdotcomAdvertsResetTop";break;case"bottom":Am="bbcdotcomAdvertsResetBottom";break;case"mpu":Am="bbcdotcomAdvertsResetMpu";break;default:Am=""}Ai().addClass(Am)},addBodyClass:function(Am){Ai().addClass(z+Am)},moveAd:function(An,Am){a=function(){if(A.dom.get("#"+z+Am).length>0){var Ap=A.dom.get("#"+z+An);var Ao=A.dom.get("#"+z+Am);Ap.get("script").remove();Ao.removeClass(Ae);Ao.html(Ap.html());A.dom.get("#"+z+An).remove()}}},setPageVersion:function(Am){AK=true;if(Am==="4"){Al=Am}},getPageVersion:function(){return Al},empCompanion:function(){var Am=d("companion");return Am},empCompanionResponse:function(Aq,Ao){if(Ao==undefined){Ao="bbccom_companion"}var Ar="companion";AJ[Ar]=AE;var Am=document.createElement("div");Am.setAttribute("class","comp_banner_holder");var An=document.createElement("iframe");An.setAttribute("width","300");An.setAttribute("scrolling","no");An.setAttribute("frameBorder","no");An.setAttribute("src",Aq);var Ap=document.getElementById(Ao);Ap.className="bbccom_companion bbccom_visibility_show";Am.appendChild(An);Ap.appendChild(Am)},createElement:function(Ao,An){Ao=document.createElement(Ao);for(var Am in An){Ao.setAttribute(Am,An[Am])}return Ao},empSlideCompanionResponse:function(Ar,Ap){if(Ap==undefined){Ap="bbccom_companion"}var Am=this.createElement("div",{"class":"comp_banner_holder"});var Ao={width:300,height:60,scrolling:"no",frameBorder:"no",src:Ar};var An=this.createElement("iframe",Ao);Am.appendChild(An);var Aq=document.getElementById(Ap);Aq.className="companion_parent bbccom_visibility_show";var As=A.anim.css(Aq,0.5,{height:{from:0,to:84}},{tween:A.tweens.easeOut()});A.events.addListener(As,"complete",function(At){Aq.appendChild(Am)});As.start()},adTextWrapper:function(){var Am=document.createElement("div");Am.className="bbccom_text";Am.innerHTML="Advertisement";return Am},removeCompanionBodyClasses:function(Ap,Ao){for(var Am in AO[Ap]){var An=X+AO[Ap][Am];if(Ao==0||(Am!=Ao&&Am!="def")){if(Ai().hasClass(An)){Ai().removeClass(An)}}}},replaceAd:function(At,Am){var Aw=Am.indexOf("sz");var Ar=Am.slice(Aw);var Ao=Aw+Ar.indexOf(";");var As=Am.slice(Aw,Ao);var Ax=As.slice(3);var Ap="bbccom_"+At;var Aq=document.getElementById(Ap);var An=Ax.slice(0,Ax.indexOf("x"));var Av=Ax.slice(Ax.indexOf("x")+1);var Au=this.tryReplaceAd(At,Am,Aq,An,Av);if(!Au&&At=="mpu"){var Ap="bbccom_"+At+"_high";var Aq=document.getElementById(Ap);this.tryReplaceAd(At,Am,Aq,An,Av)}},tryReplaceAd:function(As,Ar,Ap,Aq,Am){if(Ap!==null){if((Aq==0)&&(Am==0)){AN(As,true);this.removeCompanionBodyClasses(As,Aq)}else{this.removeCompanionBodyClasses(As,Aq);if(AO[As][Aq]!=""&&!Ai().hasClass(X+AO[As][Aq])){Ai().addClass(X+AO[As][Aq])}var Ao={width:Aq,height:Am,scrolling:"no",frameBorder:"no",src:Ar};var An=this.createElement("iframe",Ao);Ap.innerHTML="";Ap.appendChild(this.adTextWrapper());Ap.appendChild(An)}return true}else{return false}},setScriptRoot:function(Am){J=Am},setVideoAds:function(Am){var An=this.createElement("video",{controls:"controls",src:Am});var Ao=document.getElementById("bbccom_video");Ao.appendChild(An)},getNewsGvl3:function(){return E},getScriptRoot:function(){return J},getPredicates:function(){return L()},getSectionUrl:function(){return S},getConfig:function(){return AJ},loaddisabledInterstitial:Ab,closeInterstitial:AI}}()}});var bbcdotcom={av:{}};bbcdotcom.av.emp={hasPlayers:function(){return(typeof (embeddedMedia)=="object"&&typeof (embeddedMedia.playerInstances)=="object")},getPlayers:function(){return embeddedMedia.playerInstances},configureAll:function(){var B=bbcdotcom.av.emp;if(B.hasPlayers()){var A=B.getPlayers();for(instance in A){B.adverts.configure(A[instance]);B.events.configure(A[instance])}}}};bbcdotcom.av.emp.adverts={configure:function(A){var B=bbcdotcom.av.emp.adverts.companion.getCompanionId(A.domId);A.set("preroll",BBC.adverts.empCompanion());A.set("companionSize","300x60");A.set("companionType","adi");A.set("companionId","bbccom_companion_"+B)}};bbcdotcom.av.emp.events={register:{onPlaybackProgress:function(A){if(this.evLock){this.evLock=false;this.call("getItem",[this.domId],"getItemKind");this.metadata.mediaLength=A.duration;this.metadata.mediaId=this.attrs.id;this.metadata.adId=null;bbcdotcom.av.emp.analytics.callback("mediaStarted",this.metadata);this.metadata.mediaOffset=0;bbcdotcom.av.emp.analytics.callback("mediaPlaying",this.metadata)}else{this.metadata.mediaOffset=A.progress}},onPlaylistStarted:function(A){this.metadata.mediaName=A.title;this.metadata.mediaPlayerName=A.version},onPlaylistCompleted:function(A){bbcdotcom.av.emp.analytics.callback("playlistCompleted",this.metadata)},onMediaCompleted:function(A){this.evLock=true;bbcdotcom.av.emp.analytics.callback("mediaCompleted",this.metadata)},cueItem:function(A){this.call("getItem",[this.domId],"getItemKind")}},configure:function(A){A.onMediaPlayerInitialised=function(){for(event in bbcdotcom.av.emp.events.register){A.evLock=true;A.register(event);A[event]=bbcdotcom.av.emp.events.register[event];A.getItemKind=function(B){this.metadata.mediaType=B.item.kind};A.metadata={}}}}};bbcdotcom.av.emp.analytics={callback:function(A,B){switch(A){case"mediaStarted":startMovie(B);break;case"mediaPlaying":playMovie(B);break;case"mediaCompleted":stopMovie(B);break;case"playlistCompleted":endMovie(B);break}}};bbcdotcom.av.emp.adverts.companion={getCompanionId:function(C){var B=C.split("-"),A="";if(B.length>=2){A=B[1]}else{A=false}return A}}; \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/common/3_2/bbc_fmtj_common.js b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/common/3_2/bbc_fmtj_common.js
deleted file mode 100755
index 3d5b34098..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/common/3_2/bbc_fmtj_common.js
+++ /dev/null
@@ -1 +0,0 @@
-bbc.fmtj.utils.createObject("bbc.fmtj.common");bbc.fmtj.common.isReady=false;bbc.fmtj.common.version="3_2";gloaddisableder.loaddisabled(["glow","1","glow.dom","glow.events"],{async:true,onLoad:function(d){var b=d,a=d.dom,c=d.events;bbc.fmtj.common.bookmarks=(function(){var h="bbc.fmtj.common.bookmarks.display.DISPLAY_POPUP";var m="bbc.fmtj.common.bookmarks.display.DISPLAY_IFRAME";return{createBookmarks:f,display:{DISPLAY_POPUP:h,DISPLAY_IFRAME:m}};function f(p){if(p.container===undefined){p.container=".bookmark-list";}if(p.headline===undefined){p.headline=bbc.fmtj.page.headline;}if(p.site===undefined){p.site=bbc.fmtj.page.site;}if(p.storyId===undefined){p.storyId=bbc.fmtj.page.storyId;}if(p.sectionId===undefined){p.sectionId=bbc.fmtj.page.sectionId;}if(p.url===undefined){p.url=bbc.fmtj.page.url;}if(p.edition===undefined){p.edition=bbc.fmtj.page.edition;}if(p.display===undefined){p.display=h;}l(p);}function l(q){this.o=q;var p=a.get(q.container+" li a");c.addListener(p,"click",n,this);}function n(p){o.service=a.get(p.attachedTo).text();j(o);g(o);return false;}function j(p){bbc.fmtj.common.liveStats.createWebBug({referrer:document.location,pageType:"soc_"+p.service.toLowerCase(),sectionId:p.sectionId});return false;}function g(p){switch(p.display){case h:i(p);break;case m:e(p);break;default:break;}return false;}function i(q){var p=k(q.service,q.url,q.headline);bbc.fmtj.common.window.createPopup({url:p,resizable:1,scrollbars:1,width:750});return false;}function e(r){var q=k(r.service,r.url,r.headline);var p='<div id="bookmarkLightbox" class="bookmark-panel"><h2 class="hd">'+r.service+'</h2><div><iframe src="'+q+'">Your browser does not support frames.</iframe></div></div>';gloaddisableder.loaddisabled(["glow","1","glow.widgets.Panel"],{async:true,onLoad:function(t){var s=new t.widgets.Panel(t.dom.create(p),{width:750,theme:"dark",modal:true,anim:"fade"});s.show();}});}function k(p,q,s){var r="";switch(p.toLowerCase()){case"delicious":r="httpdisabled://del.icio.us/post?v=4&noui&jump=close&url="+q+"&title="+s;break;case"digg":r="httpdisabled://digg.com/remote-submit?phase=2&url="+q+"&title="+s;break;case"reddit":r="httpdisabled://reddit.com/submit?url="+q+"&title="+s;break;case"facebook":r="httpdisabled://www.facebook.com/sharer.php?u="+q+"&t="+s;break;case"stumbleupon":r="httpdisabled://www.stumbleupon.com/submit?url="+q+"&title="+s;break;default:break;}return r;}})();bbc.fmtj.common.cookies=(function(){var h={};return{cookie:k,loaddisabled:g,store:j,remove:f,create:e,read:i,erase:l};function e(p,s,m,u,r,t){var n=[];if(m!==null&&m!==undefined){var q=new Date(new Date(new Date()).getTime()+m*3600000).toUTCString();n.push("; expires="+q);}if(u!==null&&u!==undefined){n.push("; path="+u);}if(r!==null&&r!==undefined){n.push("; domain="+r);}if(t!==null&&t!==undefined){n.push("; secure="+t);}document.cookie=p+"="+s+n.join("");}function i(n){var q=n+"=";var m=document.cookie.split(";");for(var p=0;p<m.length;p++){var r=m[p];while(r.charAt(0)==" "){r=r.substring(1,r.length);}if(r.indexOf(q)==0){return r.substring(q.length,r.length);}}return null;}function l(m,q,n,p){e(m,"",-1,q,n,p);}function k(m){this._content=m.content;this._document=document;this._name=m.name;this._expiration=null;this._hours;this._path=null;this._domain=null;this._secure=false;if(m.hours!==undefined){this._expiration=new Date(new Date()).getTime()+m.hours*3600000;}if(m.path!==undefined){this._path=m.path;}if(m.domain!==undefined){this._domain=m.domain;}if(m.secure!==undefined){this._secure=m.secure;}return{hours:this._hours,path:this._path,name:this._name,domain:this._domain,secure:this._secure,content:this._content};}function g(m){}function j(p){var q=new String();var n=q.stringify(this._content);var m=this._name+"="+n;if(this._expiration!==undefined){this._expiration=new Date(this._expiration);m+="; expires="+this._expiration.toUTCString();}if(this._path!==undefined){m+="; path="+this._path;}if(this._domain!==undefined){m+="; domain="+this._domain;}if(this._secure!==undefined){m+="; secure";}this._document.cookie=m;}function f(m){}h.Cookie.prototype.store=function(){var p=new String();var n=p.stringify(this._content);var m=this._name+"="+n;if(this._expiration!==undefined){this._expiration=new Date(this._expiration);m+="; expires="+this._expiration.toUTCString();}if(this._path!==undefined){m+="; path="+this._path;}if(this._domain!==undefined){m+="; domain="+this._domain;}if(this._secure!==undefined){m+="; secure";}this._document.cookie=m;};h.Cookie.prototype.loaddisabled=function(t){if(t!==undefined){this._name=t;}var p=this._document.cookie;if(p==""){return false;}var n=p.indexOf(this._name+"=");if(n==-1){return false;}n+=this._name.length+1;var q=p.indexOf(";",n);if(q==-1){q=p.length;}var u=unescape(p.substring(n,q));var v=u.split("&");var s=false;for(var r=0;r<v.length;r++){if(v[r].search(/:/i)!=-1){v[r]=v[r].split(":");s=true;}else{this.content=v;}}if(s){this.content={};for(var r=0;r<v.length;r++){var m=unescape(v[r][1]);if(m=="false"){m=false;}else{if(m=="true"){m=true;}else{if(m.indexOf("[")!=-1){m=m.substring(1,m.length-1);if(m){m=m.split(",");}else{m=new Array();}}}}this.content[v[r][0]]=m;}}return true;};h.Cookie.prototype.remove=function(){var m=this._name+"=";if(this._path!==undefined){m+="; path="+this._path;}if(this._domain!==undefined){m+="; domain="+this._domain;}m+="; expires=Fri, 02-Jan-1970 00:00:00 GMT";this._document.cookie=m;};})();String.prototype.stringify=function(f){var e=":";if(arguments[1]){if(arguments[1]=="="){e="=";}}this._obj=f;if(typeof this._obj=="object"){if(this._obj!="[object Object]"){this._isArray=true;}this._str="";for(var g in this._obj){if(this._isArray){property="";}else{property=g+e;}if(typeof this._obj[g]!="function"){this._str=String(this._str)+property+this._obj[g]+"&";}}this._isArray=false;this._str=escape(this._str.substring(0,(this._str.length-1)));return(String(this._str));}if(typeof this._obj=="string"){this._str=escape(this._obj);return(String(this._str));}};bbc.fmtj.common.liveStats=(function(){return{initialise:g,createWebBug:h};function h(j){if(j.baseUrl===undefined){(j.baseUrl="httpdisabled://stats.bbc.co.uk/o.gif?");}if(j.siteName===undefined){j.siteName=bbc.fmtj.page.siteToServe;}if(j.pageType===undefined){(j.pageType="-");}if(j.storyId===undefined){j.storyId=bbc.fmtj.page.storyId;}if(j.sectionId===undefined){j.sectionId=bbc.fmtj.page.sectionId;}if(j.edition===undefined){j.edition=bbc.fmtj.page.editionToServe;}if(j.url===undefined){j.url=bbc.fmtj.page.uri;}if(j.referrer===undefined){j.referrer=bbc.fmtj.page.referrer;}if(j.queryString===undefined){j.queryString="-";}if(j.randomNumber===undefined){j.randomNumber=f();}var k=[j.baseUrl,"s",j.siteName,"t",j.pageType,"i",j.storyId,"p",j.sectionId,"a",j.edition,"u",j.url,"r",j.referrer,"q",j.queryString,"Z",j.randomNumber,""];b.onDomReady(function(){var l=new Image(1,1);l.src=k.join("~RS~");});return true;}function g(){b.ready(function(){c.addListener(document,"click",i);});}function i(n){var l=a.get(n.source);while(l.length>0&&l[0].attributes!==null&&!l.hasAttr("href")){l=a.get(l.parent());if(l.is("html, head, body")){return;}}var m=[];var j=true;m.push(e(l));var k=l.ancestors();k.filter(function(){return !(a.get(this).is("html, head, body"));}).each(function(){if(!j){return null;}var p=a.get(this);var q=e(p);m.push(q);if(isNaN(Number(q))){j=false;}});if(m.length>1||(m.length===1&&m[0]!="0")){document.cookie="BBCLiveStatsClick="+m.reverse().join("|")+";domain=bbc.co.uk;path=/;expires="+new Date(new Date().getTime()+8000).toGMTString()+";";}}function e(j){if(j.length>0&&j[0].attributes!==null&&j.hasAttr("id")){return(j.attr("id"));}var l=0;var k=j.prev();while(k.length>0){k=k.prev();l++;}return l;}function f(){var j=parseInt((Math.random()*10000)/100);if(j==100||j<10){j=99;}return j;}})();bbc.fmtj.common.removeNoScript=function(){a.get(".noscript").remove();};bbc.fmtj.common.tabs=(function(){var j=[];var i=0;return{createTabs:h};function h(m){var l=a.get(".tabbed");l.each(function(n){g(a.get(l[n]));});}function g(q){var l="bbc_fmtj_common_tabs_unique_index_"+f();q.addClass(l);var p=q.get(".tab");var m=q.get(".panel");var n=new a.NodeList();var r=new a.NodeList();p.each(function(u){var t=a.get(p.item(u));var v=true;var s=false;do{if(t.hasClass("tabbed")&&!t.hasClass(l)&&!v){s=true;}t=a.get(t.parent());v=false;}while(!t.hasClass(l)&&!s);if(!s){n.push(a.get(p.item(u)));}});m.each(function(u){var t=a.get(m.item(u));var v=true;var s=false;do{if(t.hasClass("tabbed")&&!t.hasClass(l)&&!v){s=true;}t=a.get(t.parent());v=false;}while(!t.hasClass(l)&&!s);if(!s){r.push(a.get(m.item(u)));}});q.removeClass(l);if(n.length!=r.length){return false;}n.each(function(s){k(n,r,s,q);});return true;}function k(n,m,l,p){c.addListener(n[l],"click",function(q){e(n,m,l);q.preventDefault();q.stopPropagation();},this);c.addListener(a.get(n[l]).get("a"),"focus",function(q){e(n,m,l);q.preventDefault();q.stopPropagation();},this);}function e(n,m,l){a.get(n,m).removeClass(void");a.get(n[l],m[l]).addClass(void");}function f(){return i++;}})();bbc.fmtj.common.window=(function(){var h=[];var g=-1;return{createPopup:j,href:voider:k,resizeTo:f};function f(l){if(l.height===undefined){l.height=window.height;}if(l.width===undefined){l.width=window.width;}window.resizeTo(l.width,l.height);}function e(l){if(l.url!==undefined){window.location.href=l.url;}return;}function k(l){if(l.url!==undefined){void(l.url);}return;}function j(n){if(n.url===undefined){n.url="";}if(n.toolbar===undefined){n.toolbar=0;}if(n.scrollbars===undefined){n.scrollbars=0;}if(n.location===undefined){n.location=0;}if(n.status===undefined){n.status=0;}if(n.menubar===undefined){n.menubar=0;}if(n.resizable===undefined){n.resizable=0;}if(n.top===undefined){n.top=100;}if(n.left===undefined){n.left=100;}if(n.width===undefined){n.width=671;}if(n.height===undefined){n.height=373;}if(n.name===undefined){n.name="win"+new Date().getTime();}if(n.parameters===undefined){n.parameters=b.lang.interpolate("toolbar={toolbar},scrollbars={scrollbars},location={location},status={status},menubar={menubar},resizable={resizable},width={width},height={height},top={top},left={left};",n);}var l=void(n.url,n.name,n.parameters);var m={id:++g,window:l,config:n};h.push(m);return m;}function i(l){}})();bbc.fmtj.common.isReady=true;}}); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/config/apps/4_5/bbc_fmtj_config.js b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/config/apps/4_5/bbc_fmtj_config.js
deleted file mode 100755
index ecdd98e53..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/config/apps/4_5/bbc_fmtj_config.js
+++ /dev/null
@@ -1 +0,0 @@
-bbc.fmtj.queue.register({namespace:"bbc.fmtj.apps.carousel",method:"createCarousel",script:"httpdisabled://news.bbcimg.co.uk/js/app/picture_gallery/2_1/carousel/carousel.js"});bbc.fmtj.queue.register({namespace:"bbc.fmtj.apps.personalisationPanel",method:"initialise",script:"httpdisabled://news.bbcimg.co.uk/js/app/personalisation_panel/1_9/personalisation_panel.js"});bbc.fmtj.queue.register({namespace:"bbc.fmtj.apps.pictureGallery",method:"createGallery",scripts:{foot:["httpdisabled://news.bbcimg.co.uk/js/app/picture_gallery/2_1/carousel/carousel.js","httpdisabled://news.bbcimg.co.uk/js/app/picture_gallery/2_1/slideshow/slideshow.js","httpdisabled://news.bbcimg.co.uk/js/app/picture_gallery/2_1/picture_gallery/picture_gallery.js"]}});bbc.fmtj.queue.register({namespace:"bbc.fmtj.apps.site_wide_alert",method:"checkAlert",scripts:{inline:["httpdisabled://news.bbcimg.co.uk/js/app/site_wide_alert/v1_2/site_wide_alert.js"]}});bbc.fmtj.queue.register({namespace:"bbc.fmtj.apps.slideshow",method:"createSlideShow",script:"httpdisabled://news.bbcimg.co.uk/js/app/picture_gallery/2_1/slideshow/slideshow.js"});bbc.fmtj.queue.register({namespace:"bbc.fmtj.apps.ticker",method:"initialise",script:"httpdisabled://news.bbcimg.co.uk/js/app/ticker/2_1/ticker.js"});bbc.fmtj.queue.register({namespace:"bbc.fmtj.net.json.model",method:"addModule",script:"httpdisabled://news.bbcimg.co.uk/js/net/json/jsonloaddisableder/2_12/jsonloaddisableder.js"}); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/core/3_2/bbc_fmtj.js b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/core/3_2/bbc_fmtj.js
deleted file mode 100755
index 6678eb017..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/core/3_2/bbc_fmtj.js
+++ /dev/null
@@ -1 +0,0 @@
-var $render;var $useMap;var $loaddisabledView;gloaddisableder.loaddisabled(["glow","1","glow.dom"],{onLoad:function(b){function a(f){var d=f.split("."),e=0,c=d.length,g=window;for(;e<c;e++){if(g[d[e]]===undefined){g[d[e]]={};}g=g[d[e]];}return g;}a("bbc.fmtj");bbc.fmtj.utils=(function(){return{createObject:a,isArray:c,prefixUrl:d};function c(e){if(e===undefined){return false;}return e.push!==undefined;}function d(e,f){if(e.toLowerCase().indexOf("httpdisabled")!=0){var g=document.domain.toLowerCase();if(g==="news.bbc.co.uk"||g==="bbc.co.uk"){if(f===undefined){f="httpdisabled://news.bbcimg.co.uk";}e=f+e;}}return e;}})();bbc.fmtj.queue=(function(){var l={},e={},f,d;return{callback:o,register:n};function k(p,r,q){var s=m(window,r);s.apply(p,q);}function c(p,r,q){if(typeof l[r]!=="object"||l[r]===null){l[r]=new Array();}l[r][l[r].length]={fContext:p,fName:r,fArgs:q};}function o(q){if(typeof l[q]==="object"&&l[q]!==null){for(var p=0;p<l[q].length;p++){k(l[q][p].fContext,l[q][p].fName,l[q][p].fArgs);}l[q]=null;}}function g(p){if(e[p]!==undefined){return;}e[p]={loaddisableding:true};if(!b.isReady){void('<script type="text/javascript" src="'+p+'"><\/script>');}else{j(p);}}function h(q){if(e[q]!==undefined){return;}e[q]={loaddisableding:true};if(f===undefined){f=document.getElementsByTagName("head")[0];}var p=document.createElement("script");p.type="text/javascript";p.src=q;f.appendChild(p);}function j(p){if(e[p]!==undefined){return;}e[p]={loaddisableding:true};b.onDomReady(function(){if(d===undefined){d=document.getElementsByTagName("body")[0];}var q=document.createElement("script");q.type="text/javascript";q.src=p;d.appendChild(q);});}function m(s,A){var p=true;var u=A.split(".");var w=s;for(i=0;i<u.length;i++){var v=u[i].indexOf("[");if(v>0){var t=/\[([0-9]*)\]/;var r=u[i].substr(0,v);var q=t.exec(u[i])[1];w=w[r];w=w[q];}else{w=w[u[i]];}p=(typeof w!=="undefined");if(!p){return null;}}return w;}function n(s){if(s.namespace===undefined){alert("No namespace specified to register script.");return;}if(s.method===undefined){alert("No method specified to register script.");return;}if(s.script===undefined&&s.scripts===undefined){alert("No sources specified to register script.");return;}var q=bbc.fmtj.utils.createObject(s.namespace);var r;var t;if(bbc.fmtj.utils.isArray(s.method)){r=s.method;}else{r=new Array(s.method);}for(var p=0;p<r.length;p++){t=r[p];q[t]=function(){c(this,s.namespace+"."+t,arguments);if(s.script!==undefined){j(s.script);}if(s.scripts!==undefined){if(s.scripts.head!==undefined){for(var u=0;u<s.scripts.head.length;u++){h(s.scripts.head[u]);}}if(s.scripts.inline!==undefined){for(var u=0;u<s.scripts.inline.length;u++){g(s.scripts.inline[u]);}}if(s.scripts.foot!==undefined){for(var u=0;u<s.scripts.foot.length;u++){j(s.scripts.foot[u]);}}}};}q.isReady=false;}})();bbc.fmtj.components=(function(){var c=[];return{registerNamespace:g,render:f,useMap:d,loaddisabledView:e};function g(h){c.splice(0,0,h);}function f(l){if(window.gloaddisableder===undefined){return false;}var n;for(var m=0;m<c.length;m++){if(c[m][l]!==undefined){n=c[m][l];break;}}if(n!==undefined){var k=[];for(var h=1;h<arguments.length;h++){k.push(arguments[h]);}n.apply(this,k);}}function d(h){if(window.gloaddisableder===undefined){return false;}gloaddisableder.use("bbc.fmtj.view",h);gloaddisableder.map.setProperties("bbc.fmtj.view",{$versionPath:"",$path:"{$base}{$versionPath}/"});}function e(h,k){if(window.gloaddisableder===undefined){return false;}var j=k;j.splice(0,0,h);j.splice(0,0,"bbc.fmtj.view");gloaddisableder.loaddisabled(j);}})();$render=bbc.fmtj.components.render;$useMap=bbc.fmtj.components.useMap;$loaddisabledView=bbc.fmtj.components.loaddisabledView;}}); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/locationservices/locator/v4_0/locator.js b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/locationservices/locator/v4_0/locator.js
deleted file mode 100755
index a46fb0510..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/locationservices/locator/v4_0/locator.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(){if(typeof window.locator=="object"){return;}var n,w,L,k,d,A={},F="LocatorMessages";gloaddisableder.loaddisabled(["glow","1","glow.dom","glow.events","glow.net","glow.i18n"],{onLoad:function(P){n=P;w=n.events;L=n.net;k=n.lang;d=n.i18n;n.ready(function(){A.cookie=v();});d.addLocaleModule(F,"en",{help:{title:"My Location Help",body:"The My Location feature takes a location of your choice and uses it to display relevant information on the BBC News and Weather websites. You only need to set it in one place and the information is automatically shared."}});}});var y="MYLOC",h=".bbc.co.uk",u="365",O=4,e="@",q="|",g="~";var b=false;var K=4;var p=true,M="cachebuster=cb{random}",t="locator";var N={A:"WCW",B:"WID",C:"LOCATOR"};var J="httpdisabled://news.bbc.co.uk",H="/weather/util/search/WeatherSuggestJSON",m="/weather/util/search/WeatherSearch",o="/weather/forecast/{loc}/Location";var B=J+H+".{format}?region={region}&search={search}&jsoncallback={callback}",s=J+m+".{format}?region={region}&search={search}&jsoncallback={callback}",f=J+m+".{format}?region={region}&lat={lat}&lon={lon}&radius={radius}&jsoncallback={callback}",D=J+o+".{format}?jsoncallback={callback}",c={format:"json",region:"world",search:""};var j={};var z=function(P,V,T){if(!V){return;}var T=T||{};if(j[P]){j[P].abort();j[P]=null;}if(t=="locator"){var R="c"+locator._callbackManagement.nextId++;P=k.interpolate(P,{callback:"locator._callbackManagement."+R});locator._callbackManagement[R]=function(W){j[P].destroy();j[P]=null;V(W);};}if(typeof T.useCache!=null&&!T.useCache){var Q=[new Date().getTime(),parseInt(Math.random()*100000)].join(""),U=(P.indexOf("?")>0?"&":"?");P+=U+k.interpolate(M,{random:Q});}var S=L.loaddisabledScript(P,{onLoad:function(W){j[P]=null;V(W);},onError:function(){j[P]=null;},useCache:true});if(t=="locator"){}j[P]=S;};var r=function(P){return N[P];};var G=function(Q){for(var P in N){if(N[P]==Q){return P;}}return null;};var I=function(Q,R){for(var S=0,P=Q.length;S<P;S++){if(Q[S]&&Q[S].name==R){return S;}}return null;};var i=function(P,Q){var R=I(P,Q);if(R!=null){return P[R];}else{return null;}};var E=function(P,R){var Q=i(P,R);if(!Q&&l(R)){Q={name:R,value:""};P.push(Q);}return Q;};var l=function(P){return !!G(P);};var a=function(P,Q){var R=I(P,Q);if(R!=null){delete P[R];}};var C=function(R,P){var P=P||{},Y=[],V="",Q;if(!A.shouldWriteToCookie()){return;}for(var S=0,T=R.dataStores.length;S<T;S++){var X=R.dataStores[S];if(X!=null&&X.name!=null&&X.value!=null){var W=G(X.name),Z=encodeURI(X.value),U=W+Z;Y.push(U);}}V=Y.join(q);Q=[(R.version?R.version:O),V].join(e);A.util.Cookie.create(y,Q,u,h);};var v=function(){var P=A.util.Cookie.read(y),Q={dataStores:[]},ac,Y,R,V,U;if(typeof P==="string"){P=unescape(P);ac=P.split(e);try{Y=parseInt(ac[0])?parseInt(ac[0]):null;V=ac[1];if(Y){Q.version=Y;}else{x();}if(V){U=V.split(q);for(var W=0,X=U.length;W<X;W++){var ab=U[W],aa=ab.charAt(0),Z=r(aa),S=decodeURI(ab.slice(1));Q.dataStores.push({name:Z,value:S});}}else{x();}}catch(T){x();}}return Q;};var x=function(){A.util.Cookie.destroy(y,h);};A={locales:{msg:F},EVENTS:{locationChanged:"locationChanged",autoSuggestSelected:"autoSuggestSelected",userShownLocationChange:"userShownLocationChange",userConfirmedLocationChange:"userConfirmedLocationChange",userCancelledLocationChange:"userCancelledLocationChange",userShownClearLocation:"userShownClearLocation",userConfirmedClearLocation:"userConfirmedClearLocation",userCancelledClearLocation:"userCancelledClearLocation"},cookie:{version:null,dataStores:[]},migrate:function(Q){var P=this;this.cookie=v();if(locator.getSharedLocationId()&&(P.cookie.version<O)){if(locator.debug){console.log("migrate()");}locator.fetchFromDataSet(locator.getSharedLocationId,function(R){if(locator.debug){console.log("migrate info: ",R,R.id,R.name,R.isNearest);}if(R&&R.id&&R.name){locator.getInfoFor(R.id,R.name,R.isNearest,function(T){P.cookie.version=O;var S=[];if(T.where_i_live){S.push(T.where_i_live);}if(T.where_i_live_alt){S.push(T.where_i_live_alt);}locator._setDataSet("WID",S.join("~"));if(locator.debug){console.log("migrate: success (migrated)");}if(typeof Q==="function"){Q();}});}else{if(locator.debug){console.log("migrate: no location data for migration in cookie (error)");}if(typeof Q==="function"){Q();}}},"wcw");}else{if(locator.debug){console.log("migrate: no shared location or cookie at latest version ");}if(typeof Q==="function"){Q();}}},on:function(P,Q){return w.addListener(this,P,Q);},getSharedLocationId:function(){this.cookie=v();var P=i(this.cookie.dataStores,"WCW");if(!this.COOKIE_EXTENDED&&P){C(this.cookie);this.COOKIE_EXTENDED=true;}if(P){return P.value;}return null;},getCookieVersion:function(){return this.cookie.version;},isIdValid:function(R){var Q=true;if(Q&&R=="undefined"){Q=false;}if(Q&&(R==undefined||R==null)){Q=false;}if(Q&&R.split){var P=R.split(g);Q=(P.length==K)?true:false;}return Q;},setSharedLocationId:function(S,Q){var Q=Q||{};if(S instanceof locator.Location){S=S.toString();}if(!this.isIdValid(S)||!this.shouldWriteToCookie()){return;}var R=E(this.cookie.dataStores,"WCW");R.value=S;var P=i(this.cookie.dataStores,"WID");if(P){a(this.cookie.dataStores,"WID");}this.cookie.version=O;C(this.cookie);if(Q._beforeEvent){Q._beforeEvent();}w.fire(this,this.EVENTS.locationChanged,{locationId:S});},clearSharedLocation:function(){if(!this.shouldWriteToCookie()){return;}A.util.Cookie.destroy(y,h);w.fire(this,this.EVENTS.locationChanged,{locationId:null});},hasSharedLocationIdChanged:function(P){return !!getSavedLocation()==P;},shouldWriteToCookie:function(){var Q=(this.cookie.version?this.cookie.version:O),P=O;return !!(Q<=P);},getMessageForId:function(P){var Q=d.getLocaleModule(locator.locales.msg);return Q[P]?Q[P]:null;},searchByPlaceName:function(S,X,P){var P=P||{},V=P.searchType||"full",W=P.startIndex||null,U=P.type||null,R=k.apply(c,P),Q,T;R.search=S;if(V=="suggest"){Q=k.interpolate(B,R);}else{Q=k.interpolate(s,R);}if(W){Q+="&startIndex="+W;}if(U){Q+="&type="+U;}z(Q,X,{useCache:p});},searchByCoordinatesWithRadius:function(U,T,P,V,S){var R=n.lang.apply(c,{lon:U,lat:T,radius:P}),Q=k.interpolate(f,R);if(!V){return;}z(Q,V,{useCache:p});},searchByPostcode:function(Q,T,S){var R=n.lang.apply(c,{search:encodeURIComponent(Q)}),P=k.interpolate(s,R);if(!T){return;}z(P,function(V){var U=null;if(V.results&&V.results[0]){U=V.results[0];}T(U);},{useCache:p});},getInfoFor:function(S,R,U,T){var Q=n.lang.apply(c,{loc:S,area:encodeURIComponent(R)}),P=k.interpolate(D,Q);if(U==true){P+="&area="+Q.area;}if(!T){return;}z(P,function(W){var V=null;if(W.location){T(W.location);}},{useCache:p});},fetchFromDataSet:function(U,W,S){if(!U){return null;}if(S=="wcw"){var V=i(this.cookie.dataStores,"WCW");var R=(V&&V.value)?V.value.split(g):[null,null,null,null];W({id:R[0],name:R[1],isNearest:R[2],nationId:R[3]});}else{if(S=="wid"){var Q=i(this.cookie.dataStores,"WID"),T={id:null,alt:null};if(Q&&Q.value){var P=(Q&&Q.value)?Q.value.split(g):[null,null];T={id:(P[0]?P[0]:null),alt:(P[1]?P[1]:null)};}W(T);}else{throw Error("Data Set not supported");}}},_setDataSet:function(Q,R){if(!this.shouldWriteToCookie()){return;}var P=E(this.cookie.dataStores,Q);P.value=R;C(this.cookie);},_setLegacyCookieVersion:function(P){O=P;},_callbackManagement:{nextId:0}};A.Location=(function(){var P=function(T,Q,S,R){this.id=T;this.name=Q;if(S==1){this.isNearest=true;}else{this.isNearest=false;}this.nationId=R;};P.DELIM=g;P.parse=function(R){var S=R.split(P.DELIM),V=S[0],Q=S[1],U=S[2],T=S[3];return new P(V,Q,U,T);};P.prototype={toString:function(){var Q=[this.id,this.name,(this.isNearest?"1":"0"),this.nationId];return Q.join(P.DELIM);}};return P;})();if(!window.locator){window.locator=A;}})();(function(){var a={create:function(d,g,h,f){var e="";if(h){var c=new Date();c.setTime(c.getTime()+(h*24*60*60*1000));var b="; expires="+c.toGMTString();}else{var b="";}e=d+"="+g+b+"; path=/";if(f){e+="; domain="+f;}document.cookie=e;},read:function(d){var f=d+"=";var b=document.cookie.split(";");for(var e=0;e<b.length;e++){var g=b[e];while(g.charAt(0)==" "){g=g.substring(1,g.length);}if(g.indexOf(f)==0){return g.substring(f.length,g.length);}}return null;},destroy:function(b,c){a.create(b,"",-1,c);}};if(typeof window.locator=="object"&&typeof window.locator.util!="object"){window.locator.util={Cookie:a,bind:function(b,c){return function(){c.apply(b,arguments);};}};}})();(function(){var a;gloaddisableder.loaddisabled(["glow","1","glow.dom","glow.events","glow.widgets.AutoSuggest"],{onLoad:function(b){var d={},c="postcode";a=b;d.AutoSuggest=function(e,f){var f=f||{};this.minimumThreshold=3;this.removeDuplicates=f.removeDuplicates!=undefined?f.removeDuplicates:true;this.formatItem=f.formatItem||this.formatItem;this.searchRegion=f.searchRegion;this.showSearchMessage=f.showSearchMessage!=undefined?f.showSearchMessage:false;this.autoSuggest=new a.widgets.AutoSuggest(e,function(){return[];},a.lang.apply(f,{onInputChange:locator.util.bind(this,this.inputChange),onItemSelect:locator.util.bind(this,this.itemSelect),formatItem:this.formatItem,width:f.width,activeOnShow:this.autoSelectFirstItemInList,className:f.className}));this.locale=a.i18n.getLocaleModule(locator.locales.ui);this.searchingMessage=this.locale.autoSuggest.searching;this.noResultsMessage=this.locale.autoSuggest.noResults;this.inputElement=this.autoSuggest.inputElement;};d.AutoSuggest.prototype={autoSelectFirstItemInList:false,itemElementStart:"<span>",itemElementEnd:"</span>",searchingClass:"searching",searchingMessage:"",noResultsMessage:"",inputElement:null,show:function(){this.autoSuggest.show();},hide:function(){this.autoSuggest.hide();},displaySearchingMessage:function(){this.autoSuggest.inputElement.addClass(this.searchingClass);if(this.showSearchMessage){this.displayMessage(this.searchingMessage);}},displayNoResultsMessage:function(){this.displayMessage('<span class="no-results">'+this.noResultsMessage+"</span>");},displayMessage:function(f){this.autoSuggest.setData([{name:f}]);this.autoSuggest.find(f);var e=this;window.setTimeout(function(){e.autoSuggest.show();},10);},formatItem:function(e){return e.name+(e.context?", "+e.context:"");},inputChange:function(){if(this.autoSuggest.val().length<this.minimumThreshold){return;}this.displaySearchingMessage();locator.searchByPlaceName(this.autoSuggest.val(),locator.util.bind(this,this.updateSearchResults),{searchType:"suggest",region:this.searchRegion});},itemSelect:function(e){var f=e.selectedItem.name;if(f.match(this.searchingMessage)||f.match(this.noResultsMessage)){}else{a.events.fire(locator,locator.EVENTS.autoSuggestSelected,{name:f,item:e.selectedItem});if(!e.defaultPrevented()){}}e.preventDefault();return false;},updateSearchResults:function(o){var k={},p=[],m=o[1],j=o[2],n=o[3],e=o[4],r=o[5],q=0,g,f;for(var h=0,l=m.length;h<l;h++){g=m[h];f=j[h];forecastLoc=n[h];hasForecastPage=e[h]==="1"?true:false;isForecastLoc=r[h]==="true"?true:false;comparison=g+f;if(!k[comparison]){if(this.removeDuplicates){k[comparison]=true;}if(f!=c){p.push({name:g,context:f,forecastLoc:forecastLoc,hasForecastPage:hasForecastPage,isForecastLoc:isForecastLoc});}else{q++;}}}this.autoSuggest.inputElement.removeClass(this.searchingClass);if(p.length==0&&q==0){this.displayNoResultsMessage();}else{if(p.length>0){this.autoSuggest.setData(p);this.autoSuggest.find();}}}};if(!window.locator){window.locator={};}if(!window.locator.ui){window.locator.ui={};}window.locator.ui=d;}});})();(function(){var b,a="postcode";gloaddisableder.loaddisabled(["glow","1","glow.dom","glow.events","glow.widgets.AutoSuggest","glow.i18n"],{onLoad:function(e){b=e;locator.locales.ui="LocatorUI";b.i18n.addLocaleModule(locator.locales.ui,"en",{changeLocationButton:"Change My Location",confirmSave:{confirm:"Confirm",cancel:"Cancel",back:"Back",titleSet:'You have chosen to set My Location to: <span class="locator-loc">{location}</span>',bodySet:'<p>My Location is also shared with the <a href="/weather">BBC Weather</a> site.</p><p>Press <span class="locator-action">Confirm</span> to set your Location, or <span class="locator-action">Cancel</span> to leave it unset.</p>',titleChange:'You have chosen to change My Location from: <span class="locator-loc-old">{locationOld}</span> to: <span class="locator-loc">{location}</span>',bodyChange:'<p>My Location is also shared with the <a href="/weather">BBC Weather</a> site.<p>Press <span class="locator-action">Confirm</span> if you are happy to make this change, or press <span class="locator-action">Cancel</span> to leave My Location as it is.</p>'},confirmClear:{confirm:"Confirm",cancel:"Cancel",title:"You have chosen to clear My Location.",body:'<p>Changing your setting here will also clear your location on the <a href="/weather">BBC Weather</a> site.</p><p>Please press <span class="locator-action">Confirm</span> to clear My Location, or press <span class="locator-action">Cancel</span> to leave it set to:</p><p><span class="locator-loc">{location}</span></p>'},results:{title:"Search Results for '{searchTerm}'"},pagination:{next:"Next",previous:"Prev"},autoSuggest:{searching:"Searching",noResults:"No results found, please try again"}});var c=[];window.locator.ui.Search=function(f,g){this.container=b.dom.get(f);this.searchTerm="";this.searchRegion=g.searchRegion;this.locale=b.i18n.getLocaleModule(locator.locales.ui);};window.locator.ui.Search.prototype={previousContents:[],search:function(g,h){var h=h||{};this.searchTerm=g;this.searchType=h.searchType||null;if(locator.debug){console.log("Search for %o with opts %o",g,h);}this.resetState();var f=this;locator.searchByPlaceName(g,function(j){if(!j){return;}if(j.results.length==0){b.events.fire(f,"noResults");}else{if(j.results.length==1){var i=j.results[0];if(i.has_forecast==0&&(i.type=="County"||i.type=="soundex_County")){if(locator.debug){console.log("COUNTY - only one result, searching again");}f.search(i.site_name,{searchType:"county_state"});}else{var k=k=new locator.Location(i.loc,i.site_name,(i.is_fsssi=="true"?false:true),(i.nation_id?i.nation_id:0));if(i.container){k.container=i.container;}if(locator.debug){console.log("Location object from search: ",k);}f.confirmLocationChange(k,function(l){if(locator.debug){console.log("Success!",l);}locator.setSharedLocationId(l.location.toString(),{_beforeEvent:function(){var m=[];if(i.where_i_live){m.push(i.where_i_live);}if(i.where_i_live_alt){m.push(i.where_i_live_alt);}locator._setDataSet("WID",m.join("~"));}});},function(l){if(locator.debug){console.log("User declined, go back.");}},{disambiguated:false});}}else{f.disambiguate(j);}}},{region:this.searchRegion,type:this.searchType});},showLocationChangeDialogue:function(m,q,i,f){var g=locator.getSharedLocationId()==null?false:true;var h=m.name+(m.container&&m.container!==a?", "+m.container:"");var s=this;var p=g?this.locale.confirmSave.titleChange:this.locale.confirmSave.titleSet;p=b.lang.interpolate(p,{location:h,locationOld:f.locationOld});var l=g?this.locale.confirmSave.bodyChange:this.locale.confirmSave.bodySet;var r=f.disambiguated?this.locale.confirmSave.back:this.locale.confirmSave.cancel;var o=b.lang.apply(this.locale,{title:p,body:l,cancel:r});var k=b.dom.create('<div class="locator-confirm"><p class="locator-panel-header"><strong>{title}</strong></p><div>{body}</div></div>',{interpolate:o});var n=b.dom.create('<button type="submit">{confirmSave.confirm}</button>',{interpolate:o});var j=b.dom.create('<button type="submit">{cancel}</button>',{interpolate:o});k.append(j).append(n);this.previousContents.push(this.container.children());if(locator.debug){console.log("Pushed previous contents onto stack",this.previousContents.length);}b.events.fire(locator,locator.EVENTS.userShownLocationChange,{location:m});if(g){locator.transition(this.container,k.children(),"fadeIn");}else{locator.transition(this.container,k.children(),"slideDown");}b.events.addListener(n,"click",function(t){t.location=m;b.events.fire(locator,locator.EVENTS.userConfirmedLocationChange,t);s.previousContents.pop();q(t);if(!t.defaultPrevented()){s.container.empty();}s.container.removeClass("locator-msg-confirm");});b.events.addListener(j,"click",function(t){t.location=m;b.events.fire(locator,locator.EVENTS.userCancelledLocationChange,t);var u=s.previousContents.pop();i(t);if(!t.defaultPrevented()){locator.transition(s.container,u,"fadeIn");}s.container.removeClass("locator-msg-confirm");if(f.disambiguated){s.container.addClass("locator-msg-disambiguate");}});},confirmLocationChange:function(h,l,g,k){this.container.addClass("locator-msg-confirm");var j=locator.getSharedLocationId()==null?false:true;var i=h.name+(h.container&&h.container!==a?", "+h.container:"");var f=this;if(j){locator.fetchFromDataSet(locator.getSharedLocationId(),function(m){k.locationOld=(m&&m.name)?m.name:"Not Set";f.showLocationChangeDialogue(h,l,g,k);},"wcw");}else{this.showLocationChangeDialogue(h,l,g,k);}},resetState:function(){this.container.empty();this.container.removeClass("locator-msg-disambiguate");this.container.removeClass("locator-msg-confirm");this.previousContents=[];},invokeLocationChangeFromSingleResult:function(f){if(locator.debug){console.log("invokeLocationChangeFromSingleResult: ",f);}var g=new locator.Location(f.loc,(f.area_name?f.area_name:f.name),(f.area_name?true:false),(f.nation_id?f.nation_id:0));if(f.county){g.container=f.county;}this.resetState();this.confirmLocationChange(g,function(h){if(locator.debug){console.log("Success!",h);}locator.setSharedLocationId(h.location.toString(),{_beforeEvent:function(){var i=[];if(f.where_i_live){i.push(f.where_i_live);}if(f.where_i_live_alt){i.push(f.where_i_live_alt);}if(i.length>0){locator._setDataSet("WID",i.join("~"));}}});},function(h){if(locator.debug){console.log("User declined, go back.");}},{disambiguated:false});},disambiguate:function(l){if(l.results&&l.results.length>0){this.container.addClass("locator-msg-disambiguate");var j=b.lang.interpolate(this.locale.results.title,{searchTerm:l.searchTerms});var f=l.results;var i='<div><p class="locator-panel-header"><strong>{resultsTitle}</strong></p><div class="locator-results"></div></div>';var g=b.dom.create(i,{interpolate:{resultsTitle:j}});var h=this.createResultsList(f);g.get(".locator-results").append(h);this.content=g;if(l.itemsPerPage<=l.totalResults){var k=new locator.ui.Paginator(this,this.content,l.itemsPerPage,l.totalResults);}locator.transition(this.container,this.content.children(),"slideDown");this.attachResultEventListeners();}},attachResultEventListeners:function(){var f=this;b.events.addListener(this.container.get(".locator-results a"),"click",function(g){var i=b.dom.get(g.source);if(i.data("type")&&i.data("type")=="county_state"&&i.data("searchTerm")){if(locator.debug){console.log("COUNTY - result click, searching again");}f.search(i.data("searchTerm"),{searchType:"county_state"});}else{f.container.removeClass("locator-msg-disambiguate");var h=i.data("loc");if(locator.debug){console.log("location selected",h);}f.selectLocation(h);}});},fetchResultSetAndUpdateResultsList:function(i,g,f){if(locator.debug){console.log("Fetch new result set for %o start %o, end %o for el %o",this.searchTerm,i,g);}var h=this;locator.searchByPlaceName(this.searchTerm,function(k){if(k.results){var j=h.createResultsList(k.results);j.attr("start",i+1);h.container.get(".locator-results").empty().append(j);h.attachResultEventListeners();f?f():null;}},{startIndex:i,region:this.searchRegion,type:this.searchType});},createResultsList:function(l){var j=b.dom.create("<ol></ol>"),m,n,h;for(var k=0,g=l.length;k<g;k++){h=l[k];m=b.dom.create('<li><a href="javascript:;">'+h.site_name+(h.type!=a&&h.container?", "+h.container:"")+"</a></li>");anchor=m.get("a");n=new locator.Location(h.loc,h.site_name,(h.is_fsssi=="true"?false:true),(h.nation_id?h.nation_id:0));if(h.container){n.container=h.container;}var f=[];if(h.where_i_live){f.push(h.where_i_live);}if(h.where_i_live_alt){f.push(h.where_i_live_alt);}n._wids=f;anchor.data("loc",n);if(h.has_forecast==0&&(h.type=="County"||h.type=="soundex_County")){if(locator.debug){console.log("COUNTY - attach county_state type to anchor.data");}anchor.data("searchTerm",h.site_name);anchor.data("type","county_state");}j.append(m);}return j;},selectLocation:function(f){if(locator.debug){console.log("selectLocation ",f);}this.confirmLocationChange(f,function(g){var h=g.location;if(locator.debug){console.log("Confirm change: ",h.id,h.name);}locator.setSharedLocationId(h.toString(),{_beforeEvent:function(){if(h._wids&&h._wids.length){locator._setDataSet("WID",h._wids.join("~"));}}});},function(g){var h=g.location;if(locator.debug){console.log("Request failed, should go back?");}},{disambiguated:true});},on:function(f,g){b.events.addListener(this,f,g);}};window.locator.transition=function(h,j,g,i){var i=i||{},k=i.duration||0.3,f=i.tween||b.tweens.easeOut();if(locator.debug){console.log("transition: ",h,j,g,k,f);}h.empty();switch(g){case"slideDown":h.css("height","0px").css("overflow","hidden");break;case"slideUp":h.css("overflow","hidden");break;case"fadeIn":h.css("opacity",0);break;case"fadeOut":break;}h.append(j);b.anim[g](h,k,{tween:f});};window.locator.initAutoSuggest=function(q){var q=q||{},h=q.inputSelector||".locator-auto-suggest",g=b.dom.get(h),z=q.submitSelector||".locator-search",t=b.dom.get(z),u=q.formSelector||".locator-form",n=b.dom.get(u),m=q.msgSelector||".locator-msg",r=b.dom.get(m),p=q.parentSelector,l=p?b.dom.get(p):null,k=q.defaultSelectedEvent!=undefined?q.defaultSelectedEvent:true,x,o;function A(i){var B=i.locationId;if(B){if(l&&!l.hasClass("locator-location-set")){l.addClass("locator-location-set");}}else{if(l&&l.hasClass("locator-location-set")){l.removeClass("locator-location-set");}}}locator.on("locationChanged",A);A({locationId:locator.getSharedLocationId()});o=new locator.ui.Search(r,q);var w=0,y=c.length,v=g,s;for(;w<y;w++){s=c[w];if(s.eq(v)){return;}}if(g.length===0||t.length===0||n.length===0){return;}x=new locator.ui.AutoSuggest(g,q);c.push(x.inputElement);var f=b.events.addListener(x.inputElement,"click",function(i){b.dom.get(this).val("");b.events.removeListener(f);});if(k){locator.on("autoSuggestSelected",function(i){x.hide();var B=i.item,D=(B.hasForecastPage&&B.forecastLoc&&B.context!==""),C=B.name;if(D){locator.getInfoFor(B.forecastLoc,B.name,!B.isForecastLoc,function(E){o.invokeLocationChangeFromSingleResult(E);});}else{if(B.context===""){o.search(C);}else{o.search(C,{searchType:"county_state"});}}});}var j=g.val();o.on("noResults",function(i){x.displayNoResultsMessage();});if(k){b.events.addListener(n,"submit",function(i){var B=g.val();i.preventDefault();if(j!==B){o.search(B);}return false;});}return x;};var d;locator.ui.Paginator=function(i,g,h,f){this.parent=i;this.locale=b.i18n.getLocaleModule(locator.locales.ui);this.startIndex=0;this.endIndex=h;this.currentPage=1;this.itemsPerPage=h;this.totalItems=parseInt(f);this.totalPages=Math.ceil(this.totalItems/this.endIndex);this.maxPagesToShow=5;this.maxPagesToShowHigher=10;this.numResultsPageToTriggerHigherPagination=10;this.pageMoreChar="&hellip;";this.pageJoinChar="|";this.container=b.dom.get(g);var j='<div class="locator-controls"><a href="#locator-previous" class="locator-control-prev disabled"><span class="locator-pagination-prev"></span>{pagination.previous}</a><div class="locator-pages"></div><a href="#locator-next" class="locator-control-next disabled">{pagination.next}<span class="locator-pagination-next"></span></a></div>';this.controls=b.dom.create(j,{interpolate:this.locale});this.container.append(this.controls);this.updatePrevNextLinks();this.attachEventListeners();if(locator.debug){console.log("Paging init: perPage %o, total %o, pages %o",this.itemsPerPage,this.totalItems,this.totalItems/this.endIndex);}};locator.ui.Paginator.prototype={createPageListHtml:function(){var j="<li>"+this.pageMoreChar+"</li>",q=this.maxPagesToShow,g,o,m,l,n,p;if(this.totalPages>=this.numResultsPageToTriggerHigherPagination){q=this.maxPagesToShowHigher;}g=Math.ceil(q/2);if(this.currentPage<=g||this.totalPages<=q){o=1;l=q;}else{o=this.currentPage-g+1;l=this.currentPage-g+q;}if(l>this.totalPages){l=this.totalPages;}if(locator.debug){console.log("Generating page list: currentPage: %o, currentPageOffset: %o, totalPages: %o, pageStart: %o, pageEnd: %o",this.currentPage,g,this.totalPages,o,l);}n=(o>1)?true:false;p=(l<this.totalPages)?true:false;var f="<ol>";if(n){f+=j;}for(var h=o,k=l;h<=k;h++){f+="<li"+(h==1?' class="first"':"")+'><a href="#locator-page'+h+'"'+(h==this.currentPage?' class="selected" ':"")+">"+h+"</a></li>";}if(p){f+=j;}f+="</ol>";return f;},attachEventListeners:function(){var f=this;b.events.addListener(this.controls.get(".locator-control-prev"),"click",function(g){if(locator.debug){console.log("click prev");}var h=b.dom.get(this);if(f.startIndex!=0){if(locator.debug){console.log("prev is ok");}f.parent.fetchResultSetAndUpdateResultsList(f.startIndex-f.itemsPerPage,f.endIndex-f.itemsPerPage,function(){f.startIndex-=f.itemsPerPage;f.endIndex-=f.itemsPerPage;f.currentPage--;f.updatePrevNextLinks();});}g.preventDefault();});b.events.addListener(this.controls.get(".locator-control-next"),"click",function(g){if(locator.debug){console.log("click next");}if(f.currentPage<f.totalPages){if(locator.debug){console.log("proceed to next");}f.parent.fetchResultSetAndUpdateResultsList(f.startIndex+f.itemsPerPage,f.endIndex+f.itemsPerPage,function(){f.startIndex+=f.itemsPerPage;f.endIndex+=f.itemsPerPage;f.currentPage++;f.updatePrevNextLinks();});}g.preventDefault();});b.events.addListener(this.controls.get(".locator-pages"),"click",function(h){var i=parseInt(b.dom.get(h.source).text());if(locator.debug){console.log("clicked page %o (type: %o)",i,typeof i);}if(typeof i=="number"&&!window.isNaN(i)&&f.currentPage!=i){var j=f.itemsPerPage*(i-1),g=(f.itemsPerPage*i)+f.itemsPerPage;f.parent.fetchResultSetAndUpdateResultsList(j,g,function(){f.startIndex=j;f.endIndex=g;f.currentPage=i;f.updatePrevNextLinks();});}h.preventDefault();});},updatePrevNextLinks:function(){var f=this.currentPage;if(this.currentPage>1){this.controls.get(".locator-control-prev").removeClass("disabled");}else{this.controls.get(".locator-control-prev").addClass("disabled");}if(this.currentPage<this.totalPages){this.controls.get(".locator-control-next").removeClass("disabled");}else{this.controls.get(".locator-control-next").addClass("disabled");}this.controls.get(".locator-pages").empty().append(this.createPageListHtml());},next:function(){if(locator.debug){console.log("next");}},previous:function(){if(locator.debug){console.log("prev");}}};window.locator.initSavedLocationDisplay=function(f){var f=f||".locator-saved-location",h=b.dom.get(f);if(h.length==0){return;}function g(i){var j=i.locationId;if(j){locDetails=locator.fetchFromDataSet(j,function(l){var k=(l&&l.name)?l.name:"Not Set";h.text(k);},"wcw");}else{h.text("Not set");}}locator.on("locationChanged",g);g({locationId:locator.getSharedLocationId()});};window.locator.clearLocation=function(k){var k=k||".locator-msg",f=b.dom.get(k);if(f.length==0){return;}var i;locator.fetchFromDataSet(locator.getSharedLocationId(),function(o){i=(o&&o.name)?o.name:"Not Set";},"wcw");var m=b.i18n.getLocaleModule(locator.locales.ui);var n=b.lang.interpolate(m.confirmClear.body,{location:i});m=b.lang.apply(m,{templWithLoc:n});var h=b.dom.create('<div class="locator-confirm"><p class="locator-panel-header"><strong>{confirmClear.title}</strong></p><div>{templWithLoc}</div></div>',{interpolate:m});var l=b.dom.create('<button type="submit">{confirmClear.confirm}</button>',{interpolate:m});var g=b.dom.create('<button type="submit">{confirmClear.cancel}</button>',{interpolate:m});h.append(g).append(l);var j=f.children();b.events.fire(locator,locator.EVENTS.userShownClearLocation);locator.transition(f,h.children(),"slideDown");b.events.addListener(l,"click",function(o){if(locator.debug){console.log("Confirm clear location");}b.events.fire(locator,locator.EVENTS.userConfirmedLocationChange,o);locator.clearSharedLocation();if(!o.defaultPrevented()){f.empty();}});b.events.addListener(g,"click",function(o){if(locator.debug){console.log("Cancelled clear location");}b.events.fire(locator,locator.EVENTS.userCancelledClearLocation,o);if(!o.defaultPrevented()){f.empty();f.append(j);}});};}});})(); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/50112000/jpg/_50112416_010706746-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/50112000/jpg/_50112416_010706746-1.jpg
deleted file mode 100755
index f7059ba5e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/50112000/jpg/_50112416_010706746-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/50906000/jpg/_50906324_006353309-2.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/50906000/jpg/_50906324_006353309-2.jpg
deleted file mode 100755
index 64feb645d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/50906000/jpg/_50906324_006353309-2.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/51990000/jpg/_51990536_011672235-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/51990000/jpg/_51990536_011672235-1.jpg
deleted file mode 100755
index a1a70e47c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/51990000/jpg/_51990536_011672235-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52015000/jpg/_52015349_flag_reuters_144.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52015000/jpg/_52015349_flag_reuters_144.jpg
deleted file mode 100755
index 5a4453977..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52015000/jpg/_52015349_flag_reuters_144.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52054000/jpg/_52054442_mj.144.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52054000/jpg/_52054442_mj.144.jpg
deleted file mode 100755
index 7e996c00b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52054000/jpg/_52054442_mj.144.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52057000/jpg/_52057539_arniecomp.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52057000/jpg/_52057539_arniecomp.jpg
deleted file mode 100755
index 8acb511e6..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52057000/jpg/_52057539_arniecomp.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52058000/jpg/_52058296_holdring_thinks.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52058000/jpg/_52058296_holdring_thinks.jpg
deleted file mode 100755
index 3f5edd74c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52058000/jpg/_52058296_holdring_thinks.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52058000/jpg/_52058744_jex_1012144_de27-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52058000/jpg/_52058744_jex_1012144_de27-1.jpg
deleted file mode 100755
index 32d8f3753..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52058000/jpg/_52058744_jex_1012144_de27-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52063000/jpg/_52063276_52063272.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52063000/jpg/_52063276_52063272.jpg
deleted file mode 100755
index 2c82074c9..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52063000/jpg/_52063276_52063272.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52064000/jpg/_52064940_94471941.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52064000/jpg/_52064940_94471941.jpg
deleted file mode 100755
index ef8036a31..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52064000/jpg/_52064940_94471941.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52065000/jpg/_52065323_aionscreenshot,ncsoft.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52065000/jpg/_52065323_aionscreenshot,ncsoft.jpg
deleted file mode 100755
index 6cfff0b94..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52065000/jpg/_52065323_aionscreenshot,ncsoft.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52068000/jpg/_52068942_jex_1012675_de09-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52068000/jpg/_52068942_jex_1012675_de09-1.jpg
deleted file mode 100755
index 4c252cd4d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52068000/jpg/_52068942_jex_1012675_de09-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52069000/jpg/_52069270_011711396-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52069000/jpg/_52069270_011711396-1.jpg
deleted file mode 100755
index 02539eb55..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52069000/jpg/_52069270_011711396-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072075_52072074.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072075_52072074.jpg
deleted file mode 100755
index 86a564bb3..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072075_52072074.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072121_-3.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072121_-3.jpg
deleted file mode 100755
index 48025005e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072121_-3.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072276_jex_1012855_de27-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072276_jex_1012855_de27-1.jpg
deleted file mode 100755
index fc8ffe683..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52072000/jpg/_52072276_jex_1012855_de27-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52073000/jpg/_52073406_008253948-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52073000/jpg/_52073406_008253948-1.jpg
deleted file mode 100755
index 38ed1ae84..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52073000/jpg/_52073406_008253948-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52073000/jpg/_52073764_011717136-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52073000/jpg/_52073764_011717136-1.jpg
deleted file mode 100755
index 7a307528c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52073000/jpg/_52073764_011717136-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52074000/jpg/_52074033_jex_1013006_de27.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52074000/jpg/_52074033_jex_1013006_de27.jpg
deleted file mode 100755
index 51ef1d269..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52074000/jpg/_52074033_jex_1013006_de27.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52075000/jpg/_52075786_stewart_getty304.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52075000/jpg/_52075786_stewart_getty304.jpg
deleted file mode 100755
index 826b1ed59..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52075000/jpg/_52075786_stewart_getty304.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52076000/jpg/_52076863_jex_1013152_de27-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52076000/jpg/_52076863_jex_1013152_de27-1.jpg
deleted file mode 100755
index 15a233edf..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52076000/jpg/_52076863_jex_1013152_de27-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077604_jex_1013246_de27-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077604_jex_1013246_de27-1.jpg
deleted file mode 100755
index 801aa8722..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077604_jex_1013246_de27-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077792_52077791.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077792_52077791.jpg
deleted file mode 100755
index a2101f2f8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077792_52077791.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077993_ivory_coast.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077993_ivory_coast.jpg
deleted file mode 100755
index 1dc9a0fe2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52077000/jpg/_52077993_ivory_coast.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52078000/jpg/_52078134_astuteshoot.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52078000/jpg/_52078134_astuteshoot.jpg
deleted file mode 100755
index b8dcf1daf..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52078000/jpg/_52078134_astuteshoot.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52078000/jpg/_52078945_jex_1013338_de27-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52078000/jpg/_52078945_jex_1013338_de27-1.jpg
deleted file mode 100755
index 7c41e2dde..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52078000/jpg/_52078945_jex_1013338_de27-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52079000/jpg/_52079170_jex_1013354_de30-1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52079000/jpg/_52079170_jex_1013354_de30-1.jpg
deleted file mode 100755
index cef7cd110..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/media/images/52079000/jpg/_52079170_jex_1013354_de30-1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/sol/shared/img/v4/commonwealth_games_2010/cg_bbccom_banner_sprite2.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/sol/shared/img/v4/commonwealth_games_2010/cg_bbccom_banner_sprite2.png
deleted file mode 100755
index 8edc15904..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/sol/shared/img/v4/commonwealth_games_2010/cg_bbccom_banner_sprite2.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/components/components.css b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/components/components.css
deleted file mode 100755
index f55eada81..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/components/components.css
+++ /dev/null
@@ -1 +0,0 @@
-.feature-promotion-accordion-holder{position:relative;z-index:100;}.feature-promotion-accordion-holder .heading-24{font-size:1.846em;font-weight:bold;letter-spacing:-1px;line-height:24px;text-rendering:optimizelegibility;padding:2px 0 9px;}.feature-promotion-accordion{position:relative;clear:both;overflow:hidden;width:624px;height:171px;margin:0 0 16px;}.feature-promotion-accordion ul{margin:0;padding:0;width:1000%;height:100%;}.feature-promotion-accordion ul li{position:relative;overflow:hidden;float:left;display:inline;clear:none;margin:0 0 0 1px;padding:0;width:304px;list-style:none;background-color:#808080;background-repeat:no-repeat;height:100%;}.feature-promotion-accordion li.first{margin-left:0;}.feature-promotion-accordion li.accordion-closed{width:159px;}.feature-promotion-accordion li .accordion-link,.feature-promotion-accordion li .accordion-link *{display:block;cursor:pointer;text-decoration:none;}.feature-promotion-accordion li .accordion-hover-layer{display:none;}.feature-promotion-accordion li.accordion-closed .accordion-hover-layer{opacity:.3;display:block;position:absolute;left:0;top:0;height:100%;width:100%;z-index:10;background-color:#fff;-webkit-transition:opacity 1s ease-out;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=30)";filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30);}.feature-promotion-accordion li.accordion-hover .accordion-hover-layer{opacity:.1;-webkit-transition:opacity .2s ease-in;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=20)";filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);}.feature-promotion-accordion li .accordion-overlay{z-index:20;display:block;}.feature-promotion-accordion li .accordion-overlay-content{display:block;}.feature-promotion-accordion li .accordion-overlay{background:transparent url(../img/accordian_overlay.png) bottom left repeat;display:block;position:absolute;bottom:0;height:68px;left:0;width:100%;overflow:hidden;}.ie .feature-promotion-accordion li .accordion-overlay{bottom:-1px;}.feature-promotion-accordion li a.accordion-link:active .accordion-overlay{background:#D1700E;}.blq-js .feature-promotion-accordion li.accordion-closed a.accordion-link:active .accordion-overlay,.blq-js .feature-promotion-accordion li.accordion-closed .accordion-overlay{background:transparent url(../img/accordian_overlay.png) -1952px bottom repeat;}.blq-js .feature-promotion-accordion li.accordion-right a.accordion-link:active .accordion-overlay,.blq-js .feature-promotion-accordion li.accordion-right .accordion-overlay{background:transparent url(../img/accordian_overlay.png) -976px bottom repeat;}.feature-promotion-accordion li .accordion-link,.feature-promotion-accordion li .accordion-link strong,.feature-promotion-accordion li .accordion-link p.description{color:#fff;}.feature-promotion-accordion li strong.title{display:block;margin:0;padding:8px 8px 0;}.feature-promotion-accordion li a.accordion-link:hover strong.title,.feature-promotion-accordion li a.accordion-link:focus strong.title{text-decoration:underline;}.blq-js .feature-promotion-accordion li.accordion-closed a.accordion-link:hover strong.title,.blq-js .feature-promotion-accordion li.accordion-closed a.accordion-link:focus strong.title{text-decoration:none;}.feature-promotion-accordion li p.description{margin:0;padding:0 8px 8px;font-weight:normal;}.feature-promotion-accordion li.accordion-closed p.description{display:none;}.full-height-accordion{height:287px;}.full-height-accordion ul li{width:448px;}.full-height-accordion li.accordion-closed{width:87px;}.also-in-news{position:relative;overflow:visible;width:624px;margin:0 0 12px;padding-top:0;border-top:1px solid #ddd;}.also-in-news h2{position:relative;padding:7px 0 8px 0;border-bottom:1px solid #ddd;}.also-in-news ul{position:relative;overflow:hidden;width:304px;margin:0 0 4px;padding-top:7px;padding-left:320px;}.also-in-news li{padding-bottom:8px;}.also-in-news .column-1{position:relative;float:left;clear:left;display:inline;overflow:visible;margin-left:-320px;width:304px;}.also-in-news .column-2{clear:none;position:relative;width:304px;}.also-in-news .column-2{float:right;}.also-in-news .small-image{width:176px;padding-left:128px;padding-bottom:10px;}.also-in-news .small-image img{float:left;display:inline;margin-top:3px;margin-left:-128px;width:112px;height:63px;}.also-in-news .gvl3-icon{position:absolute;top:0;left:0;}.also-in-news .gvl3-icon-wrapper{position:absolute;top:3px;left:0;}.also-in-news .gvl3-icon-wrapper .gvl3-icon{position:relative;top:auto;left:auto;}.also-in-news a.from-external-source{display:block;margin-left:0;}.container-av-best .av-live-streams{position:relative;margin-top:-20px;margin-bottom:16px;padding-top:5px;}.av-live-streams{background:#ededed;width:320px;padding:0 8px;}.av-live-streams li{position:relative;clear:both;display:block;overflow:hidden;padding:7px 0 8px;border-top:solid 1px #ddd;}.av-live-streams li.latest-summary{border-top:none;}.av-live-streams .av-live-streams-include{position:relative;clear:both;display:block;padding:0;}.av-live-streams li.first-child{border-top:none;}.av-live-streams .gvl3-icon{position:absolute;top:8px;left:0;}.container-av-best .av-live-streams li.latest-summary{border-top:0;padding-top:7px;}.av-live-streams li.latest-summary .gvl3-icon{top:0;}.av-live-streams .news-channel-promotion li{clear:both;}.av-live-streams li.latest-summary h3,.av-live-streams li.latest-summary a{float:left;display:inline;position:relative;}.container-av-best .av-live-streams li.latest-summary h3{padding-right:10px;padding-bottom:0;}.av-live-streams li.latest-summary a{padding-left:20px;padding-right:8px;}.container-av-best .av-live-streams .news-channel-promotion li.has-icon-boxedlive{padding-bottom:8px;}.av-stories-best{position:relative;overflow:hidden;width:336px;margin:0 0 16px;background:#eee;z-index:5;}.av-stories-best .av-best-header{position:relative;padding:8px;}.av-stories-best .list-wrapper{position:relative;clear:both;overflow:scroll;overflow-y:hidden;width:100%;}.blq-js .av-stories-best .list-wrapper{overflow:visible;}.av-stories-best .carousel,.av-stories-best .av-best-items{position:relative;clear:both;overflow:hidden;width:400%;height:124px;background:#ccc;-webkit-user-select:text;}.av-stories-best .carousel li,.av-stories-best .av-best-items li{position:relative;clear:none;display:inline;float:left;overflow:hidden;width:128px;border-right:1px solid #ededed;height:116px;padding:0 7px 8px 8px;background:#D1700E;}.av-stories-best .carousel li.carousel-added{display:none;}.av-stories-best .carousel li *,.av-stories-best .av-best-items li *{color:white;font-weight:normal;}.av-stories-best .carousel li img,.av-stories-best .av-best-items li img{position:relative;display:block;width:144px;height:81px;margin:0 -8px;padding-bottom:4px;}.av-stories-best .carousel li .gvl3-icon-wrapper,.av-stories-best .av-best-items li .gvl3-icon-wrapper{position:absolute;top:0;left:0;opacity:1;z-index:10;-webkit-transition:opacity .2s ease-in;}.av-stories-best .single-item,.av-stories-best .two-items{height:auto;width:100%;}.av-stories-best .single-item li,.av-stories-best .two-items li{clear:both;height:auto;width:320px;padding-top:8px;padding-right:8px;border-right:none;}.av-stories-best .two-items li+li{border-top:1px solid white;}.av-stories-best .single-item li img,.av-stories-best .two-items li img{float:left;display:inline;margin:-8px 8px -8px -8px;padding-bottom:0;}.blq-js .av-best-carousel{display:block;}.blq-js .av-stories-best .carousel-window{background:#888;padding:0 24px;width:288px!important;}.blq-js .av-stories-best .not-visible .gvl3-icon-wrapper{opacity:0;-webkit-transition:opacity .2s ease-in;}.blq-js .ie .av-stories-best .not-visible .gvl3-icon-wrapper,.blq-js .ie7 .av-stories-best .not-visible .gvl3-icon-wrapper{display:none;}.blq-js .av-stories-best .gvl3-carousel{position:relative;margin:0;overflow:visible;clear:both;height:124px;}.blq-js .av-stories-best .pageNav{position:absolute;right:0;top:-1px;height:1px!important;width:100%!important;overflow:visible;text-align:right;}.blq-js .av-stories-best .pageNav li{position:relative;cursor:pointer;background:none;height:8px;width:8px;margin-right:3px;}.blq-js .av-stories-best .pageNav .carousel-prev-disabled,.blq-js .av-stories-best .pageNav .carousel-prev-disabled a,.blq-js .av-stories-best .pageNav .carousel-next-disabled,.blq-js .av-stories-best .pageNav .carousel-next-disabled a{cursor:default;}.blq-js .av-stories-best .pageNav .dot{float:none;display:inline;text-align:right;}.blq-js .av-stories-best .dotLabel{position:relative;top:-23px;left:-5px;display:-moz-inline-stack;display:inline-block;text-align:left;width:8px!important;height:8px!important;background:#505050;}.blq-js .ie .av-stories-best .dotLabel,.blq-js .ie7 .av-stories-best .dotLabel{display:inline;}.blq-js .av-stories-best .dotActive .dotLabel{background:#D1700E;}.blq-js .av-stories-best #leftarrow{position:absolute;margin:0;padding:0;left:0;top:1px;width:23px;height:124px;z-index:10;border-right:1px solid #ededed;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/carousel-prev-next-3.png) no-repeat!important;background-position:0 center!important;-webkit-animation-name:carousel-arrow;-webkit-animation-duration:.6s;-webkit-animation-iteration-count:1;-webkit-animation-timing-function:ease-in;}.blq-js .av-stories-best #leftarrow.carousel-prev-disabled{background-position:-24px center!important;}.blq-js .av-stories-best #rightarrow{position:absolute;margin:0;padding:0;right:0;top:1px;width:24px;height:124px;z-index:10;border-left:1px solid #ededed;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/carousel-prev-next-3.png) no-repeat!important;background-position:-72px center!important;-webkit-animation-name:carousel-arrow;-webkit-animation-duration:.6s;-webkit-animation-iteration-count:1;-webkit-animation-timing-function:ease-in;}.blq-js .av-stories-best #rightarrow.carousel-next-disabled{background-position:-48px center!important;}.blq-js .av-stories-best #leftarrow .dotLabel,.blq-js .av-stories-best #rightarrow .dotLabel{display:none;}@-webkit-keyframes carousel-arrow{from{opacity:0;}to{opacity:1;}}.av-stories-now{position:relative;overflow:hidden;width:624px;margin:0 0 16px;z-index:5;}.av-stories-now .av-now-header{position:relative;margin-top:-1px;padding:0 0 9px;font-size:1.846em;font-weight:bold;letter-spacing:-1px;line-height:24px;text-rendering:optimizelegibility;}.av-stories-now .list-wrapper{position:relative;clear:both;overflow:scroll;overflow-y:hidden;width:100%;}.blq-js .av-stories-now .list-wrapper{overflow:visible;}.av-stories-now .carousel,.av-stories-now .av-best-items{position:relative;clear:both;overflow:hidden;width:400%;height:124px;background:#ccc;-webkit-user-select:text;}.av-stories-now .carousel li,.av-stories-now .av-best-items li{position:relative;clear:none;display:inline;float:left;overflow:hidden;width:128px;border-right:1px solid white;height:116px;padding:0 7px 8px 8px;background:#D1700E;}.av-stories-now .carousel li.carousel-added{display:none;}.ie .av-stories-now .carousel li,.ie .av-stories-now .av-best-items li{height:116px;}.av-stories-now .carousel li *,.av-stories-now .av-best-items li *{color:white;font-weight:normal;}.av-stories-now .carousel li img,.av-stories-now .av-best-items li img{position:relative;display:block;width:144px;height:81px;margin:0 -8px;padding-bottom:4px;}.av-stories-now .carousel li .gvl3-icon-wrapper,.av-stories-now .av-best-items li .gvl3-icon-wrapper{position:absolute;top:0;left:0;opacity:1;z-index:10;-webkit-transition:opacity .2s ease-in;}.blq-js .av-best-carousel{display:block;}.blq-js .av-stories-now .carousel-window{background:#888;padding:0 24px;width:576px!important;}.blq-js .av-stories-now .not-visible .gvl3-icon-wrapper{opacity:0;-webkit-transition:opacity .2s ease-in;}.blq-js .ie .av-stories-now .not-visible .gvl3-icon-wrapper,.blq-js .ie7 .av-stories-now .not-visible .gvl3-icon-wrapper{display:none;}.blq-js .av-stories-now .gvl3-carousel{position:relative;margin:0;overflow:visible;clear:both;height:124px;}.blq-js .av-stories-now .pageNav{position:absolute;right:-8px;top:-1px;height:1px!important;width:100%!important;overflow:visible;text-align:right;}.blq-js .av-stories-now .pageNav li{position:relative;cursor:pointer;background:none;height:8px;width:8px;margin-right:3px;}.blq-js .av-stories-now .pageNav .carousel-prev-disabled,.blq-js .av-stories-now .pageNav .carousel-prev-disabled a,.blq-js .av-stories-now .pageNav .carousel-next-disabled,.blq-js .av-stories-now .pageNav .carousel-next-disabled a{cursor:default;}.blq-js .av-stories-now .pageNav .dot{float:none;display:inline;text-align:right;}.blq-js .av-stories-now .dotLabel{position:relative;top:-23px;left:-5px;display:-moz-inline-stack;display:inline-block;text-align:left;width:8px!important;height:8px!important;background:#505050;}.blq-js .ie .av-stories-now .dotLabel,.blq-js .ie7 .av-stories-now .dotLabel{display:inline;}.blq-js .av-stories-now .dotActive .dotLabel{background:#D1700E;}.blq-js .av-stories-now #leftarrow{position:absolute;margin:0;padding:0;left:-8px;top:1px;width:23px;height:124px;z-index:10;border-right:1px solid white;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/carousel-prev-next-3.png) no-repeat!important;background-position:0 center!important;-webkit-animation-name:carousel-arrow;-webkit-animation-duration:.6s;-webkit-animation-iteration-count:1;-webkit-animation-timing-function:ease-in;}.blq-js .av-stories-now #leftarrow.carousel-prev-disabled{background-position:-24px center!important;}.blq-js .av-stories-now #rightarrow{position:absolute;margin:0;padding:0;right:8px;top:1px;width:24px;height:124px;z-index:10;border-left:1px solid white;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/carousel-prev-next-3.png) no-repeat!important;background-position:-72px center!important;-webkit-animation-name:carousel-arrow;-webkit-animation-duration:.6s;-webkit-animation-iteration-count:1;-webkit-animation-timing-function:ease-in;}.blq-js .av-stories-now #rightarrow.carousel-next-disabled{background-position:-48px center!important;}.blq-js .av-stories-now #leftarrow .dotLabel,.blq-js .av-stories-now #rightarrow .dotLabel{display:none;}@-webkit-keyframes carousel-arrow{from{opacity:0;}to{opacity:1;}}.av-stories-source{position:relative;overflow:hidden;width:336px;margin:64px 0 16px;background:#eee;z-index:5;}.av-stories-source .av-best-header{position:relative;padding:8px;}.av-stories-source .list-wrapper{position:relative;clear:both;overflow:scroll;overflow-y:hidden;width:100%;}.blq-js .av-stories-source .list-wrapper{overflow:visible;}.av-stories-source .carousel,.av-stories-source .av-best-items{position:relative;clear:both;overflow:hidden;width:400%;height:124px;background:#ccc;-webkit-user-select:text;}.av-stories-source .carousel li,.av-stories-source .av-best-items li{position:relative;clear:none;display:inline;float:left;overflow:hidden;width:128px;border-right:1px solid #ededed;height:116px;padding:0 7px 8px 8px;background:#D1700E;}.av-stories-source .carousel li.carousel-added{display:none;}.av-stories-source .carousel li *,.av-stories-source .av-best-items li *{color:white;font-weight:normal;}.av-stories-source .carousel li img,.av-stories-source .av-best-items li img{position:relative;display:block;width:144px;height:81px;margin:0 -8px;padding-bottom:4px;}.av-stories-source .carousel li .gvl3-icon-wrapper,.av-stories-source .av-best-items li .gvl3-icon-wrapper{position:absolute;top:0;left:0;opacity:1;z-index:10;-webkit-transition:opacity .2s ease-in;}.av-stories-source .single-item,.av-stories-source .two-items{height:auto;width:100%;}.av-stories-source .single-item li,.av-stories-source .two-items li{clear:both;height:auto;width:320px;padding-top:8px;padding-right:8px;border-right:none;}.av-stories-source .two-items li+li{border-top:1px solid white;}.av-stories-source .single-item li img,.av-stories-source .two-items li img{float:left;display:inline;margin:-8px 8px -8px -8px;padding-bottom:0;}.blq-js .av-best-carousel{display:block;}.blq-js .av-stories-source .carousel-window{background:#888;padding:0 24px;width:288px!important;}.blq-js .av-stories-source .not-visible .gvl3-icon-wrapper{opacity:0;-webkit-transition:opacity .2s ease-in;}.blq-js .ie .av-stories-source .not-visible .gvl3-icon-wrapper,.blq-js .ie7 .av-stories-source .not-visible .gvl3-icon-wrapper{display:none;}.blq-js .av-stories-source .gvl3-carousel{position:relative;margin:0;overflow:visible;clear:both;height:124px;}.blq-js .av-stories-source .pageNav{position:absolute;right:0;top:-1px;height:1px!important;width:100%!important;overflow:visible;text-align:right;}.blq-js .av-stories-source .pageNav li{position:relative;cursor:pointer;background:none;height:8px;width:8px;margin-right:3px;}.blq-js .av-stories-source .pageNav .carousel-prev-disabled,.blq-js .av-stories-source .pageNav .carousel-prev-disabled a,.blq-js .av-stories-source .pageNav .carousel-next-disabled,.blq-js .av-stories-source .pageNav .carousel-next-disabled a{cursor:default;}.blq-js .av-stories-source .pageNav .dot{float:none;display:inline;text-align:right;}.blq-js .av-stories-source .dotLabel{position:relative;top:-23px;left:-5px;display:-moz-inline-stack;display:inline-block;text-align:left;width:8px!important;height:8px!important;background:#505050;}.blq-js .ie .av-stories-source .dotLabel,.blq-js .ie7 .av-stories-source .dotLabel{display:inline;}.blq-js .av-stories-source .dotActive .dotLabel{background:#D1700E;}.blq-js .av-stories-source #leftarrow{position:absolute;margin:0;padding:0;left:0;top:1px;width:23px;height:124px;z-index:10;border-right:1px solid #ededed;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/carousel-prev-next-3.png) no-repeat!important;background-position:0 center!important;-webkit-animation-name:carousel-arrow;-webkit-animation-duration:.6s;-webkit-animation-iteration-count:1;-webkit-animation-timing-function:ease-in;}.blq-js .av-stories-source #leftarrow.carousel-prev-disabled{background-position:-24px center!important;}.blq-js .av-stories-source #rightarrow{position:absolute;margin:0;padding:0;right:0;top:1px;width:24px;height:124px;z-index:10;border-left:1px solid #ededed;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/carousel-prev-next-3.png) no-repeat!important;background-position:-72px center!important;-webkit-animation-name:carousel-arrow;-webkit-animation-duration:.6s;-webkit-animation-iteration-count:1;-webkit-animation-timing-function:ease-in;}.blq-js .av-stories-source #rightarrow.carousel-next-disabled{background-position:-48px center!important;}.blq-js .av-stories-source #leftarrow .dotLabel,.blq-js .av-stories-source #rightarrow .dotLabel{display:none;}@-webkit-keyframes carousel-arrow{from{opacity:0;}to{opacity:1;}}.big-picture-teaser{display:block;overflow:hidden;float:none;clear:both;background-color:#ededed;position:relative;padding-bottom:8px;margin-bottom:16px;}.big-picture-teaser .heading-24{font-size:1.846em;font-weight:bold;letter-spacing:-1px;line-height:24px;text-rendering:optimizelegibility;padding:8px 0 10px 8px;}.big-picture-teaser .teaser-link{display:block;padding-left:32px;position:relative;overflow:hidden;}.big-picture-teaser .teaser-link img{margin-bottom:6px;margin-left:-32px;float:none;position:relative;display:block;}.big-picture-teaser .teaser-link .gvl3-icon{position:absolute;bottom:-5px;left:8px;float:left;}.image-light-box .tr,.image-light-box .tl,.image-light-box .tb,.image-light-box .tc .bars,.image-light-box .br,.image-light-box .bl,.image-light-box .bb{display:none;}.image-light-box .panel-hd,.image-light-box .panel-bd,.image-light-box .panel-ft{padding:0!important;margin:0!important;background:#fff!important;color:#000!important;}.blq-js .image-light-box .panel-hd,.blq-js .image-light-box .panel-bd,.blq-js .image-light-box .panel-ft{background-color:#ededed!important;}.blq-js .image-light-box .panel-hd .hd{padding:10px 8px;}.blq-js .ie7 .image-light-box .panel-hd .hd{font-size:2.4em;padding:14px 8px 14px 8px;}.blq-js .ie7 .image-light-box .panel-hd{display:block;}.blq-js .image-light-box .c a.panel-close{background-image:url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.png)!important;background-position:-510px 0!important;background-repeat:none;overflow:hidden;width:15px;height:16px;margin:14px 10px 0 0!important;}.blq-js .ie .image-light-box .c a.panel-close{background-image:url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.gif)!important;right:10px;}.blq-js .image-light-box .panel-ft .ft{font-size:1.3em;padding:5px 8px 14px;width:auto!important;}.ie .big-picture-teaser,.ie .big-picture-teaser .teaser-link,.ie7 .big-picture-teaser,.ie7 .big-picture-teaser .teaser-link{height:1%;}.blq-js .ie .glow173-panel .c,.blq-js .ie .image-light-box .panel-ft{width:100%;}.share-help{position:relative;width:230px;float:right;padding:0;}.share-help ul{padding:0 0 16px 0;margin:0;position:relative;}.share-help ul li{background:none;float:left;margin:0 0 0 5px;padding:0 1px;}.share-help ul li.facebook-context{overflow:visible;height:1px;position:relative;}.share-help ul li a{display:block;padding:0 0 0 16px;background-image:url(../../../../../1_4_9/cream/hi/shared/img/story_sprite.gif);background-repeat:no-repeat;text-indent:-6000px;text-decoration:none;float:left;}body.ie li.twitter a,body.ie li.facebook-popup a,.body.ie li.share a,body.ie li.email a,body.ie li.print a{width:1px;}.share-help ul .twitter a{background-position:-300px 0;}.share-help ul .share a{background-position:-460px 0;}.share-help ul .email a{background-position:-620px 0;}.share-help ul .print a{background-position:-773px 0;}.share-help iframe{top:-2px;left:0;overflow:hidden;width:80px;height:24px;font-family:Helvetica;}.blq-js .share-help ul{padding:0 0 11px 0;}.blq-js li.delicious,.blq-js li.digg,.blq-js li.reddit,.blq-js li.stumbleupon,.blq-js li.mixx,.blq-js li.google{display:none;}.share-help ul li.delicious a{background-position:-3650px 0;}.share-help ul li.digg a{background-position:-2200px 0;}.share-help ul li.facebook a{background-position:0 0;}.share-help ul li.reddit a{background-position:-2650px 0;}.share-help ul li.stumbleupon a{background-position:-2400px 0;}.share-help ul li.twitter a{background-position:-300px 0;}.share-help ul li.mixx a{background-position:-2900px 0;}.share-help ul li.google a{background-position:-3150px 0;}.story .share-help{position:relative;width:240px;float:right;margin:8px -160px -2px 0;padding:0;z-index:1;}#main-content .layout-block-a.expanded .share-help,.story-wide .share-help,.storybody-halfwide-include .share-help{margin-right:0;}.ie .story .story-body .share-help{width:245px!important;}.bbccom_slot_xxl .story .share-help{margin:8px 0 0 0;float:right;width:120px;}.story .share-help h3{position:absolute;left:-5000px;top:-5000px;}.story .share-help ul{float:right;}.story .share-help ul li{background:none;}.story .share-body-bottom .share-help{position:relative;clear:both;float:left;margin:0 0 16px;width:100%;}.story .share-body-bottom .share-help h3{position:relative;top:0;left:0;padding:0 0 8px 0;margin:0 0 16px 0;border-bottom:1px solid #ccc;}.story .share-body-bottom .share-help ul{float:left;height:20px;}.blq-js .story .share-body-bottom .share-help ul{width:102px!important;}.blq-js .story .share-body-bottom .share-help ul li{position:absolute;margin:0;}.blq-js .story .share-body-bottom .share-help ul li.email{top:0;left:0;}.blq-js .story .share-body-bottom .share-help ul li.print{position:absolute;top:0;left:23px;}.blq-js .story .share-body-bottom .share-help ul li.facebook-popup{position:absolute;top:0;left:92px;}.blq-js .media-asset .share-help ul li.facebook-popup,.blq-js .photo-gallery .share-help ul li.facebook-popup{position:absolute;top:0;left:67px;}.blq-js .story .share-body-bottom .share-help ul li.twitter{position:absolute;top:0;left:69px;}.blq-js .story .share-body-bottom .share-help ul li.share{position:absolute;top:0;left:46px;}.blq-js .story .share-body-bottom .share-help ul li.facebook{position:absolute;top:0;left:92px;width:160px;}.story .share-body-bottom .share-help ul li.facebook-context{position:absolute;left:94px;}.story .share-body-bottom .share-help iframe{font-family:Helvetica;left:0;overflow:hidden;}.media-asset .share-help,.photo-gallery .share-help{clear:both;position:relative;float:left!important;width:100%!important;padding:8px 0 0 0;height:76px;margin:0 0 16px 0;}.media-asset .share-help h3,.photo-gallery .share-help h3{padding:0 0 8px 0;margin:0 0 14px 0;border-bottom:1px solid #ccc;}.blq-js .media-asset .share-help ul,.blq-js .photo-gallery .share-help ul{width:102px!important;}.media-asset .share-help ul,.photo-gallery .share-help ul{float:left;}.blq-js .media-asset .share-help ul li,.blq-js .photo-gallery .share-help ul li{position:absolute;}.media-asset .share-help ul li.email,.photo-gallery .share-help ul li.email{top:0;left:-2px;}.media-asset .share-help ul li.print,.photo-gallery .share-help ul li.print{position:absolute;top:0;left:21px;display:none;}.blq-js .media-asset .share-help ul li.twitter,.blq-js .photo-gallery .share-help ul li.twitter{position:absolute;top:0;left:44px;}.media-asset .share-help ul li.share,.photo-gallery .share-help ul li.share{position:absolute;top:0;left:21px;}.media-asset .share-help ul li.facebook-context,.photo-gallery .share-help ul li.facebook-context{left:68px;}.media-asset .share-help iframe,.photo-gallery .share-help iframe{font-family:Helvetica;left:0!important;overflow:hidden;}.container-travel-best{background-color:#EDEDED;padding:0 8px;clear:both;position:relative;margin-bottom:16px;overflow:auto;}.ie .container-travel-best{height:1%;}.container-travel-best .heading-24{font-size:24px;font-weight:bold;letter-spacing:-1px;margin:0;padding:8px 0 8px 0;text-rendering:optimizelegibility;line-height:24px;}.container-travel-best h2 a{line-height:24px;}.container-travel-best .useful-links{border-top:none;margin:0;}.container-travel-best .useful-links .useful-links-header{border-bottom:medium none;display:block;font-size:15px;font-weight:bold;letter-spacing:normal;line-height:16px;padding:8px 0 0 0;position:relative;text-rendering:optimizelegibility;}.container-travel-best .useful-links ul{overflow:hidden;padding:0;position:relative;width:304px;}.container-travel-best .useful-links .column-1,.container-travel-best .useful-links .column-2{clear:both;display:block;float:none;margin-left:0;overflow:visible;position:relative;width:100%;padding-bottom:0;}.container-travel-best .useful-links ul a{padding-right:0;font-weight:normal;}.correspondent-byline{position:relative;display:block;clear:both;overflow:hidden;width:624px;top:-5px;margin:0 -160px 12px 0;background:#333;}.bbccom_slot_xxl .correspondent-byline{margin-right:0;width:464px;}.correspondent-byline-inner{position:relative;overflow:visible;border-top:16px solid white;}.correspondent-byline *{color:#ccc;}.correspondent-byline .name,.correspondent-byline a{font-weight:bold;color:white;}.correspondent-byline .byline-lead-in{position:absolute;left:-5000%;}.correspondent-byline .correspondent-portrait{position:relative;float:right;display:inline;z-index:10;}.correspondent-byline .correspondent-portrait img{position:relative;display:block;height:104px;width:144px;margin-top:-16px;}.correspondent-byline .name{float:left;display:inline;font-size:24px;line-height:28px;padding:10px 8px 2px;letter-spacing:-1px;}.correspondent-byline .bbc-role{display:block;clear:left;position:relative;top:1px;font-size:16px;line-height:20px;padding:0 8px;color:#D2700E;}.correspondent-byline ul.social-links{margin:-2px 0 0;position:relative;overflow:hidden;padding:0;}.correspondent-byline ul.social-links li{position:relative;float:left;display:inline;margin:5px 0 0;padding:0 8px;border-left:1px solid #505050;background:none;line-height:16px;}.correspondent-byline ul.social-links li:first-child{border:none;}.correspondent-byline ul.social-links li a{font-size:13px;}.story-feature .correspondent-byline{margin:0 0 11px;top:0;padding:0 0 3px 118px;width:auto;background:transparent;border-bottom:1px solid #D8D8D8;}.story-feature .correspondent-byline .byline-picture{position:relative;float:left;display:inline;margin:0 0 0 -118px;}.story-feature .correspondent-byline .byline-picture img{margin:0!important;width:112px;height:63px;}.story-feature .correspondent-byline .byline-heading{position:relative;color:#505050;font-weight:bold;font-size:24px;letter-spacing:-1px;top:1px;line-height:28px;padding:0 8px 0 0;margin:0;}.story-feature .correspondent-byline .byline-name{display:block;color:#505050;font-size:16px;line-height:20px;margin-bottom:1px;}.story-feature .correspondent-byline .byline-title{position:relative;top:-1px;display:block;padding:0 8px 0 0;color:#D2700E;font-size:16px;line-height:20px;}.correspondent-facts{position:relative;display:block;clear:both;margin:0 0 16px;background:#ededed;}.correspondent-facts .correspondent-facts-header{font-size:24px;font-weight:bold;letter-spacing:-1px;line-height:24px;text-rendering:optimizelegibility;padding:10px 8px 14px;}.correspondent-facts p{padding:0 8px 8px;font-size:15px;line-height:20px;}.correspondent-facts p *{font-size:inherit;line-height:inherit;}.correspondent-facts h3{padding:4px 0 0;font-size:16px;color:#80989a;}.correspondents-more{position:relative;display:block;clear:both;margin:0 0 16px;background:#ededed;}.correspondents-more .correspondents-more-header{font-size:24px;font-weight:bold;letter-spacing:-1px;line-height:24px;text-rendering:optimizelegibility;padding:10px 8px;}.correspondents-more ul{padding:0 8px;}.correspondents-more ul li{position:relative;overflow:hidden;padding:5px 0 9px 120px;}.correspondents-more ul li .name{display:block;font-size:16px;color:inherit;}.correspondents-more ul li .bbc-role{padding-top:2px;display:block;font-weight:normal;color:#D2700E;}.correspondents-more ul li img{position:relative;float:left;display:inline;margin:2px 0 0 -120px;width:112px;height:63px;}.correspondents-more hr{display:none;}.ie .correspondents-more hr{display:block;}.correspondent-promo{position:relative;clear:both;display:block;overflow:hidden;padding-left:160px;}.index #now .correspondent-promo{width:464px;margin:0 0 16px 0;}.index #best .correspondent-promo{width:176px;margin:0 0 16px 0;}.story .layout-block-a .correspondent-promo{width:304px;margin:2px 0 16px 0;}.correspondent-promo-inner{position:relative;overflow:visible;padding-top:24px;}.correspondent-promo-inner a:after{content:"\00a0";float:left;position:relative;margin-left:-5000%;}.correspondent-promo .name{font-weight:bold;}.correspondent-promo .promo-lead-in{position:absolute;left:-5000%;}.correspondent-promo .correspondent-portrait{position:relative;margin-top:-24px;margin-left:-160px;float:left;display:inline;overflow:hidden;}.correspondent-promo .correspondent-portrait img{position:relative;display:block;margin-bottom:-1px;width:144px;height:104px;}.correspondent-promo .name{display:block;color:inherit;font-size:24px;line-height:28px;padding:2px 8px 0 0;letter-spacing:-1px;}.correspondent-promo .bbc-role{display:block;position:relative;top:-1px;font-size:16px;line-height:20px;padding:0 8px 0 0;color:#D2700E;}.correspondent-promo ul.social-links{margin:0;overflow:hidden;padding:2px 0 8px;}.correspondent-promo ul.social-links li{position:relative;float:left;display:inline;margin:0;line-height:16px;padding:0 8px;border-left:1px solid #ccc;background:none;}.correspondent-promo ul.social-links li:first-child{border:none;padding-left:0;}.index #best .correspondent-promo ul.social-links li{clear:both;padding-left:0;border:none;}.correspondent-promo ul.social-links li a{font-size:13px;}.correspondent-promo .correspondent-promo-item{position:relative;clear:both;margin:0 0 0 -160px;background:#ededed;}.correspondent-promo .correspondent-promo-item .article{padding:8px;}.correspondent-promo .correspondent-promo-item .article+.article{border-top:8px solid white;}.correspondent-promo .correspondent-promo-item .blog h2{padding:2px 0 6px;font-size:16px;}.correspondent-promo .correspondent-promo-item .blog .article-date{color:#888;}.correspondent-promo .correspondent-promo-item .blog p{padding:0 0 4px;}.correspondent-promo .correspondent-promo-item .twitter h2{padding:1px 0 3px;font-size:16px;line-height:20px;font-weight:normal;}.correspondent-promo .correspondent-promo-item .twitter p{padding:0 0 4px;font-size:18px;line-height:20px;}.container-country-profile{clear:both;position:relative;overflow:hidden;width:608px;margin:0 0 16px;padding:8px;background:#EDEDED;}.container-country-profile .container-country-profile-header{font-size:24px;font-size:1.846em;font-weight:bold;letter-spacing:-0.05em;line-height:24px;text-indent:-2px;padding:0;}.container-country-profile .tab{padding:8px 16px 9px 0;position:relative;background:transparent;z-index:100;font-size:1.231em;font-weight:bold;line-height:23px;}.container-country-profile .panel{position:relative;overflow:hidden;background:#fff;width:608px;}.container-country-profile .panel h3.more{position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden;}.container-country-profile .panel ul.column{width:152px;float:left;padding:4px 0 10px;}.container-country-profile .panel li{display:block;padding:8px 8px 2px 8px;}.ie .container-country-profile .panel li a{padding-bottom:4px;height:1%;}.container-country-profile .panel li.first-child{border-top:none;}.blq-js .container-country-profile-tabbed .container-country-profile-header{padding-bottom:8px;}.blq-js .container-country-profile-tabbed .tab{float:left;display:inline;top:0;padding-left:8px;cursor:pointer;}.blq-js .container-country-profile-tabbed void{background:#fff;}.blq-js .container-country-profile-tabbed h3.tab a{color:#505050;}.blq-js .container-country-profile-tabbed void a{color:#D1700E;}.blq-js .container-country-profile-tabbed .panel{position:absolute;float:right;display:inline;clear:right;right:-500%;margin-right:0;margin-top:40px;opacity:0;}.blq-js .ie .container-country-profile-tabbed .panel,.blq-js .ie7 .container-country-profile-tabbed .panel{clear:none;}.blq-js .container-country-profile-tabbed void{position:relative;margin-right:-608px;right:608px;opacity:1;-webkit-transition:opacity .2s ease-in;}.blq-js .ie .container-country-profile-tabbed void,.blq-js .ie7 .container-country-profile-tabbed void{margin-top:32px;}.container-digest-grid{position:relative;display:block;clear:both;overflow:hidden;margin:0;min-height:16px;padding-top:4px;}.container-digest-grid .heading-24{font-size:1.846em;font-weight:bold;letter-spacing:-1px;line-height:24px;text-rendering:optimizelegibility;padding:2px 0 9px;}.digest-grid{position:relative;display:block;clear:both;overflow:hidden;margin:0 0 20px;min-height:16px;border-top:1px solid #DDD;padding-top:4px;}.digest-grid .digest-unit{position:relative;float:left;display:inline;width:144px;margin-left:16px;}.digest-grid .digest-unit .heading-16{display:block;font-size:1.231em;font-weight:bold;line-height:20px;padding:4px 0 8px;position:relative;text-rendering:optimizelegibility;}.digest-grid .digest-unit .heading-16 a{line-height:20px;}.digest-grid .first-child{margin-left:0;}.digest-grid .digest-unit img{display:block;margin-bottom:6px;}.digest-grid li{position:relative;padding-top:8px;}.digest-grid li.standard-no-image{padding-top:0;}.digest-grid .stacked-144{position:relative;padding-top:0;}.digest-grid .standard-no-image a:hover .headline,.digest-grid .standard-no-image a:focus .headline,.digest-grid .stacked-144 a:hover,.digest-grid .stacked-144 a:focus{text-decoration:none;}.digest-grid .standard-no-image a:hover .headline,.digest-grid .standard-no-image a:focus .headline,.digest-grid .stacked-144 a:hover .headline,.digest-grid .stacked-144 a:focus .headline{text-decoration:underline;}.digest-grid .standard-no-image a .headline,.digest-grid .stacked-144 a .headline{color:#1F4F82;}.digest-grid .standard-no-image a:visited .headline,.digest-grid .stacked-144 a:visited .headline{color:#4A7194;}.digest-grid .standard-no-image a:active .headline,.digest-grid .stacked-144 a:active .headline{color:#D1700E;}.digest-grid .standard-no-image{position:relative;}.digest-grid .standard-no-image .gvl3-icon,.digest-grid .gvl3-icon-wrapper{position:absolute;top:0;left:0;}.digest-grid .gvl3-icon-wrapper .gvl3-icon{position:relative;top:0;}.digest-grid .gvl3-icon{position:absolute;top:7px;left:0;}.digest-grid .gvl3-icon-live{top:8px;}.digest-grid-text-only{position:relative;display:block;clear:both;overflow:hidden;margin:0 0 20px;min-height:16px;border-top:1px solid #DDD;padding-top:4px;}.digest-grid-text-only+.digest-grid-text-only{margin-top:-16px;border-top:none;padding-top:5px;}.digest-grid-text-only .digest-unit{position:relative;float:left;display:inline;width:144px;margin-left:16px;}.digest-grid-text-only .digest-unit h3{display:block;padding:7px 0 0;position:relative;}.digest-grid-text-only .digest-unit .heading-11{font-size:.846em;font-weight:normal;line-height:16px;text-transform:uppercase;text-rendering:optimizelegibility;color:#505050;}.digest-grid-text-only .heading-11:active{color:#D1700E;}.digest-grid-text-only .first-child{margin-left:0;}.digest-grid-text-only .standard-no-image{position:relative;}.digest-grid-text-only .gvl3-icon{position:absolute;top:-1px;left:0;}.digest-grid-text-only .gvl3-icon-live{top:0;}.container-digest-grid .include-wrapper{position:relative;overflow:hidden;clear:both;margin:0 0 8px 0;width:100%;}.container-digest-grid .include-wrapper .simple-promo h3,.container-digest-grid .include-wrapper .simple-promo p{display:inline;}.container-digest-grid .include-wrapper .geo-digest-region{width:304px;padding-top:0;margin-bottom:0;}.container-digest-grid #personalisation{width:304px;padding-top:4px;border-bottom:none;}.container-digest-grid #personalisation .locator-forms{width:608px;}.container-digest-grid #personalisation .options{top:8px;}.include-wrapper+.digest-wrapper{border-top:none;}.container-digest-grid .geo-digest-region #personalisation .column-1{width:296px;}.container-digest-grid .geo-digest-region #personalisation .column-2{width:296px;margin-left:6px;}.container-digest-grid .container-block-grid{display:block;overflow:auto;clear:both;position:relative;}.digest-grid-list-column{position:relative;float:left;display:inline;width:304px;padding-bottom:9px;}.digest-grid-list-column+.digest-grid-list-column{padding-left:16px;}.digest-grid-list-column .digest-unit{position:relative;padding-top:5px;padding-bottom:16px;}.digest-grid-list-column .heading-16{font-size:1.231em;font-weight:bold;line-height:20px;text-rendering:optimizelegibility;}.digest-grid-list-column .standard-no-image{border-top:1px solid #ddd;padding-top:6px;position:relative;}.digest-grid-list-column .standard-no-image .gvl3-icon{position:absolute;top:5px;left:0;}.digest-grid .digest-unit .heading-16 .or-text{left:-9000px;position:absolute;}.digest-grid .digest-unit .heading-16 .vertical-line{border-left:2px solid #505050;font-size:.76em;margin-left:5px;margin-right:5px;}.ie .container-digest-grid .digest-grid-text-only,.ie .container-digest-grid .digest-grid .standard-no-image,.ie .container-digest-grid .digest-grid-text-only .standard-no-image,.ie7 .container-digest-grid .digest-grid-text-only,.ie7 .container-digest-grid .digest-grid .standard-no-image,.ie7 .container-digest-grid .digest-grid-text-only .standard-no-image{height:1%;}.ie .container-digest-grid .digest-grid,.ie .container-digest-grid .digest-grid .digest-unit,.ie7 .container-digest-grid .digest-grid,.ie7 .container-digest-grid .digest-grid .digest-unit{height:1%;}.ie .container-digest-grid .digest-grid .digest-unit ul,.ie .container-digest-grid .digest-grid .digest-unit li,.ie7 .container-digest-grid .digest-grid .digest-unit ul,.ie7 .container-digest-grid .digest-grid .digest-unit li{height:1%;}.ie .digest-grid-list-column .standard-no-image{height:1%;}.container-single-section-digest{position:relative;clear:both;}.container-single-section-digest .container-single-section-digest-heading{font-size:1.846em;font-weight:bold;letter-spacing:-1px;line-height:24px;text-rendering:optimizelegibility;padding:2px 0 9px;}.container-single-section-digest .digest-grid-text-only{border-top:none;}#ent-widget{padding:0;margin:0;height:303px;width:606px;background-color:#EDEDED;color:#505050;font-family:Verdana,Arial,sans-serif;font-size:13px;}#ent-widget ul{margin:0;padding:0;padding-left:9px;list-style-type:none;}#ent-widget li{margin:0;padding:0;list-style-type:none;}#ent-widget h2,#ent-widget h3,#ent-widget h4{padding:0;margin:0;font-weight:bold;}#ent-widget h2{padding-top:9px;padding-left:9px;font-size:21px;color:#505050;margin-bottom:10px;}#ent-widget h3{font-size:13px;color:#505050;}#ent-widget p{padding:0;margin:0;margin-bottom:10px;}#ent-widget a{color:#194E80;text-decoration:none;}#ent-widget a:hover{text-decoration:underline;}#ent-widget .column-1{float:left;clear:left;overflow:visible;position:relative;width:300px;}#ent-widget .column-2{float:left;margin-left:10px;clear:none;position:relative;width:280px;}#ent-widget .column-1 h3{font-size:15px;font-weight:bold;}#ent-widget .column-1 a{font-size:17px;font-weight:bold;}#ent-widget .column-2 p{font-weight:bold;}.container-expert-views{width:624px;padding-top:0;}.container-expert-views h2{margin-top:0;border-top:1px solid #DDD;}.digest-wrapper-header{margin-top:0;padding-top:3px;}.container-expert-views{margin-top:0;overflow:hidden;}.container-expert-views .digest{float:left;display:inline;width:304px;margin-left:16px;}.container-expert-views .new-row{margin-left:0;clear:both;}.container-expert-views .digest div.first-child{padding-left:0;}.container-expert-views .digest ul{width:304px;padding-left:0;margin-bottom:7px;}.container-expert-views .digest .medium-image{width:144px;padding-bottom:14px;margin-top:4px;margin-left:0;}.container-expert-views .digest .medium-image .digest-story-header{padding-bottom:4px;}.container-expert-views .digest .medium-image img{margin-bottom:-3px;top:3px;}.container-expert-views .digest .medium-image .gvl3-icon-wrapper{top:3px;}.expert-odd .first-child .first-child .gvl3-icon-wrapper{top:3px;}.container-expert-views .digest .no-image{width:304px;}.container-expert-views .digest .no-image .digest-story-header{padding-bottom:4px;}.container-expert-views .digest .column-1{width:304px;margin-left:0;}.container-expert-views .digest .column-2{position:relative;float:left;clear:none;display:inline;overflow:hidden;width:304px;margin-left:0;}.expert-odd div.first-child{width:624px;padding-left:0;margin-left:0;}.expert-odd .digest{margin-bottom:0;}div.expert-odd .digest ul{margin-bottom:1px;}.expert-odd .digest li{clear:both;}.expert-odd div.first-child ul{position:relative;overflow:auto;width:304px;margin:1px 0 9px;padding-left:320px;}.expert-odd div.first-child li{padding-bottom:8px;}.expert-odd div.first-child .medium-image{position:relative;clear:both;overflow:hidden;width:464px;margin-left:-320px;margin-top:4px;padding-bottom:15px;padding-left:160px;}.expert-odd div.first-child .no-image{padding-left:-320px;}.expert-odd div.first-child .medium-image .digest-story-header{position:relative;padding-bottom:4px;}.expert-odd div.first-child .medium-image img{position:relative;float:left;display:inline;margin-left:-160px;width:144px;height:81px;top:3px;}.expert-odd div.first-child .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;width:304px;margin-left:-320px;}.expert-odd div.first-child .column-2{clear:none;position:relative;width:304px;}.container-expert-views .digest-wrapper-header{margin-bottom:-1px;}.digest-wrapper-header a{line-height:24px;}.container-expert-views .digest .column-1,.container-expert-views .digest .column-2{display:block;float:none;}.expert-odd .digest .no-image{width:304px;padding-right:0;margin-left:0;padding-bottom:6px;}.expert-odd .digest .medium-image{padding-bottom:14px;}.expert-even div.digest .no-image{padding-bottom:6px;margin-top:4px;}.expert-odd div.first-child .no-image{margin-top:4px;padding-right:0;width:342px;margin-left:-320px;}.container-expert-views .digest ul{margin-bottom:16px;}.ie .container-expert-views .medium-image,.ie7 .container-expert-views .medium-image{padding-bottom:0!important;}.ie .container-expert-views .digest .column-1,.ie .container-expert-views .digest .column-2{position:relative;float:left!important;}.ie7 .container-expert-views .no-image p{margin-bottom:-4px;}.ie .container-expert-views .no-image,.ie7 .container-expert-views .no-image{padding-bottom:0;}.ie .container-expert-views div.digest ul,.ie7 .container-expert-views div.digest ul{padding-bottom:0;margin-bottom:0;}.ie .container-expert-views.expert-even .digest{height:1%!important;}div.expert-even div.digest ul{margin-bottom:1px;}div.expert-even hr.breaker{margin-bottom:8px;}.ie div.expert-even hr.breaker,.ie7 div.expert-even hr.breaker{margin-bottom:0;}.feature-digest{position:relative;overflow:visible;width:624px;margin:0;padding-top:3px;}.feature-digest .feature-digest-header{position:relative;margin-bottom:3px;padding-top:9px;padding-bottom:11px;line-height:16px;}.feature-digest ul{position:relative;overflow:hidden;}.feature-digest li.new-row,.feature-digest li.first-child{margin-left:0;}.feature-digest li{position:relative;width:144px;margin-left:16px;border-top:1px solid #D8D8D8;padding:8px 0 16px 0;}.feature-digest li.new-row{clear:both;}.feature-digest .medium-image img{position:relative;float:left;width:144px;height:81px;margin-bottom:8px;}.feature-digest .medium-image .gvl3-icon-wrapper{top:8px;left:0;}.feature-digest li h3{padding-bottom:4px;}.feature-digest .feature-stories li{display:-moz-inline-box;-moz-box-orient:vertical;display:inline-block;vertical-align:top;word-wrap:break-word;}* html .feature-digest .feature-stories li{display:inline;}*+html .feature-digest .feature-stories li{display:inline;}.feature-digest .feature-stories li>*{display:table;table-layout:fixed;overflow:hidden;}* html .feature-digest .story-list li{width:144px;}.feature-digest .story-list li>*{width:144px;}.feature-digest .story-list{width:624px;}.feature-digest .no-image .gvl3-icon{position:absolute;top:8px;left:0;}.generic-tiled-digest{position:relative;overflow:visible;width:624px;margin:0;padding-top:3px;}.generic-tiled-digest .generic-tiled-digest-header{position:relative;margin-bottom:3px;padding-top:9px;padding-bottom:11px;line-height:16px;}.generic-tiled-digest ul{position:relative;overflow:hidden;}.generic-tiled-digest li.new-row,.generic-tiled-digest li.first-child{margin-left:0;}.generic-tiled-digest li{position:relative;width:144px;margin-left:16px;border-top:1px solid #D8D8D8;padding:8px 0 16px 0;}.generic-tiled-digest li.new-row{clear:both;}.generic-tiled-digest .medium-image img{position:relative;float:left;width:144px;height:81px;margin-bottom:8px;}.generic-tiled-digest .medium-image .gvl3-icon-wrapper{top:8px;left:0;}.generic-tiled-digest li h3{padding-bottom:4px;}.generic-tiled-digest .digest-stories li{display:-moz-inline-box;-moz-box-orient:vertical;display:inline-block;vertical-align:top;word-wrap:break-word;}* html .generic-tiled-digest .digest-stories li{display:inline;}*+html .generic-tiled-digest .digest-stories li{display:inline;}.generic-tiled-digest .digest-stories li>*{display:table;table-layout:fixed;overflow:hidden;}* html .generic-tiled-digest .story-list li{width:144px;}.generic-tiled-digest .story-list li>*{width:144px;}.generic-tiled-digest .story-list{width:624px;}.generic-tiled-digest .no-image .gvl3-icon{position:absolute;top:8px;left:0;}.featured-site-top-stories{position:relative;clear:both;overflow:visible;width:624px;margin:0 0 13px;border-top:1px solid #ddd;}.featured-site-top-stories+script+.featured-site-include{margin-top:-17px;}.ie7 .featured-site-top-stories+.featured-site-include{margin-top:-17px;}.featured-site-top-stories h2{position:relative;padding:7px 0 8px;margin-bottom:7px;border-bottom:1px solid #ddd;}.ie7 .featured-site-top-stories h2,.ie .featured-site-top-stories h2{position:relative;padding-top:7px;}.featured-site-top-stories ul{position:relative;overflow:auto;width:304px;margin:10px 0 4px;padding-left:320px;}.featured-site-top-stories li{padding-bottom:7px;padding-top:1px;}.featured-site-top-stories .with-summary{position:relative;clear:both;overflow:hidden;width:512px;margin:-3px 0 10px -320px;padding-right:112px;padding-bottom:14px;border-bottom:1px solid #ddd;}.featured-site-top-stories .with-summary h3{position:relative;margin-top:2px;margin-bottom:4px;}.featured-site-top-stories .medium-image{position:relative;clear:both;overflow:hidden;width:464px;margin:-1px 0 10px -320px;padding-bottom:9px;padding-left:160px;border-bottom:1px solid #ddd;}.featured-site-top-stories .medium-image h3{position:relative;margin-bottom:4px;}.featured-site-top-stories .medium-image img{float:left;display:inline;margin-left:-160px;width:144px;height:81px;}.featured-site-top-stories .large-image{position:relative;clear:both;overflow:hidden;width:304px;margin:-3px 0 10px -320px;padding-bottom:7px;padding-left:320px;border-bottom:1px solid #ddd;}.featured-site-top-stories .large-image h3{position:relative;margin-bottom:4px;padding-top:2px;}.featured-site-top-stories .large-image img{float:left;display:inline;margin-left:-320px;width:304px;height:171px;}.featured-site-top-stories .classic-image{position:relative;clear:both;overflow:hidden;width:382px;margin:-1px 0 10px -320px;padding-bottom:8px;padding-left:242px;border-bottom:1px solid #ddd;}.featured-site-top-stories .classic-image h3{position:relative;margin-bottom:8px;}.featured-site-top-stories .classic-image img{float:left;display:inline;margin-left:-242px;width:226px;height:170px;}.featured-site-top-stories .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;width:304px;margin-left:-320px;}.featured-site-top-stories .column-2{clear:none;position:relative;width:304px;}.ie .featured-site-top-stories .column-2{float:right;}.featured-site-top-stories .see-also{width:100%;margin-top:8px;margin-bottom:2px;padding:0;overflow:hidden;}.featured-site-top-stories .medium-image .see-also{margin-bottom:0;}.featured-site-top-stories .see-also li{padding-top:0;padding-bottom:8px;position:relative;float:left;display:inline;width:100%;}.featured-site-top-stories .see-also .story{font-size:1em;}.featured-site-top-stories .see-also .play-audio{text-indent:20px;}.featured-site-top-stories .see-also .play-video{text-indent:16px;}.featured-site-top-stories .gvl3-icon{position:absolute;top:0;left:0;}.featured-site-top-stories .with-summary gvl3-icon{top:-2px;}.featured-site-top-stories .gvl3-icon-wrapper{position:absolute;top:0;left:-320px;}.featured-site-top-stories .medium-image .gvl3-icon-wrapper{left:-160px;}.featured-site-top-stories .classic-image .gvl3-icon-wrapper{left:-242px;}.featured-site-top-stories .large-image .gvl3-icon-wrapper{top:3px;}.ie7 .featured-site-top-stories .gvl3-icon-wrapper,.ie .featured-site-top-stories .gvl3-icon-wrapper{top:4px;}.featured-site-top-stories .gvl3-icon-wrapper .gvl3-icon{position:relative;top:auto;left:auto;}.ie7 .featured-site-top-stories li.first-child hr,.ie .featured-site-top-stories li.first-child hr{visibility:hidden;}.container-featured-other-site{position:relative;clear:both;}.container-featured-other-site-heading{border-bottom:1px solid #DDD;border-top:1px solid #DDD;margin-bottom:-1px;padding:7px 0 8px;position:relative;}.feature-generic,.container-features-and-analysis{position:relative;overflow:visible;width:336px;padding-bottom:8px;margin:0 0 16px;background:#ededed;}.ie .feature-generic,.ie .container-features-and-analysis{padding-bottom:2px;}.bbccom_slot_xxl .feature-generic,.bbccom_slot_xxl .container-features-and-analysis{width:496px;}.feature-generic .features-header,.container-features-and-analysis .features-header{padding:8px;}.feature-generic ul,.container-features-and-analysis ul{position:relative;overflow:hidden;padding:0 8px 0;clear:both;}.feature-generic li,.container-features-and-analysis li{position:relative;display:block;clear:both;overflow:hidden;zoom:1;}.feature-generic li .gvl3-icon,.container-features-and-analysis li .gvl3-icon{position:absolute;top:9px;left:0;}.feature-generic li.large-image .gvl3-icon-wrapper,.container-features-and-analysis li.large-image .gvl3-icon-wrapper{position:absolute;top:0;left:0;}.feature-generic li.medium-image .gvl3-icon-wrapper,.container-features-and-analysis li.medium-image .gvl3-icon-wrapper{position:absolute;top:8px;left:-120px;}.ie .feature-generic li.medium-image .gvl3-icon-wrapper,.ie .container-features-and-analysis li.medium-image .gvl3-icon-wrapper,.ie7 .feature-generic li.medium-image .gvl3-icon-wrapper,.ie7 .container-features-and-analysis li.medium-image .gvl3-icon-wrapper{top:10px;}.feature-generic li .gvl3-icon-wrapper .gvl3-icon,.container-features-and-analysis li .gvl3-icon-wrapper .gvl3-icon{position:relative;top:0;left:0;}.feature-generic li.no-image .gvl3-icon,.container-features-and-analysis li.no-image .gvl3-icon{top:6px;}.feature-generic li.large-image,.container-features-and-analysis li.large-image{width:320px;margin:0 -8px 0;padding:8px 8px 12px;border-bottom:1px solid #fff;background:#505050;}.ie .feature-generic li.large-image,.ie .container-features-and-analysis li.large-image{display:inline;}.feature-generic li.large-image .feature-header,.container-features-and-analysis li.large-image .feature-header{margin-bottom:3px;overflow:visible;}.feature-generic li.large-image img,.container-features-and-analysis li.large-image img{position:relative;display:block;margin:-8px -8px 8px;width:336px;height:auto;border-bottom:1px solid #fff;}.feature-generic li.large-image p,.container-features-and-analysis li.large-image p{padding-top:2px;}.feature-generic li.large-image *,.container-features-and-analysis li.large-image *{color:#fff;}.feature-generic li.medium-image,.container-features-and-analysis li.medium-image{padding:0 0 0 120px;position:relative;margin-bottom:-2px;}.feature-generic li.medium-image:first-child,.container-features-and-analysis li.medium-image:first-child{margin-top:-8px;}.ie7 .feature-generic li.medium-image,.ie7 .container-features-and-analysis li.medium-image,.ie .feature-generic li.medium-image,.ie .container-features-and-analysis li.medium-image{margin-bottom:-14px;}.feature-generic li.medium-image .feature-header,.container-features-and-analysis li.medium-image .feature-header{position:relative;padding-top:7px;margin-bottom:-1px;}.feature-generic li.medium-image img,.container-features-and-analysis li.medium-image img{position:relative;float:left;display:inline;margin-top:1px;margin-left:-120px;width:112px;height:63px;}.feature-generic li.medium-image p,.container-features-and-analysis li.medium-image p{padding-bottom:4px;padding-top:6px;}.feature-generic li.no-image,.container-features-and-analysis li.no-image{padding:7px 0 4px;}.feature-generic li.no-image .feature-header,.container-features-and-analysis li.no-image .feature-header{margin-bottom:-1px;}.feature-generic li.no-image p,.container-features-and-analysis li.no-image p{padding:6px 0 0;}.feature-generic li.first-child,.container-features-and-analysis li.first-child{background:#d2700f;}.feature-generic li.first-child *,.container-features-and-analysis li.first-child *,.container-features-and-analysis li.first-child a:visited{color:#fff;}.feature-generic li.large-image a.from-external-source:visited,.container-features-and-analysis li.large-image a.from-external-source:visited{color:#fff;}.feature-generic .solo-other-label a.from-external-source,.container-features-and-analysis .solo-other-label a.from-external-source{margin:6px 0 0 0;display:block;position:relative;}.digest{position:relative;overflow:visible;width:624px;margin:0;padding-top:3px;border-top:1px solid #ddd;}.digest .digest-header{position:relative;margin-bottom:3px;padding-top:9px;padding-bottom:11px;line-height:16px;border-bottom:1px solid #ddd;}.ie .digest-multiple .first-child .digest-header,.ie .digest .digest-header{height:1%;}.digest ul{position:relative;overflow:hidden;width:304px;margin:1px 0 0;padding-left:320px;}.digest li{padding-bottom:8px;}.digest-world-service .digest li.first-child{padding-top:8px;}.digest .gvl3-icon{position:absolute;top:-1px;left:0;}.digest .no-image{position:relative;clear:both;overflow:hidden;width:464px;margin-left:-320px;padding-bottom:14px;margin-top:8px;padding-right:160px;}.digest .medium-image{position:relative;clear:both;overflow:hidden;width:464px;margin-left:-320px;padding-bottom:15px;padding-left:160px;margin-top:4px;}.digest .medium-image .has-icon-listen{text-indent:0;}.digest .medium-image .has-icon-watch{text-indent:0;}.digest .medium-image .gvl3-icon-wrapper{position:absolute;left:-160px;top:3px;}.digest .medium-image .gvl3-icon{position:relative;top:auto;left:auto;}.digest .no-image{padding-left:0;}.digest .medium-image .digest-story-header{position:relative;padding-bottom:4px;}.digest .medium-image img{position:relative;float:left;display:inline;margin-left:-160px;margin-bottom:-3px;width:144px;height:81px;top:3px;}.digest .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;width:304px;margin-left:-320px;}.digest .column-2{clear:none;position:relative;width:304px;}.ie .digest .column-2{float:right;}.digest h3.rtl,.digest .rtl *{direction:rtl;text-align:right;}.ie .digest-double .rtl .medium-image a,.ie .expert-even .rtl .medium-image a{margin-left:0;position:relative;}.ie7 .rtl li a{position:relative;right:-15px;}.ie .digest-double .rtl .medium-image a .link-text,.ie7 .digest-double .rtl .medium-image a .link-text,.ie .expert-even .rtl .medium-image a .link-text,.ie7 .expert-even .rtl .medium-image a .link-text{display:block;width:100%;cursor:pointer;color:inherit;}.ie7 .digest-double .rtl .medium-image img,.ie7 .expert-even .rtl .medium-image img{left:-16px;}.ie .digest-double .rtl .medium-image img,.ie .expert-even .rtl .medium-image img{position:absolute;right:160px;float:none;}.ie .digest-multiple .rtl .medium-image a,.ie7 .digest-multiple .rtl .medium-image a{height:1%;}.digest .rtl .gvl3-icon{left:auto;right:-8px;}.ie .digest-double .rtl .gvl3-icon-wrapper,.ie .expert-even .rtl .gvl3-icon-wrapper{left:-304px;}.digest .rtl .gvl3-icon-wrapper .gvl3-icon{right:auto;}.container-expert-views{border-top:none;position:relative;clear:both;margin-bottom:11px;}.container-category-digests,.container-section-digests{position:relative;clear:both;overflow:hidden;margin-bottom:8px;}.digest-wrapper-header{position:relative;padding-bottom:8px;padding-top:7px;margin-top:-1px;margin-bottom:-1px;border-bottom:1px solid #ddd;}.container-expert-views .digest{margin-top:0;}.digest-double .digest,.expert-even .digest{float:left;display:inline;width:304px;margin-left:16px;}.digest-double div.first-child,.expert-even div.first-child{margin-left:0;}.digest-double .digest ul,.expert-even .digest ul{width:304px;padding-left:0;margin-bottom:4px;}.digest-double .no-image,.expert-even .no-image{position:relative;clear:both;overflow:hidden;width:100%;margin-left:0;padding-bottom:14px;margin-top:0;padding-right:0;}.digest-double .medium-image,.expert-even .medium-image{width:144px;padding-bottom:14px;margin-left:0;}.ie .digest-double .digest,.ie .expert-even .digest{height:226px;}.ie .digest-world-service .digest{height:0;}.digest-double .no-image,.expert-even .no-image{width:304px;}.digest-double .column-1,.expert-even .column-1{width:304px;margin-left:0;}.digest-double .column-2,.expert-even .column-2{position:relative;float:left;clear:none;display:inline;overflow:hidden;width:304px;margin-left:0;}.digest-multiple{margin-bottom:7px;}.ie .digest-multiple{height:1%;}.digest-multiple .digest{float:left;display:inline;width:144px;margin-left:16px;}.container-category-digests .digest{margin-bottom:4px;}.ie .digest-multiple .digest{height:208px;}.digest-multiple div.first-child{margin-left:0;}.digest-multiple .digest ul{width:144px;padding-left:0;margin-bottom:5px;}.digest-multiple .no-image{position:relative;clear:both;overflow:hidden;width:100%;margin-left:0;padding-bottom:14px;margin-top:8px;padding-right:0;}.digest-multiple .medium-image{width:144px;padding-left:0;padding-bottom:6px;margin-left:0;margin-top:5px;}.ie .digest-multiple .medium-image hr,.ie7 .digest-multiple .medium-image hr,.ie .digest-multiple .no-image hr,.ie7 .digest-multiple .no-image hr{display:none;}.digest-multiple .medium-image a,.digest-multiple .no-image a{display:block;}.digest-multiple .medium-image img{float:none;display:block;margin-left:0;padding-bottom:13px;}.digest-multiple .medium-image .gvl3-icon-wrapper{position:absolute;left:0;top:3px;}.digest-multiple .column-1{width:144px;margin-left:0;}.digest-multiple .column-2,.ie .digest-multiple .column-2{position:relative;float:left;clear:both;display:inline;overflow:hidden;width:144px;margin-left:0;}.digest-multiple .new-row,.container-section-digest .new-row,.container-expert-views .new-row{clear:both;margin-left:0;}.text-first .digest li.medium-image h4{padding-top:3px;padding-bottom:2px;margin-left:-160px;}.text-first .digest li.medium-image h4 a{line-height:1;}.text-first .digest li.medium-image img{margin-top:18px;left:160px;}.text-first .digest .medium-image .gvl3-icon-wrapper{left:0;top:24px;}.text-first .digest .no-image h4{padding-top:4px;}.digest-single .digest .no-image p,.digest-double .digest li.no-image p,.digest-multiple .digest li.no-image p{padding-top:4px;}.digest-double .no-image{padding-top:4px;padding-bottom:8px;}.digest-multiple .digest li.no-image{padding-bottom:8px;}.ie .digest-single .digest .medium-image,.ie7 .digest-single .digest .medium-image{padding-bottom:8px;}.ie .digest-single .digest .no-image,.ie .digest-double .digest .no-image,.ie7 .digest-single .digest .no-image,.ie7 .digest-double .digest .no-image{padding-bottom:0;}.ie .digest-double .digest .medium-image h4 img,.ie7 .digest-double .digest .medium-image h4 img{margin-top:0;}.geo-digest-vertical{position:relative;overflow:hidden;margin:0 0 16px;padding:0 8px;width:632px;border:8px solid #262835;border-width:8px 0;background:#262835;text-shadow:0 0 1px rgba(0,0,0,0.1);}.ie .geo-digest{float:left;}.geo-digest-vertical-header{padding-top:4px;}.geo-digest-vertical .geo-digest-region{margin-bottom:0;}.geo-digest-vertical .geo-digest-section ul{width:288px;}.geo-digest-vertical .tab{position:relative;padding:17px 16px 7px 0;}.geo-digest-vertical .tab a,.geo-digest-vertical-header{color:#f0f0f0;}.blq-js .geo-digest-vertical{padding-right:304px;width:312px;background:#262835 url(../img/geo-digest-vertical-panel.gif) 312px top repeat-y;}.blq-js .geo-digest-vertical .geo-digest-vertical-header{position:relative;padding-bottom:12px;}.blq-js .geo-digest-vertical .tab{position:relative;float:left;display:inline;clear:left;width:280px;margin-left:-4px;border-top:1px solid #3c3e51;padding:8px 16px 7px 4px;cursor:pointer;}.blq-js .geo-digest-vertical .tab a{color:#a9a9a9;}.blq-js .geo-digest-vertical void{background:#3c3e51;width:288px;border-bottom:1px solid #3c3e51;margin-bottom:-1px;}.blq-js .geo-digest-vertical void a{color:#f0f0f0;}.blq-js .geo-digest-vertical .geo-digest-region{padding-left:8px;float:right;display:inline;clear:right;margin-right:-296px;}.blq-js .geo-digest-vertical .geo-digest-section{padding-top:1px;}.blq-js .geo-digest-vertical .panel{opacity:0;position:absolute;right:-5000%;}.blq-js .geo-digest-vertical void{opacity:1;left:312px;top:0;-webkit-transition:opacity .2s ease-in;}.blq-js .geo-digest-vertical .geo-digest-region .column-1{clear:none;display:block;float:none;margin-left:0;}#england-map{position:relative;margin:0 63px 15px 57px;height:241px;width:192px;background-image:url(../img/england-map.png);background-repeat:none;overflow:hidden;}#england-map ul li{list-style:none;width:1px;height:1px;position:absolute;overflow:visible;left:-1px;top:-1px;}#england-map ul li a,#england-map ul li a span{position:absolute;display:block;text-indent:-50000px;overflow:visible;line-height:1px;padding:0;font-size:1px;}#england-map ul li a{width:1px;height:1px;overflow:visible;left:0;top:0;}#england-map ul li a span{background-image:url(../img/england-map.png);background-repeat:none;filter:alpha(opacity=0);opacity:0;-moz-opacity:0;-webkit-transition:opacity 1s ease-out;cursor:pointer;}.blq-js #england-map ul li a.selected span,#england-map ul li a:hover span,#england-map ul li a:active span,#england-map ul li a:focus span{filter:alpha(opacity=100);opacity:1;-moz-opacity:1;-webkit-transition:opacity .2s ease-in;}.blq-js #england-map ul li a.selected,#england-map ul li a:active,#england-map ul li a:focus{outline:0;}#england-map-region-1 a span.filler-1{background-position:1px 242px;top:0;left:0;height:53px;width:85px;}#england-map-region-1 a span.filler-2{background-position:1px 189px;top:53px;left:0;height:22px;width:30px;}#england-map-region-1 a span.filler-3{background-position:145px 189px;top:53px;left:48px;height:22px;width:37px;}#england-map-region-1 a span.filler-4{background-position:1px 167px;top:75px;left:0;height:35px;width:95px;}#england-map-region-2 a span.filler-1{background-position:107px 242px;top:0;left:86px;height:56px;width:107px;}#england-map-region-3 a span.filler-1{background-position:107px 185px;top:57px;left:86px;height:17px;width:107px;}#england-map-region-3 a span.filler-2{background-position:97px 168px;top:74px;left:96px;height:24px;width:97px;}#england-map-region-3 a span.filler-3{background-position:70px 144px;top:98px;left:123px;height:12px;width:70px;}#england-map-region-3 a span.filler-4{background-position:70px 132px;top:110px;left:123px;height:13px;width:22px;}#england-map-region-4 a span.filler-1{background-position:1px 131px;top:111px;left:0;height:39px;width:105px;}#england-map-region-5 a span.filler-1{background-position:97px 155px;top:99px;left:96px;height:11px;width:26px;}#england-map-region-5 a span.filler-2{background-position:87px 132px;top:110px;left:106px;height:14px;width:16px;}#england-map-region-5 a span.filler-3{background-position:87px 118px;top:124px;left:106px;height:26px;width:22px;}#england-map-region-6 a span.filler-1{background-position:1px 91px;top:151px;left:0;height:38px;width:99px;}#england-map-region-6 a span.filler-2{background-position:1px 53px;top:189px;left:0;height:53px;width:69px;}#england-map-region-7 a span.filler-1{background-position:47px 131px;top:111px;left:146px;height:13px;width:47px;}#england-map-region-7 a span.filler-2{background-position:64px 118px;top:124px;left:129px;height:27px;width:64px;}#england-map-region-7 a span.filler-3{background-position:74px 91px;top:151px;left:119px;height:13px;width:74px;}#england-map-region-8 a span.filler-1{background-position:93px 91px;top:151px;left:100px;height:39px;width:18px;}#england-map-region-8 a span.filler-2{background-position:123px 52px;top:190px;left:70px;height:24px;width:48px;}#england-map-region-8 a span.filler-3{background-position:123px 28px;top:214px;left:70px;height:28px;width:6px;}#england-map-region-8 a span.filler-4{background-position:82px 28px;top:214px;left:111px;height:28px;width:7px;}#england-map-region-9 a span.filler-1{background-position:74px 77px;top:165px;left:119px;height:77px;width:74px;}#england-map-region-10 a span.filler-1{background-position:162px 188px;top:54px;left:31px;height:20px;width:16px;}#england-map-region-10 a span.filler-2{background-position:116px 27px;top:215px;left:77px;height:26px;width:33px;}.geo-digest-solo-header{padding:8px 0;}.geo-digest-section{position:relative;overflow:visible;margin:0 0 5px;}.ie .geo-digest-section{height:1%;}.geo-digest-section-header{padding-top:11px;padding-bottom:5px;border-bottom:1px solid #ddd;}.geo-digest-section ul{padding-top:7px;padding-bottom:7px;overflow:hidden;width:288px;}.geo-digest-section li{margin-top:8px;width:100%;position:relative;float:left;display:inline;clear:left;}.geo-digest-section .gvl3-icon{position:absolute;top:-1px;left:0;}.geo-digest-region{position:relative;overflow:hidden;margin:0 0 8px;width:288px;padding:8px 8px 0 312px;background:#3c3e51;}.geo-digest-region-header,#personalisation h3{position:relative;padding-top:4px;padding-bottom:12px;margin-left:-304px;width:592px;}.geo-digest-region .column-1{position:relative;float:left;display:inline;clear:left;width:288px;margin-left:-304px;}.geo-digest-region .column-2{width:288px;}.ie7 .geo-digest-region .column-2,.ie .geo-digest-region .column-2{float:right;clear:right;}.geo-digest-region .geo-digest-section{margin-top:0;}.geo-digest-region-header,#personalisation h3,.geo-digest-region .geo-digest-section-header,.geo-digest-section-header a.story{color:#f0f0f0;}.geo-digest-region .geo-digest-section-header{border-bottom-color:#262835;}.geo-digest-region .geo-digest-section ul{padding-bottom:8px;margin-bottom:-1px;margin-top:-8px;}.geo-digest-region a{color:#ACC2D4;text-shadow:0 0 1px #3c3e51;}.geo-digest-region a.from-external-source{color:#F0F0F0;display:block;margin-left:0;text-indent:0;}#world-map{margin:16px 24px 17px 16px;}#geo-world-news-digest .geo-digest-region-header{top:-69px;margin-bottom:4px;position:absolute;left:-50000px;}.container-geographic-regions-generic{position:relative;clear:both;overflow:hidden;width:608px;margin:0 0 16px;padding:8px 8px 0;background:#262835;text-shadow:0 0 1px rgba(0,0,0,0.1);}.ie .container-geographic-regions-generic{float:left;}.container-geographic-regions-generic .tab{padding:11px 16px 12px 8px;position:relative;background:transparent;z-index:100;}.container-geographic-regions-generic .tab a{color:#f0f0f0;}.container-geographic-regions-generic .panel{position:relative;}.container-geographic-regions-generic .uk-news-heading,.container-geographic-regions-generic .world-news-heading{left:-50000px;margin-bottom:4px;position:absolute;top:-69px;}.container-geographic-regions-generic .around-uk-digest-header{color:#f0f0f0;padding-bottom:12px;margin-left:-304px;padding-top:4px;position:relative;width:592px;}.container-geographic-regions-generic .geo-digest-region .vertical-line{border-left:2px solid #f0f0f0;margin-left:5px;margin-right:5px;font-size:.76em;}.container-geographic-regions-generic .geo-digest-region .or-text{position:absolute;left:-9000px;}.ie #geo-uk-news-digest{height:1%;}.blq-js .container-geographic-regions-generic .tab{float:left;display:inline;top:0;cursor:pointer;}.blq-js .container-geographic-regions-generic void{background:#3c3e51;}.blq-js .container-geographic-regions-generic .panel{position:absolute;float:right;display:inline;clear:right;right:-500%;margin-right:0;margin-top:40px;opacity:0;}.blq-js .ie .container-geographic-regions-generic .panel,.blq-js .ie7 .container-geographic-regions-generic .panel,.blq-js .ie8 .container-geographic-regions-generic .panel{margin-top:39px;clear:none;}.blq-js .ie .container-geographic-regions-generic .panel{height:1%;}.blq-js .container-geographic-regions-generic void{position:relative;margin-right:-608px;right:608px;opacity:1;-webkit-transition:opacity .2s ease-in;}.extra-padding .column-top{margin-top:92px;}#geo-wales-news-digest .column-2{clear:right;}#wales-map{float:right;width:138px;height:138px;background:transparent url(../img/wales-map.png) no-repeat top left;margin:-7px 80px -15px 0;}#geo-scotland-news-digest .column-2{clear:right;}#scotland-map{float:right;width:251px;height:220px;background:transparent url(../img/scotland-map.png@v.2) no-repeat top left;margin:8px 0 4px;}#world-map{position:relative;height:151px;width:240px;background-image:url('../img/world-map.png');background-repeat:none;overflow:hidden;}#world-map ul li{list-style:none;width:1px;height:1px;position:absolute;overflow:visible;left:-1px;top:-1px;}#world-map ul li a,#world-map ul li a span{position:absolute;display:block;text-indent:-50000px;overflow:visible;line-height:1px;padding:0;font-size:1px;}#world-map ul li a{width:1px;height:1px;overflow:visible;left:0;top:0;}#world-map ul li a span{background-image:url('../img/world-map.png');background-repeat:none;filter:alpha(opacity=0);opacity:0;-moz-opacity:0;-webkit-transition:opacity 1s ease-out;cursor:pointer;}#world-map ul li a:hover span,#world-map ul li a:active span,#world-map ul li a:focus span{filter:alpha(opacity=100);opacity:1;-moz-opacity:1;-webkit-transition:opacity .2s ease-in;}#world-map ul li a:active,#world-map ul li a:focus{outline:0;}#world-map-us-canada a span.filler-1{background-position:1px 152px;top:0;left:0;height:20px;width:77px;}#world-map-us-canada a span.filler-2{background-position:1px 132px;top:20px;left:0;height:18px;width:71px;}#world-map-us-canada a span.filler-3{background-position:1px 114px;top:38px;left:0;height:25px;width:81px;}#world-map-us-canada a span.filler-4{background-position:1px 89px;top:63px;left:0;height:28px;width:109px;}#world-map-latin-america a span.filler-1{background-position:1px 60px;top:92px;left:0;height:60px;width:109px;}#world-map-africa a span.filler-1{background-position:131px 69px;top:83px;left:110px;height:17px;width:37px;}#world-map-africa a span.filler-2{background-position:131px 52px;top:100px;left:110px;height:52px;width:57px;}#world-map-europe a span.filler-1{background-position:163px 152px;top:0;left:78px;height:21px;width:122px;}#world-map-europe a span.filler-2{background-position:169px 131px;top:21px;left:72px;height:16px;width:128px;}#world-map-europe a span.filler-3{background-position:159px 115px;top:37px;left:82px;height:25px;width:118px;}#world-map-europe a span.filler-4{background-position:131px 90px;top:62px;left:110px;height:6px;width:90px;}#world-map-europe a span.filler-5{background-position:131px 84px;top:68px;left:110px;height:14px;width:57px;}#world-map-middle-east a span.filler-1{background-position:93px 69px;top:83px;left:148px;height:16px;width:19px;}#world-map-south-asia a span.filler-1{background-position:73px 70px;top:82px;left:168px;height:70px;width:17px;}#world-map-asia-pacific a span.filler-1{background-position:40px 152px;top:0;left:201px;height:69px;width:40px;}#world-map-asia-pacific a span.filler-2{background-position:74px 83px;top:69px;left:167px;height:13px;width:74px;}#world-map-asia-pacific a span.filler-3{background-position:55px 70px;top:82px;left:186px;height:71px;width:55px;}#scotland-map-hover{float:right;width:251px;height:220px;background:transparent url(../img/scotland-map-hover.png) no-repeat top left;margin:8px 0 4px;position:relative;}#scotland-map-hover ul li{list-style:none;width:1px;height:1px;position:absolute;overflow:visible;left:-1px;top:-1px;}#scotland-map-hover ul li a,#scotland-map-hover ul li a span{position:absolute;display:block;text-indent:-50000px;overflow:visible;line-height:1px;padding:0;font-size:1px;}#scotland-map-hover ul li a{width:1px;height:1px;overflow:visible;left:0;top:0;}#scotland-map-hover ul li a span{background-image:url(../img/scotland-map-hover.png);background-repeat:none;filter:alpha(opacity=0);opacity:0;-moz-opacity:0;-webkit-transition:opacity 1s ease-out;cursor:pointer;}#scotland-map-hover ul li a:hover span,#world-map-hover ul li a:active span,#world-map-hover ul li a:focus span{filter:alpha(opacity=100);opacity:1;-moz-opacity:1;-webkit-transition:opacity .2s ease-in;}#scotland-map-hover ul li a:active,#world-map-hover ul li a:focus{outline:0;}#scotland-news-map-edinburgh-east-fife a span.filler-1{background-position:-115px 89px;top:132px;left:116px;height:21px;width:81px;}#scotland-news-map-edinburgh-east-fife a span.filler-2{background-position:-105px 77px;top:144px;left:106px;height:18px;width:10px;}#scotland-news-map-edinburgh-east-fife a span.filler-3{background-position:-115px 68px;top:153px;left:116px;height:9px;width:16px;}#scotland-news-map-glasgow-west a span.filler-1{background-position:1px 103px;top:118px;left:0;height:15px;width:60px;}#scotland-news-map-glasgow-west a span.filler-2{background-position:1px 88px;top:133px;left:0;height:16px;width:81px;}#scotland-news-map-glasgow-west a span.filler-3{background-position:1px 72px;top:149px;left:0;height:7px;width:97px;}#scotland-news-map-glasgow-west a span.filler-4{background-position:1px 65px;top:156px;left:0;height:20px;width:105px;}#scotland-news-map-glasgow-west a span.filler-5{background-position:1px 45px;top:176px;left:0;height:12px;width:93px;}#scotland-news-map-glasgow-west a span.filler-6{background-position:1px 33px;top:188px;left:0;height:5px;width:79px;}#scotland-news-map-glasgow-west a span.filler-7{background-position:1px 28px;top:193px;left:0;height:15px;width:65px;}#scotland-news-map-highlands-islands a span.filler-1{background-position:1px 212px;top:9px;left:0;height:27px;width:138px;}#scotland-news-map-highlands-islands a span.filler-2{background-position:1px 185px;top:36px;left:0;height:32px;width:120px;}#scotland-news-map-highlands-islands a span.filler-3{background-position:1px 153px;top:68px;left:0;height:43px;width:105px;}#scotland-news-map-highlands-islands a span.filler-4{background-position:1px 110px;top:111px;left:0;height:6px;width:81px;}#scotland-news-map-highlands-islands a span.filler-5{background-position:-60px 104px;top:117px;left:61px;height:15px;width:20px;}#scotland-news-map-east-orkney-shetland a span.filler-1{background-position:-138px 212px;top:9px;left:139px;height:107px;width:78px;}#scotland-news-map-east-orkney-shetland a span.filler-2{background-position:-105px 152px;top:69px;left:106px;height:42px;width:33px;}#scotland-news-map-east-orkney-shetland a span.filler-3{background-position:-120px 184px;top:37px;left:121px;height:32px;width:18px;}#scotland-news-map-east-orkney-shetland a span.filler-4{background-position:-126px 110px;top:111px;left:127px;height:5px;width:12px;}#scotland-news-map-south-scotland a span.filler-1{background-position:-132px 67px;top:154px;left:133px;height:59px;width:64px;}#scotland-news-map-south-scotland a span.filler-2{background-position:-105px 58px;top:163px;left:106px;height:50px;width:27px;}#scotland-news-map-south-scotland a span.filler-3{background-position:-93px 44px;top:177px;left:94px;height:36px;width:12px;}#scotland-news-map-south-scotland a span.filler-4{background-position:-79px 32px;top:189px;left:80px;height:24px;width:14px;}#scotland-news-map-south-scotland a span.filler-5{background-position:-65px 27px;top:194px;left:66px;height:19px;width:14px;}#scotland-news-map-tayside-central a span.filler-1{background-position:-81px 109px;top:112px;left:82px;height:36px;width:15px;}#scotland-news-map-tayside-central a span.filler-2{background-position:-96px 109px;top:112px;left:97px;height:43px;width:8px;}#scotland-news-map-tayside-central a span.filler-3{background-position:-104px 109px;top:112px;left:105px;height:19px;width:21px;}#scotland-news-map-tayside-central a span.filler-4{background-position:-104px 90px;top:131px;left:105px;height:12px;width:10px;}#scotland-news-map-tayside-central a span.filler-5{background-position:-125px 104px;top:117px;left:126px;height:14px;width:71px;}#wales-map-hover{float:right;width:138px;height:138px;background:transparent url(../img/wales-map-hover.png) no-repeat top left;margin:-7px 80px -15px 0;position:relative;}#wales-map-hover ul li{list-style:none;width:1px;height:1px;position:absolute;overflow:visible;left:-1px;top:-1px;}#wales-map-hover ul li a,#wales-map-hover ul li a span{position:absolute;display:block;text-indent:-50000px;overflow:visible;line-height:1px;padding:0;font-size:1px;}#wales-map-hover ul li a{width:1px;height:1px;overflow:visible;left:0;top:0;}#wales-map-hover ul li a span{background-image:url(../img/wales-map-hover.png);background-repeat:none;filter:alpha(opacity=0);opacity:0;-moz-opacity:0;-webkit-transition:opacity 1s ease-out;cursor:pointer;}#wales-map-hover ul li a:hover span,#world-map-hover ul li a:active span,#world-map-hover ul li a:focus span{filter:alpha(opacity=100);opacity:1;-moz-opacity:1;-webkit-transition:opacity .2s ease-in;}#wales-map-hover ul li a:active,#world-map-hover ul li a:focus{outline:0;}#wales-news-map-north-west a span.filler-1{background-position:-14px 123px;top:16px;left:15px;height:39px;width:65px;}#wales-news-map-north-west a span.filler-2{background-position:-14px 85px;top:55px;left:15px;height:5px;width:58px;}#wales-news-map-mid a span.filler-1{background-position:-15px 78px;top:61px;left:16px;height:21px;width:65px;}#wales-news-map-mid a span.filler-2{background-position:-80px 94px;top:45px;left:81px;height:37px;width:45px;}#wales-news-map-mid a span.filler-3{background-position:-80px 94px;top:56px;left:74px;height:5px;width:7px;}#wales-news-map-mid a span.filler-4{background-position:-15px 57px;top:82px;left:16px;height:6px;width:47px;}#wales-news-map-mid a span.filler-5{background-position:-79px 57px;top:82px;left:80px;height:8px;width:45px;}#wales-news-map-mid a span.filler-6{background-position:-79px 49px;top:90px;left:80px;height:7px;width:18px;}#wales-news-map-mid a span.filler-7{background-position:-79px 42px;top:97px;left:80px;height:4px;width:5px;}#wales-news-map-south-west a span.filler-1{background-position:-62px 56px;top:83px;left:63px;height:25px;width:17px;}#wales-news-map-south-west a span.filler-2{background-position:-79px 37px;top:102px;left:80px;height:5px;width:4px;}#wales-news-map-south-west a span.filler-3{background-position:-15px 50px;top:89px;left:16px;height:34px;width:47px;}#wales-news-map-south-west a span.filler-4{background-position:-62px 31px;top:108px;left:63px;height:16px;width:14px;}#wales-news-map-north-east a span.filler-1{background-position:-80px 123px;top:16px;left:81px;height:28px;width:45px;}#wales-news-map-south-east a span.filler-1{background-position:-84px 41px;top:98px;left:85px;height:27px;width:40px;}#wales-news-map-south-east a span.filler-2{background-position:-76px 31px;top:108px;left:77px;height:18px;width:8px;}#wales-news-map-south-east a span.filler-3{background-position:-98px 49px;top:90px;left:99px;height:8px;width:26px;}.container-guides{position:relative;clear:both;overflow:hidden;}.ie .container-guides{height:1%;overflow:auto;}.ie7 .container-guides{height:1%;overflow:auto;padding-bottom:16px;}.guide-content{float:left;display:inline;position:relative;padding-top:0;margin-bottom:16px;}.full-width-guides .guide-content{background-color:#505050;width:624px;display:block;padding-top:4px;}.full-width-guides .wide-content-group h3 a{padding-left:16px;}.ie .full-width-guides .guide-content .guide{margin-top:4px;}.ie .full-width-guides .guide-content{display:block;padding-top:0;}.guides-stories-header{padding:8px 0;}.guide-content .guide{background-color:#505050;padding:11px 0 4px;}.guide-content .guide h3 img{display:inline;float:left;margin-top:-11px;position:relative;z-index:2;}.guide-content .guide h3 a{color:#fff;margin:3px 8px 0 0;}.guide-content .guide p{color:#fff;margin:1px 8px 8px 16px;}.guide-content .wide-content-group{margin-left:304px;width:320px;margin-top:-4px;}.guide-content .wide-content-group img{border-right:1px solid #FFF;margin-left:-304px;}.guide-content .stacked-content-group{width:304px;}.container-guides .first-group .stacked-content-group{margin-right:16px;display:block;}.guide-content .stacked-content-group h3{padding-left:8px;}.guide-content .stacked-content-group h3 img{border-bottom:1px solid #FFF;margin-bottom:8px;margin-left:-8px;float:none;margin-top:-14px;}.guide-content .stacked-content-group .guide p{margin-left:8px;}.guide-content .stacked-content-group .guide,.guide-content .stacked-content-group .guide h3,.guide-content .stacked-content-group .guide h3 a,.guide-content .stacked-content-group .guide h3 img{display:block;}.guide-content .stacked-content-group .guide h3 a{padding-right:0;margin-right:0;}.ie .guide-content .stacked-content-group .guide{margin-top:4px;}.stacked-overlay-guides .guide{background:none;padding:11px 0 0 0;}.stacked-overlay-guides .guide .overlay{position:absolute;width:288px;bottom:1px;left:0;z-index:10;cursor:pointer;padding:9px 8px 7px;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/transparencies/rgba-0-0-0-07.png) repeat;}.ie .stacked-overlay-guides .guide .overlay{background:black;}.stacked-overlay-guides .guide a:active .overlay{background:#D2700F;}.stacked-overlay-guides .guide h3 a.story .summary{font-weight:normal;}.stacked-overlay-guides .guide h3 a.story:hover,.stacked-overlay-guides .guide h3 a.story:focus{text-decoration:none;}.stacked-overlay-guides .guide h3 a.story:hover .headline,.stacked-overlay-guides .guide h3 a.story:focus .headline{text-decoration:underline;}.stacked-overlay-guides .guide h3 a.story:hover .summary,.stacked-overlay-guides .guide h3 a.story:focus .summary{text-decoration:none;}.stacked-overlay-guides .guide h3 .overlay strong,.stacked-overlay-guides .guide h3 a.story .summary{color:#fff;display:block;}.stacked-overlay-guides .guide h3 a .overlay strong{font-weight:bold;padding-bottom:2px;}.guide-content .stacked-overlay-guides h3 img{margin-bottom:0;}.ie .guide-content .stacked-overlay-guides{margin-bottom:0;margin-top:-4px;}.ie .guide-content .stacked-overlay-guides .overlay{bottom:0;}.container-guides .wide-content-group .gvl3-icon-wrapper,.container-guides .stacked-overlay-guides .gvl3-icon-wrapper{left:0;top:0;z-index:10;}.hyper-foldout{position:relative;overflow:hidden;clear:both;width:464px;margin:0 0 15px;margin-top:-1px;}.hyper-foldout .hyper-foldout-header{position:relative;display:block;padding:8px 8px;background:#505050;color:#fff;text-shadow:0 0 1px rgba(0,0,0,0.3);font-weight:bold;}.blq-js .hyper-foldout .hyper-foldout-header{padding:0;}.blq-js .hyper-foldout .hyper-foldout-header a{position:relative;display:block;width:448px;padding:8px;background:#505050;color:#fff;text-shadow:0 0 1px rgba(0,0,0,0.3);font-weight:bold;}.blq-js .hyper-foldout .hyper-foldout-header{cursor:pointer;}.blq-js .hyper-foldout .hyper-foldout-header a:hover,.blq-js .hyper-foldout .hyper-foldout-header a:focus{background:#323232;}.blq-js void .hyper-foldout-header a:link,.blq-js void .hyper-foldout-header a:hover,.blq-js void .hyper-foldout-header a:focus,.blq-js .hyper-foldout .hyper-foldout-header a:active{background:#D1700E;}.hyper-foldout .hyper-foldout-header .hyper-foldout-arrow{position:absolute;top:8px;right:8px;width:16px;height:16px;overflow:hidden;text-indent:-50000%;background:url(../../../../../1_4_9/cream/hi/shared/img/foldout-arrow.gif) left 0 no-repeat;}.blq-js .hyper-foldout-header a .hyper-foldout-arrow{background-position:left 0;}.blq-js .hyper-foldout-header a:hover .hyper-foldout-arrow,.blq-js .hyper-foldout-header a:focus .hyper-foldout-arrow{background-position:center 0;}.blq-js .hyper-foldout-header a:active .hyper-foldout-arrow{background-position:right 0;}.blq-js void .hyper-foldout-header a .hyper-foldout-arrow,.blq-js void .hyper-foldout-header a:hover .hyper-foldout-arrow,.blq-js void .hyper-foldout-header a:focus .hyper-foldout-arrow,.blq-js void .hyper-foldout-header a:active .hyper-foldout-arrow{background-position:right -160px;}.hyper-foldout .hyper-foldout-panel{position:relative;float:left;display:inline;width:464px;clear:both;margin-top:1px;overflow:hidden;background:#f0f0f0;}.blq-js .hyper-foldout .hyper-foldout-panel{height:0;}.hyper-foldout .hyper-foldout-panel ul{position:relative;overflow:hidden;clear:both;float:left;display:inline;padding:11px 8px 5px 240px;}.hyper-foldout .hyper-foldout-panel li{position:relative;width:224px;padding-bottom:8px;}.hyper-foldout .hyper-foldout-panel .column-1{float:left;display:inline;clear:left;margin-left:-232px;}.ie .hyper-foldout .hyper-foldout-panel .column-2,.ie7 .hyper-foldout .hyper-foldout-panel .column-2{float:right;}.hyper-promotional-content{position:relative;display:block;overflow:hidden;clear:both;width:336px;background:#ededed;margin-bottom:16px;}.hyper-promotional-content h2{font-size:1.846em;font-weight:bold;letter-spacing:-0.05em;line-height:24px;padding:8px;position:relative;text-indent:-1px;}.hyper-promotional-content li h3{float:left;display:inline;clear:both;width:100%;font-weight:bold;padding:4px 0 0 0;overflow:visible;}.hyper-promotional-content ul{background:#d1700e;list-style-type:none;padding:0 8px 7px;}.hyper-promotional-content ul li{clear:both;position:relative;display:block;overflow:hidden;padding-bottom:11px;}.ie .hyper-promotional-content ul li{height:1%;}.hyper-promotional-content ul li.first-child{padding-top:8px;}.hyper-promotional-content ul li p{color:#fff;position:relative;clear:both;padding:4px 0;}.hyper-promotional-content ul li a,.hyper-promotional-content ul li a:visited,.hyper-promotional-content ul li a:active{color:#fff;}.hyper-promotional-content ul li.large-image{overflow:visible;padding-top:0;}.hyper-promotional-content li.large-image img{border-bottom:solid 1px #fff;display:block;height:189px;margin:-4px 0 6px -8px;position:relative;width:336px;}.hyper-promotional-content ul li.medium-image{padding:8px 0 0 152px;}.hyper-promotional-content li.medium-image h3{float:none;display:inline;overflow:auto;}.hyper-promotional-content li.medium-image img{display:inline;float:left;position:relative;top:3px;margin-left:-152px;height:81px;width:144px;}.hyper-promotional-content ul li.medium-image p{clear:none;display:block;}.hyper-promotional-content .large-image .gvl3-icon-wrapper{left:-8px;position:absolute;top:0;}.hyper-promotional-content .medium-image .gvl3-icon-wrapper{left:0;position:absolute;top:11px;}.hyper-promotional-content .gvl3-icon{left:0;position:absolute;top:3px;}.hyper-promotional-content .first-child .gvl3-icon{top:11px;}.hyper-promotional-content .gvl3-icon-wrapper .gvl3-icon{left:auto;position:relative;top:auto;}.bbccom_slot_xxl #bbccom_module_hyper-promotional-content{clear:both;}.bbccom_slot_xxl .hyper-promotional-content{width:496px;}.bbccom_slot_xxl .hyper-promotional-content ul{overflow:hidden;width:480px;padding-bottom:0;}.bbccom_slot_xxl .hyper-promotional-content li{width:224px;padding-right:16px;clear:none;float:left;display:inline;margin-top:8px;}.bbccom_slot_xxl .hyper-promotional-content ul li.first-child{width:100%;padding-right:0;margin-top:0;}.bbccom_slot_xxl .hyper-promotional-content ul li.large-image{float:none;display:block;margin-top:0;padding:8px 0 0 336px;width:144px;height:180px;}.bbccom_slot_xxl .hyper-promotional-content li.large-image h3{float:none;display:block;clear:both;}.bbccom_slot_xxl .hyper-promotional-content li.large-image img{border-bottom:none;position:absolute;top:0;left:0;margin-top:0;margin-bottom:0;}.bbccom_slot_xxl .hyper-promotional-content li.large-image p{clear:none;}.bbccom_slot_xxl .hyper-promotional-content ul li.medium-image{width:auto;float:none;display:block;clear:both;margin-top:0;padding-bottom:8px;}.bbccom_slot_xxl .hyper-promotional-content li.medium-image img{top:1px;}.bbccom_slot_xxl .hyper-promotional-content li.medium-image .gvl3-icon-wrapper{top:9px;}.hyper-container-title{position:relative;overflow:visible;width:464px;margin:0 0 4px;padding-top:7px;border-top:1px solid #ddd;}.hyper-container-title .hyper-container-title-header{position:relative;margin-top:1px;margin-bottom:10px;padding-bottom:1px;}.hyper-container-title .hyper-container-title-header a.special-report{position:relative;display:block;margin-top:-9px;margin-bottom:-12px;padding:9px 8px 12px;z-index:1;color:#fff;background:#d60000;}.hyper-container-title .hyper-depth-header{position:relative;margin:-7px 0 0;padding:11px 0 12px;overflow:hidden;}.ie .hyper-container-title .hyper-depth-header{height:1%;}.hyper-container-title .hyper-depth-header-branded{border-bottom:3px solid #ddd;z-index:0;}.hyper-container-title .hyper-depth-header-branded a{position:relative;display:block;margin-top:-11px;margin-bottom:-13px;padding:11px 0 13px;z-index:1;}.hyper-container-title .hyper-depth-header-branded img{position:absolute;bottom:0;right:0;z-index:-10;}.hyper-container-title .hyper-depth-header a.special-report{position:relative;display:block;margin-top:-11px;margin-bottom:-13px;padding:11px 8px 13px;z-index:1;color:#fff;background:#CD1211;}.hyper-related-assets{position:relative;overflow:visible;width:464px;margin:0 0 2px;padding-top:11px;border-top:1px solid #ddd;}.hyper-related-assets .hyper-depth-stories-header{position:relative;margin-top:3px;margin-bottom:12px;}.hyper-related-assets ul{position:relative;overflow:hidden;width:224px;margin:-3px 0 4px;padding-left:240px;}.hyper-related-assets li{position:relative;padding-bottom:8px;}.hyper-related-assets .gvl3-icon{position:absolute;top:-1px;left:0;}.hyper-related-assets .gvl3-icon-wrapper{position:absolute;top:0;}.hyper-related-assets .gvl3-icon-wrapper .gvl3-icon{position:relative;top:auto;left:auto;}.hyper-related-assets .with-summary{position:relative;clear:both;overflow:hidden;width:352px;margin-top:0;margin-left:-240px;padding-right:112px;margin-bottom:8px;}.hyper-related-assets .with-summary .hyper-story-header{position:relative;float:left;display:inline;width:100%;margin-bottom:0;}.hyper-related-assets .medium-image{position:relative;clear:both;overflow:hidden;width:304px;margin-top:-2px;margin-left:-240px;padding-bottom:7px;padding-left:160px;}.hyper-related-assets .medium-image .hyper-story-header{position:relative;margin-bottom:0;}.hyper-related-assets .medium-image img{position:relative;float:left;display:inline;margin-left:-160px;width:144px;height:81px;top:2px;}.hyper-related-assets .medium-image .gvl3-icon-wrapper{top:2px;left:-160px;}.hyper-related-assets .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;width:224px;margin-left:-240px;}.hyper-related-assets .column-2{clear:none;position:relative;width:224px;}.ie .hyper-related-assets .column-2{float:right;}.top-section-stories{width:464px;background-color:#ededed;overflow:auto;clear:both;}.top-section-stories h3{position:relative;}.ie .top-section-stories .column-1 h3,.ie .top-section-stories .column-2 h3{float:left;}.top-section-stories h3 .gvl3-icon-wrapper{position:absolute;top:1px;left:-152px;}.top-section-stories .column-1 h3 .gvl3-icon,.top-section-stories .column-2 h3 .gvl3-icon{position:absolute;top:0;left:0;}.top-section-stories ul{margin:0 8px 0 8px;}.top-section-stories .top-section-stories-header{padding:8px;}.top-section-stories li{padding-bottom:8px;position:relative;}.top-section-stories .medium-image{clear:both;margin-top:-1px;overflow:hidden;padding-bottom:12px;padding-left:152px;position:relative;}.ie .top-section-stories .medium-image{margin-bottom:8px;}.top-section-stories .medium-image img{display:inline;float:left;top:1px;height:81px;margin-left:-152px;position:relative;width:144px;}.top-section-stories .medium-image h3{margin-bottom:1px;position:relative;}.top-section-stories .column-1{clear:left;display:inline;float:left;margin-left:0;overflow:hidden;position:relative;width:216px;padding-right:16px;}.top-section-stories .column-2{clear:none;position:relative;float:left;width:216px;}.container-local-weather-and-travel{width:464px;background-color:#ededed;overflow:auto;padding:0;}.container-local-weather-and-travel .travel .useful-links{width:224px;margin-bottom:0;padding-bottom:0;margin-left:0;}.container-local-weather-and-travel .travel,.container-local-weather-and-travel .weather{border-top:1px solid #DDD;}.container-local-weather-and-travel .weather .data-feed-now h3{border-bottom:1px solid #DDD;padding:8px 0 7px;}.container-local-weather-and-travel .data-feed-now h3#weather_sitelabel{border-bottom:none;padding-bottom:0;}.container-local-weather-and-travel .travel{padding:0;margin:0 8px 0 8px;width:216px;float:left;display:inline;}.container-local-weather-and-travel .travel .useful-links{width:216px;}.container-local-weather-and-travel .travel .useful-links ul{width:216px;padding:7px 0 0 0;}.container-local-weather-and-travel .travel .useful-links li.column-1,.container-local-weather-and-travel .travel .useful-links li.column-2{margin-left:0;float:left;padding-left:0;}.container-local-weather-and-travel .travel .useful-links li a{padding-right:0;}.container-local-weather-and-travel .weather .data-feed-now h2,.container-local-weather-and-travel .travel .useful-links .useful-links-header{padding:8px 0 7px;border-bottom:1px solid #DDD;}.container-local-weather-and-travel .weather{width:216px;float:left;margin-left:8px;}.container-local-weather-and-travel .weather img{float:left;margin-right:8px;}.container-local-weather-and-travel .weather .stripes div{margin:8px 0 8px 0;}.container-local-weather-and-travel .weather ul li.wind{display:none;visibility:hidden;}.container-local-weather-and-travel .data-feed-now .next3daysweather{padding-top:1px;}.container-local-weather-and-travel .data-feed-now .next3daysweather h4{float:right;width:151px;font-weight:normal;}.ie .container-local-weather-and-travel .data-feed-now .next3daysweather ul{margin-top:-8px;}.hyperpuff .useful-links{border-top:none;background-color:#ededed;width:464px padding-bottom:4px;}.hyperpuff .useful-links ul{width:224px;padding:4px 0 0 240px;}.hyperpuff .useful-links .column-1{width:216px;margin-left:-240px;padding-left:8px;}.hyperpuff .useful-links .column-2{width:216px;}.hyperpuff .useful-links .column-top h3{padding-top:11px;border-top:1px solid #DDD;}.hyperpuff .useful-links li a{padding-right:0;}.hyperpuff .useful-links li .gvl3-icon{top:11px;}.blq-js .hypertabs{position:relative;overflow:hidden;height:41px;}.blq-js .hypertabs .hypertab-container{overflow:hidden;position:relative;background:#eee;}.blq-js .hypertabs a.hypertab-nav{z-index:1000;position:absolute;top:0;height:100%;}.blq-js .hypertabs ul{margin:0;position:relative;border-top:8px solid #eee;border-left:8px solid #eee;border-right:8px solid #eee;background:#eee;height:33px!important;padding:0;}.hypertabs ul li,.story-body .hypertabs ul li,.story-wide .hypertabs ul li{margin:0 0 8px;padding:0;background:none;}.hypertabs ul li.selected{background-colour:#eee;}.hypertabs ul li.selected a{color:#D1700E;}.blq-js .hypertabs ul li{background-image:none;display:inline;float:left;font-weight:bold;margin:5px 0 5px 0;text-align:center;border-right:1px solid #666;padding:0;}.blq-js .hypertabs li.selected{margin:0 0 0 -1px;padding:5px 0 0 0;height:33px!important;background:#fff;color:#D1700E;border:none;}.blq-js .hypertabs ul li.last-child{border-right:none;}.blq-js .hypertabs ul li a{display:block;padding:0 10px;font-weight:bold;white-space:nowrap;}.blq-js .hypertabs ul li.selected a{color:#D1700E;}.blq-js .hypertabs a.hypertab-prev-disabled{background-position:0 -522px;cursor:default;}.blq-js .hypertabs a.hypertab-next-disabled{background-position:0 -579px;cursor:default;}.blq-js .hypertabs .hypertab-prev{text-indent:-5000px;background-image:url(../../../../../1_4_9/cream/hi/shared/img/story_sprite.png);background-repeat:no-repeat;background-position:0 -7px;width:23px;}.blq-js .hypertabs .hypertab-next{text-indent:-5000px;background-image:url(../../../../../1_4_9/cream/hi/shared/img/story_sprite.png);background-repeat:no-repeat;background-position:0 -64px;width:23px;}.languages{position:relative;clear:both;overflow:hidden;padding:0 8px;background-color:#eee;margin:0 0 24px;}.languages h3{position:relative;display:block;padding:8px 0 11px;}.ie .languages h3 a,.ie7 .languages h3 a{line-height:24px;}.languages h4{position:relative;clear:both;display:block;}.languages h5{position:absolute;left:-50000%;}.languages ul{position:relative;overflow:hidden;float:left;display:inline;width:25%;padding:9px 0 4px;}.languages ul li{float:left;display:inline;width:136px;padding:0 16px 8px 0;}.ie .languages ul li,.ie7 .languages ul li{width:120px;}.languages ul li span.lang-with-image{position:absolute;margin-left:-50000%;float:left;display:inline;padding-right:5px;color:#505050;font-weight:normal;cursor:pointer;z-index:10;}.languages ul li a:hover,.languages ul li a:focus{text-decoration:none;}.languages ul li .lang-sprite{position:relative;cursor:pointer;margin:-4px 0;float:left;display:inline;height:24px;width:30px;background:red;overflow:hidden;text-indent:-5000px;background:transparent url(../img/languages-sprite.gif) no-repeat;}.languages ul li span.lang-albanian{background-position:-16px 0;width:28px;}.languages ul li a:hover span.lang-albanian,.languages ul li a:focus span.lang-albanian{background-position:-16px -24px;}.languages ul li span.lang-arabic{background-position:-59px 0;width:27px;}.languages ul li a:hover span.lang-arabic,.languages ul li a:focus span.lang-arabic{background-position:-59px -24px;}.languages ul li span.lang-azeri{background-position:-101px 0;width:66px;}.languages ul li a:hover span.lang-azeri,.languages ul li a:focus span.lang-azeri{background-position:-101px -24px;}.languages ul li span.lang-bangla{background-position:-182px 0;width:27px;}.languages ul li a:hover span.lang-bangla,.languages ul li a:focus span.lang-bangla{background-position:-182px -24px;}.languages ul li span.lang-bermese{background-position:-224px 0;width:88px;}.languages ul li a:hover span.lang-bermese,.languages ul li a:focus span.lang-bermese{background-position:-224px -24px;}.languages ul li span.lang-carribbean{background-position:-327px 0;width:53px;}.languages ul li a:hover span.lang-carribbean,.languages ul li a:focus span.lang-carribbean{background-position:-327px -24px;}.languages ul li span.lang-chinese{background-position:-395px 0;width:27px;}.languages ul li a:hover span.lang-chinese,.languages ul li a:focus span.lang-chinese{background-position:-395px -24px;}.languages ul li span.lang-french{background-position:-437px 0;width:46px;}.languages ul li a:hover span.lang-french,.languages ul li a:focus span.lang-french{background-position:-437px -24px;}.languages ul li span.lang-hausa{background-position:-498px 0;width:32px;}.languages ul li a:hover span.lang-hausa,.languages ul li a:focus span.lang-hausa{background-position:-498px -24px;}.languages ul li span.lang-hindi{background-position:-545px 0;width:23px;}.languages ul li a:hover span.lang-hindi,.languages ul li a:focus span.lang-hindi{background-position:-545px -24px;}.languages ul li span.lang-indonesian{background-position:-583px 0;width:53px;}.languages ul li a:hover span.lang-indonesian,.languages ul li a:focus span.lang-indonesian{background-position:-583px -24px;}.languages ul li span.lang-kinyarwanda{background-position:-651px 0;width:72px;}.languages ul li a:hover span.lang-kinyarwanda,.languages ul li a:focus span.lang-kinyarwanda{background-position:-651px -24px;}.languages ul li span.lang-kirundi{background-position:-738px 0;width:44px;}.languages ul li a:hover span.lang-kirundi,.languages ul li a:focus span.lang-kirundi{background-position:-738px -24px;}.languages ul li span.lang-kyrgyz{background-position:-797px 0;width:37px;}.languages ul li a:hover span.lang-kyrgyz,.languages ul li a:focus span.lang-kyrgyz{background-position:-797px -24px;}.languages ul li span.lang-macedonian{background-position:-849px 0;width:69px;}.languages ul li a:hover span.lang-macedonian,.languages ul li a:focus span.lang-macedonian{background-position:-849px -24px;}.languages ul li span.lang-nepali{background-position:-933px 0;width:32px;}.languages ul li a:hover span.lang-nepali,.languages ul li a:focus span.lang-nepali{background-position:-933px -24px;}.languages ul li span.lang-pashto{background-position:-980px 0;width:29px;}.languages ul li a:hover span.lang-pashto,.languages ul li a:focus span.lang-pashto{background-position:-980px -24px;}.languages ul li span.lang-persian{background-position:-1024px 0;width:28px;}.languages ul li a:hover span.lang-persian,.languages ul li a:focus span.lang-persian{background-position:-1024px -24px;}.languages ul li span.lang-brasil{background-position:-1067px 0;width:30px;}.languages ul li a:hover span.lang-brasil,.languages ul li a:focus span.lang-brasil{background-position:-1067px -24px;}.languages ul li span.lang-portuguese{background-position:-1112px 0;width:56px;}.languages ul li a:hover span.lang-portuguese,.languages ul li a:focus span.lang-portuguese{background-position:-1112px -24px;}.languages ul li span.lang-russian{background-position:-1183px 0;width:88px;}.languages ul li a:hover span.lang-russian,.languages ul li a:focus span.lang-russian{background-position:-1183px -24px;}.languages ul li span.lang-serbian{background-position:-1287px 0;width:29px;}.languages ul li a:hover span.lang-serbian,.languages ul li a:focus span.lang-serbian{background-position:-1287px -24px;}.languages ul li span.lang-sinhala{background-position:-1331px 0;width:41px;}.languages ul li a:hover span.lang-sinhala,.languages ul li a:focus span.lang-sinhala{background-position:-1331px -24px;}.languages ul li span.lang-somali{background-position:-1387px 0;width:35px;}.languages ul li a:hover span.lang-somali,.languages ul li a:focus span.lang-somali{background-position:-1387px -24px;}.languages ul li span.lang-mundo{background-position:-1437px 0;width:38px;}.languages ul li a:hover span.lang-mundo,.languages ul li a:focus span.lang-mundo{background-position:-1437px -24px;}.languages ul li span.lang-swahili{background-position:-1490px 0;width:38px;}.languages ul li a:hover span.lang-swahili,.languages ul li a:focus span.lang-swahili{background-position:-1490px -24px;}.languages ul li span.lang-tamil{background-position:-1543px 0;width:28px;}.languages ul li a:hover span.lang-tamil,.languages ul li a:focus span.lang-tamil{background-position:-1543px -24px;}.languages ul li span.lang-turkish{background-position:-1586px 0;width:38px;}.languages ul li a:hover span.lang-turkish,.languages ul li a:focus span.lang-turkish{background-position:-1586px -24px;}.languages ul li span.lang-ukrainian{background-position:-1639px 0;width:60px;}.languages ul li a:hover span.lang-ukrainian,.languages ul li a:focus span.lang-ukrainian{background-position:-1639px -24px;}.languages ul li span.lang-urdu{background-position:-1715px 0;width:23px;}.languages ul li a:hover span.lang-urdu,.languages ul li a:focus span.lang-urdu{background-position:-1715px -24px;}.languages ul li span.lang-uzbek{background-position:-1753px 0;width:35px;}.languages ul li a:hover span.lang-uzbek,.languages ul li a:focus span.lang-uzbek{background-position:-1753px -24px;}.languages ul li span.lang-vietnamese{background-position:-1803px 0;width:55px;}.languages ul li a:hover span.lang-vietnamese,.languages ul li a:focus span.lang-vietnamese{background-position:-1803px -24px;}.languages .languages-footer{position:relative;clear:both;border-top:1px solid #d8d8d8;width:100%;padding:11px 0 12px;}.ie .languages .languages-footer{height:1%;}.lead-feature-now{position:relative;clear:both;overflow:hidden;width:624px;padding:8px 0 0;margin-bottom:17px;}.lead-feature-now a:hover,.lead-feature-now a:focus{text-decoration:none;}.lead-feature-now .overlay{position:absolute;width:272px;bottom:0;left:0;z-index:10;cursor:pointer;padding:7px 16px 11px;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/transparencies/rgba-0-0-0-07.png) repeat;}.ie .lead-feature-now .overlay{bottom:-1px;background:black;}.lead-feature-now a:active .overlay{background:#D2700F;}.lead-feature-now .headline{display:block;color:white;position:relative;margin-bottom:7px;}.lead-feature-now a:hover .headline,.lead-feature-now a:focus .headline{text-decoration:underline;}.lead-feature-now .summary{display:block;color:white;font-weight:normal;}.lead-feature-now .story img{display:block;position:relative;}.lead-feature-now .gvl3-icon-wrapper{top:8px;left:0;}.live-event-promo{position:relative;clear:both;overflow:hidden;margin:8px 0 16px;}.live-event-promo h2{position:absolute;left:-5000%;}.live-event-promo .live-event-promo-action{display:block;overflow:hidden;position:relative;z-index:10;padding-bottom:400px;margin:0 0 -400px;}.live-event-promo a.live-event-promo-action:hover,.live-event-promo a.live-event-promo-action:focus{text-decoration:none;}.live-event-promo .live-event-promo-title{float:left;display:inline;margin-right:8px;padding:0 8px 0 66px;line-height:32px;color:white;font-weight:bold;font-size:20px;background:#D60000 url(../../../../../1_4_9/cream/hi/shared/img/live-icon-32.gif) no-repeat 2px center;}.live-event-promo a.live-event-promo-action:hover .live-event-promo-title,.live-event-promo a.live-event-promo-action:focus .live-event-promo-title{text-decoration:underline;}.live-event-promo .live-event-promo-video{display:block;padding:7px 8px 1px;line-height:24px;color:white;font-weight:bold;font-size:13px;background:#333;}.live-event-promo .live-event-promo-video strong{position:relative;top:4px;float:left;display:inline;padding-right:4px;color:white;text-transform:uppercase;}.live-event-promo .live-event-promo-video .gvl3-icon{position:relative;top:3px;float:left;display:inline;}.live-event-promo ol{background:#505050;}.live-event-promo ol *{color:white;}.live-event-promo ol li{padding:4px 8px;}.live-event-promo ol li img,.live-event-promo ol li .icon-front,.live-event-promo ol li .icon-back{display:none;}.live-event-promo li .item-info{font-weight:bold;}.story-body .live-event-promo{clear:both;display:inline;float:right;margin:0 -160px 16px 16px;position:relative;width:304px;}.bbccom_slot_xxl .story-body .live-event-promo{margin-right:0;}.story-body .live-event-promo .live-event-promo-action{position:absolute;height:100%;width:100%;top:0;left:0;padding-bottom:0;margin-bottom:0;}.story-body .live-event-promo .live-event-promo-action,.story-body .live-event-promo .live-event-promo-action *{cursor:pointer;}.story-body .live-event-promo .live-event-promo-title{float:none;display:block;margin-right:0;}.story-body .live-event-promo .live-event-promo-video{position:absolute;width:100%;bottom:0;left:0;padding-top:3px;}.story-body .live-event-promo ol{position:relative;padding:32px 0 28px;margin:0;}.story-body .live-event-promo ol *{font-size:13px;line-height:16px;}.story-body .live-event-promo ol li{padding:8px;margin:0;}.story-body .live-event-promo ol li p{margin:0;}.livestats{clear:both;position:relative;overflow:hidden;width:320px;margin:0 0 16px;padding:8px 8px 8px;background:#ededed;}.bbccom_slot_xxl .livestats{width:480px;}.livestats .livestats-header{font-size:24px;font-size:1.846em;font-weight:bold;letter-spacing:-0.05em;line-height:24px;text-indent:-1px;padding:0;}.livestats .tab{padding:9px 16px 10px 0;position:relative;background:transparent;z-index:100;font-size:1.231em;font-weight:bold;line-height:20px;}.livestats .panel{position:relative;overflow:hidden;width:320px;background:#fff;}.bbccom_slot_xxl .livestats .panel{width:480px;}.livestats .panel li{clear:both;display:block;overflow:hidden;border-top:1px solid #eee;position:relative;zoom:1;}.livestats .panel li a{position:relative;overflow:visible;float:left;display:inline;width:283px;padding:11px 29px 12px 8px;}.bbccom_slot_xxl .livestats .panel li a{width:442px;}.ie7 .livestats .panel li a,.ie .livestats .panel li a{padding-bottom:8px;height:1%;}.livestats .panel li.first-child{border-top:none;}.livestats .panel li.first-child a{padding-top:12px;}.livestats .has-icon-listen{text-indent:25px;}.livestats .has-icon-watch{text-indent:20px;}.livestats .gvl3-icon{position:absolute;top:11px;left:9px;}.livestats .livestats-icon{position:absolute;right:7px;top:50%;margin-top:-18px;height:36px;width:14px;cursor:pointer;overflow:hidden;text-indent:-50000px;background:#a9a9a9 url(../img/livestats-sprite-ko.png) repeat;-webkit-transition:all 1s ease-out;}.ie .livestats .livestats-icon{background-color:transparent;background-image:url(../img/livestats-sprite.gif);}.livestats a:hover .livestats-icon,.livestats a:focus .livestats-icon{background-color:#d1700e;-webkit-transition:.2s ease-in;}.livestats .livestats-monday{background-position:1px -45px;right:3px;}.ie .livestats a:hover .livestats-monday,.ie .livestats a:focus .livestats-monday{background-position:-335px -45px;}.livestats .livestats-tuesday{background-position:-31px -46px;right:3px;}.ie .livestats a:hover .livestats-tuesday,.ie .livestats a:focus .livestats-tuesday{background-position:-367px -46px;}.livestats .livestats-wednesday{background-position:-63px -45px;right:3px;}.ie .livestats a:hover .livestats-wednesday,.ie .livestats a:focus .livestats-wednesday{background-position:-399px -45px;}.livestats .livestats-thursday{background-position:-95px -45px;right:3px;}.ie .livestats a:hover .livestats-thursday,.ie .livestats a:focus .livestats-thursday{background-position:-431px -45px;}.livestats .livestats-friday{background-position:-127px -45px;right:3px;}.ie .livestats a:hover .livestats-friday,.ie .livestats a:focus .livestats-friday{background-position:-463px -45px;}.livestats .livestats-saturday{background-position:-159px -45px;right:3px;}.ie .livestats a:hover .livestats-saturday,.ie .livestats a:focus .livestats-saturday{background-position:-495px -45px;}.livestats .livestats-sunday{background-position:-191px -46px;right:3px;}.ie .livestats a:hover .livestats-sunday,.ie .livestats a:focus .livestats-sunday{background-position:-527px -46px;}.livestats .livestats-1{background-position:1px -5px;}.ie .livestats a:hover .livestats-1,.ie .livestats a:focus .livestats-1{background-position:-335px -5px;}.livestats .livestats-2{background-position:-32px -5px;}.ie .livestats a:hover .livestats-2,.ie .livestats a:focus .livestats-2{background-position:-368px -5px;}.livestats .livestats-3{background-position:-64px -5px;}.ie .livestats a:hover .livestats-3,.ie .livestats a:focus .livestats-3{background-position:-400px -5px;}.livestats .livestats-4{background-position:-96px -5px;}.ie .livestats a:hover .livestats-4,.ie .livestats a:focus .livestats-4{background-position:-432px -5px;}.livestats .livestats-5{background-position:-127px -5px;}.ie .livestats a:hover .livestats-5,.ie .livestats a:focus .livestats-5{background-position:-463px -5px;}.livestats .livestats-6{background-position:-160px -5px;}.ie .livestats a:hover .livestats-6,.ie .livestats a:focus .livestats-6{background-position:-496px -5px;}.livestats .livestats-7{background-position:-192px -5px;}.ie .livestats a:hover .livestats-7,.ie .livestats a:focus .livestats-7{background-position:-528px -5px;}.livestats .livestats-8{background-position:-224px -5px;}.ie .livestats a:hover .livestats-8,.ie .livestats a:focus .livestats-8{background-position:-560px -5px;}.livestats .livestats-9{background-position:-256px -5px;}.ie .livestats a:hover .livestats-9,.ie .livestats a:focus .livestats-9{background-position:-592px -5px;}.livestats .livestats-10{width:26px;background-position:-287px -5px;}.ie .livestats a:hover .livestats-10,.ie .livestats a:focus .livestats-10{background-position:-623px -5px;}.blq-js .livestats-tabbed .livestats-header{padding-bottom:8px;}.blq-js .livestats-tabbed .tab{float:left;display:inline;top:0;padding:7px 16px 6px 8px;cursor:pointer;}.blq-js .ie .livestats-tabbed .tab,.blq-js .ie7 .livestats-tabbed .tab{padding-top:9px;padding-bottom:8px;}.blq-js .livestats-tabbed void{background:#fff;}.blq-js .livestats-tabbed void a{color:#d2700f;}.blq-js .livestats-tabbed .panel{position:absolute;float:right;display:inline;clear:right;right:-500%;margin-right:0;margin-top:32px;opacity:0;}.blq-js .ie .livestats-tabbed .panel,.blq-js .ie7 .livestats-tabbed .panel{clear:none;}.blq-js .livestats-tabbed void{position:relative;margin-right:-320px;right:320px;opacity:1;-webkit-transition:opacity .2s ease-in;}.blq-js .bbccom_slot_xxl .livestats-tabbed void{margin-right:-480px;right:480px;}.blq-js .ie .livestats-tabbed void,.blq-js .ie7 .livestats-tabbed void{margin-top:32px;}.livestats .has-icon-watch .gvl3-icon-watch{width:15px;}.livestats .has-icon-watch .gvl3-icon-watch{background-position:-1301px -0px;}.livestats .has-icon-watch a:active .gvl3-icon-watch{background-position:-1301px -16px;}.container-promo-best{clear:both;position:relative;}.container-local{clear:both;overflow:hidden;margin:0 0 16px 0;padding:0 8px 0 8px!important;background:#ededed;}.local-av{overflow:visible;}.local-av-header{font-size:24px;font-weight:bold;letter-spacing:-1px;line-height:24px;margin:8px 0 8px 0;text-rendering:optimizelegibility;}.local-av-header a{line-height:24px;}.ie .local-av .local-av-header{padding-top:8px;}.local-av h3{font-size:13px;font-weight:normal;line-height:16px;text-transform:uppercase;text-rendering:optimizelegibility;}.local-av .program-time{font-weight:bold;}.local-av .local-radio-now .program-time{padding:2px 0 0 0;display:inline-block;width:90px;}.container-local .feature-item{position:relative;display:block;clear:both;margin:8px -8px 7px;}.container-local .feature-item *{cursor:pointer;}.container-local .feature-item .overlay{position:absolute;width:320px;bottom:0;left:0;z-index:10;cursor:pointer;padding:8px 8px 7px;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/transparencies/rgba-0-0-0-07.png) repeat;}.ie .container-local .feature-item .overlay{background:black;}.container-local a.feature-item:active .overlay{background:#D2700F;}.container-local a.feature-item .summary{font-weight:normal;}.container-local a.feature-item:hover,.container-local a.feature-item:focus,.container-local a.feature-item:hover .summary,.container-local a.feature-item:focus .summary{text-decoration:none;}.container-local a.feature-item:hover .headline,.container-local a.feature-item:focus .headline{text-decoration:underline;}.container-local .feature-item .overlay strong,.container-local .feature-item .overlay .summary{color:#fff;display:block;}.container-local a.feature-item .overlay strong{position:relative;float:left;display:inline;clear:both;font-weight:bold;padding-bottom:2px;}.container-local a.feature-item .overlay strong.has-icon-podcast{padding-left:15px;}.container-local a.feature-item .overlay .gvl3-icon{position:absolute;top:0;left:0;}.container-local .feature-item img{display:block;}.local-radio-now{clear:both;padding-top:7px;border-top:1px solid #ddd;}.local-radio-now h3{position:absolute;left:-5000px;}.local-radio-now .local-now{position:relative;overflow:visible;padding-bottom:10px;padding-right:4px;font-size:1.231em;font-weight:bold;line-height:16px;text-rendering:optimizelegibility;}.local-av .local-radio-now .gvl3-icon{top:2px;}.local-radio-next{margin-bottom:4px;}.local-radio-next h3{display:inline;padding-right:3px;}.local-av .local-radio-next .program-time{padding:2px 0 0 0;display:inline-block;width:90px;}.local-radio-services{position:relative;clear:both;overflow:hidden;padding-top:2px;padding-bottom:8px;}.local-radio-services h3{position:absolute;left:-5000px;}.local-radio-services li{padding-left:9px;margin-left:7px;float:left;display:inline;background:url(../img/nav-divider.png) center left no-repeat;}.local-radio-services li:first-child{padding-left:0;margin-left:0;background:none;}.ie .local-radio-services{height:1%;}.local-av-regional-variations{padding:8px 0;border-top:1px solid #ddd;}.local-av-alt-language{clear:both;padding-top:0;border-top:1px solid #ddd;}.local-av-alt-language .local-now{position:relative;float:left;display:inline;overflow:visible;}.local-av-alt-language .local-now .gvl3-icon{position:absolute;top:0;left:0;}.local-av-tv{clear:both;margin-top:1px;padding-bottom:8px;border-top:1px solid #ddd;width:100%;}.local-av-tv-only{border-top:none;}.local-av-tv .local-av-header{margin-bottom:2px;}.local-tv-now h3{position:absolute;float:left;left:-5000px;}.local-tv-now .local-now{position:relative;float:left;display:inline;clear:both;overflow:visible;padding-left:24px;margin-top:4px;padding-top:1px;}.local-radio-podcast{clear:both;overflow:hidden;padding-bottom:8px;border-top:1px solid #ddd;padding-top:8px;}.local-radio-podcast .local-podcast{position:relative;float:left;display:inline;overflow:visible;padding-left:0;padding-left:18px;}.local-av .local-radio-podcast .gvl3-icon{position:absolute;top:1px;left:0;}.local-av .local-tv-now .gvl3-icon{position:absolute;top:1px;left:0;}.local-av .gvl3-icon{position:relative;top:0;left:0;float:left;}.local-av-alt-language .gvl3-icon-boxedlive{top:1px;}.local-av .has-icon-boxedwatch,.local-av .has-icon-live,.local-av .has-icon-boxedlive{text-indent:0;}.local-av-times{clear:left;display:block;padding-top:1px;}.local-weather .next3daysweather .stripes{background-color:#fff;float:left;padding:0;}.local-weather .next3daysweather .stripes li{font-size:13px;}.local-weather .next3daysweather .stripes div.time{width:84px;float:left;margin-right:20px;}.local-weather .next3daysweather .stripes img{margin:0 0 4px 0;}.local-weather .next3daysweather a{color:#369;}.local-weather .next3daysweather a:hover{color:#0D3059;}.local-weather .next3daysweather .stripes h3{padding:0 0 4px;font-weight:normal;}.local-weather .next3daysweather p{width:285px;margin:7px 0 10px 0;font-size:1.2em;}.local-weather .next3daysweather p a{font-size:.9em;}.local-weather .next3daysweather .stripes .c3{margin-right:10px!important;}.local-weather .next3daysweather .clear{clear:both;}.local-weather{background-color:#EDEDED;clear:both;float:left;padding:8px;position:relative;width:320px;}.ie .local-weather,.ie7 .local-weather{overflow:hidden;margin-bottom:0;}.weather-dropdown ul{position:relative;padding-top:24px;overflow:hidden;background-color:#FFF;height:0;margin-bottom:8px;padding-bottom:8px;}.weather-dropdown ul li{cursor:pointer;margin:8px 8px 0;}.ie .weather-dropdown ul,.ie7 .weather-dropdown ul{padding-top:32px;padding-bottom:0;}.weather-dropdown ul li a{display:block;}.weather-dropdown ul li.selected{top:0;position:absolute;font-weight:bold;width:100%;left:0;}.weather-dropdown ul li.selected a{color:black;}.local-weather .tabbed void{background-color:#FFF;}.local-weather .tabbed div.panel{display:none;clear:both;background-color:#FFF;padding:8px;}.local-weather .tabbed void{display:block;}.local-weather .stripes .wind{display:none;}.local-weather .tabbed div.weather-video{padding-top:16px;}.ie7 .local-weather .tabbed ul{overflow:auto;}.ie .local-weather .tabbed ul{overflow:hidden;height:1%;}.local-weather h2{padding-top:8px;padding-bottom:8px;}#local-weather-title{margin-top:8px;line-height:24px;font-size:24px;}.local-weather-loc-id li{font-size:16px;font-weight:bold;line-height:18px;}.local-weather .tabbed li.tab{cursor:pointer;display:inline;float:left;margin-right:8px;padding:9px 16px 10px 8px;}.ie .local-weather .tabbed li.tab{overflow:auto;height:1%;margin-bottom:0;}.local-weather li.tab{font-size:16px;font-weight:bold;line-height:18px;}.local-weather-links{padding:8px 0 8px 0;}.local-weather .weathervideo{border:1px solid #ccc;border-top:0;padding:1px 10px 10px;}.o .local-weather .weathervideo{border:none;}.local-weather .weathervideo div{min-height:181px;}.local-weather .emp{margin:0 auto;display:block;margin:16px auto 0;width:256px;margin-bottom:8px;overflow:auto;position:relative;}.ie .local-weather .emp,.ie .local-weather .tabbed div.weather-video{height:1%;}.weather-dropdown ul li.selected{background:url("../img/arrow_foldout.png") no-repeat scroll 294px 1px transparent;}.ie .weather-dropdown ul li.selected{background:url("../img/arrow_foldout.gif") no-repeat scroll 294px 1px transparent;}.weather-dropdown void li.selected{background-position:-93px 2px;}.ie .local-weather .tabbed div.panel{width:304px;}.ie .local-weather .next3daysweather .stripes .c3{margin-right:5px!important;}.ie .weather-dropdown{position:relative;}.ie .weather-dropdown ul{position:static;}.ie .weather-dropdown ul li{height:1%;}.local-travel-box{background-color:#EDEDED;margin:0;padding:0 0 8px 0;}.local-travel-box h3{font-weight:bold;font-size:15px;padding-top:10px;line-height:16px;}.local-travel-box p a{margin-left:8px;font-size:12px;font-weight:normal;}.local-travel-incident{background-color:#FFF;margin:0;padding-bottom:8px;padding-right:8px;}.ie .local-travel-incident{height:1%;}.local-travel-box .local-travel-incident h3{color:#D07128;font-size:15px;line-height:26px;padding-top:0;margin-left:8px;}.local-travel-incident p{color:#505050;font-size:15px;font-weight:bold;margin-left:40px;}.local-travel-incident p a{color:#1f4f82;font-size:12px;line-height:14px;margin-left:0;font-weight:normal;}.road-incident{background:url("../img/roadicon.gif") 8px 27px no-repeat #fff;width:24px height:24px;}.local-traffic-links{font-weight:normal;font-size:13px;line-height:16px;display:block;}.local-journey-planner{font-weight:bold;padding-top:8px;}#travel-key-info{margin:-10px 0 12px 0;}.market-data{position:relative;overflow:hidden;clear:both;background-color:#ededed;padding:0 8px;margin:0 0 16px;width:320px;}.market-data h2{position:relative;display:inline;float:left;padding:8px 0 8px;z-index:10;}.market-data h2 a{line-height:24px;}.market-data .mkt-last-updated{position:relative;padding:16px 0 0;text-align:right;color:#505050;}.market-data .mkt-table{position:relative;clear:both;width:100%;}.market-data .mkt-table .table-headers{display:none;}.market-data .mkt-table td{background-color:#fff;color:#505050;padding:7px 8px 8px;border-bottom:1px solid #ededed;text-align:right;width:1%;}.market-data .mkt-table td.mkt-index{width:96%;text-align:left;}.market-data .mkt-table td.mkt-percent{font-weight:bold;}.market-data .mkt-table .mkt-trend-image{display:block;width:9px;height:7px;}.market-data .mkt-table .mkt-trend{text-align:left;text-indent:-9999px;}.market-data .mkt-table td{white-space:nowrap;vertical-align:middle;}.market-data .mkt-table .mkt-up .mkt-trend-image{background:transparent url(../../../../../1_4_9/cream/hi/shared/img/market-data-up.png) 0 0 no-repeat;}.market-data .mkt-table .mkt-down .mkt-trend-image{background:transparent url(../../../../../1_4_9/cream/hi/shared/img/market-data-down.png) 0 0 no-repeat;}.ie .market-data .mkt-table .mkt-up .mkt-trend-image{background:transparent url(../../../../../1_4_9/cream/hi/shared/img/market-data-up.gif) 0 0 no-repeat;}.ie .market-data .mkt-table .mkt-down .mkt-trend-image{background:transparent url(../../../../../1_4_9/cream/hi/shared/img/market-data-down.gif) 0 0 no-repeat;}.market-data .mkt-table .mkt-nochange .mkt-trend-image,.ie .market-data .mkt-table .mkt-nochange .mkt-trend-image{background:none;}.market-data .mkt-footer{padding:11px 0 12px;position:relative;clear:both;overflow:visible;width:100%;}.market-data .mkt-footer p{position:relative;overflow:hidden;display:inline;}.market-data .mkt-footer .mkt-ticker{float:none;display:inline;clear:both;}.market-data .mkt-footer .mkt-data-delayed{float:right;display:inline;text-align:right;color:#505050;padding-top:2px;}.ie .market-data .mkt-footer .mkt-data-delayed,.ie7 .market-data .mkt-footer .mkt-data-delayed{margin-top:-16px;}.market-data .mkt-footer .gvl3-icon{float:left;display:inline;}#marketdata_v4 .livestats{background:none repeat scroll 0 0 #EDEDED;clear:both;margin:0;overflow:hidden;padding:0;position:relative;width:613px;border-top:8px solid #EDEDED;border-left:8px solid #EDEDED;border-right:8px solid #EDEDED;}#marketdata_v4 .livestats-tabbed void{background:none repeat scroll 0 0 #FFF;}#marketdata_v4 .livestats-tabbed .tab{cursor:pointer;font-size:1em;display:inline;float:left;padding:0 3px 7px 3px;top:0;margin:0;border-right:5px solid #EDEDED;}#marketdata_v4 .livestats-tabbed .tablast{border-right:0;}#marketdata_v4 .livestats-tabbed void a{color:#D2700F;}#marketdata_v4 .border-bottom td{border-bottom:1px solid #DDD;}#marketdata_v4 .border-bottom-dark{border-bottom:1px solid #999;}#marketdata_v4 .statsclick{font-weight:normal;}#marketdata_v4 .statsclick b{color:#1F4F82;}#marketdata_v4 .instructions{padding:10px 0 5px 0;}#marketdata_v4 .statslo{color:#C00;}#marketdata_v4 .statshi{color:#3C8100;}.marketdata_v4_container-now{margin:0 11px 16px 0;width:629px;}#main-content .layout-block-c{border-top:8px solid #eee;}.playlist{clear:both;position:relative;float:left;display:inline;margin:0;padding:0 8px 12px 8px;width:960px;background:#eee;}.iplayer{border-right:none;border-left:none;padding:16px 8px 10px 8px;background:#000;}.iplayer h2,.iplayer li a{color:#ec43a0;}.iplayer h2,.iplayer li span.date{color:#fff;font-weight:normal;}.playlist h2{display:inline;float:left;margin:0 8px 0 0;padding:0;position:relative;width:144px;}.playlist ul{position:relative;overflow:hidden;float:left;display:inline;}.playlist li{position:relative;display:inline;float:left;margin:0 0 0 16px;width:144px;padding:0;}.ie .playlist li{margin:0 0 0 14px;}.playlist img{left:0;position:absolute;top:0;}.playlist li a{position:relative;display:block;padding:84px 0 0 0;margin:0;width:146px;}.playlist li h3 a .gvl3-icon-wrapper{position:absolute;top:0;left:0;z-index:10;}.hyper-container-title .playlist li h3{margin:0;padding:0;}.more-galleries{clear:both;position:relative;float:left;display:inline;background:#eee;margin:0;padding:16px 0 0 0;width:100%;margin:0 0 16px 0;}.more-galleries h2{display:inline;float:left;margin:3px 0 0 16px;padding:0;position:relative;width:128px;}.more-galleries ul{float:right;position:relative;overflow:hidden;width:816px;}.more-galleries li{position:relative;display:inline;float:left;margin:0 0 0 14px;width:146px;padding:0;height:160px;overflow:hidden;}.more-galleries img{left:0;position:absolute;top:0;}.more-galleries li a{position:relative;display:block;padding:83px 0 0 0;margin:0;width:126px;}.more-galleries li h3 a span{position:absolute;top:0;left:0;display:block;text-indent:-5000px;background-image:url(../img/story_sprite.gif);background-repeat:no-repeat;background-position:-4200px 0;height:32px;width:32px;z-index:10;}.most-watched-list{padding:0;margin-left:16px;margin-bottom:0;}.most-watched-list h2{padding:8px;}.most-watched-list .most-pop-carousel{margin:0;width:320px!important;}.most-watched-list .most-pop-carousel .carousel-light{position:relative;padding-bottom:4px;}.most-watched-list .most-pop-carousel .carousel-light .carousel-window{height:652px!important;background:#ededed;}.bbccom_companion .most-watched-list .most-pop-carousel .carousel-light .carousel-window{height:722px!important;}.bbccom_slot_mpu .most-watched-list .most-pop-carousel .carousel-light .carousel-window{height:216px!important;}.most-watched-list .most-pop-carousel .carousel-nav{position:absolute;width:320px!important;height:24px!important;overflow:hidden;z-index:50;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/most_watched.png) 0 0 no-repeat;}.most-watched-list .most-pop-carousel .carousel-nav span{display:none;}.most-watched-list .most-pop-carousel .carousel-nav .carousel-label{display:block;position:absolute;width:1px;overflow:hidden;left:-50000%;}.most-watched-list .most-pop-carousel .carousel-prev{top:0;background-position:0 0;}.most-watched-list .most-pop-carousel .carousel-prev-disabled{background-position:0 -24px;display:none;}.most-watched-list .most-pop-carousel .carousel-next{bottom:0;background-position:0 -72px;}.most-watched-list .most-pop-carousel .carousel-next-disabled{background-position:0 -48px;display:none;}.most-watched-list ol{padding-top:8px;}.most-watched-list li{position:relative;clear:both;overflow:hidden;height:72px;width:152px;padding:0 40px 0 128px;top:-4px;}.most-watched-list li img{position:absolute;top:3px;left:8px;width:112px;height:63px;}.most-watched-list li .gvl3-icon-wrapper{position:absolute;top:3px;left:8px;z-index:30;}.most-watched-list li .gvl3-icon-wrapper .gvl3-icon{position:relative;top:0;left:0;}.most-watched-list li .livestats-icon{top:-11px;margin-top:0;background-image:url(../img/sprite_most_watched_ko.png);}.ie .most-watched-list li .livestats-icon{background-color:transparent;background-image:url(../img/sprite_most_watched.gif);}.most-watched-list li.ol1 .livestats-icon{background-position:1px 0;}.ie .most-watched-list li.ol1 a:hover .livestats-icon,.ie .most-watched-list li.ol1 a:focus .livestats-icon{background-position:-560px -0px;}.most-watched-list li.ol2 .livestats-icon{background-position:-32px 0;}.ie .most-watched-list li.ol2 a:hover .livestats-icon,.ie .most-watched-list li.ol2 a:focus .livestats-icon{background-position:-593px -0px;}.most-watched-list li.ol3 .livestats-icon{background-position:-64px 0;}.ie .most-watched-list li.ol3 a:hover .livestats-icon,.ie .most-watched-list li.ol3 a:focus .livestats-icon{background-position:-625px -0px;}.most-watched-list li.ol4 .livestats-icon{background-position:-95px 0;}.ie .most-watched-list li.ol4 a:hover .livestats-icon,.ie .most-watched-list li.ol4 a:focus .livestats-icon{background-position:-656px -0px;}.most-watched-list li.ol5 .livestats-icon{background-position:-127px 0;}.ie .most-watched-list li.ol5 a:hover .livestats-icon,.ie .most-watched-list li.ol5 a:focus .livestats-icon{background-position:-688px -0px;}.most-watched-list li.ol6 .livestats-icon{background-position:-159px 0;}.ie .most-watched-list li.ol6 a:hover .livestats-icon,.ie .most-watched-list li.ol6 a:focus .livestats-icon{background-position:-720px -0px;}.most-watched-list li.ol7 .livestats-icon{background-position:-192px 0;}.ie .most-watched-list li.ol7 a:hover .livestats-icon,.ie .most-watched-list li.ol7 a:focus .livestats-icon{background-position:-753px -0px;}.most-watched-list li.ol8 .livestats-icon{background-position:-223px 0;}.ie .most-watched-list li.ol8 a:hover .livestats-icon,.ie .most-watched-list li.ol8 a:focus .livestats-icon{background-position:-784px -0px;}.most-watched-list li.ol9 .livestats-icon{background-position:-254px 0;}.ie .most-watched-list li.ol9 a:hover .livestats-icon,.ie .most-watched-list li.ol9 a:focus .livestats-icon{background-position:-815px -0px;}.most-watched-list li.ol10 .livestats-icon{width:26px;background-position:-287px 0;}.ie .most-watched-list li.ol10 a:hover .livestats-icon,.ie .most-watched-list li.ol10 a:focus .livestats-icon{background-position:-848px -0px;}.most-watched-list li.ol11 .livestats-icon{width:26px;background-position:-331px 0;}.ie .most-watched-list li.ol11 a:hover .livestats-icon,.ie .most-watched-list li.ol11 a:focus .livestats-icon{background-position:-892px -0px;}.most-watched-list li.ol12 .livestats-icon{width:26px;background-position:-376px 0;}.ie .most-watched-list li.ol12 a:hover .livestats-icon,.ie .most-watched-list li.ol12 a:focus .livestats-icon{background-position:-937px -0px;}.most-watched-list li.ol13 .livestats-icon{width:26px;background-position:-422px 0;}.ie .most-watched-list li.ol13 a:hover .livestats-icon,.ie .most-watched-list li.ol13 a:focus .livestats-icon{background-position:-983px -0px;}.most-watched-list li.ol14 .livestats-icon{width:26px;background-position:-465px 0;}.ie .most-watched-list li.ol14 a:hover .livestats-icon,.ie .most-watched-list li.ol14 a:focus .livestats-icon{background-position:-1026px -0px;}.most-watched-list li.ol15 .livestats-icon{width:26px;background-position:-511px 0;}.ie .most-watched-list li.ol15 a:hover .livestats-icon,.ie .most-watched-list li.ol15 a:focus .livestats-icon{background-position:-1072px -0px;}.newstracker-list{clear:both;overflow:hidden;padding-bottom:7px;}.newstracker-list h3{border-bottom:1px solid #CCC;border-top:1px solid #CCC;clear:both;margin:0 0 8px;padding:8px 0 7px;width:100%;}.newstracker-list ul li{padding:3px 0 13px 0;width:223px;clear:both;float:left;display:inline;position:relative;background:none;}.newstracker-list ul li.even{float:right;display:inline;clear:none;}.newstracker-list span{font-weight:normal;display:block;padding:0;}.newstracker-list a strong{color:#1F527B;display:block;}.newstracker-list a{font-weight:bold;display:block;padding:0;background-repeat:no-repeat;}.newstracker-list p{clear:both;margin:0 0 16px 0;}.newstracker-list .di{clear:both;padding:11px 0 13px 0;}.other-site-content{float:left;display:inline;position:relative;padding-top:16px;margin-bottom:16px;}.ie .other-site-content,.ie7 .other-site-content{margin-top:4px;}.full-width-other-site .other-site-content{background-color:#EDEDED;width:624px;padding:0;}.other-site-content-header{padding:8px 0;}.other-site-content .wide-content-group .first-other-promo{background-color:#505050;padding:16px 0 4px;padding-bottom:20px;min-height:60px;}.ie7 .other-site-content .wide-content-group .first-other-promo{min-height:auto;}.other-site-content .wide-content-group .first-other-promo h3 img{display:inline;float:left;margin-top:-16px;position:relative;margin-right:16px;border-right:1px solid #fff;}.other-site-content .wide-content-group .first-other-promo h3 a{color:#fff;}.other-site-content .wide-content-group .first-other-promo p{color:#fff;margin:4px 8px 8px 0;}.other-site-content .wide-content-group .other-promo{padding:0 8px 8px 0;background-color:#EDEDED;}.other-site-content .wide-content-group .second-promo{border-top:1px solid #fff;padding-top:9px;}.other-site-content .wide-content-group{padding:0;overflow:auto;height:100%;}.other-site-content .single-story{background-color:#505050;}.other-site-content .stacked-content-group .first-other-promo{background-color:#505050;padding:0 0 4px;}.other-site-content .stacked-content-group .first-other-promo h3 img{display:block;position:relative;z-index:2;}.other-site-content .stacked-content-group .first-other-promo h3 a{color:#fff;margin:0;padding-left:0;}.other-site-content .stacked-content-group .first-other-promo p{color:#fff;margin:4px 8px 8px 16px;}.other-site-content .stacked-content-group li.other-promo{padding:0 8px 8px 16px;}.other-site-content .stacked-content-group li.second-promo{border-top:1px solid #fff;padding-top:8px;}.other-site-content .stacked-content-group{width:304px;}.container-other-site-promotion .first-group .stacked-content-group{margin-right:16px;}.other-site-content .stacked-content-group h3{padding-left:8px;margin-left:0;}.other-site-content .stacked-content-group h3 img{border-bottom:1px solid #FFF;margin-bottom:8px;margin-left:-8px;padding-left:0;margin-top:-17px;}.other-site-content .stacked-content-group .first-other-promo p{margin-left:8px;}.other-site-content .stacked-content-group li.other-promo{background-color:#F0F0F0;padding-left:8px;}.other-site-content .stacked-overlay-other-site-promotion .first-other-promo{background:none;padding:1px 0 0 0;position:relative;}.stacked-overlay-other-site-promotion .first-other-promo .overlay{position:absolute;width:288px;bottom:0;left:0;z-index:10;cursor:pointer;padding:9px 8px 7px;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/transparencies/rgba-0-0-0-07.png) repeat;}.ie .stacked-overlay-other-site-promotion .first-other-promo .overlay{background:black;}.stacked-overlay-other-site-promotion .first-other-promo a:active .overlay{background:#D2700F;}.stacked-overlay-other-site-promotion .first-other-promo h3 a.story .summary{font-weight:normal;}.stacked-overlay-other-site-promotion .first-other-promo h3 .overlay strong,.stacked-overlay-other-site-promotion .first-other-promo h3 a.story .summary{color:#fff;display:block;}.stacked-overlay-other-site-promotion .first-other-promo a:hover,.stacked-overlay-other-site-promotion .first-other-promo a:focus{text-decoration:none;}.stacked-overlay-other-site-promotion .first-other-promo a:hover .headline,.stacked-overlay-other-site-promotion .first-other-promo a:focus .headline{text-decoration:underline;}.stacked-overlay-other-site-promotion .first-other-promo a:hover .summary,.stacked-overlay-other-site-promotion .first-other-promo a:focus .summary{text-decoration:none;}.stacked-overlay-other-site-promotion .first-other-promo h3 a .overlay strong{font-weight:bold;padding-bottom:2px;}.other-site-content .stacked-overlay-other-site-promotion .first-other-promo h3 img{margin-bottom:0;border-bottom:none;}.other-site-content .stacked-overlay-other-site-promotion li.second-promo{border-top:none;}.ie .other-site-content .stacked-overlay-other-site-promotion{margin-bottom:0;}.ie .other-site-content .stacked-overlay-other-site-promotion .overlay{bottom:-1px;}.ie7 .other-site-content .stacked-overlay-other-site-promotion .second-promo,.ie .other-site-content .stacked-overlay-other-site-promotion .second-promo{margin-top:-3px;}.ie7 .stacked-overlay-other-site-promotion li.first-other-promo,.ie .stacked-overlay-other-site-promotion li.first-other-promo{height:1%;}.other-top-stories{position:relative;overflow:auto;width:624px;margin:0 0 15px 0;padding-top:0;border-top:1px solid #ddd;clear:both;}.other-top-stories .other-top-stories-header{position:relative;margin-bottom:0;padding:7px 0 8px;border-bottom:1px solid #ddd;}.other-top-stories-stories{position:relative;overflow:hidden;padding-left:320px;width:304px;margin:4px 0 4px;}.other-top-stories-stories li{position:relative;padding-top:7px;margin-bottom:1px;}.other-top-stories .gvl3-icon{position:absolute;top:6px;left:0;}.other-top-stories .with-summary .gvl3-icon{top:6px;}.other-top-stories-stories .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;width:304px;margin-left:-320px;}.other-top-stories-stories .column-2{clear:none;position:relative;width:304px;}.ie .other-top-stories-stories .column-2{float:right;clear:right;}.other-top-stories-stories .with-summary{margin-top:-1px;padding-bottom:6px;padding-top:6px;margin-bottom:7px;border-top:1px solid #ddd;}.other-top-stories-stories p{position:relative;}.other-top-stories-stories .with-summary p{margin-top:4px;}.other-top-stories-stories h2 a.from-external-source,.other-top-stories-stories h3 a.from-external-source{display:block;text-indent:0;width:250px;margin-left:0;}.container-hyper-topic-cluster .hyper-container-title{position:relative;border-top:none;margin:0;padding-top:0;width:624px;}.container-hyper-topic-cluster .hyper-container-title .hyper-depth-header{border-top:1px solid #DDD;margin-bottom:0;padding:6px 0 8px;position:relative;}.ie .other-top-stories .other-top-stories-header a,.ie .container-hyper-topic-cluster .hyper-container-title .hyper-depth-header a,.ie7 .container-hyper-topic-cluster .hyper-container-title .hyper-depth-header a{line-height:24px;}#personalisation{position:relative;float:none;clear:left;overflow:hidden;width:288px;padding:0 8px 3px 312px;margin-left:-312px;margin-right:-8px;margin-bottom:7px;border-bottom:1px solid #262835;}.ie #personalisation{height:1%;}#personalisation.location-set .locator-forms,#personalisation .locator-msg-disambiguate{background:#262835;}#personalisation .locator-forms{margin-left:-304px;width:592px;position:relative;overflow:visible;}.ie #personalisation .locator-forms{height:1%;}#personalisation.location-set .locator-forms{margin:0 -8px 0 -312px;padding:8px 8px 1px;overflow:hidden;}#personalisation .geo-digest-region-header{margin-bottom:0;}#personalisation.change-my-location .geo-digest-region-header{margin-bottom:12px;}#personalisation .locator-form,#personalisation .clear-form{width:592px;display:block;float:none;margin:0;}.blq-js #personalisation-panel-location-form label{position:absolute;margin-top:4px;left:0;display:block;text-transform:none;font-size:.923em;line-height:16px;padding-left:8px;z-index:10;}.blq-js #personalisation-panel-location-form label.input-has-focus{opacity:.3;filter:alpha(opacity=30);}.blq-js #personalisation-panel-location-form label.input-has-content{opacity:0;filter:alpha(opacity=0);}#personalisation .locator-auto-suggest{position:relative;float:left;display:inline;width:245px;padding:0 7px;height:24px;line-height:24px;border:none;font-size:.923em;border-right:1px solid #eee;margin-bottom:8px;}#personalisation .locator-auto-suggest:focus{outline:none;}#personalisation .locator-search{color:black;cursor:pointer;float:left;display:inline;line-height:1.8;margin:0;width:29px;text-indent:-2000em;padding:0;height:24px;border:none;background:white url(../../../../../../../static.bbc.co.uk/frameworks/barlesque/1.3.2/newnav/img/search_icon.png) no-repeat center center;}#personalisation .options{top:0;right:0;padding-right:31px;position:absolute;height:23px;}#personalisation .options li{float:left;display:inline;}#personalisation .options a{position:relative;float:left;display:inline;padding:3px 6px;margin-right:8px;color:#f0f0f0;border:1px solid #f0f0f0;}#personalisation .options a:hover,#personalisation .options a:focus{text-decoration:none;}#personalisation .close-my-location{top:12px;right:12px;cursor:pointer;display:block;font-size:1px;height:16px;width:16px;line-height:1px;overflow:hidden;text-indent:-5000px;z-index:10;margin:0;padding:0;position:absolute;color:#F0F0F0;background:url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.png) no-repeat scroll -510px -32px;}.ie #personalisation .close-my-location{background-image:url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.gif);}#personalisation .help-button,#personalisation .options .help-button{position:absolute;top:0;right:8px;margin:0;padding:0;width:22px;height:22px;background:url(../img/personalisation-help-icon.gif) no-repeat center 4px;}#personalisation .locator-msg{clear:both;padding-top:7px;}#personalisation .locator-msg{clear:both;padding:7px 8px 4px 8px;margin-left:-8px;margin-bottom:-3px;margin-right:-8px;}#personalisation.location-not-set .locator-msg{margin-left:0;margin-right:0;}#personalisation .locator-msg ol li a{color:#ACC2D4;font-weight:bold;}#personalisation .locator-msg *{color:#f0f0f0;font-weight:normal;}#personalisation .locator-msg ol li{margin:4px 0;}#personalisation .locator-msg p.locator-panel-header{font-size:1.4em;font-size:1.231em;font-weight:bold;letter-spacing:-0.05em;line-height:24px;margin-bottom:11px;padding-top:0;padding-bottom:0;position:relative;text-indent:-1px;margin-top:0;}#personalisation .locator-msg-disambiguate p.locator-panel-header{margin-top:0;margin-bottom:5px;padding-top:0;border-bottom:solid 1px #4e515a;padding-bottom:1px;}#personalisation .locator-msg-disambiguate p.locator-panel-header strong{position:relative;display:block;padding-top:4px;padding-bottom:4px;}#personalisation .locator-msg p{margin:8px 0;}#personalisation .locator-msg p a{font-weight:bold;color:#ACC2D4;}#personalisation .locator-msg .locator-loc{position:relative;padding-top:5px;padding-bottom:4px;display:block;width:592px;font-size:1.5em;font-weight:bold;letter-spacing:-0.05em;line-height:24px;text-indent:-1px;border-bottom:solid 1px #262835;}#personalisation.location-set .locator-msg .locator-loc{border-bottom:solid 1px #3c3e51;}#personalisation .locator-msg-disambiguate .locator-loc{border-bottom:none;padding-bottom:5px;}#personalisation .locator-controls{margin-top:8px;padding-bottom:8px;}#personalisation .locator-controls:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#personalisation .locator-controls .locator-control-prev,#personalisation .locator-controls .locator-control-next{position:relative;padding-left:20px;display:block;font-weight:bold;color:#ACC2D4;}#personalisation .locator-controls .locator-control-prev{margin-top:4px;}#personalisation .locator-controls .locator-control-next{padding-right:20px;padding-left:5px;margin-top:4px;}#personalisation .locator-controls .disabled,#personalisation .locator-controls .locator-pages .selected{color:#d07128;text-decoration:none;cursor:default;}#personalisation .locator-controls .locator-pages a{border-left:solid 1px #ACC2D4;padding:0 5px;}#personalisation .locator-controls .locator-pages .first a{border-left:none;padding-left:0;}#personalisation .locator-results{padding-top:2px;padding-bottom:12px;}#personalisation span.locator-pagination-prev,#personalisation span.locator-pagination-next{overflow:hidden;position:absolute;height:15px;width:13px;left:0;background:url(../../../../../1_4_9/cream/hi/shared/img/GVL3-icons-test.png) no-repeat -200px -32px;}#personalisation span.locator-pagination-next{left:auto;right:0;background-position:-226px -32px;}#personalisation .disabled span.locator-pagination-prev{background-position:-200px -16px;}#personalisation .disabled span.locator-pagination-next{background-position:-226px -16px;}#personalisation .locator-controls .locator-control-prev,#personalisation .locator-controls .locator-pages,#personalisation .locator-controls .locator-pages ol,#personalisation .locator-controls .locator-pages li{float:left;display:inline;}#personalisation .locator-controls a{float:left;padding-right:8px;}#personalisation .locator-controls li{list-style-type:none;}#personalisation .locator-confirm p{position:relative;padding-top:3px;padding-bottom:5px;display:block;width:592px;}#personalisation .locator-confirm a{font-weight:bold;color:#ACC2D4;}#personalisation .locator-confirm .locator-action,#personalisation .locator-msg .locator-action{font-weight:bold;}#personalisation button{padding:4px 8px;background:transparent;border:1px solid #fff;margin-right:8px;margin-top:4px;margin-bottom:11px;cursor:pointer;}#personalisation .clear-form button{background:transparent;border:none;margin:3px 8px 12px 0;cursor:pointer;padding:0;font-size:1.1em;font-weight:bold;color:#ACC2D4;display:inline;}.ie7 #personalisation .clear-form button,.ie #personalisation .clear-form button{text-align:left;}#personalisation .clear-form button:hover,#personalisation .clear-form button:focus{text-decoration:underline;}#personalisation .geo-digest-section{margin-top:6px;padding:0 0 4px;}#personalisation .geo-digest-section ol{padding-top:8px;overflow:hidden;}#personalisation .geo-digest-section ol.news-stories{padding-top:11px;}.ie7 #personalisation .geo-digest-section li,.ie #personalisation .geo-digest-section li{padding-bottom:0;margin-top:4px;}#personalisation .column-1 ol{padding-top:4px 0;}#personalisation .weather-forecast *{color:#f0f0f0;}#personalisation .weather-forecast p a{color:#ACC2D4;}#personalisation .weather-forecast h4,#personalisation .news-stories h4{font-size:1.231em;font-weight:bold;line-height:20px;padding-bottom:3px;border-bottom:1px solid #262835;}#personalisation .news-stories h4 a{color:#fff;}#personalisation .weather-forecast .weather-days li{position:relative;float:left;display:inline;width:84px;clear:none;padding-top:3px;padding-right:8px;}#personalisation .weather-forecast h5{padding-bottom:12px;}#personalisation .weather-forecast .weather-type{position:relative;margin-top:-1px;display:block;font-weight:bold;}#personalisation .weather-forecast .max-temperature,#personalisation .weather-forecast .min-temperature{display:block;}#personalisation .weather-forecast p{clear:both;}#personalisation.location-not-set .geo-digest-section{display:none;}#personalisation .locator-auto-suggest-overlay li.odd,#personalisation .locator-auto-suggest-overlay li.even{background:#fff;color:#174f82;font-size:1.2em;font-weight:bold;padding:4px 8px;border-bottom:solid 1px #ccc;}#personalisation .locator-auto-suggest-overlay li.active{background:#d1700e;color:#fff;border-bottom:solid 1px #d1700e;}.ie #personalisation .weather-days,.ie7 #personalisation .weather-days{clear:both;margin-bottom:8px;}.ie7 #personalisation .news-stories li{padding-bottom:8px;}#personalisation.location-not-set .locator-msg-confirm,#personalisation.location-not-set .locator-msg-disambiguate{margin-left:-8px;margin-right:-8px;margin-bottom:-4px;position:relative;}.ie #personalisation.location-not-set .locator-msg-confirm,.ie #personalisation.location-not-set .locator-msg-disambiguate{height:1%;width:592px;padding-bottom:16px;}#personalisation .locator-msg-confirm{margin-bottom:-1px;}.panel-hd .hd{font-size:24px;font-weight:bold;letter-spacing:-0.05em;line-height:24px;text-indent:-1px;}.panel-bd .bd{font-size:13px;line-height:16px;font-weight:bold;}.panel-bd .bd p{padding:8px 0;}#personalisation-panel-auto-suggest{width:304px!important;}#personalisation-panel-auto-suggest .autosuggest-light li{color:#1F4F82;font-weight:bold;}#personalisation-panel-auto-suggest .autosuggest-light li.odd{background:#fff;}#personalisation .location-panel,#personalisation .we-remembered-panel{position:relative;margin-left:-312px;margin-right:-8px;width:592px;padding:0 8px;background:#f0f0f0;}#personalisation .location-panel h4,#personalisation .we-remembered-panel h4{padding-top:12px;margin-bottom:7px;padding-bottom:12px;border-bottom:1px solid #dcdcdc;}#personalisation .we-remembered-panel h4 a{position:absolute;top:8px;right:11px;height:20px;width:20px;overflow:hidden;text-indent:-50000%;background:transparent url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.png) no-repeat;background-position:-507px 4px;}.ie #personalisation .we-remembered-panel h4 a{background-image:url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.gif);}#personalisation .location-panel p{padding-top:4px;padding-bottom:4px;}#personalisation .we-remembered-panel p{padding-top:4px;padding-bottom:11px;}#personalisation .location-panel ul{padding-top:8px;padding-bottom:7px;}#personalisation .location-panel li{font-weight:bold;margin:1px 0 4px;cursor:pointer;font-size:1.231em;font-weight:bold;line-height:20px;}#personalisation-panel-auto-suggest{background:#323232;background:rgba(50,50,50,0.7);width:456px!important;padding:8px;margin-left:-8px;}#personalisation-panel-auto-suggest ul{border:none;}#personalisation-panel-auto-suggest ul li{width:440px;display:block;font-size:13px;font-weight:bold;padding:4px 8px;line-height:16px;}#personalisation-panel-auto-suggest ul li:hover,#personalisation-panel-auto-suggest ul li.active{background:#D2700F!important;color:white!important;text-decoration:underline;}.geo-digest-region-2{position:relative;clear:both;display:none;margin:0 0 16px;}.blq-js .geo-digest-region-2{display:block;}.geo-digest-region-2 #personalisation{padding:0 0 0 304px;margin:0;width:320px;}.geo-digest-region-2 .personalisation-wrapper{position:relative;margin-left:-304px;padding:4px 0 0 312px;background:#323232;-webkit-font-smoothing:antialiased;}.geo-digest-region-2 .geo-digest-region-header,.geo-digest-region-2 #personalisation h3{padding-bottom:8px;}.container-digest-grid .geo-digest-region-2 #personalisation.location-not-set .options,.container-single-section-digest .geo-digest-region-2 #personalisation.location-not-set .options{top:40px;}.geo-digest-region-2 #personalisation .locator-auto-suggest{width:412px;}.geo-digest-region-2 #personalisation .locator-msg .locator-loc,.geo-digest-region-2 #personalisation.location-set .locator-msg .locator-loc{border-bottom:none;padding-bottom:1px;}.geo-digest-region-2 #personalisation .locator-msg-disambiguate p.locator-panel-header{border-bottom:none;margin-bottom:2px;}.geo-digest-region-2 #personalisation .locator-results{padding-bottom:4px;}.geo-digest-region-2 #personalisation .locator-msg button{background:white;color:#323232;font-weight:bold;}.geo-digest-region-2 #personalisation .clear-form button{margin-bottom:8px;}.geo-digest-region-2 #personalisation.location-set .locator-forms,.geo-digest-region-2 #personalisation .locator-msg-disambiguate{background:none;}.geo-digest-region-2 #personalisation .locator-forms{width:608px!important;}.geo-digest-region-2 #personalisation .locator-form{position:relative;}.geo-digest-region-2 #personalisation .locator-auto-suggest{margin-bottom:0;}.geo-digest-region-2 #personalisation .geo-digest-section{margin-top:16px;}.geo-digest-region-2 #personalisation div.news-stories{position:relative;float:left;display:inline;width:304px;margin-left:-304px;background:white;}.geo-digest-region-2 #personalisation .options a{opacity:1;}.geo-digest-region-2 #personalisation .news-stories *,.geo-digest-region-2 #personalisation .weather-forecast *{color:#505050;text-shadow:none;}.geo-digest-region-2 #personalisation .news-stories a,.geo-digest-region-2 #personalisation .weather-forecast a{color:#1F4F82;}.geo-digest-region-2 #personalisation .news-stories a:visited,.geo-digest-region-2 #personalisation .weather-forecast a:visited{color:#4A7194;}.geo-digest-region-2 #personalisation .news-stories a:active,.geo-digest-region-2 #personalisation .weather-forecast a:active{color:#D1700E;}.geo-digest-region-2 #personalisation .news-stories h4{border-color:#ddd;padding:7px 0;border-top:1px solid #ddd;}.geo-digest-region-2 #personalisation .geo-digest-section ol.news-stories{padding-top:4px;}.geo-digest-region-2 #personalisation div.weather-forecast{position:relative;width:304px;margin-left:16px;background:#ededed;}.ie .geo-digest-region-2 #personalisation div.weather-forecast{float:right;display:inline;}.geo-digest-region-2 #personalisation .weather-forecast h4{padding:8px;border:none;}.geo-digest-region-2 #personalisation .geo-digest-section ol.weather-days{padding:1px 0 8px 8px;background:white;margin:0 8px;overflow:hidden;position:relative;display:block;}.ie .geo-digest-region-2 #personalisation .geo-digest-section ol.weather-days{height:1%;}.geo-digest-region-2 #personalisation .weather-forecast p{padding:8px 8px 4px;}.geo-digest-region-2 #personalisation .weather-forecast li p{padding:0;}.geo-digest-region-2 #personalisation.location-set .personalisation-wrapper{background:transparent;}.geo-digest-region-2 #personalisation.location-set .personalisation-wrapper h3{font-size:16px;letter-spacing:0;margin-bottom:-8px;margin-left:-312px;color:#505050;}.geo-digest-region-2 #personalisation.change-my-location .personalisation-wrapper h3{margin-bottom:0;}.geo-digest-region-2 #personalisation.location-set .options{right:-8px;}.geo-digest-region-2 #personalisation.location-set .options a{border-color:#ccc;color:#505050;}.geo-digest-region-2 #personalisation.location-set .options a.help-button{background:url(http://news.bbcimg.co.uk/view/@css_hi_news@/cream/hi/news/img/personalisation-help-icon-2.gif) no-repeat center center;}.geo-digest-region-2 #personalisation.location-set .locator-forms{background:#323232;}.geo-digest-region-2 #personalisation.location-set .locator-forms *{-webkit-font-smoothing:antialiased;}.geo-digest-region-2 #personalisation .location-panel,.geo-digest-region-2 #personalisation .we-remembered-panel{width:608px;margin-top:16px;background:#ccc;}.geo-digest-region-2 #personalisation .location-panel h4,.geo-digest-region-2 #personalisation .we-remembered-panel h4{border-color:white;}.geo-digest-region-2 #personalisation.location-not-set .geo-digest-section{display:none;}.ie .geo-digest-region-2 #personalisation button,.ie7 .geo-digest-region-2 #personalisation button{padding:2px 4px;}.geo-digest-region-2 #personalisation .personalisation-wrapper a,.geo-digest-region-2 #personalisation .personalisation-wrapper .clear-form button{color:#A9C0D3;}.geo-digest-region-2 #personalisation .locator-msg-confirm .locator-loc-old{font-weight:bold;}.geo-digest-region-2 #personalisation{border-bottom:none;}.ie .geo-digest-region-2 #personalisation.location-not-set .news-stories,.ie .geo-digest-region-2 #personalisation.location-not-set .weather-forecast{display:none;}.podcasts-range-module{clear:both;position:relative;overflow:hidden;width:336px;margin:16px 0 5px;padding-top:4px;padding-bottom:4px;background:#eee;}.podcasts-range-module .podcasts-range-module-header{padding:4px 8px 8px;}.podcasts-range-module ul{overflow:visible;padding:8px 8px 12px;}.podcasts-range-module li{position:relative;float:left;display:inline;width:100%;padding-bottom:8px;}.podcasts-range-module .gvl3-icon{position:absolute;top:0;left:0;}.podcasts-range-module .medium-image{width:238px;padding-left:78px;padding-bottom:16px;margin-bottom:-1px;}.podcasts-range-module .medium-image img{position:relative;float:left;display:inline;width:70px;height:70px;margin-left:-78px;}.podcasts-range-module .medium-image .gvl3-icon-wrapper{position:absolute;top:0;left:0;}.podcasts-range-module .medium-image .gvl3-icon{position:relative;top:auto;left:auto;}.container-programme-promotion{position:relative;overflow:visible;width:336px;margin:0 0 16px;background:#000;clear:both;}.bbccom_slot_xxl .container-programme-promotion{width:496px;}.container-programme-promotion .programmes-header{font-size:24px;font-size:1.846em;font-weight:bold;letter-spacing:-0.05em;line-height:24px;text-indent:-2px;color:#fff;display:block;padding:8px;}.container-programme-promotion a.iplayer-branding{right:8px;color:#fff;position:absolute;overflow:hidden;text-indent:-50000px;top:12px;width:122px;height:22px;background:url(../img/programmes-iplayer-brand.png) no-repeat top left;}.container-programme-promotion .programmes-section-header,.container-programme-promotion .data-feed-best h3{font-size:16px;font-size:1.231em;font-weight:bold;line-height:20px;padding:9px 8px 0;margin-bottom:-5px;}.container-programme-promotion .programmes-header a,.container-programme-promotion .programmes-section-header a,.container-programme-promotion .data-feed-best h3 a{color:#A9C0D3;}.container-programme-promotion .programmes-header a{display:block;}.container-programme-promotion ul{position:relative;overflow:hidden;padding:0 8px 0;clear:both;}.container-programme-promotion ul.programme-breakout{padding-top:0;padding-bottom:0;}.container-programme-promotion li{position:relative;display:block;clear:both;overflow:hidden;padding-bottom:1px;zoom:1;}.container-programme-promotion li a{color:#A9C0D3;}.container-programme-promotion li p{color:#eee;}.container-programme-promotion li.large-image{width:320px;margin:0 -8px;padding:8px 8px 8px;border-bottom:none;background:#505050;}.bbccom_slot_xxl .container-programme-promotion li.large-image{padding:8px 8px 0 344px;width:144px;border-bottom:1px solid #fff;}.ie .container-programme-promotion li.large-image,.ie7 .container-programme-promotion li.large-image{display:inline;}.container-programme-promotion li.large-image .programme-header{margin-bottom:5px;overflow:visible;font-size:16px;font-size:1.231em;font-weight:bold;}.container-programme-promotion li.large-image .story img{position:relative;display:block;margin:-8px -8px 9px;width:336px;height:189px;border-bottom:1px solid #fff;}.bbccom_slot_xxl .container-programme-promotion li.large-image .story img{float:left;display:inline;margin:-8px 0 0 -344px;border-bottom:none;}.container-programme-promotion li.large-image *{color:#fff;}.container-programme-promotion li.medium-image{padding:0 0 0 120px;list-style:none outside;}.container-programme-promotion li.medium-image .programme-header{position:relative;padding-top:5px;}.container-programme-promotion li.medium-image img{position:relative;float:left;display:inline;margin-top:3px;margin-left:-120px;width:112px;height:63px;}.container-programme-promotion li.medium-image p{padding-bottom:1px;}.container-programme-promotion li.no-image{padding:12px 0 2px;list-style:none outside;}.container-programme-promotion li.first-child{background:#d2700f;}.container-programme-promotion li.first-child *{color:#fff;}.container-programme-promotion li.first-item{padding-top:4px;}.container-programme-promotion li .gvl3-icon{position:absolute;top:11px;left:0;}.container-programme-promotion li.large-image .gvl3-icon-wrapper{position:absolute;top:0;left:0;}.container-programme-promotion li.medium-image .gvl3-icon-wrapper{position:absolute;top:8px;left:-120px;}.container-programme-promotion li .gvl3-icon-wrapper .gvl3-icon{position:relative;top:0;left:0;}.container-programme-promotion .data-feed-best{margin:0 8px;padding:0;}.container-programme-promotion .data-feed-best h3{padding:9px 0 8px;margin-bottom:-6px;}.container-programme-promotion .data-feed-best ul{padding:0 0 8px;}.container-programme-promotion .programme-breakout li.no-image{border-bottom:medium none;margin:0 -8px;padding:8px 8px 7px;width:320px;}.bbccom_slot_xxl .container-programme-promotion .programme-breakout li.no-image{width:480px;}.programme-breakout li.no-image .programme-header{font-size:1.231em;font-weight:bold;line-height:20px;margin-bottom:1px;position:relative;}.programme-breakout li.no-image .programme-header a{position:relative;}.programme-breakout li.no-image .gvl3-icon{left:-20px;top:0;position:absolute;}.programme-breakout li.no-image .gvl3-icon-invert-boxedlive{left:-32px;}.ie .programme-breakout li.no-image .gvl3-icon-invert-boxedlive{left:0;}.ie .container-programme-promotion hr,.ie7 .container-programme-promotion hr{margin-bottom:-10px;display:block;}.ie .programme-breakout .programme-header a.story{color:#fff;}.best-quote-box{position:relative;clear:both;overflow:hidden;margin:0 0 16px;padding:43px 8px 7px;background:#ededed url(../../../../../1_4_9/cream/hi/shared/img/index-quote.png) left 4px no-repeat;}.best-quote-box .strapline{display:block;padding-top:0;font-size:1.846em;font-weight:bold;letter-spacing:-1px;line-height:24px;}.best-quote-box blockquote{display:block;overflow:visible;padding:6px 16px 4px 0;font-size:1.231em;font-weight:bold;line-height:20px;}.best-quote-box blockquote img{position:relative;margin:3px -24px 11px -8px;display:block;}.best-quote-box blockquote *{line-height:20px;}.best-quote-box blockquote.solo-block{padding-top:34px;}.best-quote-box .quote_credit{display:block;padding:3px 0 0;}.best-quote-box .related-links{border-top:1px solid #d8d8d8;position:relative;margin-top:9px;padding:8px 0 4px;}.best-quote-box .related-links li{padding:3px 0 1px;position:relative;}.best-quote-box .related-links li .gvl3-icon{position:absolute;left:0;top:2px;}.ie .best-quote-box .related-links li .gvl3-icon{left:-20px;}.ie .best-quote-box .related-links li.has-icon-boxedlive .gvl3-icon{left:0;}.secondary-top-story{position:relative;overflow:visible;width:624px;margin:0;padding-top:8px;padding-bottom:8px;border-top:1px solid #ddd;}.secondary-top-story .secondary-story-header{padding-top:2px;margin-bottom:4px;}.secondary-top-story .with-summary{position:relative;clear:both;overflow:hidden;width:512px;padding-right:112px;padding-bottom:12px;}.secondary-top-story .medium-image{position:relative;clear:both;overflow:hidden;width:464px;padding-bottom:13px;padding-left:160px;}.secondary-top-story .medium-image img{position:relative;float:left;display:inline;top:3px;margin-top:-1px;margin-left:-160px;width:144px;height:81px;}.secondary-top-story .large-image{position:relative;clear:both;overflow:hidden;width:304px;padding-left:320px;padding-bottom:11px;}.secondary-top-story .large-image img{position:relative;float:left;display:inline;top:3px;margin-top:-1px;margin-left:-320px;width:304px;height:171px;}.ie .secondary-top-story .large-image img,.ie7 .secondary-top-story .large-image img{padding-bottom:8px;}.secondary-top-story .classic-image{position:relative;clear:both;overflow:hidden;width:384px;padding-bottom:11px;padding-left:240px;}.secondary-top-story .classic-image img{position:relative;float:left;display:inline;top:3px;margin-left:-240px;width:226px;height:170px;}.secondary-top-story p{position:relative;margin-top:3px;}.secondary-top-story li{position:relative;}.secondary-top-story .gvl3-icon{position:absolute;top:0;left:0;}.secondary-top-story .with-summary .secondary-story-header .gvl3-icon{top:2px;}.secondary-top-story .gvl3-icon-wrapper{position:absolute;top:4px;left:0;}.secondary-top-story .classic-image .gvl3-icon-wrapper{top:5px;}.ie7 .secondary-top-story .gvl3-icon-wrapper,.ie .secondary-top-story .gvl3-icon-wrapper{top:4px;}.ie7 .secondary-top-story .classic-image .gvl3-icon-wrapper,.ie .secondary-top-story .classic-image .gvl3-icon-wrapper{top:5px;}.secondary-top-story .gvl3-icon-wrapper .gvl3-icon{position:relative;top:auto;left:auto;}.secondary-top-story .see-also{clear:none;display:inline;float:left;position:relative;width:100%;margin:4px 0 -8px 0;padding:0;}.ie .secondary-top-story .see-also{width:90%;}.secondary-top-story .with-summary .see-also{margin-bottom:-8px;width:304px;padding-left:320px;}.secondary-top-story .with-summary .see-also .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;width:304px;margin-left:-320px;}.secondary-top-story .with-summary .see-also .column-2{width:304px;float:none;clear:none;display:block;}.ie .secondary-top-story .with-summary .see-also .column-2,.ie7 .secondary-top-story .with-summary .see-also .column-2{float:right;}.secondary-top-story .medium-image .see-also{float:right;clear:none;width:224px;padding-left:240px;margin-bottom:-9px;}.secondary-top-story .medium-image .see-also li{float:none;clear:none;display:block;}.secondary-top-story .medium-image .see-also .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;width:224px;margin-left:-240px;}.secondary-top-story .medium-image .see-also .column-2{width:224px;}.ie .secondary-top-story .medium-image .see-also .column-2,.ie7 .secondary-top-story .medium-image .see-also .column-2{float:right;}.secondary-top-story .see-also li{clear:left;display:inline;float:left;padding-bottom:8px;width:100%;}.secondary-top-story .see-also .play-audio{text-indent:20px;}.secondary-top-story .see-also .play-video{text-indent:16px;}.secondary-top-story .see-also .play-audio-icon{width:14px;left:-20px;background:url(../../../../../1_4_9/cream/hi/shared/img/icons/listen-charcoal.png) no-repeat center left;}.secondary-top-story .see-also .play-video-icon{width:12px;left:-16px;background:url(../../../../../1_4_9/cream/hi/shared/img/icons/play-charcoal.png) no-repeat center left;}.secondary-top-story .see-also .play-audio-icon,.secondary-top-story .see-also .play-video-icon{top:1px;height:14px;}body #blq-container #blq-container-inner .secondary-top-story .see-also a.is-index{font-weight:bold;}.blq-js .bbc-st{display:none;}#blq-main .bbc-st{float:right;position:relative;top:-3px;}#page-bookmark-links-head .bbc-st{margin-right:-7px;}#page-bookmark-links-foot .bbc-st{float:left;}.bbc-st p{display:inline;}#blq-main ul.bbc-st-buttons{width:auto!important;}#blq-main ul.bbc-st-buttons li{position:relative;}.share-form{width:320px;padding-top:8px;}.ie .share-form{width:290px;}.share-form ul.networks{position:relative;overflow:hidden;padding:16px 0 16px 0;}.share-form ul.networks li{width:125px;float:left;padding:0 0 8px 24px;background-image:url(../../../../../1_4_9/cream/hi/shared/img/story_sprite.gif);background-repeat:no-repeat;}body.ie .share-form ul.networks{width:280px;}body.ie .share-form ul.networks li{width:100px;padding:0 0 8px 25px;}.share-form a.share-help-link{font-size:13px;}.share-form ul.networks li.delicious{background-position:-3650px 0;margin:0 16px 0 0;}.share-form ul.networks li.digg{background-position:-2200px 0;}.share-form ul.networks li.facebook{background-position:0 0;margin:0 16px 0 0;}.share-form ul.networks li.reddit{background-position:-2650px 0;}.share-form ul.networks li.stumbleupon{background-position:-2400px 0;margin:0 16px 0 0;}.share-form ul.networks li.twitter{background-position:-300px 0;}.share-form ul.networks li.mixx{background-position:-2900px 0;margin:0 16px 0 0;}.share-form ul.networks li.google{background-position:-3150px 0;}.share-help ul li.delicious a{background-position:-3650px 0;}.share-help ul li.digg a{background-position:-2200px 0;}.share-help ul li.facebook a{background-position:0 0;}.share-help ul li.reddit a{background-position:-2650px 0;}.share-help ul li.stumbleupon a{background-position:-2400px 0;}.share-help ul li.twitter a{background-position:-300px 0;}.share-help ul li.mixx a{background-position:-2900px 0;}.share-help ul li.google a{background-position:-3150px 0;}.blq-js #socialBookMarks li.delicious,.blq-js #socialBookMarks li.digg,.blq-js #socialBookMarks li.facebook,.blq-js #socialBookMarks li.reddit,.blq-js #socialBookMarks li.stumbleupon,.blq-js #socialBookMarks li.mixx,.blq-js #socialBookMarks li.google{display:block;}.panel-light .c{background:#FFF!important;}.glow173-panel .panel-close,.glow173-panel .panel-light .panel-close{background-image:url(../../../../../1_4_9/cream/hi/shared/img/story_sprite.gif);background-repeat:no-repeat;background-position:-3500px 0;}.panel-light .c .panel-hd{margin:0 15px 0 10px!important;padding-left:0!important;}.glowNoMask .panel-light .bb{border-color:#fff!important;}#share-links-panel-top .br,#share-links-panel-bottom .br{background:url(../../../../../1_4_9/cream/hi/shared/img/cbr.png);}.ie7 #share-links-panel-top .br,.ie7 #share-links-panel-bottom .br,.ie #share-links-panel-top .br,.ie #share-links-panel-bottom .br{background:none;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/view/1_4_9/cream/hi/shared/img/cbr.png',sizingMethod='crop');}#share-links-panel-top .bl,#share-links-panel-bottom .bl{background:url(../../../../../1_4_9/cream/hi/shared/img/cbl.png);}.ie7 #share-links-panel-top .bl,.ie7 #share-links-panel-bottom .bl,.ie #share-links-panel-top .bl,.ie #share-links-panel-bottom .bl{background:none;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/view/1_4_9/cream/hi/shared/img/cbl.png',sizingMethod='crop');}.simple-guide-list{margin:0 0 0 16px;}.simple-guide-list ul li{padding:0 0 8px 0;position:relative;float:none;display:block;overflow:auto;}.simple-guide-list-heading{font-size:1.231em;border-top:1px solid #ccc;border-bottom:1px solid #ccc;padding:8px 0;margin:0 0 16px 0;}.simple-guide-list li.medium-image{clear:both;overflow:hidden;padding-bottom:13px;padding-left:160px;position:relative;width:144px;}.simple-guide-list li.medium-image img{display:inline;float:left;height:81px;margin-left:-160px;margin-top:-1px;position:relative;top:3px;width:144px;}.simple-guide-list h3{position:relative;}.simple-guide-list li.medium-image .gvl3-icon{position:absolute;top:2px;left:0;}.simple-guide-list .gvl3-icon{left:0;position:absolute;top:-1px;}.simple-guide-list li.medium-image .gvl3-icon-wrapper{position:absolute;left:0;top:2px;}.simple-guide-list li .gvl3-icon-wrapper .gvl3-icon{left:auto;position:relative;top:auto;}.ie .simple-guide-list .has-icon-boxedlisten .gvl3-icon,.ie .simple-guide-list .has-icon-boxedwatch .gvl3-icon{margin:0 0 0 -20px;}.ie .simple-guide-list .has-icon-boxedlive a{padding:0 0 0 35px;}.simple-story-list ul li{padding:0 0 8px 0;position:relative;}.simple-story-list .gvl3-icon{left:0;position:absolute;top:-1px;}.ie .simple-story-list .has-icon-boxedlisten .gvl3-icon,.ie .simple-story-list .has-icon-boxedwatch .gvl3-icon{margin:0 0 0 -20px;}.ie .simple-story-list .has-icon-boxedlive a{padding:0 0 0 35px;}.single-split-column-layout{float:left;width:304px;}#site-wide-alert,#site-wide-alert p,#site-wide-alert h2 span,#site-wide-alert p.close_alert{background:none;color:#fff;padding:0;margin:0;}#site-wide-alert *{color:white;}#site-wide-alert h2{padding:0 30px 3px 8px;width:auto;}#site-wide-alert p a{color:#fff;font-weight:400;}#site-wide-alert{clear:both;overflow:hidden;background:#ce1211;margin:8px 0 4px;width:auto;padding:7px 0 10px;position:relative;}#site-wide-alert p{padding:0 8px 0;}#site-wide-alert p.close_alert{background:transparent url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.png) -488px -33px no-repeat;display:block;width:14px;height:14px;position:absolute;right:8px;top:8px;}.ie #site-wide-alert p.close_alert{background:transparent url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.gif) -511px -33px no-repeat;}#site-wide-alert p.close_alert a{display:block;width:11px;height:11px;text-indent:-9999px;padding:0;}.social-link-digests{background:#ededed;clear:both;margin:0 0 16px;overflow:hidden;padding-bottom:12px;position:relative;width:336px;}.social-link-digest .social-link-header{display:block;font-size:1.231em;font-weight:bold;line-height:20px;padding:8px 8px 0;position:relative;text-rendering:optimizelegibility;}.social-link-digest ul{padding:0 8px;}.social-link-digest p{padding:0 0 8px;}.social-link-digest li a.story{font-weight:normal;}#special-events-promotion-now-include h2{padding-bottom:8px;width:auto;}.special-reports-component{position:relative;overflow:hidden;margin-bottom:21px;width:624px;}.special-reports-wrapper{background-color:#D1700E;float:left;display:inline;position:relative;padding-top:11px;padding-left:320px;width:304px;}.special-reports-header{padding:8px 0;}.special-reports-component .top-report{padding-right:8px;padding-bottom:12px;}.special-reports-component .top-report h3 img{display:inline;float:left;margin-top:-11px;position:relative;z-index:2;border-right:1px solid #FFF;margin-left:-320px;}.special-reports-component .top-report h3 a{color:#fff;padding:3px 8px 0 0;}.special-reports-component .top-report p{color:#fff;margin:4px 8px 8px 0;}.special-reports-component .more-special-reports{background-color:#EDEDED;kbackground-color:pink;position:absolute;bottom:0;width:320px;border-top:1px solid #FFF;right:0;}.special-reports-component .more-special-reports h3{margin:11px 16px 0 16px;}.special-reports-component .more-special-reports ul{margin:4px 16px 11px 16px;}.special-reports-component .more-special-reports ul li{padding:4px 0;}.ie .special-reports-component .more-special-reports{bottom:-1px;}.container-archived-content{clear:both;margin-bottom:16px;position:relative;}.container-archived-content-heading{padding:8px 0 4px 0;border-top:1px solid #DDD;margin-top:0;margin-bottom:8px;}.container-archived-content-heading span{border-bottom:1px solid #DDD;padding-bottom:15px;display:block;width:464px;}.find-a-representative{position:relative;display:block;width:100%;clear:both;overflow:hidden;margin:0 0 22px;}.find-a-representative h2{font-size:1.231em;font-weight:bold;line-height:16px;padding-bottom:12px;padding-top:12px;position:relative;}.blq-js .find-a-representative h2{padding-bottom:8px;}.find-a-representative legend,.find-a-representative legend span{position:absolute;left:-5000%;}.blq-js .find-a-representative label{position:absolute;margin-top:5px;left:0;width:580px;display:block;text-transform:none;font-size:.923em;line-height:16px;padding:5px 8px 6px;}.blq-js .find-a-representative label.input-has-focus{color:#ccc;}.blq-js .find-a-representative label.input-has-content{color:white;display:none;}.find-a-representative .input{position:relative;clear:both;display:inline;float:left;margin-top:5px;height:16px;width:580px;line-height:24px;padding:4px 7px 4px;border:1px solid #ddd;border-right:none;font-size:.923em;text-transform:none;}.ie7 .find-a-representative .input,.ie .find-a-representative .input{padding:0 7px;height:24px;}.blq-js .find-a-representative .input{background-color:transparent;}.find-a-representative .input:focus{outline:0;}.find-a-representative .submit{position:relative;display:inline;float:left;margin-top:5px;height:26px;width:29px;line-height:24px;background:#fff url(../../../../../1_4_9/cream/hi/shared/img/search.png) no-repeat center center;border:1px solid #ddd;padding:0;text-indent:-2000em;overflow:hidden;cursor:pointer;}.find-a-representative .glow-errorMsg{display:block!important;position:absolute;text-indent:-5000%;overflow:hidden;top:0;right:0;width:100%;height:100%;background:rgba(255,255,0,0.1);}.ie8 .find-a-representative .glow-errorMsg,.ie7 .find-a-representative .glow-errorMsg{background:yellow;filter:alpha(opacity=10);}.ie .find-a-representative .glow-errorMsg{background:yellow;filter:alpha(opacity=10);padding:5px 8px 6px;margin:0 0 -11px -16px;}.find-a-representative .glow-errorSummary{display:none!important;}.school-tables-finder{position:relative;clear:both;overflow:hidden;margin:0 0 16px;padding:8px;background:#ededed;width:608px;}.ie .school-tables-finder{height:1%;}.school-tables-finder .strapline{position:relative;margin-top:-2px;padding-bottom:1px;}.school-tables-finder .strapline a{line-height:24px;}.school-tables-finder .description{padding:9px 0 3px;line-height:20px;}.school-tables-finder fieldset{position:relative;margin-bottom:16px;background:white;}.school-tables-finder label{display:block;width:296px;padding:6px 0;white-space:nowrap;font-weight:bold;background:#ededed;overflow:hidden;}.blq-js .school-tables-finder label{position:absolute;top:0;left:0;width:250px;padding:6px 8px;background:transparent;font-weight:normal;}.school-tables-finder label.input-has-focus{color:#ccc;}.school-tables-finder label.input-has-content{color:white;display:none;}.school-tables-finder #school-tables-finder-select label{border-bottom:1px solid #ededed;padding-bottom:5px;}.blq-js .school-tables-finder #school-tables-finder-select label{border-bottom:none;padding-bottom:6px;padding-right:38px;width:210px;cursor:pointer;background:url(../../../../../1_4_9/cream/hi/shared/img/select-arrow.png) no-repeat center right;}.school-tables-finder #school-tables-finder-search{position:relative;float:left;display:inline;width:296px;padding:8px 0 4px;}.school-tables-finder #school-tables-finder-search .text{position:relative;float:left;display:inline;font-size:13px;height:16px;width:252px;line-height:16px;padding:6px 7px 6px;border:none;border-top:1px solid #ededed;background:transparent;}.school-tables-finder #school-tables-finder-search .submit{float:right;display:inline;height:28px;margin:0;width:30px;line-height:16px;padding:0;text-indent:-2000%;overflow:hidden;border:none;cursor:pointer;border-left:1px solid #ededed;border-top:1px solid #ededed;background:white url(../../../../../1_4_9/cream/hi/shared/img/search.png) no-repeat 50% 50%;}.blq-js .school-tables-finder #school-tables-finder-search .text,.blq-js .school-tables-finder #school-tables-finder-search .submit{border-top:none;}.school-tables-finder #school-tables-finder-select{position:relative;float:right;display:inline;width:296px;padding:8px 0 4px;}.school-tables-finder #school-tables-finder-select select{position:absolute;top:30px;left:4px;width:240px;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px;-moz-box-shadow:0 0 10px rgba(0,0,0,0.3);-webkit-box-shadow:0 0 10px rgba(0,0,0,0.3);box-shadow:0 0 10px rgba(0,0,0,0.3);font-size:13px;line-height:16px;font-family:Arial;color:#505050;}.blq-js .school-tables-finder #school-tables-finder-select select{position:absolute;padding:8px;top:-56px;left:0;width:264px;border:none;}.school-tables-finder #school-tables-finder-select option{display:block;font-size:13px;font-family:Arial;color:#505050;}.school-tables-finder #school-tables-finder-select .submit{float:right;display:inline;text-align:center;margin:0;height:28px;padding:6px;line-height:16px;overflow:hidden;border:none;cursor:pointer;border-left:1px solid #ededed;background:#505050;color:white;font-weight:bold;text-transform:uppercase;font-size:13px;}.ie .school-tables-finder #school-tables-finder-select .submit,.ie7 .school-tables-finder #school-tables-finder-select .submit{padding:6px 3px;}.blq-js .school-tables-finder #school-tables-finder-select .submit{border-left-width:8px;}.school-tables-finder input:focus,.school-tables-finder select:focus{outline:none;}.school-tables-finder .glow-errorMsg{display:block!important;position:absolute;text-indent:-5000%;overflow:hidden;top:0;width:100%;height:100%;background:rgba(255,255,0,0.1);}.ie8 .school-tables-finder .glow-errorMsg,.ie7 .school-tables-finder .glow-errorMsg{background:yellow;filter:alpha(opacity=10);}.ie .school-tables-finder .glow-errorMsg{background:yellow;filter:alpha(opacity=10);padding:6px 8px;margin:0 0 -12px -16px;}.school-tables-finder #school-tables-finder-search .glow-errorMsg{right:0;}.school-tables-finder #school-tables-finder-select .glow-errorMsg{right:31px;}.school-tables-finder .glow-errorSummary{display:none!important;}.nhs-ratings-finder{position:relative;clear:both;overflow:hidden;margin:0 0 16px;padding:8px;width:608px;background:#ededed;}.ie .nhs-ratings-finder{height:1%;}.nhs-ratings-finder .strapline{position:relative;margin-top:-1px;padding-bottom:1px;}.nhs-ratings-finder .strapline a{line-height:24px;}.nhs-ratings-finder .description{padding:9px 0 3px;line-height:20px;}.nhs-ratings-finder fieldset{position:relative;margin-bottom:8px;background:white;}.nhs-ratings-finder label{display:block;width:608px;padding:6px 0;white-space:nowrap;font-weight:bold;background:#ededed;overflow:hidden;}.blq-js .nhs-ratings-finder label{position:absolute;top:0;left:0;width:562px;padding:6px 8px;background:transparent;font-weight:normal;}.nhs-ratings-finder label.input-has-focus{color:#ccc;}.nhs-ratings-finder label.input-has-content{color:white;display:none;}.nhs-ratings-finder #nhs-ratings-finder-search{position:relative;float:left;display:inline;width:608px;padding:8px 0 0;}.nhs-ratings-finder #nhs-ratings-finder-search .text{position:relative;float:left;display:inline;font-size:13px;height:16px;width:563px;line-height:16px;padding:6px 7px 6px;border:none;border-top:1px solid #ededed;background:transparent;}.nhs-ratings-finder #nhs-ratings-finder-search .submit{float:right;display:inline;height:28px;width:30px;margin:0;line-height:16px;padding:0;text-indent:-2000%;overflow:hidden;border:none;cursor:pointer;border-left:1px solid #ededed;border-top:1px solid #ededed;background:white url(../../../../../1_4_9/cream/hi/shared/img/search.png) no-repeat 50% 50%;}.blq-js .nhs-ratings-finder #nhs-ratings-finder-search .text,.blq-js .nhs-ratings-finder #nhs-ratings-finder-search .submit{border-top:none;}.nhs-ratings-finder input:focus,.nhs-ratings-finder select:focus{outline:none;}.nhs-ratings-finder .warning{font-size:11px;text-transform:uppercase;}.nhs-ratings-finder .glow-errorMsg{display:block!important;position:absolute;text-indent:-5000%;overflow:hidden;top:0;right:0;width:100%;height:100%;background:rgba(255,255,0,0.1);}.ie8 .nhs-ratings-finder .glow-errorMsg,.ie7 .nhs-ratings-finder .glow-errorMsg{background:yellow;filter:alpha(opacity=10);}.ie .nhs-ratings-finder .glow-errorMsg{background:yellow;filter:alpha(opacity=10);padding:6px 8px;margin:0 0 -12px -16px;}.nhs-ratings-finder .glow-errorSummary{display:none!important;}.special-event-promotion-best{margin-bottom:16px;}.se-promo-now-inc{margin-bottom:16px;position:relative;overflow:hidden;width:624px;}.se-promo-now-inc .se-promo-now-inc-header{line-height:34px;padding-bottom:8px;}.se-promo-best-inc{background:none repeat scroll 0 0 #EDEDED;margin:0 0 16px;overflow:visible;padding-bottom:8px;position:relative;width:336px;}.se-promo-best-inc .se-promo-best-inc-header{padding:8px;}.se-promo-best-inc ul{margin-left:8px;}.se-promo-best-inc ul li{margin-bottom:16px;padding-right:8px;padding-left:16px;background-image:url(../../../../../1_4_9/cream/hi/shared/img/story_sprite.gif);background-position:-1200px 5px;background-repeat:no-repeat;width:304px;}.se-promo-best-inc ul li h3 a,.se-promo-best-inc ul li h3{font-weight:normal;}.have-your-say-inc{background:none repeat scroll 0 0 #EDEDED;margin:0 0 16px;overflow:visible;padding-bottom:2px;position:relative;width:336px;}.have-your-say-inc .have-your-say-inc-header{padding:8px;}.have-your-say-inc ul{margin-left:8px;}.have-your-say-inc ul li{margin-bottom:8px;padding-right:8px;padding-left:16px;background-image:url(../../../../../1_4_9/cream/hi/shared/img/story_sprite.gif);background-position:-1200px 5px;background-repeat:no-repeat;width:304px;}.have-your-say-inc ul.domestic-inc li.with-contact-numbers{background-position:-1200px 12px;}.have-your-say-inc ul.international-inc li.with-contact-numbers{background-position:-1200px 5px;}.have-your-say-inc ul.international-inc li.with-contact-numbers .contact-number{padding-top:1px;}.have-your-say-inc ul.international-inc li.with-contact-numbers .core-text,.have-your-say-inc ul.international-inc li.with-contact-numbers .contact-number{display:block;}.have-your-say-inc ul li h3{font-weight:normal;}.have-your-say-inc .contact-method{font-weight:bold;}.have-your-say-inc .contact-number{color:#D1700E;}.have-your-say-inc ul li .core-text{font-weight:normal!important;}.external-linkbox{position:relative;overflow:visible;width:336px;padding-bottom:8px;margin:0 0 16px;background:#ededed;}.bbccom_slot_xxl .external-linkbox{width:496px;}.external-linkbox .strapline{padding:8px 8px 0;}.external-linkbox ul{position:relative;overflow:hidden;padding:0 8px 0;clear:both;}.external-linkbox li{position:relative;display:block;clear:both;overflow:hidden;}.external-linkbox li.medium-image{padding:0 0 0 120px;position:relative;margin-bottom:-2px;}.ie7 .external-linkbox li.medium-image,.ie .external-linkbox li.medium-image{margin-bottom:-14px;}.external-linkbox li.medium-image .item-header{position:relative;padding-top:7px;margin-bottom:-1px;}.external-linkbox li.medium-image img{position:relative;float:left;display:inline;margin-top:1px;margin-left:-120px;width:112px;height:63px;}.external-linkbox li.medium-image p{padding-bottom:4px;padding-top:6px;}#splash{position:relative;overflow:hidden;width:448px;padding-left:528px;min-height:100px;padding-bottom:12px;margin-top:9px;min-height:290px;}.ie #splash{overflow:visible;height:290px;}#splash .splash-header{position:relative;padding-bottom:7px;}#splash .splash-header img{position:relative;float:left;display:inline;top:5px;margin-left:-528px;width:512px;height:288px;}#splash #splashSlideShow{position:relative;float:left;display:inline;top:5px;margin-left:-528px;width:512px;min-height:288px;}#splash .splash-emp{position:relative;float:left;display:inline;top:5px;margin-left:-528px;width:512px;min-height:288px;padding-bottom:1px;}#splash .splash-emp .caption{position:absolute;left:-5000%;overflow:hidden;}#splash .splash-emp .warning{position:relative;}#splash .splash-emp .warning .holding{width:100%;height:auto;}#splash .splash-emp .warning p{position:absolute;top:0;left:0;width:496px;padding:4px 8px;background:black;background:rgba(0,0,0,0.7);color:white;font-size:16px;font-weight:bold;}#splash .see-also{position:relative;float:left;display:inline;clear:none;overflow:hidden;padding-left:232px;width:216px;margin-top:12px;margin-bottom:-5px;}#splash .see-also li{position:relative;padding-top:4px;width:216px;}#splash .see-also li a{font-weight:normal;}#splash .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;margin-left:-232px;}#splash .column-2{clear:none;position:relative;}.ie #splash .column-2,.ie7 #splash .column-2{float:right;}.ie7 #splash .see-also,.ie #splash .see-also{width:215px;}.ie7 #splash .see-also li.column-2,.ie #splash .see-also li.column-2{width:215px;}#splash .see-also .first-child-live{margin-top:-1px;float:none;display:block;width:438px;}body #blq-container #blq-container-inner #splash .see-also .first-child-live a.story{font-weight:bold;}body #blq-container #blq-container-inner #splash .see-also a.is-index{font-weight:bold;}.ie #splash .see-also .first-child-live,.ie7 #splash .see-also .first-child-live{left:-16px;}#splash .gvl3-icon{position:absolute;top:3px;left:0;}.ie7 #splash .gvl3-icon,.ie #splash .gvl3-icon{top:5px;}#splash .splash-header .gvl3-icon{top:3px;}.ie7 #splash .splash-header .gvl3-icon{top:7px;}.ie #splash .splash-header .gvl3-icon{top:7px;}#splash .first-child-live .gvl3-icon{top:4px;}.ie #splash .first-child-live .gvl3-icon{top:3px;}.ie #splash .splash-header .gvl3-icon-boxedlisten,.ie #splash .splash-header .gvl3-icon-boxedwatch{left:-21px;}#splash .has-icon-live .gvl3-icon{top:4px;}.ie7 #splash .has-icon-live .gvl3-icon,.ie #splash .has-icon-live .gvl3-icon{top:6px;}#splash .gvl3-icon-wrapper{position:absolute;top:5px;left:-528px;}.ie7 #splash .gvl3-icon-wrapper{top:10px;}.ie #splash .gvl3-icon-wrapper{top:10px;left:-528px;}#splash .gvl3-icon-wrapper .gvl3-icon{position:relative;top:auto;left:auto;}.ie7 #splash .gvl3-icon-wrapper .gvl3-icon,.ie #splash .gvl3-icon-wrapper .gvl3-icon{top:auto;}.ie7 .splash-top-story h2.has-icon-boxedwatch,.ie .splash-top-story h2.has-icon-boxedwatch{border:1px solid #fff;}.ie7 #splash .splash-header,.ie #splash .splash-header{border:1px solid #fff;}.splash-top-story .splash-emp object{display:block;}#splash .splash-emp .warning img{width:512px;height:288px;}.split-column-now-layout{clear:both;margin:0 0 16px 0;}.split-column-now-layout .secondary-top-story{clear:both;border:none;}.split-column-now-layout .split-column-now-heading,.split-column-now-layout .secondary-top-story-heading{clear:both;font-size:1.846em;font-weight:bold;letter-spacing:-1px;line-height:24px;border-top:1px solid #ccc;border-bottom:1px solid #ccc;padding:8px 0;}.secondary-top-story .secondary-top-story-heading{clear:both;font-size:1.846em;font-weight:bold;letter-spacing:-1px;line-height:24px;border-bottom:1px solid #ccc;padding:3px 0 8px 0;margin:0 0 16px 0;}#ticker{z-index:10;}.blq-js .ie #ticker{height:8px;}.has-ticker #ticker{min-height:41px;}.blq-js .ie .has-ticker #ticker{height:41px;}#ticker-container{position:relative;display:block;overflow:hidden;clear:both;padding-bottom:4px;min-height:41px;}.ie #ticker-container{height:41px;}#ticker{position:relative;display:block;overflow:hidden;clear:both;}.ie7 #ticker{filter:none;}#tickerHolder{position:relative;display:block;overflow:hidden;clear:both;}.ticker_container{color:#1F527B;background-color:#fff;position:relative;display:block;overflow:visible;clear:both;margin-top:4px;padding-bottom:4px;border-bottom:1px solid #ddd;}.ie .ticker_container{height:1%;}.renderer_output{position:relative;display:block;overflow:hidden;clear:both;width:100%;height:32px;}.ticker_container div.title_container,.ticker_container p.ticker_content{position:relative;z-index:1;}.ticker_container h4.ticker_title,.ticker_container p.ticker_content,.ticker_container li{float:left;}.ticker_container p.ticker_content{margin-left:8px;}.ticker_container ul.ticker_controls{float:right;margin-right:-8px;margin-top:-16px;padding-right:8px;}.ticker_container p.ticker_content{white-space:nowrap;width:auto;background:#fff;}.ticker_container p.ticker_content a{font-weight:normal;}.ticker_warning .ticker_container p.ticker_content a{font-weight:bold;}.ticker_container a.media_type{float:left;background:url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.png) no-repeat scroll 0 0 transparent;cursor:pointer;display:block;font-size:1px;height:15px;line-height:1px;margin:0;overflow:hidden;position:relative;text-indent:-5000px;z-index:10;}.ticker_container a.ticker_audio{background-position:-907px 0;width:16px;}.ticker_container a.ticker_video{background-position:-1301px 0;width:16px;}.ticker_container a.ticker_live{background-position:-973px 0;width:27px;}.ticker_container .ticker_controls span{background:url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.png) no-repeat scroll 0 0 transparent;cursor:pointer;display:block;font-size:1px;height:15px;line-height:1px;margin:0 8px 5px 0;overflow:hidden;position:relative;text-indent:-5000px;z-index:10;opacity:.7;}.ie .ticker_container .ticker_controls span{filter:alpha(opacity=70);}.ticker_container .ticker_controls a:hover span,.ticker_container .ticker_controls a:focus span{opacity:1;}.ie .ticker_container .ticker_controls a:hover span,.ie .ticker_container .ticker_controls a:focus span{filter:alpha(opacity=100);}.ticker_container .ticker_controls .started span{background-position:-27px 0;width:12px;}.ticker_container .ticker_controls .stopped span{background-position:-5px 0;width:11px;}.ticker_container .ticker_controls .prev span{background-position:-224px 0;width:10px;}.ticker_container .ticker_controls .next span{background-position:-247px 0;width:10px;}.ticker_container .ticker_controls .started a:active span{background-position:-27px -16px;}.ticker_container .ticker_controls .stopped a:active span{background-position:-5px -16px;}.ticker_container .ticker_controls .prev a:active span{background-position:-224px -16px;}.ticker_container .ticker_controls .next a:active span{background-position:-247px -16px;}.title_container,.ticker_title{float:left;display:inline;overflow:visible;}.title_container,.ticker_content{padding:8px 0 8px;}.ticker_warning div.title_container{padding:8px 0 8px 8px;}.ticker_warning p.ticker_content{white-space:nowrap;color:#fff;background:transparent;}.ticker_warning .bg_bar{background:#d60000;left:0;position:absolute;width:100%;height:29px;}.ticker_warning .in_sequence{display:none;}.ticker_warning .ticker_container .ticker_controls span{opacity:1;}.ie .ticker_warning .ticker_container .ticker_controls span{filter:alpha(opacity=100);}.ticker_warning .ticker_container h4.ticker_title{text-transform:uppercase;font-weight:bold;color:#fff;font-size:1.1em;}.ticker_warning .ticker_container p.ticker_content a.ticker_content_anchor{color:#fff;font-size:1.1em;}.ticker_warning .ticker_container .ticker_controls .started span,.ticker_warning .ticker_container .ticker_controls .started a:active span{background-position:-27px -32px;}.ticker_warning .ticker_container .ticker_controls .stopped span,.ticker_warning .ticker_container .ticker_controls .stopped a:active span{background-position:-5px -32px;}.ticker_warning .ticker_container .ticker_controls .prev span,.ticker_warning .ticker_container .ticker_controls .prev a:active span{background-position:-224px -32px;}.ticker_warning .ticker_container .ticker_controls .next span,.ticker_warning .ticker_container .ticker_controls .next a:active span{background-position:-247px -32px;}.ticker_warning .ticker_container a.ticker_audio{background-position:-907px -32px;}.ticker_warning .ticker_container a.ticker_video{background-position:-1301px -32px;}.ticker_warning .ticker_container a.ticker_live{background-position:-973px -32px;}div.ticker_container h4.ticker_title{font-size:1em;font-weight:bold;text-transform:capitalize;padding-right:8px;background:#fff;}.ticker_warning div.ticker_container h4.ticker_title{font-size:1em;font-weight:bold;text-transform:uppercase;background:transparent;}.ticker_container p.ticker_content{position:relative;margin-left:0;}.ticker_container p.has-icon-ticker_audio{padding-left:21px;}.ticker_container p.has-icon-ticker_video{padding-left:21px;}.ticker_container p.has-icon-ticker_live{padding-left:35px;}.ticker_container .media_type{display:block;background:url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.png) no-repeat scroll 0 0 transparent;cursor:pointer;font-size:1px;height:15px;line-height:1px;margin:0 8px 0 0;overflow:hidden;position:absolute;top:7px;left:0;text-indent:-5000px;z-index:10;opacity:.7;}.ie .ticker_container .media_type,.ie .ticker_container .ticker_controls span{background-image:url(../../../../../1_4_9/cream/hi/shared/img/gvl3-icons-0-2.gif);filter:alpha(opacity=70);}.ticker_container .ticker_audio{background-position:-1323px 0;width:16px;}.ticker_container a:hover .ticker_audio,.ticker_container a:focus .ticker_audio{opacity:1;}.ie .ticker_container a:hover .ticker_audio,.ie .ticker_container a:focus .ticker_audio{filter:alpha(opacity=100);}.ticker_container a:active .ticker_audio{background-position:-1323px -16px;}.ticker_warning .ticker_container .ticker_audio,.ticker_warning .ticker_container a:active .ticker_audio{background-position:-1323px -32px;opacity:1;filter:alpha(opacity=100);}.ticker_container .ticker_video{background-position:-1301px 0;width:16px;}.ticker_container a:hover .ticker_video,.ticker_container a:focus .ticker_video{opacity:1;background-position:-1301px -16px;}.ie .ticker_container a:hover .ticker_video,.ie .ticker_container a:focus .ticker_video{filter:alpha(opacity=100);}.ticker_container a:active .ticker_video{background-position:-1301px -16px;}.ticker_warning .ticker_container .ticker_video,.ticker_warning .ticker_container a:active .ticker_video{background-position:-1301px -32px;opacity:1;filter:alpha(opacity=100);}.ticker_container .ticker_live,.ticker_container a:hover .ticker_live,.ticker_container a:focus .ticker_live,.ticker_container a:active .ticker_live{background-position:-973px 0;width:27px;opacity:1;margin-top:1px;}.ie .ticker_container .ticker_live{filter:alpha(opacity=100);}.ticker_warning .ticker_container .ticker_live,.ticker_warning .ticker_container a:hover .ticker_live,.ticker_warning .ticker_container a:focus .ticker_live,.ticker_warning .ticker_container a:active .ticker_live{background:url(../../../../../1_4_9/cream/hi/shared/img/gvl3-live-icon-inverted.gif) no-repeat scroll 0 1px transparent;opacity:1;filter:alpha(opacity=100);}.ticker_container ul.ticker_controls{position:absolute;margin-top:0;top:8px;right:0;}.ticker_warning .ticker_container p.ticker_content a.ticker_content_anchor{font-size:1em;text-shadow:0 0 1px solid rgba(0,0,0,0.5);}#tickerHolder .spacer{position:absolute;}.ticker_warning .bg_bar{height:100%;margin-bottom:-2px;}.static-ticker h2{padding:4px 0;font-size:1.3em;}.static-ticker li{padding:4px 0;border-top:1px solid #E6E6E6;text-transform:uppercase;}.static-ticker li a{text-transform:none;}.static-ticker{clear:both;position:relative;border-bottom:1px solid #E6E6E6;font-size:1em;}.ticker ul.tickerItem .tickerEntry{margin:8px 0;}.ticker ul.tickerItem .tickerEntry .tickerPrompt{font-weight:bold;margin-right:4px;}.ticker ul.tickerItem .tickerEntry .tickerHeadline a.story{position:relative;}.ticker ul.tickerItem .tickerEntry .tickerHeadline .has-icon-boxedlisten a.story,.ticker ul.tickerItem .tickerEntry .tickerHeadline .has-icon-boxedwatch a.story{padding-left:23px;}.ticker ul.tickerItem .tickerEntry .tickerHeadline .has-icon-boxedlive a.story{padding-left:33px;}.ticker ul.tickerItem .tickerEntry .tickerHeadline .gvl3-icon{position:absolute;left:0;top:0;}.ticker .hidden{position:absolute;left:-9999px;}.top-stories-range-module{clear:both;position:relative;overflow:hidden;width:336px;margin:16px 0 16px;padding-top:4px;padding-bottom:4px;background:#ededed;}.top-stories-range-module a:hover .new-story-icon,.top-stories-range-module a:focus .new-story-icon{background:#ededed;}.bbccom_slot_xxl #main-content .top-stories-range-module{width:100%;}.top-stories-range-module .top-stories-range-module-header{padding:4px 8px 7px;}.top-stories-range-module ul{overflow:visible;padding:4px 8px 12px;}.top-stories-range-module li{position:relative;float:left;display:inline;width:100%;padding-bottom:8px;}.top-stories-range-module .gvl3-icon{position:absolute;top:0;left:0;}.top-stories-range-module .medium-image{width:144px;padding-left:151px;padding-bottom:14px;margin-bottom:-1px;margin-top:-4px;}.bbccom_slot_xxl .top-stories-range-module .medium-image{width:320px;}.top-stories-range-module .medium-image img{position:relative;float:left;display:inline;width:144px;height:81px;margin-left:-151px;margin-top:3px;margin-bottom:0;}.top-stories-range-module .medium-image .gvl3-icon-wrapper{position:absolute;top:3px;left:0;}.top-stories-range-module .medium-image .gvl3-icon{position:relative;top:auto;left:auto;}#top-story{position:relative;overflow:hidden;width:624px;margin:0;padding-top:3px;padding-bottom:5px;border-top:1px solid #ddd;}#top-story .top-story-header{width:624px;padding-bottom:8px;width:auto;}#top-story .top-story-header a{line-height:1;}#top-story.medium-image{width:464px;padding-left:160px;padding-bottom:9px;}#top-story.medium-image .top-story-header{position:relative;margin-left:-160px;}#top-story.medium-image .top-story-header img{position:relative;margin-bottom:5px;margin-left:-160px;left:160px;width:144px;height:81px;}.ie #top-story.large-image .top-story-header img{margin-top:7px;top:-7px;}#top-story.large-image{width:304px;padding-left:320px;margin-bottom:8px;position:relative;zoom:1;}#top-story.large-image .top-story-header{position:relative;margin-left:-320px;}#top-story.large-image .top-story-header img{position:relative;margin-bottom:0;margin-left:-320px;left:320px;width:304px;height:171px;zoom:1;}.ie #top-story.large-image .top-story-header{padding-left:320px;}#top-story.classic-image{width:382px;padding-left:242px;padding-bottom:9px;}#top-story.classic-image .top-story-header{position:relative;margin-left:-242px;}#top-story.classic-image .top-story-header img{position:relative;margin-bottom:4px;margin-left:-242px;left:242px;width:226px;}.ie #top-story.classic-image .top-story-header,.ie #top-story.classic-image p,.ie #top-story.classic-image .see-also{padding-left:242px;}#top-story.medium-image .top-story-header img,#top-story.large-image .top-story-header img,#top-story.classic-image .top-story-header img{float:left;display:inline;margin-top:42px;}.ie #top-story.medium-image .top-story-header img,.ie #top-story.large-image .top-story-header img,.ie #top-story.classic-image .top-story-header img,.ie7 #top-story.medium-image .top-story-header img,.ie7 #top-story.large-image .top-story-header img,.ie7 #top-story.classic-image .top-story-header img{margin-top:3px;}.firefox-older-than-3-5 #top-story.medium-image .top-story-header img,.firefox-older-than-3-5 #top-story.large-image .top-story-header img,.firefox-older-than-3-5 #top-story.classic-image .top-story-header img{margin-top:8px;}#top-story.no-image{padding-bottom:18px;}#top-story.no-image .top-story-header{width:624px;position:relative;overflow:hidden;}#top-story.no-image p{max-width:624px;}#top-story.special-emp{width:224px;padding-left:400px;}#top-story.special-emp .top-story-header{width:624px;position:relative;overflow:hidden;margin-left:-400px;}#top-story.special-emp .top-story-emp{position:relative;float:left;display:inline;margin-top:2px;margin-bottom:3px;margin-left:-400px;width:384px;}.ie #top-story.special-emp .top-story-emp{margin-left:0;}.ie #top-story.special-emp .top-story-header{padding-left:400px;}#top-story.special-emp .caption{position:absolute;left:-5000%;overflow:hidden;}#top-story.slideshow{width:224px;padding-left:400px;}#top-story.special-emp p,#top-story.special-emp .see-also,#top-story.slideshow p,#top-story.slideshow .see-also{width:224px;max-width:224px!important;float:right;clear:right;display:block;}#top-story.slideshow .top-story-header{width:624px;position:relative;overflow:hidden;margin-left:-400px;}#top-story.slideshow #topStorySlideShow{position:relative;float:left;display:inline;overflow:hidden;margin-top:2px;margin-bottom:10px;margin-left:-400px;width:384px;height:216px;background:#ccc;}.ie #top-story.slideshow #topStorySlideShow{margin-left:0;}.ie #top-story.slideshow .top-story-header{padding-left:400px;}#top-story .gvl3-icon{position:absolute;top:3px;left:0;}#top-story .top-story-header .gvl3-icon{top:3px;}#top-story .top-story-header .gvl3-icon-live{top:4px;}.ie #top-story.special-emp .top-story-header .gvl3-icon,.ie #top-story.slideshow .top-story-header .gvl3-icon{left:400px;}#top-story .gvl3-icon-wrapper .gvl3-icon{position:relative;top:auto;left:auto;}#top-story .gvl3-icon-wrapper{position:absolute;bottom:-31px;left:0;}.ie7 #top-story .gvl3-icon-wrapper{bottom:-32px;}.ie #top-story.small-image .gvl3-icon-wrapper{bottom:84px;}.ie #top-story.medium-image .gvl3-icon-wrapper{bottom:56px;}.ie #top-story.large-image .gvl3-icon-wrapper{bottom:149px;}.ie #top-story.classic-image .gvl3-icon-wrapper{bottom:149px;}#top-story p{max-width:464px;}.ie7 #top-story.large-image p{float:left;}#top-story .see-also{float:left;display:inline;width:100%;margin-bottom:-1px;position:relative;zoom:1;}.ie #top-story .see-also{float:right;}#top-story.special-emp .see-also,#top-story.slideshow .see-also{float:right;}#top-story.medium-image .see-also{float:right;clear:none;width:224px;padding-left:240px;margin-bottom:0;padding-bottom:11px;}#top-story.medium-image .see-also li{float:none;clear:none;display:block;margin-bottom:4px;}#top-story.medium-image .see-also .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;width:224px;margin-left:-240px;}#top-story.medium-image .see-also .column-2{width:224px;}.ie #top-story.medium-image .see-also .column-2,.ie7 #top-story.medium-image .see-also .column-2{float:right;}#top-story .see-also li{position:relative;float:left;display:inline;clear:both;padding-top:4px;}#top-story.special-emp .see-also li,#top-story.slideshow .see-also li{width:224px;float:right;}#top-story.large-image .see-also li,#top-story.large-image p{width:304px;float:right;display:inline;}#top-story .see-also li a{font-weight:normal;}body #blq-container #blq-container-inner #top-story .see-also a.is-index{font-weight:bold;}#top-story.no-image .see-also{padding-left:320px;}#top-story.no-image .see-also .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;margin-left:-320px;width:304px;}#top-story.no-image .see-also .column-2{clear:none;float:none;display:block;position:relative;width:304px;}#top-story.small-image .see-also{width:232px;padding-left:232px;float:right;display:inline;clear:none;}#top-story.small-image .see-also .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;margin-left:-232px;width:216px;}#top-story.small-image .see-also .column-2{clear:none;float:none;display:block;position:relative;width:216px;}.ie #top-story.no-image .see-also .column-2,.ie #top-story.small-image .see-also .column-2{float:right;}.ie #top-story hr,.ie7 #top-story hr{margin:-9px 0 -4px;display:block;}.ie8 #top-story .top-story-emp{margin-top:-12px;}#top-story .top-story-emp object{display:block;}.ie #top-story.medium-image .top-story-header img,.ie7 #top-story.medium-image .top-story-header img{padding-bottom:14px;}.ie8 #top-story.special-emp .top-story-emp{margin-top:2px;}.container-hyper-topic-cluster,.container-hyper-topic-cluster .hyperpuff{position:relative;display:block;overflow:auto;clear:both;width:624px;}.topic-cluster{position:relative;overflow:auto;width:624px;margin:0 0 16px;padding-top:0;border-top:1px solid #ddd;clear:both;}.topic-cluster .topic-cluster-header{position:relative;margin-bottom:0;padding:7px 0 8px;border-bottom:1px solid #ddd;}.topic-cluster-stories{position:relative;overflow:hidden;padding-left:320px;width:304px;margin:-1px 0 12px;}.topic-cluster .topic-cluster-stories{margin-bottom:0;}.topic-cluster-stories li{position:relative;padding-top:8px;}.topic-cluster .gvl3-icon{position:absolute;top:8px;left:0;}.topic-cluster .with-summary .gvl3-icon{top:9px;}.topic-cluster-stories .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;width:304px;margin-left:-320px;}.topic-cluster-stories .column-2{clear:none;position:relative;width:304px;}.ie .topic-cluster-stories .column-2{float:right;clear:right;}.topic-cluster-stories .with-summary{padding-bottom:6px;padding-top:10px;margin-bottom:5px;border-top:1px solid #ddd;}.topic-cluster-stories p{position:relative;}.topic-cluster-stories .with-summary p{margin-top:4px;}.topic-cluster-stories .first-child p{margin-bottom:1px;}.topic-cluster-stories h2 a.from-external-source,.topic-cluster-stories h3 a.from-external-source{display:block;text-indent:0;margin-left:0;}.container-hyper-topic-cluster .hyper-container-title{position:relative;border-top:none;margin:0;padding-top:0;width:624px;}.container-hyper-topic-cluster .hyper-container-title .hyper-depth-header{border-top:1px solid #DDD;margin-top:0;margin-bottom:0;padding:7px 0 8px;position:relative;}.ie .topic-cluster .topic-cluster-header a,.ie .container-hyper-topic-cluster .hyper-container-title .hyper-depth-header a,.ie7 .container-hyper-topic-cluster .hyper-container-title .hyper-depth-header a{line-height:24px;}.traffic-travel{background-color:#ededed;padding:0 8px 8px;margin:0 0 1px;}.traffic-travel h2{font-size:1.846em;line-height:1.846em;letter-spacing:-0.04em;color:#1F527B;}.traffic-travel h3{color:#666;font-size:1.2em;line-height:1.2em;letter-spacing:-0.04em;padding-bottom:12px;}.traffic-travel .incident-box{padding:6px 8px 6px 40px;background:#fff url(../../../../../1_4_9/cream/hi/shared/img/traffic_icon.gif) 8px 8px no-repeat;}.traffic-travel .incident-box p{color:#666;}.useful-links{position:relative;clear:both;overflow:hidden;width:100%;margin:0 0 12px;border-top:1px solid #ddd;}.useful-links .useful-links-header{position:relative;padding:7px 0 8px 0;border-bottom:1px solid #ddd;}.useful-links ul{position:relative;overflow:hidden;width:304px;padding:11px 0 0 320px;}.useful-links li{padding-bottom:8px;position:relative;}.useful-links .gvl3-icon{position:absolute;top:0;left:0;}.story .useful-links .gvl3-icon{left:8px;top:8px;}.useful-links .gvl3-icon-wrapper{position:absolute;top:0;}.useful-links .gvl3-icon-wrapper .gvl3-icon{position:relative;top:auto;left:auto;}.useful-links .column-1{position:relative;float:left;clear:left;display:inline;overflow:hidden;width:304px;margin-left:-320px;}.useful-links .column-2{clear:none;position:relative;width:304px;}.ie .useful-links .column-2{float:right;}.useful-links a{padding-right:16px;}.double-useful-links{clear:both;position:relative;width:100%;overflow:auto;display:block;}.double-useful-links .useful-links{float:left;clear:none;width:304px;}.double-useful-links .useful-links-2{margin-left:16px;}.double-useful-links .useful-links ul{padding-left:0;}.double-useful-links .useful-links li{margin-left:0;float:none;display:block;}.weather-3day{position:relative;overflow:hidden;clear:both;background-color:#ededed;padding:0 8px;margin:0 0 16px;width:320px;}.weather-3day h2{position:relative;display:inline;float:left;padding:8px 0 7px;}.weather-3day h2 a{line-height:24px;}.weather-3day h3{clear:left;color:#505050;margin:0 0 14px;}.weather-3day h4{font-weight:normal;}.weather-3day li.first{background:#fff;display:block;margin:0 0 6px;padding:4px 0 4px 5px;}.ie .weather-3day li.first{display:inline-block;}.weather-3day li.help{position:absolute;right:0;top:7px;}.weather-3day .next3daysweather{clear:both;border-bottom:medium none;margin:0;width:100%;}.weather-3day .next3daysweather .stripes{float:left;display:inline;background:#fff;margin:0;width:320px;}.weather-3day .next3daysweather .stripes li,.weather-3day .next3daysweather .stripes li strong{font-weight:400;color:#505050;}.weather-3day .next3daysweather .stripes li.wind{display:none;}.weather-3day .next3daysweather .stripes li strong{font-weight:800;}.weather-3day .next3daysweather .stripes div.time{float:left;padding:4px 8px 12px;border-left:2px solid #ededed;width:106px;min-height:152px;}.ie .weather-3day .next3daysweather .stripes div.time{height:152px;}.weather-3day .next3daysweather .stripes div.c1{border-left:none;width:87px;}.weather-3day .next3daysweather .stripes div.c2{width:94px;}.weather-3day .next3daysweather .stripes div.c3{width:87px;}.weather-3day .next3daysweather .stripes img{margin:4px 0 7px;}.weather-3day .next3daysweather a{color:#369;}.weather-3day .next3daysweather a:hover{color:#0D3059;}.weather-3day .next3daysweather .stripes h3{font-weight:400;margin:0 0 3px;}.weather-3day .next3daysweather .clear{clear:both;}.weather-3day .weather-5day-forecast{padding:8px 0;}.weather-4items{position:relative;overflow:hidden;clear:both;background-color:#ededed;padding:0 8px 8px 8px;margin:0 0 16px;width:608px;}.weather-4items h2{position:relative;display:inline;float:left;padding:8px 0 7px;}.weather-4items h2 a{line-height:24px;}.weather-4items h3{clear:left;color:#505050;margin:0 0 14px;}.weather-4items h4{font-weight:normal;}.weather-4items li.first{background:#fff;display:block;margin:0 0 6px;padding:4px 0 4px 5px;}.ie .weather-4items li.first{display:inline-block;}.weather-4items li.help{position:absolute;right:0;top:7px;}.weather-4items .fruitmachine{clear:both;border-bottom:medium none;margin:0;width:100%;}.weather-4items .fruitmachine .stripes{float:left;display:inline;background:#fff;margin:0;width:608px;}.ie .weather-4items .fruitmachine .stripes{margin-bottom:-6px;}.weather-4items .fruitmachine .stripes li,.weather-4items .fruitmachine .stripes li strong{font-weight:400;color:#505050;}.weather-4items .fruitmachine .stripes li.wind{display:none;}.weather-4items .fruitmachine .stripes li strong{font-weight:800;}.weather-4items .fruitmachine .stripes div.time{float:left;padding:4px 8px 12px;border-left:2px solid #ededed;width:106px;padding-bottom:200px;margin-bottom:-184px;}.ie .weather-4items .fruitmachine .stripes div.time{height:152px;}.weather-4items .fruitmachine .stripes div.c1{border-left:none;}.weather-4items .fruitmachine .stripes div.c1,.weather-4items .fruitmachine .stripes div.c4{padding-right:8px;width:133px;}.weather-4items .fruitmachine .stripes div.c2,.weather-4items .fruitmachine .stripes div.c3{padding-right:8px;width:134px;}.weather-4items .fruitmachine .stripes div.time ul{margin-right:51px;}.weather-4items .fruitmachine .stripes img{margin:4px 0 7px;}.weather-4items .fruitmachine a{color:#369;}.weather-4items .fruitmachine a:hover{color:#0D3059;}.weather-4items .fruitmachine .stripes h3{font-weight:400;margin:0 0 3px;}.weather-4items .fruitmachine .clear{clear:both;}.weather-4items .weather-5day-forecast{padding:8px 0;}.weather-4items h4{font-weight:bold;margin:8px 0 9px;}.weather-4items p.weather-home{position:absolute;right:8px;top:15px;}#www-bbcarabic-com h4.digest-story-header a{font-family:"Arabic Transparent","Simplified Arabic",arial,verdana,sans-serif;}.ie7 .digest-world-service #www-bbcarabic-com .rtl li a{right:0;}.ie7 #www-bbcarabic-com.digest .digest-header{height:100%;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/accordian_overlay.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/accordian_overlay.png
deleted file mode 100755
index 72f7a23cb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/accordian_overlay.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/arrow_foldout.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/arrow_foldout.gif
deleted file mode 100755
index 1e2d14325..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/arrow_foldout.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/arrow_foldout.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/arrow_foldout.png
deleted file mode 100755
index fd1304a9d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/arrow_foldout.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/england-map.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/england-map.png
deleted file mode 100755
index 005e4216e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/england-map.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/geo-digest-vertical-panel.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/geo-digest-vertical-panel.gif
deleted file mode 100755
index 8114fe9ca..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/geo-digest-vertical-panel.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/languages-sprite.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/languages-sprite.gif
deleted file mode 100755
index d4ac275cb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/languages-sprite.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/livestats-sprite-ko.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/livestats-sprite-ko.png
deleted file mode 100755
index 7c765379b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/livestats-sprite-ko.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/livestats-sprite.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/livestats-sprite.gif
deleted file mode 100755
index b22c386aa..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/livestats-sprite.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/nav-divider.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/nav-divider.png
deleted file mode 100755
index ce9c3f9db..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/nav-divider.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/news_masthead.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/news_masthead.gif
deleted file mode 100755
index 3677465aa..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/news_masthead.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/personalisation-help-icon.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/personalisation-help-icon.gif
deleted file mode 100755
index c2c8a6422..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/personalisation-help-icon.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/programmes-iplayer-brand.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/programmes-iplayer-brand.png
deleted file mode 100755
index 22eb3c165..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/programmes-iplayer-brand.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/red-masthead.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/red-masthead.png
deleted file mode 100755
index 54522d61e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/red-masthead.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/roadicon.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/roadicon.gif
deleted file mode 100755
index b0b198a2a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/roadicon.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/scotland-map-hover.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/scotland-map-hover.png
deleted file mode 100755
index e17928dba..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/scotland-map-hover.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/scotland-map.png@v.2 b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/scotland-map.png@v.2
deleted file mode 100755
index 4346143bf..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/scotland-map.png@v.2
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/sprite_most_watched.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/sprite_most_watched.gif
deleted file mode 100755
index 714c92fed..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/sprite_most_watched.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/sprite_most_watched_ko.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/sprite_most_watched_ko.png
deleted file mode 100755
index 7f5a87de8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/sprite_most_watched_ko.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/story_sprite.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/story_sprite.gif
deleted file mode 100755
index 7292332f3..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/story_sprite.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/subnav-divider.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/subnav-divider.png
deleted file mode 100755
index 111499fac..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/subnav-divider.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/wales-map-hover.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/wales-map-hover.png
deleted file mode 100755
index 481825a9e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/wales-map-hover.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/wales-map.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/wales-map.png
deleted file mode 100755
index 1c53b2d8c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/wales-map.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/world-map.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/world-map.png
deleted file mode 100755
index 4b6488f62..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/img/world-map.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/skin.css b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/skin.css
deleted file mode 100755
index 0bc2f152e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_11/cream/hi/news/skin.css
+++ /dev/null
@@ -1 +0,0 @@
-#blq-container-inner{background:transparent;}#blq-main{background:transparent;}#blq-main #main-content{position:relative;}#blq-main h1.banner{height:50px;font-size:1.8em;line-height:1.6em;padding:10px 0 0 112px;font-family:verdana;font-weight:normal;color:#999;}#blq-main h1.banner span{position:absolute;top:-5000px;left:-5000px;}body{background:#fff url(img/red-masthead.png) repeat-x top center;}body #blq-container{background:url(img/red-masthead.png) repeat-x scroll center top;}#header a{background:transparent url(img/news_masthead.gif) no-repeat top left;}#nav a{background:url(img/nav-divider.png) no-repeat center left;}#sub-nav a{background:url(img/subnav-divider.png) no-repeat center left;}.emp{position:relative;}.birmingham-and-black-country #header .section-title{font-size:26px;top:4px;}.south-yorkshire #header .section-title{font-size:28px;}.coventry-and-warwickshire #header .section-title{font-size:28px;}.edinburgh-east-and-fife #header .section-title{font-size:24px;top:5px;}.glasgow-and-west #header .section-title{font-size:28px;}.north-east-orkney-and-shetland #header .section-title{font-size:23px;top:5px;}.tayside-and-central #header .section-title{font-size:24px;top:5px;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/global.css b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/global.css
deleted file mode 100755
index 6e81a8f02..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/global.css
+++ /dev/null
@@ -1 +0,0 @@
- #blq-pre-mast{z-index:12;}#blq-pre-mast .pulse-pop{position:absolute;left:700px;}#blq-container.blq-gvl-3{background:transparent;}#blq-container-inner{overflow:hidden;}#blq-container.blq-gvl-3 .blq-foot-text-dark a:hover,#blq-container.blq-gvl-3 .blq-foot-text-dark a:focus{color:#4c4c4c;text-decoration:underline;}abbr{border:none;}img{-webkit-user-select:none;}#blq-foot{border-top:none;}#blq-main{position:relative;clear:both;min-width:976px;background:#fff;}#header-wrapper{position:relative;clear:both;overflow:hidden;width:100%;background:transparent;}#header{position:relative;clear:both;overflow:hidden;width:976px;margin:0 auto;padding:14px 0 16px;}#header a{position:relative;float:left;display:inline;margin:0 0 0 10px;width:124px;height:34px;text-indent:-5000px;overflow:hidden;}#header .section-title{position:relative;float:left;display:inline;margin-left:20px;margin-bottom:-7px;top:3px;}#header .section-updated{position:relative;float:left;display:inline;top:21px;margin-left:20px;}#header .section-updated .date,#header .section-updated .time-text,#header .section-updated .time{font-size:.923em;}#header .section-updated .date{color:#fff;text-shadow:0 0 1px rgba(0,0,0,0.1);}#header .section-updated .time-text,#header .section-updated .time{font-weight:normal;color:#fff;text-shadow:0 0 1px rgba(0,0,0,0.1);}#header .section-updated .time-text{padding-left:4px;}a#rss-alternative{position:absolute;right:0;top:35px;margin-right:25px;overflow:visible;color:white;}a#rss-alternative .gvl3-icon{position:absolute;top:0;right:0;margin-right:-17px;}h2.nav-title{position:absolute;left:-50000px;}#nav{clear:both;position:relative;overflow:auto;width:976px;margin:0 auto;background:#3E0C0D;}#nav li{position:relative;float:left;display:inline;list-style:none;}#nav a{display:block;padding:4px 6px 4px 6px;font-size:.923em;}#nav .first-child a{background:none;}#nav .selected{margin-right:-1px;z-index:1;}#nav .selected a{background:#ededed;padding-right:7px;color:#505050!important;}#sub-nav{position:relative;clear:both;overflow:auto;width:976px;margin:0 auto;background:#ededed;}#sub-nav li{position:relative;float:left;display:inline;list-style:none;}#sub-nav a{position:relative;display:block;padding:4px 8px 4px 8px;font-size:.923em;color:#505050;}#sub-nav .first-child a{background:none;padding:4px 8px 4px 6px;}#sub-nav li.selected{margin-right:-1px;z-index:1;}#sub-nav .selected a{padding-right:7px;background:#fff;color:#D2700F;}#content-wrapper{position:relative;clear:both;margin:0 auto;width:976px;overflow:hidden;background:#fff;}.ie #content-wrapper{height:100%;overflow:visible;}.ie7 #content-wrapper{height:100%;}.slideshow .nav{overflow:hidden;text-indent:-5000px;position:absolute;left:0;margin-top:60px;width:100%;height:60px;z-index:50;background:transparent url(img/transparencies/rgba-0-0-0-07.png) repeat;}.ie .slideshow .nav{background:black;filter:alpha(opacity=70);}.slideshow .nav .controls{position:relative;margin:9px auto 3px;width:64px;}.slideshow .nav .next{position:absolute;top:0;right:0;height:16px;width:10px;overflow:hidden;text-indent:-50000px;background:transparent url(img/gvl3-icons-0-2.png) no-repeat;background-position:-247px -32px;cursor:pointer;}.slideshow .nav .previous{position:absolute;top:0;left:0;height:16px;width:10px;overflow:hidden;text-indent:-50000px;background:transparent url(img/gvl3-icons-0-2.png) no-repeat;background-position:-224px -32px;cursor:pointer;}.slideshow .nav .playpause_button{position:absolute;display:block;height:16px;top:0;left:26px;background:transparent url(img/gvl3-icons-0-2.png) no-repeat;font-size:1px;text-indent:-5000px;overflow:hidden;cursor:pointer;}.ie .slideshow .nav .next,.ie .slideshow .nav .previous,.ie .slideshow .nav .playpause_button{background-image:url(img/gvl3-icons-0-2.gif);}.slideshow .nav .pause{width:12px;background-position:-27px -32px;}.slideshow .nav .play{width:12px;left:27px;background-position:-5px -32px;}.slideshow .imageposition{position:relative;text-align:center;width:100%;padding:7px 0 6px;text-indent:0;color:#f0f0f0;text-shadow:0 0 1px rgba(0,0,0,0.5);}.from-external-source{position:relative;white-space:nowrap;cursor:pointer;color:#888;font-weight:bold;margin:0;font-family:Arial;font-size:11px;text-transform:uppercase;line-height:16px;width:1%;white-space:nowrap;}.new-story-icon{padding-left:4px;padding-bottom:5px;font-size:11px;text-transform:uppercase;line-height:16px;letter-spacing:0;font-weight:bold;color:#900;}a:hover .new-story-icon,a:focus .new-story-icon{text-decoration:none;background:#fff;}label{-webkit-transition:color .2s ease-in;}label.input-has-content{-webkit-transition:color .1s ease-in;}#related-services{position:relative;clear:both;overflow:hidden;width:976px;margin:0 auto;padding:0 0 12px;}#related-services h2{padding:4px 0 8px;}#news-services{position:relative;float:left;display:inline;width:640px;}#news-services li{position:relative;float:left;display:inline;width:128px;padding:48px 0 0;}#news-services li .services-icon{position:absolute;left:0;overflow:hidden;text-indent:-5000px;cursor:pointer;}#news-services li#service-feeds .services-icon{top:12px;width:32px;height:32px;background:url(img/services-rss.gif) no-repeat top left;}#news-services li#service-mobile .services-icon{top:5px;width:24px;height:39px;background:url(img/services-mobile.gif) no-repeat top left;}#news-services li#service-podcasts .services-icon{top:8px;width:24px;height:36px;background:url(img/services-podcast.gif) no-repeat top left;}#news-services li#service-alerts .services-icon{top:16px;width:32px;height:27px;background:url(img/services-alert.gif) no-repeat top left;}#news-services li#service-email-news .services-icon{top:20px;width:32px;height:23px;background:url(img/services-mail.gif) no-repeat top left;}#news-related-sites{position:relative;float:left;display:inline;width:160px;padding-left:172px;}#news-related-sites h2{position:relative;margin-left:-172px;}#news-related-sites .column-1{position:relative;float:left;display:inline;clear:left;margin-left:-172px;width:332px;}#cps-info{display:none;}.livestats-web-bug{position:absolute;left:-5000%;width:1px;height:1px;}hr{position:relative;background:transparent;height:1px;overflow:hidden;margin-top:-1px;display:block;clear:both;border-color:transparent;visibility:hidden;line-height:1px;}.has-icon-watch{text-indent:15px;}.has-icon-listen{text-indent:21px;}.has-icon-boxedlive,.has-icon-live{text-indent:32px;}.has-icon-boxedwatch{text-indent:21px;}.has-icon-boxedlisten{text-indent:21px;}.ie .has-icon-boxedlive{text-indent:0;}.ie .has-icon-boxedlive a{padding-left:32px;}.gvl3-icon{position:relative;z-index:10;height:15px;background:transparent url(img/gvl3-icons-0-2.png) no-repeat;display:block;margin:0 8px 5px 0;font-size:1px;line-height:1px;text-indent:-5000px;overflow:hidden;cursor:pointer;opacity:.85;-webkit-user-select:none;}.ie7 .gvl3-icon{filter:alpha(opacity=85);}.ie .gvl3-icon{background-image:url(img/gvl3-icons-0-2.gif);filter:alpha(opacity=85);}a:hover .gvl3-icon,a:focus .gvl3-icon,.gvl3-icon-wrapper .gvl3-icon{opacity:1;}.ie a:hover .gvl3-icon,.ie a:focus .gvl3-icon,.ie .gvl3-icon-wrapper .gvl3-icon,.ie7 a:hover .gvl3-icon,.ie7 a:focus .gvl3-icon,.ie7 .gvl3-icon-wrapper .gvl3-icon{filter:alpha(opacity=100);}.gvl3-icon-wrapper{font-size:1px;line-height:1px;position:absolute;background:transparent url(img/transparencies/rgba-0-0-0-07.png) repeat;padding:8px 10px;cursor:pointer;}.ie .gvl3-icon-wrapper{background:black;filter:alpha(opacity=60);}a:hover .gvl3-icon-wrapper,a:focus .gvl3-icon-wrapper{background:black;filter:alpha(opacity=100);}a:active .gvl3-icon-wrapper{background:#d2700f;filter:alpha(opacity=100);}.gvl3-icon-wrapper .gvl3-icon{margin:0;}.gvl3-icon-wrapper .gvl3-icon-invert-listen{margin:0 -3px 0 -2px;}.gvl3-icon-watch{background-position:-5px 0;width:11px;}a:active .gvl3-icon-watch{background-position:-5px -16px;}.gvl3-icon-pause{background-position:-27px 0;width:12px;}a:active .gvl3-icon-pause{background-position:-27px -16px;}.gvl3-icon-rewind{background-position:-49px 0;width:12px;}a:active .gvl3-icon-rewind{background-position:-49px -16px;}.gvl3-icon-expand{background-position:-71px 0;width:13px;}a:active .gvl3-icon-expand{background-position:-71px -16px;}.gvl3-icon-popout{background-position:-93px 0;width:17px;}a:active .gvl3-icon-popout{background-position:-93px -16px;}.gvl3-icon-share{background-position:-115px 0;width:13px;}a:active .gvl3-icon-share{background-position:-115px -16px;}.gvl3-icon-volume{background-position:-137px 0;width:27px;}a:active .gvl3-icon-volume{background-position:-137px -16px;}.gvl3-icon-highdefinition{background-position:-181px 0;width:25px;}a:active .gvl3-icon-highdefinition{background-position:-181px -16px;}.gvl3-icon-previous{background-position:-224px 0;width:10px;}a:active .gvl3-icon-previous{background-position:-224px -16px;}.gvl3-icon-next{background-position:-247px 0;width:10px;}a:active .gvl3-icon-next{background-position:-247px -16px;}.gvl3-icon-zoomout{background-position:-269px 0;width:13px;}a:active .gvl3-icon-zoomout{background-position:-269px -16px;}.gvl3-icon-zoomin{background-position:-291px 0;width:13px;}a:active .gvl3-icon-zoomin{background-position:-291px -16px;}.gvl3-icon-pinpoint{background-position:-313px 0;width:9px;}a:active .gvl3-icon-pinpoint{background-position:-313px -16px;}.gvl3-icon-pinpoint-content{background-position:-335px 0;width:9px;}a:active .gvl3-icon-pinpoint-content{background-position:-336px -16px;}.gvl3-icon-reset{background-position:-357px 0;width:17px;}a:active .gvl3-icon-reset{background-position:-357px -16px;}.gvl3-icon-refresh{background-position:-379px 0;width:14px;}a:active .gvl3-icon-refresh{background-position:-379px -16px;}.gvl3-icon-lock{background-position:-401px 0;width:12px;}a:active .gvl3-icon-lock{background-position:-401px -16px;}.gvl3-icon-unlock{background-position:-423px 0;width:15px;}a:active .gvl3-icon-unlock{background-position:-423px -16px;}.gvl3-icon-search{background-position:-445px 0;width:13px;}a:active .gvl3-icon-search{background-position:-445px -16px;}.gvl3-icon-gridview{background-position:-467px 0;width:14px;}a:active .gvl3-icon-gridview{background-position:-467px -16px;}.gvl3-icon-listview{background-position:-489px 0;width:14px;}a:active .gvl3-icon-listview{background-position:-489px -16px;}.gvl3-icon-close{background-position:-511px 0;width:13px;}a:active .gvl3-icon-close{background-position:-511px -16px;}.gvl3-icon-yes{background-position:-533px 0;width:15px;}a:active .gvl3-icon-yes{background-position:-533px -16px;}.gvl3-icon-rate{background-position:-555px 0;width:15px;}a:active .gvl3-icon-rate{background-position:-555px -16px;}.gvl3-icon-top{background-position:-577px 0;width:14px;}a:active .gvl3-icon-top{background-position:-577px -16px;}.gvl3-icon-home{background-position:-599px 0;width:17px;}a:active .gvl3-icon-home{background-position:-599px -16px;}.gvl3-icon-print{background-position:-621px 0;width:15px;}a:active .gvl3-icon-print{background-position:-621px -16px;}.gvl3-icon-email{background-position:-643px 0;width:15px;}a:active .gvl3-icon-email{background-position:-643px -16px;}.gvl3-icon-help{background-position:-665px 0;width:13px;}a:active .gvl3-icon-help{background-position:-665px -16px;}.gvl3-icon-information{background-position:-687px 0;width:14px;}a:active .gvl3-icon-information{background-position:-687px -16px;}.gvl3-icon-alert{background-position:-709px 0;width:15px;}a:active .gvl3-icon-alert{background-position:-709px -16px;}.gvl3-icon-add{background-position:-731px 0;width:15px;}a:active .gvl3-icon-add{background-position:-731px -16px;}.gvl3-icon-favourite{background-position:-753px 0;width:13px;}a:active .gvl3-icon-favourite{background-position:-753px -16px;}.gvl3-icon-edit{background-position:-775px 0;width:13px;}a:active .gvl3-icon-edit{background-position:-775px -16px;}.gvl3-icon-rss{background-position:-797px 0;width:13px;}a:active .gvl3-icon-rss{background-position:-797px -16px;}.gvl3-icon-duration{background-position:-819px 0;width:15px;}a:active .gvl3-icon-duration{background-position:-819px -16px;}.gvl3-icon-clock{background-position:-841px 0;width:13px;}a:active .gvl3-icon-clock{background-position:-841px -16px;}.gvl3-icon-comment{background-position:-863px 0;width:13px;}a:active .gvl3-icon-comment{background-position:-863px -16px;}.gvl3-icon-guidance{background-position:-885px 0;width:14px;}a:active .gvl3-icon-guidance{background-position:-885px -16px;}.gvl3-icon-listen{background-position:-907px 0;width:16px;}a:active .gvl3-icon-listen{background-position:-907px -16px;}.gvl3-icon-viewimage{background-position:-929px 0;width:16px;}a:active .gvl3-icon-viewimage{background-position:-929px -16px;}.gvl3-icon-downloaddisabled{background-position:-951px 0;width:12px;}a:active .gvl3-icon-downloaddisabled{background-position:-951px -16px;}.gvl3-icon-live,.gvl3-icon-boxedlive{background-position:-973px 0;width:27px;opacity:1;filter:alpha(opacity=100);}a:hover .gvl3-icon-live,a:focus .gvl3-icon-live,a:active .gvl3-icon-boxedlive{background-position:-973px -16px;}.ie .gvl3-icon-live,.ie .gvl3-icon-boxedlive,.ie7 .gvl3-icon-live,.ie7 .gvl3-icon-boxedlive{filter:alpha(opacity=100);}.gvl3-icon-invert-boxedlive{background-position:-973px -31px;width:27px;opacity:1;filter:alpha(opacity=100);}a:active .gvl3-icon-invert-boxedlive{background-position:-973px -31px;}.ie .gvl3-icon-invert-boxedlive,.ie7 .gvl3-icon-invert-boxedlive{filter:alpha(opacity=100);}.gvl3-icon-mobile{background-position:-1017px 0;width:8px;}a:active .gvl3-icon-mobile{background-position:-1017px -16px;}.gvl3-icon-digitaltv{background-position:-1039px 0;width:18px;}a:active .gvl3-icon-digitaltv{background-position:-1039px -16px;}.gvl3-icon-dabradio{background-position:-1061px 0;width:22px;}a:active .gvl3-icon-dabradio{background-position:-1061px -16px;}.gvl3-icon-easytoread{background-position:-1083px 0;width:21px;}a:active .gvl3-icon-easytoread{background-position:-1083px -16px;}.gvl3-icon-pc{background-position:-1105px 0;width:17px;}a:active .gvl3-icon-pc{background-position:-1105px -16px;}.gvl3-icon-podcast{background-position:-1127px 0;width:10px;}a:active .gvl3-icon-podcast{background-position:-1127px -16px;}.gvl3-icon-newsletter{background-position:-1149px 0;width:19px;}a:active .gvl3-icon-newsletter{background-position:-1149px -16px;}.gvl3-icon-accessibility{background-position:-1171px 0;width:12px;}a:active .gvl3-icon-accessibility{background-position:-1171px -16px;}.gvl3-icon-adhd{background-position:-1191px 0;width:13px;}a:active .gvl3-icon-adhd{background-position:-1191px -16px;}.gvl3-icon-aspergers{background-position:-1213px 0;width:13px;}a:active .gvl3-icon-aspergers{background-position:-1213px -16px;}.gvl3-icon-easiertoread{background-position:-1235px 0;width:19px;}a:active .gvl3-icon-easiertoread{background-position:-1235px -16px;}.gvl3-icon-dyslexia{background-position:-1257px 0;width:22px;}a:active .gvl3-icon-dyslexia{background-position:-1257px -16px;}.gvl3-icon-boxedwatch{background-position:-1301px 0;width:16px;}a:active .gvl3-icon-boxedwatch{background-position:-1301px -16px;}.gvl3-icon-boxedlisten{background-position:-1323px 0;width:16px;}a:active .gvl3-icon-boxedlisten{background-position:-1323px -16px;}.gvl3-icon-invert-watch{background-position:-5px -32px;width:11px;}.gvl3-icon-invert-pause{background-position:-27px -32px;width:12px;}.gvl3-icon-invert-rewind{background-position:-49px -32px;width:12px;}.gvl3-icon-invert-expand{background-position:-71px -32px;width:13px;}.gvl3-icon-invert-popout{background-position:-93px -32px;width:17px;}.gvl3-icon-invert-share{background-position:-115px -32px;width:13px;}.gvl3-icon-invert-volume{background-position:-137px -32px;width:27px;}.gvl3-icon-invert-highdefinition{background-position:-181px -32px;width:25px;}.gvl3-icon-invert-previous{background-position:-224px -32px;width:10px;}.gvl3-icon-invert-next{background-position:-247px -32px;width:10px;}.gvl3-icon-invert-zoomout{background-position:-269px -32px;width:13px;}.gvl3-icon-invert-zoomin{background-position:-291px -32px;width:13px;}.gvl3-icon-invert-pinpoint{background-position:-313px -32px;width:10px;}.gvl3-icon-invert-pinpoint-content{background-position:-335px -32px;width:10px;}.gvl3-icon-invert-reset{background-position:-357px -32px;width:17px;}.gvl3-icon-invert-refresh{background-position:-379px -32px;width:14px;}.gvl3-icon-invert-lock{background-position:-401px -32px;width:12px;}.gvl3-icon-invert-unlock{background-position:-423px -32px;width:15px;}.gvl3-icon-invert-search{background-position:-445px -32px;width:13px;}.gvl3-icon-invert-gridview{background-position:-467px -32px;width:14px;}.gvl3-icon-invert-listview{background-position:-489px -32px;width:14px;}.gvl3-icon-invert-close{background-position:-511px -32px;width:13px;}.gvl3-icon-invert-yes{background-position:-533px -32px;width:15px;}.gvl3-icon-invert-rate{background-position:-555px -32px;width:15px;}.gvl3-icon-invert-top{background-position:-577px -32px;width:14px;}.gvl3-icon-invert-home{background-position:-599px -32px;width:17px;}.gvl3-icon-invert-print{background-position:-621px -32px;width:15px;}.gvl3-icon-invert-email{background-position:-643px -32px;width:15px;}.gvl3-icon-invert-help{background-position:-665px -32px;width:13px;}.gvl3-icon-invert-information{background-position:-687px -32px;width:14px;}.gvl3-icon-invert-alert{background-position:-709px -32px;width:15px;}.gvl3-icon-invert-add{background-position:-731px -32px;width:15px;}.gvl3-icon-invert-favourite{background-position:-753px -32px;width:13px;}.gvl3-icon-invert-edit{background-position:-775px -32px;width:13px;}.gvl3-icon-invert-rss{background-position:-797px -32px;width:13px;}.gvl3-icon-invert-duration{background-position:-819px -32px;width:15px;}.gvl3-icon-invert-clock{background-position:-841px -32px;width:13px;}.gvl3-icon-invert-comment{background-position:-863px -32px;width:13px;}.gvl3-icon-invert-guidance{background-position:-885px -32px;width:14px;}.gvl3-icon-invert-listen{background-position:-907px -32px;width:16px;}.gvl3-icon-invert-viewimage{background-position:-929px -32px;width:16px;}.gvl3-icon-invert-downloaddisabled{background-position:-951px -32px;width:12px;}.gvl3-icon-invert-live{background-position:-973px -32px;width:27px;opacity:1;filter:alpha(opacity=100);}.gvl3-icon-invert-mobile{background-position:-1017px -32px;width:8px;}.gvl3-icon-invert-digitaltv{background-position:-1039px -32px;width:18px;}.gvl3-icon-invert-dabradio{background-position:-1061px -32px;width:22px;}.gvl3-icon-invert-easytoread{background-position:-1083px -32px;width:21px;}.gvl3-icon-invert-pc{background-position:-1105px -32px;width:17px;}.gvl3-icon-invert-podcast{background-position:-1127px -32px;width:10px;}.gvl3-icon-invert-newsletter{background-position:-1149px -32px;width:19px;}.gvl3-icon-invert-accessibility{background-position:-1171px -32px;width:12px;}.gvl3-icon-invert-adhd{background-position:-1191px -32px;width:13px;}.gvl3-icon-invert-aspergers{background-position:-1213px -32px;width:14px;}.gvl3-icon-invert-easiertoread{background-position:-1235px -32px;width:19px;}.gvl3-icon-invert-dyslexia{background-position:-1257px -32px;width:22px;}.gvl3-icon-invert-boxedwatch{background-position:-1301px -32px;width:16px;}.gvl3-icon-invert-boxedlisten{background-position:-1323px -32px;width:16px;}.story-date-invisible,.invisible{position:absolute;top:-5000px;left:-5000px;}.debug body{background:white url(img/gvl3-grid-2.png) repeat-y center 1px;}.debug #blq-container{opacity:.6;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/GVL3-icons-test.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/GVL3-icons-test.png
deleted file mode 100755
index a8f136944..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/GVL3-icons-test.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/carousel-prev-next-3.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/carousel-prev-next-3.png
deleted file mode 100755
index d4242618d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/carousel-prev-next-3.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/cbl.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/cbl.png
deleted file mode 100755
index bd6fb3ecd..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/cbl.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/cbr.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/cbr.png
deleted file mode 100755
index 571cfef54..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/cbr.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/foldout-arrow.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/foldout-arrow.gif
deleted file mode 100755
index 2cf9da05e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/foldout-arrow.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-grid-2.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-grid-2.png
deleted file mode 100755
index 4d9f16797..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-grid-2.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-icons-0-2.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-icons-0-2.gif
deleted file mode 100755
index 88ee92591..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-icons-0-2.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-icons-0-2.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-icons-0-2.png
deleted file mode 100755
index 802647941..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-icons-0-2.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-live-icon-inverted.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-live-icon-inverted.gif
deleted file mode 100755
index 693c63ea3..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/gvl3-live-icon-inverted.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/icons/listen-charcoal.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/icons/listen-charcoal.png
deleted file mode 100755
index d16c6c56d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/icons/listen-charcoal.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/icons/play-charcoal.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/icons/play-charcoal.png
deleted file mode 100755
index a863f5572..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/icons/play-charcoal.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/index-quote.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/index-quote.png
deleted file mode 100755
index d35572436..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/index-quote.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/live-icon-32.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/live-icon-32.gif
deleted file mode 100755
index a4725534c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/live-icon-32.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-down.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-down.gif
deleted file mode 100755
index 4d89554ea..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-down.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-down.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-down.png
deleted file mode 100755
index 1aa1872d2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-down.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-up.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-up.gif
deleted file mode 100755
index 633a2cc95..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-up.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-up.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-up.png
deleted file mode 100755
index 59b46df37..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/market-data-up.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/most_watched.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/most_watched.png
deleted file mode 100755
index 8631f3294..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/most_watched.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/search.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/search.png
deleted file mode 100755
index be856addf..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/search.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/select-arrow.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/select-arrow.png
deleted file mode 100755
index d55e57a42..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/select-arrow.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-alert.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-alert.gif
deleted file mode 100755
index 4f4080016..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-alert.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-mail.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-mail.gif
deleted file mode 100755
index 1fc9f1ca1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-mail.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-mobile.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-mobile.gif
deleted file mode 100755
index babd18a8b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-mobile.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-podcast.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-podcast.gif
deleted file mode 100755
index 3fe3de206..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-podcast.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-rss.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-rss.gif
deleted file mode 100755
index 5036e5682..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/services-rss.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/story_sprite.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/story_sprite.gif
deleted file mode 100755
index f236f2503..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/story_sprite.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/story_sprite.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/story_sprite.png
deleted file mode 100755
index bbc298f40..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/story_sprite.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/traffic_icon.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/traffic_icon.gif
deleted file mode 100755
index 5fc5235d9..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/traffic_icon.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/transparencies/rgba-0-0-0-07.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/transparencies/rgba-0-0-0-07.png
deleted file mode 100755
index 2ad571dc9..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/img/transparencies/rgba-0-0-0-07.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/layout/index.css b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/layout/index.css
deleted file mode 100755
index bde1b1538..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/layout/index.css
+++ /dev/null
@@ -1 +0,0 @@
-.container-now,.container-best,.container{position:relative;display:block;overflow:hidden;margin:0;}#full-width{position:relative;clear:both;overflow:hidden;margin:0 0 -1px;padding-bottom:1px;min-height:8px;width:976px;z-index:10;background:#fff;}.container-now{position:relative;float:left;display:inline;clear:both;margin:0 16px 16px 0;width:624px;}.container-best{position:relative;float:right;display:inline;overflow:visible;width:336px;z-index:11;}.container-best{margin-top:-16px;}.front-page .container-best{margin-top:8px;}.index-date{position:relative;display:block;clear:both;padding:12px 0 4px;}.index-date .date{font-weight:bold;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/mobile.css b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/mobile.css
deleted file mode 100755
index 8307c1ccd..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/mobile.css
+++ /dev/null
@@ -1 +0,0 @@
-body{-webkit-text-size-adjust:none;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/print.css b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/print.css
deleted file mode 100755
index ca24e216c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/print.css
+++ /dev/null
@@ -1 +0,0 @@
-.embedded-hyper,.story-feature,.story-related,.more-stories,.caption,.videoInStoryA,.videoInStoryB,.videoInStoryC,.more-stories,.top-section-stories,.hypertabs,.container-local-weather-and-travel,.useful-links,#site-wide-alert,.marketdata-widget a{display:none!important;}#blq-mast,#blq-nav,#blq-footlinks,#blq-obit,#blq-acc,#debug{display:none!important;}#blq-foot{background:transparent;width:624px!important;}#blq-copy{margin-left:0!important;}body{background:white!important;}body *{color:black!important;}#blq-container{background:none!important;}#blq-container-inner{width:624px!important;padding:1.64cm 3cm!important;}#main-content{padding-bottom:47px;}a,a *{color:blue!important;text-decoration:underline;}hr{background:white!important;border:white!important;}#header a{display:block;}#header img{padding-bottom:12px;display:block;}#header{padding-bottom:9px!important;}.section-title{display:block;font-size:35px!important;padding-top:6px;padding-bottom:16px;font-family:"Gill Sans";text-transform:uppercase;font-weight:normal!important;border-bottom:3px solid black;text-indent:-2px!important;}#nav,#sub-nav,.gvl3-icon,#best,#related-services,#page-bookmark-links-head,#page-bookmark-links-foot,.story-body a.hidden,.bbccom_display_none,.layout-block-b{display:none!important;}.story-date{display:block;padding-bottom:31px;}.story-date .date{font-weight:bold;}.story-header{padding-top:.25cm;padding-bottom:52px;}.story-body p,.story-related li{font-size:13pt;line-height:24px;padding-bottom:24px;}.story-body strong,.story-body .introduction{font-weight:bold;}.story-related{padding-top:23px;}.story-related .timestamp{text-transform:none!important;font-size:13px!important;line-height:24px!important;font-weight:bold;}.story-related a{display:block;font-size:13pt;line-height:18px;}.story-related h2,.story-related h3,.story-related li{padding-bottom:12px;}.story-body h2,.story-related h2,.cross-head{display:block;font-size:13pt;line-height:24px;font-weight:bold;}#content-wrapper a.story:after{content:" ["attr(href)"]";font-size:13px;display:block;width:100%;}.caption{clear:both;margin:12px 0 25px;padding:6px 0 4px;}.story-body img{display:block;padding-bottom:4px;}.story-body form{display:none;}.story-feature,.videoInStoryB{clear:both;position:relative;overflow:hidden;margin:-6px 0 13px;padding:5px 12px 12px;border:1px dotted black;}.story-feature h2{padding-top:0;padding-bottom:7px;}.story-feature h2.quote{font-size:48px;position:absolute;top:9px;width:50px;height:50px;line-height:48px;}.story-feature blockquote p{text-indent:30px;padding-top:11px;padding-bottom:11px;}.story-feature blockquote{display:inline;}.story-feature .quote_credit{font-weight:bold;}.story-feature .quote_credit_title{display:block;}.story-feature h2.quote span,.story-feature .endquote{display:none;}.byline{display:block;overflow:auto;position:relative;margin-bottom:26px;padding-top:11px;border-top:1px dotted black;}.byline .byline-picture img{display:none;}.byline-name{display:block;font-weight:bold;}.next-container,.previous-container,.next-container a.next,.previous-container a.previous{display:none;}.more-stories,.story-related{position:relative;clear:both;padding-top:0!important;padding-bottom:12px!important;border-top:3px solid black;}.more-stories h2,.more-stories .first,.more-stories li{padding-top:12px;}.more-stories img,.rss{display:none;}.newstracker-list ul li{clear:both!important;height:auto!important;padding-bottom:12px!important;}.newstracker-list ul li.even{clear:none!important;}#cps-info{display:block!important;}.bbccom-advert{display:none!important;}#print-advert{position:absolute;right:0;top:0;}.debug body{background:white url(img/gvl3-grid-2.png) repeat-y top center!important;}.debug #blq-container{opacity:.6;}#blq-container-inner{width:100%!important;padding-left:0!important;padding-right:0!important;}#blq-container-outer{border:2px solid transparent!important;margin:0!important;padding:0!important;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/type.css b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/type.css
deleted file mode 100755
index 34a648093..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/type.css
+++ /dev/null
@@ -1,300 +0,0 @@
-
-/* Default type */
-body #blq-container #blq-main {
- font-size: 67.5%;
- font-size: 1.3em;
- -webkit-font-smoothing: antialiased;
-}
-
-* {
- color: #505050;
- font-family: Arial, Helmet, Freesans, sans-serif;
- line-height: 16px;
-}
-
-/* Knockout */
-.knockout {
- color: #fff;
- text-shadow: 0 0 1px rgba(0,0,0,0.2);
-}
-
-/* Highlight (orange) */
-.highlight {
- color: #D1700E;
-}
-
-#header .section-title {
- color: #fff;
- text-shadow: 0 0 1px rgba(0,0,0,0.1);
- font-family: "Gill Sans MT", "Gill Sans", Arial, Helmet, Freesans, sans-serif;
- font-weight: normal;
- text-transform: uppercase;
- font-size: 30px;
- letter-spacing: 0;
- line-height: 40px;
- text-rendering: optimizeLegibility;
-}
-
-/* 48px */
-.special-48 {
- font-size: 3.692em; /* 13px < 48px */
- font-weight: bold;
- letter-spacing: -2px;
- line-height: 48px;
- text-rendering: optimizeLegibility;
-}
-
-/* 36px */
-.special-36,
-#splash .splash-header .story {
- font-size: 2.769em; /* 13px < 36px */
- font-weight: bold;
- letter-spacing: -1px;
- line-height: 36px;
- text-rendering: optimizeLegibility;
-}
-
-/* 32px */
-.special-32,
-.se-promo-now-inc-header,
-#main-content h1.story-header,
-#top-story .top-story-header,.story-wide h1,
-.lead-feature-now .headline {
- font-size: 2.461em; /* 13px < 32px */
- font-weight: bold;
- letter-spacing: -1px;
- line-height: 34px;
- text-rendering: optimizeLegibility;
-}
-
-/* 24px */
-.special-24,
-.se-promo-best-inc-header,
-.top-index-stories .top-index-stories-header,
-.top-section-stories .top-section-stories-header,
-.useful-links-header,
-.also-in-news h2,
-.av-stories-best .av-best-header,
-.feature-generic .features-header, .container-features-and-analysis .features-header,
-.featured-site-top-stories h2,
-.digest-wrapper-header,
-.geo-digest-solo-header,
-.geo-digest-region-header,
-.geo-digest-vertical-header,
-.languages h3,
-.other-top-stories .other-top-stories-header,
-.podcasts-range-module .podcasts-range-module-header,
-#site-wide-alert h2,
-.special-reports-header,
-.top-stories-range-module .top-stories-range-module-header,
-.topic-cluster .topic-cluster-header,
-.market-data h2,
-.weather-3day h2,
-.other-site-content-header,
-.guides-stories-header,
-.container-hyper-topic-cluster .hyper-depth-header,
-#personalisation h3,
-#related-services h2,.media_asset .most-pop h2,.byline h2,.alert h2,tr.heading th h2,.share-help h2,.share-help h3,.story-related h2,.most-watched-list h2,.useful-links h2,.more-stories h2,
-#personalisation .location-panel h4,
-#personalisation .we-remembered-panel h4,
-.have-your-say-inc-header,
-.have-your-say-inc .contact-number,
-.container-archived-content-heading,
-.container-featured-other-site-heading,
-.feature-digest-header,
-.generic-tiled-digest-header,
-.weather-4items h2,.marketdata-widget h2 {
- font-size: 1.846em; /* 13px < 24px */
- font-weight: bold;
- letter-spacing: -1px;
- line-height: 24px;
- text-rendering: optimizeLegibility;
-}
-
-/* 20px */
-.special-20,
-.container-geographic-regions-generic .around-uk-digest-header,
-#personalisation .locator-msg-disambiguate p.locator-panel-header strong {
- font-size: 1.538em; /* 13px < 20px */
- font-weight: bold;
- letter-spacing: -1px;
- line-height: 24px;
- text-rendering: optimizeLegibility;
-}
-
-
-/* 16px */
-.special-16,
-.top-section-stories .first-child h3,
-.container-local-weather-and-travel .weather .data-feed-now h3,
-.container-local-weather-and-travel .travel .useful-links .useful-links-header,
-.feature-generic .feature-header, .container-features-and-analysis .feature-header,
-.featured-site-top-stories .with-summary .story,
-.featured-site-top-stories .medium-image .story,
-.featured-site-top-stories .large-image .story,
-.featured-site-top-stories .classic-image .story,
-.digest .digest-header,
-.geo-digest-section-header,
-.geo-digest-vertical .tab a,
-.container-geographic-regions-generic .tab a,
-.container-geographic-news-digests .tab a,
-.hyper-container-title .hyper-container-title-header,
-.hyper-related-assets .hyper-depth-stories-header,
-.hyper-foldout .hyper-foldout-header,
-.languages h4,
-.other-top-stories-stories .with-summary a.story,
-.secondary-top-story .with-summary .story,
-.secondary-top-story .medium-image .story,
-.secondary-top-story .large-image .story,
-.secondary-top-story .classic-image .story,
-.other-site-content .first-other-promo h3 a.story,
-.guide-content .guide h3 a.story,
-#site-wide-alert p,
-.special-reports-component h3 a,
-#splash .see-also .first-child-live a.story,
-.topic-cluster-stories .with-summary a.story,
-.media-asset .read-full h2, .media-asset .read-more h2, .media-asset .playlist h2, .features h2, .top-stories h2, .most-pop-story h2, h2.more-stories-head,.tabs li,.alert h3,.story-body .story-feature h2,.story-body .story-feature blockquote p,.see-also h3, #main-content .story-related h3,.features h3, .byline .byline_name,.story-body tr.subheading th, .story-body tr.subheading td h3,
-.story-body .cross-head,
-.weather-3day h3#weather_sitelabel,.more-galleries h2,.share-form ul.networks li a,.story-body .embedded-hyper h2,.hyper-promotional-content ul li.large-image h3, .hyper-promotional-content ul li.medium-image h3, .hyper-promotional-content ul li.first-child h3,
-.story-body tr.colheading th,
-.have-your-say-inc ul li h3 a,
-.have-your-say-inc ul li h3 .core-text,
-.byline .byline-name,
-.guide-content .stacked-overlay-guides .guide h3 a .overlay strong,
-.other-site-content .stacked-overlay-other-site-promotion .first-other-promo h3 a .overlay strong,
-.weather-4items h3#weather_sitelabel,
-.weather-4items h4,.dna-comment-count-personal a {
- font-size: 1.231em; /* 13px < 16px */
- font-weight: bold;
- line-height: 16px;
- text-rendering: optimizeLegibility;
-}
-
-/* 13px Normal */
-.container-local-weather-and-travel .data-feed-now h3#weather_sitelabel,
-.secondary-top-story .see-also .story,
-.see-also ul li a, #main-content .internet-links a, .features p,
-#related-services,
-.weather-3day .next3daysweather .stripes li,.weather-3day .next3daysweather .stripes li strong,.weather-3day .next3daysweather .stripes h3,.story-body #heading-2,
-.story-body table p,
-.story-body div p.caption,
-.story-body .story-feature p,
-.story-body .story-feature li,
-.guide-content .stacked-overlay-guides .guide h3 a.story,
-.other-site-content .stacked-overlay-other-site-promotion .first-other-promo h3 a.story,
-.weather-4items .next3daysweather .stripes li,
-.weather-4items .next3daysweather .stripes li strong,
-.weather-4items .next3daysweather .stripes h4 {
- font-size: 1em; /* 13px */
- line-height: 16px;
-}
-
-/* 14px Storybody */
-.story-body p,
-.story-body li,
-.story-wide li,
-.media-asset .emp-decription p,
-.photo-gallery .hypertabs li {
- font-size: 1.077em; /* 13px < 14px */
- line-height: 18px;
- text-rendering: auto;
-}
-
-/* Storybody Color */
-.story-body p,
-.story-body p strong,
-.story-body p em,
-.media_asset .emp-decription p,
-.photo-gallery .hypertabs li {
- color: #333;
-}
-
-
-/* 11px */
-.special-11,
-.special-reports-component #bbccom_module_specialreport_text,
-.market-data .mkt-last-updated,
-.market-data .mkt-footer .mkt-data-delayed,
-#pictureGallery .controls a,
-.media_asset p.published, .media_asset .warning p, #main-content .internet-links span, .top-stories li span,.see-also span.timestamp,.see-also span.section,.marketdata-widget span,
-.story-body table tfoot p,.dna-comment-count-simple a {
- font-family: Arial;
- font-size: 0.846em; /* 13px > 11px */
- text-transform: uppercase;
- line-height: 16px;
- text-rendering: optimizeLegibility;
-}
-
-
-
-/* Bold */
-strong {
- font-weight: bold;
-}
-
-/* Italic */
-em {
- font-style: italic;
-}
-
-/* Default anchor */
-a {
- color: #1F4F82;
- text-decoration: none;
- font-weight: bold;
-}
-
-/* This is a super strong overide - applies to all see alsos */
-body #blq-container #blq-container-inner .see-also a.story {
- font-weight: normal;
-}
-
-a:visited {
- color: #4A7194;
-}
-
-/* Knockout anchor */
-.knockout a,
-#nav * {
- color: #fff;
- text-shadow: 0 0 1px rgba(0,0,0,0.2);
-}
-
-/* Blue knockout anchor */
-.knockout a {
- color: #a9c0d3;
-}
-
-a.from-external-source,
-a.from-external-source:visited {
- color: #888888;
-}
-
-/* Default anchor hover/focus */
-a:hover, a:focus {
-/* color: #123E60; */
- text-decoration: underline;
- outline: none;
-}
-
-/* Knockout anchor hover/focus */
-.knockout a:hover, .knockout a:focus {
- color: #fff;
-}
-
-/* Default anchor active */
-a:active {
- color: #D1700E;
-}
-
-/* Knockout anchor active */
-.knockout a:active {
- color: #fff;
-}
-
-#blq-container #blq-container-inner img {
- font-size: 13px;
- letter-spacing: 0;
- font-weight: normal;
- font-style: italic;
-}
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/node1.bbcimg.co.uk/glow/gloader.0.1.4.js b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/node1.bbcimg.co.uk/glow/gloader.0.1.4.js
deleted file mode 100755
index 4ed91d3bb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/node1.bbcimg.co.uk/glow/gloader.0.1.4.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- Copyright 2009 British Broadcasting Corporation
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-(function(){if(window.gloaddisableder){return;}window.gloaddisableder={_requests:[],_modules:{},_expects:{},_extras:{},_errors:[],util:{getGloaddisablederFile:function(filepath){if(filepath&&/(^|^.*[\/\\])(gloaddisableder(\.[^\/\\]+)?\.js)(\?|$)/i.test(filepath)){var dir=RegExp.$1;if(dir){dir=dir.replace("cached/","");}return{dir:dir,name:RegExp.$2};}return undefined;}},map:{js:{},css:{},parse:function(libraryName,libraryVersions){var lib={name:libraryName,versions:[]};var scope={};var scopeProps=["$name","$version","$base"];scopeProps.has=function(what){for(var i=0;i<this.length;i++){if(what==this[i]){return true;}}return false;};if(gloaddisableder.mapProps&&gloaddisableder.mapProps[lib.name]){for(var p in gloaddisableder.mapProps[lib.name]){if(!scopeProps.has(p)){scopeProps.push(p);}}}for(var p=0;p<scopeProps.length;p++){scope[scopeProps[p]]=undefined;}scope.$name=lib.name;if(gloaddisableder.mapProps&&gloaddisableder.mapProps[lib.name]){for(var p in gloaddisableder.mapProps[lib.name]){scope[p]=gloaddisableder.mapProps[lib.name][p];}}for(var i=0;i<libraryVersions.length;i++){var version=libraryVersions[i];for(var v in version){if(version[v]===null){delete version[v];delete scope[v];}else{if(v.indexOf("$")===0){scope[v]=version[v];}else{if(typeof version[v]=="string"){version[v]=[version[v]];scope[v]=version[v].slice(0);}else{if(typeof version[v].push!="undefined"){scope[v]=version[v].slice(0);}else{throw new Error("invalid type: "+typeof version[v]);}}}}}for(var s in scope){if(typeof version[s]=="undefined"){if(s.indexOf("$")===0){version[s]=scope[s];}else{version[s]=scope[s].slice(0);}}}for(var p=0;p<scopeProps.length;p++){var prop=scopeProps[p];for(var vp=0;vp<p;vp++){var vprop=scopeProps[vp];if(typeof version[vprop]=="undefined"){version[prop]=scope[prop];}var patt=new RegExp("\\{\\"+vprop+"\\}","g");version[prop]=version[prop].replace(patt,version[vprop]);}}for(vi in version){if(vi.indexOf("$")===0){continue;}for(var vii=0;vii<version[vi].length;vii++){for(var p=0;p<scopeProps.length;p++){var prop=scopeProps[p];var patt=new RegExp("\\{\\"+prop+"\\}","g");version[vi][vii]=""+version[vi][vii].replace(patt,""+version[prop]);}}}lib.versions.push(version);}return lib;},add:function(){var args=[];for(var i=1;i<arguments.length;i++){args.push(arguments[i]);}var lib=gloaddisableder.map.parse(arguments[0],args);for(var i=0;i<lib.versions.length;i++){var version=lib.versions[i];for(var p in version){if(p.charAt(0)=="$"){continue;}var modId=version.$name+"/"+version.$version+"/"+p;gloaddisableder.map.js[modId]=version[p][0];gloaddisableder.map.css[modId]=version[p][1];}}},include:function(src){if(gloaddisableder.map._include[src]){return false;}else{void('<script type="text/javascript" src="'+src+'"><\/script>\n');gloaddisableder.map._include[src]=true;return true;}},_include:{},latest:function(libName,v){if(gloaddisableder.map.$latest[libName+"/"+v]){return gloaddisableder.map.$latest[libName+"/"+v];}var result=v;var parts=v.split(".");if(parts.length<3){if(parts[0]==parseInt(parts[0])&&(typeof parts[1]=="undefined"||parts[1]==parseInt(parts[1]))){var invalid=new RegExp("[a-zA-Z-]"),latest=[parts[0],null,null],mod;for(mod in gloaddisableder.map.js){var modParts=mod.split("/");if(modParts[0]==libName&&modParts[2]==libName&&!invalid.test(modParts[1])){var modVParts=modParts[1].split(".");if(modVParts[0]==parts[0]){if((typeof parts[1]=="undefined"&&(latest[1]<=modVParts[1]||(latest[1]==modVParts[1]&&latest[2]<=modVParts[2])))||(typeof parts[1]!="undefined"&&parts[1]==modVParts[1]&&latest[2]<=modVParts[2])){latest[1]=modVParts[1];latest[2]=modVParts[2];}}}}if(latest[2]!=null){result=latest.join(".");}}}gloaddisableder.map.$latest[libName+"/"+v]=result;return result;},$latest:{}},settings:{ns:"bbc.glow.gloaddisableder",get:function(name){var n=" "+gloaddisableder.settings.ns+"."+name+"=";var cookies=document.cookie.split(";");for(var i=0;i<cookies.length;i++){if((" "+cookies[i]).indexOf(n)>-1){return unescape(cookies[i].split("=")[1]);}}},set:function(name,value,path){var n=gloaddisableder.settings.ns+"."+name;document.cookie=n+"="+escape(value)+"; path="+((path)?path:"/")+";";},clear:function(name,path){var d=new Date();d.setTime(d.getTime()-1);var n=gloaddisableder.settings.ns+"."+name;document.cookie=n+"=; path="+((path)?path:"/")+"; expires=Thu, 01-Jan-70 00:00:01 GMT;";}},loaddisabledOverride:function(version){var current=gloaddisableder.settings.get("override");version=version||prompt("Enter version",current?current:"");if(version===""){gloaddisableder.settings.clear("override");}else{if(version!==null){gloaddisableder.settings.set("override",version);}}location.reloaddisabled();},loaddisabledDebug:function(){gloaddisableder.settings.set("debug","1");location.reloaddisabled();},unloaddisabledDebug:function(){gloaddisableder.settings.clear("debug");location.reloaddisabled();},expect:function(srcFile){srcFile=""+srcFile;var modsInFile=[];var modId;for(modId in gloaddisableder.map.js){if(gloaddisableder.map.js[modId]==srcFile){modsInFile.push(modId);gloaddisableder._expects[modId]=(gloaddisableder._expects[modId]||0)+1;}}},loaddisabled:function(){var r={};if(typeof arguments[arguments.length-1].length=="undefined"){r=arguments[arguments.length-1];arguments.length--;}var newRequest=new gloaddisableder.Request(r);gloaddisableder._requests.push(newRequest);var mods=[];var override=gloaddisableder.settings.get("override");for(var i=0;i<arguments.length;i++){if(override&&arguments[i][0]=="glow"){if(typeof console!="undefined"&&console.log){console.log("Overriding version '"+arguments[i][1]+"' of glow to version '"+override+"'");}arguments[i][1]=override;}mods.push(arguments[i]);}var ids=gloaddisableder.toIds(mods);newRequest.args=[];for(var i=0;i<ids.length;i++){newRequest.include(ids[i]);if(ids[i].match(/\/[^.]+$/)){newRequest.args.push(ids[i]);}}var waitCount=newRequest.waits.length;for(var i=0;i<newRequest.waits.length;i++){if(gloaddisableder._modules[newRequest.waits[i]]&&gloaddisableder._modules[newRequest.waits[i]].status==gloaddisableder.Module.IMPLEMENTED){waitCount--;}}if(waitCount>0){newRequest.status=gloaddisableder.Request.WAITING;gloaddisableder.request(ids,newRequest.async);gloaddisableder.resolve();}else{newRequest.complete();}},request:function(mIds,async){for(var i=0;i<mIds.length;i++){var m=mIds[i];if(gloaddisableder._extras[m]){gloaddisableder._modules[m]=new gloaddisableder.Module(m);var extra=gloaddisableder._extras[m];delete gloaddisableder._extras[m];gloaddisableder.provide(extra);}else{if(!gloaddisableder._modules[m]){gloaddisableder._modules[m]=new gloaddisableder.Module(m);gloaddisableder._modules[m].status=gloaddisableder.Module.REQUESTED;}}if(gloaddisableder._modules[m].status<gloaddisableder.Module.IMPLEMENTED||gloaddisableder._modules[m].css){gloaddisableder._modules[m].css=null;gloaddisableder.fetch(gloaddisableder._modules[m],async);}}},fetch:function(m,async){var cssSrc=gloaddisableder.map.css[m.id],jsSrc=gloaddisableder.map.js[m.id];gloaddisableder._modules[m.id].async=async;var force=(!async&&gloaddisableder._fetched[jsSrc]&&gloaddisableder._fetched[jsSrc].async&&gloaddisableder._modules[m.id].status<gloaddisableder.Module.IMPLEMENTED);if(cssSrc&&(force||!gloaddisableder._fetched[cssSrc])){gloaddisableder._fetched[cssSrc]={};if(document){var headElement;if(headElement=document.getElementsByTagName("head")[0]){var link;if(link=document.createElement("link")){link.href=cssSrc;link.rel="stylesheet";link.type="text/css";link.className="gloaddisableded async";headElement.appendChild(link);}}else{void('<link rel="stylesheet" type="text/css" href="'+cssSrc+'" class="gloaddisableded sync">');}}}if(!jsSrc){var msg="The gloaddisableder map is missing a JavaScript filepath for the module: "+m.id;var maps=[];for(var included_map in gloaddisableder.map._include){maps.push(included_map);}msg+=".\rMaps included are: "+maps.join(", ")+".";gloaddisableder._errors.push(msg);throw new Error(msg);}if(jsSrc){if(force||!gloaddisableder._fetched[jsSrc]){gloaddisableder._fetched[jsSrc]={};gloaddisableder.expect(jsSrc);if(async){gloaddisableder._fetched[jsSrc].async=true;var headElement=document.getElementsByTagName("head")[0];var scriptElement=document.createElement("script");scriptElement.type="text/javascript";scriptElement.src=jsSrc;scriptElement.className="gloaddisableded async";headElement.appendChild(scriptElement);}else{gloaddisableder._fetched[jsSrc].sync=true;void('<script type="text/javascript" src="'+jsSrc+'" class="gloaddisableded sync"><\/script>\n');}}else{}if(gloaddisableder._modules[m.id].status<gloaddisableder.Module.FETCHED){gloaddisableder._modules[m.id].status=gloaddisableder.Module.FETCHED;}}},_fetched:{},provide:function(m){m.id=m.library[0]+"/"+m.library[1]+"/"+m.name;if(!gloaddisableder._modules[m.id]){gloaddisableder._extras[m.id]=m;return;}if(gloaddisableder._modules[m.id].status>=gloaddisableder.Module.PROVIDED){return;}gloaddisableder._modules[m.id].status=gloaddisableder.Module.PROVIDED;gloaddisableder._modules[m.id].builder=m.builder;gloaddisableder._modules[m.id].builder.args=[];var d=gloaddisableder._modules[m.id].depends=(m.depends)?gloaddisableder.toIds(m.depends):[];if(d.length>0){var includes=[];for(var i=0;i<d.length;i++){var requests=gloaddisableder.getRequests(m);var include={async:true,ids:[]};for(var j=0;j<requests.length;j++){requests[j].include(d[i]);include.ids.push(d[i]);if(requests[j].async===false){include.async=false;}}includes.push(include);if(d[i].match(/\/[^.]+$/)){gloaddisableder._modules[m.id].builder.args.push(d[i]);}}for(var i=0;i<includes.length;i++){if(includes[i].ids.length){gloaddisableder.request(includes[i].ids,includes[i].async);}}}else{gloaddisableder.implement(m);}gloaddisableder.resolve();},_greet:function(mId){if(gloaddisableder._expects[mId]>0){gloaddisableder._expects[mId]--;}else{var msg="Unexpected module provided to gloaddisableder: "+mId;gloaddisableder._errors.push(msg);throw (msg);}},module:function(modDef){var modId=modDef.library[0]+"/"+modDef.library[1]+"/"+modDef.name;gloaddisableder._greet(modId);if(!modDef.depends){modDef.depends=[];}modDef.depends.unshift(modDef.library);gloaddisableder.provide(modDef);},library:function(modDef){var modId=modDef.name+"/"+modDef.version+"/"+modDef.name;gloaddisableder._greet(modId);if(!modDef.depends){modDef.depends=[];}modDef.library=[modDef.name,modDef.version];gloaddisableder.provide(modDef);},implement:function(m){if(gloaddisableder._modules[m.id].status!=gloaddisableder.Module.PROVIDED){return;}for(var i=0;i<gloaddisableder._modules[m.id].builder.args.length;i++){var argName=gloaddisableder._modules[m.id].builder.args[i];gloaddisableder._modules[m.id].builder.args[i]=gloaddisableder._modules[m.builder.args[i]].implementation;gloaddisableder._modules[m.id].builder.args[i].name=argName;}gloaddisableder._modules[m.id].implementation=gloaddisableder._modules[m.id].builder.apply(null,gloaddisableder._modules[m.id].builder.args);gloaddisableder._modules[m.id].status=gloaddisableder.Module.IMPLEMENTED;for(var i=0;i<gloaddisableder._requests.length;i++){gloaddisableder._requests[i].release(m.id);}},resolve:function(){MODULES:for(var m in gloaddisableder._modules){var module=gloaddisableder._modules[m];if(module.status==gloaddisableder.Module.PROVIDED){for(var j=0;j<module.depends.length;j++){var dModule=gloaddisableder._modules[module.depends[j]];if(!dModule||dModule.status!=gloaddisableder.Module.IMPLEMENTED){continue MODULES;}}gloaddisableder.implement(module);gloaddisableder.resolve();}}},getRequests:function(m){var requests=[];REQUESTS:for(var i=0;i<gloaddisableder._requests.length;i++){var request=gloaddisableder._requests[i];for(var j=0;j<request.waits.length;j++){if(request.waits[j]==m.id){requests.push(request);break REQUESTS;}}}return requests;},toIds:function(lib){var result=[];for(var i=0;i<lib.length;i++){var mods=lib[i];var libName=mods.shift();var libVersion=mods.shift();var libId=libName+"/"+gloaddisableder.map.latest(libName,libVersion);result.push(libId+"/"+libName);for(var j=0;j<mods.length;j++){result.push(libId+"/"+mods[j]);}}return result;}};gloaddisableder.Request=function(r){this.waits=[];this.status=gloaddisableder.Request.INITIAL;if(r.onLoad){r.onloaddisabled=r.onLoad;}if(r.onTimeout){r.ontimeout=r.onTimeout;}if(!r.async&&!r.onloaddisabled){this.setGlobal=true;}this.async=(typeof r.async!="undefined")?r.async:false;this.onloaddisabled=r.onloaddisabled;if(r.ontimeout){if(typeof r.timeout=="undefined"){r.timeout=20000;}this.timeoutRef=setTimeout(r.ontimeout,r.timeout);}};gloaddisableder.Request.INITIAL=-1;gloaddisableder.Request.WAITING=0;gloaddisableder.Request.COMPLETED=1;gloaddisableder.Request.prototype.include=function(mId){for(var i=0;i<this.waits.length;i++){if(this.waits[i]==mId){return;}}this.waits.push(mId);};gloaddisableder.Request.prototype.release=function(mId){var implementCount=0;for(var i=0;i<this.waits.length;i++){var wModule=gloaddisableder._modules[this.waits[i]];if(wModule&&wModule.status==gloaddisableder.Module.IMPLEMENTED){implementCount++;}}if(implementCount==this.waits.length){this.complete();}};gloaddisableder.Request.prototype.complete=function(){if(this.setGlobal){for(var i=0;i<this.waits.length;i++){var gModule=gloaddisableder._modules[this.waits[i]];window[gModule.name]=gloaddisableder._modules[this.waits[i]].implementation;}}if(this.status==gloaddisableder.Request.COMPLETED){return;}this.status=gloaddisableder.Request.COMPLETED;if(this.timeoutRef){clearTimeout(this.timeoutRef);}for(var i=0;i<this.args.length;i++){this.args[i]=gloaddisableder._modules[this.args[i]].implementation;}if(this.onloaddisabled){this.onloaddisabled.apply(null,this.args);}};gloaddisableder.Module=function(mId){this.id=mId;this.name=mId.split("/").pop();this.status=gloaddisableder.Module.INITIAL;this.css=gloaddisableder.map.css[mId];};gloaddisableder.Module.INITIAL=-1;gloaddisableder.Module.REQUESTED=0;gloaddisableder.Module.FETCHED=1;gloaddisableder.Module.PROVIDED=2;gloaddisableder.Module.IMPLEMENTED=3;gloaddisableder.isReady=false;(function(){var d=document;if(
-/*@cc_on!@*/
-false){if(typeof window.frameElement!="undefined"){d.attachEvent("onreadystatechange",function(){if(d.readyState=="complete"){d.detachEvent("onreadystatechange",arguments.callee);gloaddisableder.isReady=true;}});}else{(function(){try{d.documentElement.doScroll("left");}catch(e){setTimeout(arguments.callee,50);return;}gloaddisableder.isReady=true;})();}}else{if(typeof d.readyState!="undefined"){var f=function(){/loaddisableded|complete/.test(d.readyState)?gloaddisableder.isReady=true:setTimeout(f,10);};f();}else{var callback=function(){if(arguments.callee.fired){return;}arguments.callee.fired=true;if(gloaddisableder){gloaddisableder.isReady=true;}};if(d.addEventListener){d.addEventListener("DOMContentLoaded",callback,false);}var oldOnloaddisabled=window.onloaddisabled;window.onloaddisabled=function(){if(oldOnloaddisabled){oldOnloaddisabled();}callback();};}}})();gloaddisableder.map.setProperties=function(libraryName,props){if(typeof gloaddisableder.mapProps=="undefined"){gloaddisableder.mapProps={};}if(typeof gloaddisableder.mapProps[libraryName]=="undefined"){gloaddisableder.mapProps[libraryName]={};}for(var p in props){gloaddisableder.mapProps[libraryName][p]=props[p];}};gloaddisableder.use=function(name,opts){name=(name||"glow");opts=(opts||{});var properties={};for(var opts_name in opts){var property_name=(opts_name.indexOf("$")==0)?opts_name:"$"+opts_name;properties[property_name]=opts[opts_name];}properties.$debug=(properties.$debug||"");properties.$base=(properties.$base||gloaddisableder._baseDir+name+"/{$version}/");properties.$map=(properties.$map||gloaddisableder._baseDir+name+"/map.js");gloaddisableder.map.setProperties(name,properties);gloaddisableder.map.include(properties.$map);};})();(function(){var scripts=document.getElementsByTagName("script");for(var i=scripts.length-1;i>=0;i--){var src=scripts[i].getAttribute("src");var filespec=gloaddisableder.util.getGloaddisablederFile(src);if(typeof filespec!="undefined"){gloaddisableder._baseDir=filespec.dir;var gloaddisablederScript=scripts[i].innerHTML;if(/\S/.test(gloaddisablederScript)){eval(gloaddisablederScript);}var mapped=false;for(var p in gloaddisableder.map._include){mapped=true;continue;}if(!mapped){gloaddisableder.use();}break;}}})(); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/pixel.quantserve.com/pixel/p-ccrmZLtMqYB8w.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/pixel.quantserve.com/pixel/p-ccrmZLtMqYB8w.gif
deleted file mode 100755
index a7ab9529e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/pixel.quantserve.com/pixel/p-ccrmZLtMqYB8w.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/pixel.quantserve.com/pixel/r.html b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/pixel.quantserve.com/pixel/r.html
deleted file mode 100755
index e69de29bb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/pixel.quantserve.com/pixel/r.html
+++ /dev/null
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/sa.bbc.co.uk/bbc/bbc/s.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/sa.bbc.co.uk/bbc/bbc/s.gif
deleted file mode 100755
index 35d42e808..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/sa.bbc.co.uk/bbc/bbc/s.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/sa.bbc.co.uk/bbc/bbc/s.html b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/sa.bbc.co.uk/bbc/bbc/s.html
deleted file mode 100755
index 35d42e808..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/sa.bbc.co.uk/bbc/bbc/s.html
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.3.2/newnav/img/search_icon.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.3.2/newnav/img/search_icon.png
deleted file mode 100755
index ede38e21e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.3.2/newnav/img/search_icon.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/autosuggest_loader.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/autosuggest_loader.gif
deleted file mode 100755
index d568dc0d3..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/autosuggest_loader.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/blocks/dark.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/blocks/dark.png
deleted file mode 100755
index a03e8f486..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/blocks/dark.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/blocks/light.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/blocks/light.png
deleted file mode 100755
index ca04a45b4..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/blocks/light.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/main_sprite.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/main_sprite.png
deleted file mode 100755
index 93fb6c412..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/main_sprite.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mast_bg.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mast_bg.png
deleted file mode 100755
index 78139475b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mast_bg.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mast_colours.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mast_colours.png
deleted file mode 100755
index 3a16de88d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mast_colours.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/more_arrow.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/more_arrow.png
deleted file mode 100755
index 1cdd516e9..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/more_arrow.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mothball/bg.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mothball/bg.jpg
deleted file mode 100755
index 130aac8e1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mothball/bg.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mothball/i.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mothball/i.gif
deleted file mode 100755
index 1fcdabcb6..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/mothball/i.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/nav_divider.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/nav_divider.png
deleted file mode 100755
index 006e134f2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/nav_divider.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/panel.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/panel.png
deleted file mode 100755
index 695c8da79..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/panel.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/search_icon.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/search_icon.png
deleted file mode 100755
index ede38e21e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/search_icon.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/suggest_sprite.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/suggest_sprite.png
deleted file mode 100755
index 8f948f208..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/suggest_sprite.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/suggest_sprite_rtl.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/suggest_sprite_rtl.png
deleted file mode 100755
index 2129e0b07..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/suggest_sprite_rtl.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/tooltip.png b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/tooltip.png
deleted file mode 100755
index a030cc240..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/tooltip.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/script/barlesque.js b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/script/barlesque.js
deleted file mode 100755
index 0229aea4f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/script/barlesque.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(){var H,F,R,N=null,A={},P={searchSuggestion:"Search the BBC"},G={updateNoImagesState:function(){var S=F("#blq-search-btn")[0];if(S.currentStyle){var T=S.currentStyle.backgroundImage}else{if(window.getComputedStyle){var T=document.defaultView.getComputedStyle(S,null).getPropertyValue("background-image")}}if(T.indexOf("search_icon.png")==-1){return false}else{F("#blq-mast-home").removeClass("blq-no-images");return true}},searchTheBBCSearchHint:function(){var S=F("#blq-search");R(S,"focus",function(){if(S.val()==P.searchSuggestion){S.val("")}});R(S,"blur",function(){if(!S.val()){S.val(P.searchSuggestion)}});R(S.parent().parent(),"submit",function(T){if(S.val()==P.searchSuggestion){S.val("")}});if(S.val()==""&&!F(document.activeElement).eq(S)){S.val(P.searchSuggestion)}},addMorePanel:function(){var T=F("#blq-nav-links"),V=F("#blq-nav-main");T.css({visibility:"hidden",display:"block"});var S=F("body"),U=new H.widgets.Panel(F("#blq-nav-links"),{modal:false,hideWindowedFlash:false,width:T.width(),height:T.height(),template:'<div><div class="panel-hd"></div><div class="panel-bd"></div><div class="panel-ft"></div></div>',autoPosition:false,id:"blq-morepanel"}),X,W=function(){U.hide();V.removeClass("blq-morepanel-shown");unbind(X);return false},Z=function(){if(U.isShown){return false}U.show();V.addClass("blq-morepanel-shown");setTimeout(function(){X=R(document,"click",Y)},0);return false};T.css({visibility:""});U.container.addClass("blq-overlay").addClass("blq-gvl-3").addClass("blq-rst").appendTo("#blq-container-inner");R("#blq-nav-m a","click",Z);function Y(a){if(a.source!=U.container[0]&&!F(a.source).isWithin(U.container)){W()}}},mapPublicApi:function(){if(!window.blqOnDomReady){window.blqOnDomReady=H.ready}},addAutosuggest:function(){var S=this;if(!blq.suggest){blq.suggest=function(T){if(S.suggestion&&S.suggestion._pendingRequest){clearTimeout(S.suggestion._pendingRequest._timeout)}S.suggestion._pendingRequest=null;S.suggestion.setData(T[1]||[]);S.suggestion.find()}}H.ready(function(){var T=document.getElementById("blq-search");if(!T){return false}T.setAttribute("autocomplete","off");T.onfocus=function(){if(document.getElementById("blq-autosuggest")){return false}gloaddisableder.loaddisabled(["glow","1","glow.dom","glow.net","glow.widgets.AutoSuggest"],{async:true,onLoad:function(U){U.ready(function(){var X=U.dom.get;var W=X("#blq-mast input").filter(function(Y){return X(this).attr("name")=="scope"});W=(W.length)?W.attr("value"):"all";S.noData=false;var V=U.dom.get("#blq-container-inner").hasClass("blq-rtl");S.suggestion=new U.widgets.AutoSuggest("#blq-search",[],{index:"title",maxListLength:blq.suggest_short?3:6,activeOnShow:false,useCache:true,formatItem:function(Z){var Y=Z.title;if(Y.length>28){Y=Z.title.substring(0,25)+"...";Y+='<span class="blq-hide">'+Z.title.substring(25,Z.title.length)+"</span>"}return Y},isMatch:function(){return this.data.length?true:false},onInputChange:function(a){a.preventDefault();if(this.noData){return false}U.dom.get("#suggid").remove();if(this._pendingRequest){this._pendingRequest.abort()}var Z=this;var Y=U.data.encodeUrl({q:a.value,scope:W,format:"blq-1",callback:"blq.suggest"});this._pendingRequest=U.net.loaddisabledScript(this.searchHost+"/suggest?"+Y,{useCache:true,charset:"utf-8",onError:function(){Z.inputElement.attr("autocomplete","on");Z.noData=true},timeout:5});U.dom.get("#blq-search-btn").addClass("loaddisableding")},onDataError:function(Y){this.inputElement.attr("autocomplete","on")},onItemSelect:function(a){this.setValue(a.selectedItem.title);var Y=U.dom.get("#suggid");if(!Y.length){Y=U.dom.create('<input type="hidden" name="suggid" id="suggid" />');U.dom.get("#blq-mast form").prepend(Y)}Y.val(a.selectedItem.id);var Z=U.dom.get("#blq-mast form");Z[0].submit()}});S.suggestion.searchHost=S.searchHost||"httpdisabled://search.bbc.co.uk";S.suggestion.overlay.container.attr("id","blq-autosuggest");S.suggestion.overlay.container.addClass("blq-rst");if(V){S.suggestion.overlay.container.addClass("blq-rtl")}S.suggestion.overlay.opts.hideWindowedFlash=false;U.events.addListener(S.suggestion,"show",function(){U.dom.get("#blq-search-btn").removeClass("loaddisableding")})})}});T.onfocus=function(){}}})},setARIAValues:function(){F("#blq-acc").attr("role","navigation");F("#blq-search").attr("role","search");F("#blq-local-nav").attr("role","navigation");F("#blq-content").attr("role","main");F("#blq-nav-main").attr("role","navigation");F("#blq-nav").attr("role","navigation");F("#blq-foot").attr("role","contentinfo")},defaultGoTracking:function(){E("blq-acc",{go:"{id}3/{dir}"});E("blq-mast",{go:"{id}3/{dir}"});E("blq-nav",{go:"{id}3/{dir}"});E("blq-disclaim",{go:"{id}3/{dir}"});E("blq-sitelinks",{go:"{id}3/{count}/{dir}"});E("blq-bbclinks",{go:"{id}3/{dir}"});E("blq-nav-links",{go:"{id}3/{dir}"});E("blq-main",{external:true});if(blq.externalGoTrackingConfig){for(var U in blq.externalGoTrackingConfig){var T=blq.externalGoTrackingConfig[U];var S=H.dom.get(U);if(S.length){E(S,{go:T,external:true})}}}}};function C(){return(document.getElementById&&document.getElementsByTagName)}function E(V,f){var V=document.getElementById(V)||V,f=f||{},W=V.nodeName=="A"?[V]:V.length?V:V.getElementsByTagName("a"),k=f.external||false,h=f.path||window.location.toString().split("bbc.co.uk/")[1],d=V.id?V.id.replace(/-/g,"/"):"_auto",b=f.go||"{path}/int/{id}/{dir}",m=f.currentServer||window.location.href.split("//")[1].split("/")[0];for(var n=0;n<W.length;n++){var X=false,o=false;if((typeof W[n]!="object")||(!W[n].href)||W[n].className.indexOf("blq-nogo")!=-1||W[n].href.indexOf("/go/")!=-1||W[n].href.charAt(0)=="#"||W[n].href.charAt(window.location.toString().split("#")[0].length)=="#"||W[n].href.indexOf("mailto:")==0||W[n].href.indexOf("javascript:")==0||W[n].href.indexOf("itpc:")==0||W[n].href.indexOf("zune:")==0||W[n].href.indexOf("zcast:")==0){continue}if(W[n].href.indexOf("bbc.co.uk")!=-1&&W[n].href.indexOf("#")!=-1){if(W[n].href.indexOf(h+"#")!=-1){continue}}var c=m.replace(/\./g,"\\."),j=W[n].href.split("?")[0],l=new RegExp("^[A-Za-z]+:\\/\\/(?:[^.]+\\.)*(?:bbc\\.co\\.uk|doubleclick\\.net|"+c+")");if(!l.test(j)){if(f.go){var g=j.split("/")[2],X=true,T="/"+b.replace("{dir}",g).replace("{count}",n+1).replace("{path}",h).replace("{id}",d).replace("#","_")}else{var Y=location.pathname,X=true,T=Y+(Y.charAt(Y.length-1)=="/"?"":"/")+"ext/_auto"}}else{if(k){continue}else{var e=j.split("/"),T=b,S=e.length<5?e[e.length-1]||e[e.length-2]:e[e.length-2]||e[e.length-1];T=T.replace("{dir}",S);T=T.replace("{count}",n+1);T=T.replace("{path}",h);T=T.replace("{id}",d);T=T.replace("#","_");T="/"+T}}var Z=W[n].onclick,a,U=false;if(j.indexOf("www.bbc.co.uk")!=-1){a="httpdisabled://www.bbc.co.uk/go"+T+"/-/"+W[n].href.substring(W[n].href.indexOf("bbc.co.uk/")+10,W[n].href.length)}else{if(W[n].href.indexOf("www.bbc.com")!=-1){a="httpdisabled://www.bbc.com/go"+T+"/-/"+W[n].href.substring(W[n].href.indexOf("httpdisabled://www.bbc.com/"),W[n].href.length)}else{if(X||W[n].href.indexOf(m)==-1){a="/go"+T+"/-/"+W[n].href}else{a="/go"+T+"/-/"+W[n].href.substring(W[n].href.indexOf(m)+(m.length+1),W[n].href.length)}}}if(!W[n].blqGoTrackingHref){W[n].onclick=(function(){var i=Z;return function(){this.href=this.blqGoTrackingHref;if(typeof i=="function"){i()}}})()}W[n].blqGoTrackingHref=a}}function B(S){if(I[S]){delete I[S]}if(S=="addGoTrack"||S=="defaultGoTracking"){I.addGoTrack=function(){};I.addGoTrack.isStub=true}}function Q(){return N}function J(S){N=S}function K(S){return A[S]}function M(S,T){A[S]=T}function O(S,T){P[S]=T}function D(U,S){if(U.createTextRange){var T=U.createTextRange();T.moveStart("character",S);T.moveEnd("character",S-U.value.length);T.select()}else{if(U.selectionStart){U.focus();U.setSelectionRange(S,S)}else{U.focus()}}}function L(T){if(C()){H=T,F=T.dom.get,R=T.events.addListener;unbind=T.events.removeListener;for(var S in I){I[S]()}}}var I=(function(){return G})();window.blq={addGoTrack:E,disableFeature:B,environment:Q,setEnvironment:J,setLabel:O,flagpole:K,setFlagpole:M,availableFeatures:I};if(window.gloaddisableder){document.documentElement.className+=" blq-js";gloaddisableder.loaddisabled(["glow","1","glow.dom","glow.widgets.Panel"],{async:true,onLoad:function(S){S.ready(function(){L(S)})}})}})();var demi=(function(){var C=false,B=[],A=null;return{_reset:function(){C=false;B=[];A=null},_loaddisableded:function(){while(B.length>0){demi.getDevice(B.shift(),blq.environment())}},_addScriptTag:function(F){var D=document.getElementsByTagName("head")[0];var E=document.createElement("script");E.type="text/javascript";E.src=F;D.insertBefore(E,D.firstChild)},_setSource:function(D){A=D},getDevice:function(D){B.push(D);if(!C){C=true;demi._addScriptTag(A)}}}})(); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/style/main.css b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/style/main.css
deleted file mode 100755
index 3faacf7dc..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/style/main.css
+++ /dev/null
@@ -1 +0,0 @@
-body{font-size:62.5%;font-family:verdana,helvetica,arial,sans-serif;line-height:1;}body,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,legend,input,p,blockquote,th,td,hr{margin:0;padding:0;}h1,h2,h3,h4,h5,h6{font-size:100%;}table{border-collapse:collapse;border-spacing:0;}caption{text-align:left;font-weight:normal;}th{text-align:left;}cite,address{font-style:normal;}ol,ul{list-style:none;}sub,sup{line-height:2;}img{border:none;}pre,code{font-size:1.2em;}fieldset{border:0;}q:before,q:after{content:'';}.blq-rst{font-family:verdana,helvetica,arial,sans-serif;}.blq-rst dl,.blq-rst dt,.blq-rst dd,.blq-rst ul,.blq-rst ol,.blq-rst li,.blq-rst h1,.blq-rst h2,.blq-rst h3,.blq-rst h4,.blq-rst h5,.blq-rst h6,.blq-rst pre,.blq-rst form,.blq-rst fieldset,.blq-rst caption,.blq-rst p,.blq-rst blockquote,.blq-rst th,.blq-rst td,.blq-rst hr{margin:0;padding:0;line-height:1;font-size:100%;background-color:transparent;}.blq-rst *,.blq-rst input,.blq-rst a:link,.blq-rst a:visited{margin:0;padding:0;line-height:1;font-size:100%;font-family:verdana,helvetica,arial,sans-serif;text-decoration:none;font-weight:normal;text-transform:none;}.blq-rst table{border-collapse:collapse;border-spacing:0;}.blq-rst caption,.blq-rst legend{text-align:left;font-weight:normal;}.blq-rst th{text-align:left;}.blq-rst cite,.blq-rst address{font-style:normal;}.blq-rst ol,.blq-rst ul{list-style:none;}.blq-rst sub,.blq-rst sup{line-height:2;}.blq-rst img{border:none;}.blq-rst input,.blq-rst pre,.blq-rst code{font-size:1.1em;}.blq-rst fieldset{border:0;}.blq-rst q:before,.blq-rst q:after{content:'';}.blq-rst h1,.blq-rst h2,.blq-rst h3,.blq-rst h4,.blq-rst h5,.blq-rst h6,.blq-rst th,.blq-rst strong{font-weight:bold;}.blq-rst dt{font-weight:normal;}body{background:#fff;}.blq-hide{position:absolute;left:-2500px;width:1px;overflow:hidden;}.blq-clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#blq-container{position:relative;padding-bottom:10px;}#blq-pre-mast,#blq-container-inner{width:974px;margin:0 auto;}#blq-pre-mast{z-index:1;}#blq-container-inner{background-color:#fff;position:relative;padding-top:70px;}#blq-pre-mast,#blq-acc,#blq-mast,#blq-main,#blq-foot,#blq-nav{font-size:1.2em;line-height:1.3;font-family:verdana,helvetica,arial,sans-serif;color:#fff;}#blq-pre-mast,#blq-acc,#blq-mast,#blq-main,#blq-foot{position:relative;}#blq-mast,#blq-foot,#blq-nav{direction:ltr;}#blq-main{line-height:1;color:#000;background-color:#fff;}#blq-mast p,#blq-foot p{margin:0;padding-bottom:0;}#blq-acc ul,#blq-foot ul,#blq-foot li{list-style:none;margin:0;line-height:1.3;}#blq-acc a,#blq-mast a,#blq-foot a{text-decoration:none;font-weight:normal;}#blq-acc a:hover,#blq-mast a:hover{color:#fff;}#bbccom_bottom{width:468px;margin:14px 0 0 14px;padding:0;}#blq-acc{position:absolute;top:0;left:0;width:974px;height:69px;border-bottom:1px solid #ccc;z-index:5;}#blq-mast-home.blq-no-images{background-color:#000;}#blq-mast-home{position:absolute;top:19px;width:974px;height:50px;background:transparent url(../img/mast_bg.png) top repeat-x;}#blq-mast-home a{display:block;color:#ccc;font-size:.95em;height:24px;width:84px;padding:0;margin:8px 0 0 8px;}#blq-mast-home span.blq-home,#blq-mast-home .blq-span{position:relative;bottom:11px;left:18px;}#blq-mast-home span.blq-home{text-indent:-2000em;display:block;height:0;}#blq-mast-home a:hover,#blq-nav-main a:hover{background:left -144px url(../img/main_sprite.png) repeat-x;}#blq-mast-home a:hover{background-position:-2px -144px;}#blq-blocks{border:none;}#blq-acc-links{height:19px;width:974px;font-size:.9em;background-color:#fff;}#blq-acc li{float:left;overflow:visible;}#blq-acc-links a{line-height:1.3;color:#000;}#blq-acc-links a:hover{color:#000;text-decoration:underline;}#blq-acc li.blq-hide a:focus,#blq-acc li.blq-hide a:active{position:absolute;top:70px;left:2500px;width:966px;opacity:.9999;font-weight:bold;padding:2px;background:#ff9;border:2px solid #000;z-index:999;}#blq-acc-txt{padding-right:12px;}#blq-acc-help,#blq-acc-mobile{padding:0 12px;background:-186px -112px url(../img/main_sprite.png) no-repeat;}#blq-acc-txt,#blq-acc-help,#blq-acc-mobile{position:relative;top:3px;left:14px;}.blq-toolbar-dark #blq-acc-links,.blq-toolbar-transp #blq-acc-links{background-color:#212121;}.blq-toolbar-dark #blq-acc-links a,.blq-toolbar-transp #blq-acc-links a{color:#fff;}.blq-toolbar-transp #blq-acc-links{opacity:.7;}#blq-mast{z-index:10;position:absolute;top:0;right:9px;left:9px;height:40px;background:#646464;background:rgba(0,0,0,0.7);width:884px;padding-left:92px;}#blq-mast p input{border:0 none;}#blq-mast p input:focus{outline:none;}#blq-mast #blq-search{width:137px;margin:0 -66px 0 0;position:absolute;left:4px;top:4px;height:20px;padding:2px 3px 0 10px;background:url(../img/main_sprite.png) -66px -194px no-repeat #fff;color:#000;line-height:1.2;-webkit-border-radius:0;-webkit-appearance:none;}#blq-mast #blq-search-btn{width:66px;margin:0;padding:0;position:absolute;right:4px;top:4px;color:#000;cursor:pointer;padding-bottom:2px;background:url(../img/main_sprite.png) 0 -194px no-repeat #efefef;height:22px;line-height:1.8;-webkit-border-radius:0;-webkit-appearance:none;}#blq-autosuggest{overflow:visible;margin-top:0;padding:0;margin-left:0;background:transparent none no-repeat 0 0;}#blq-autosuggest.blq-rtl{margin-left:-29px;}#blq-autosuggest ul{border:none;background:#dcdcdc none no-repeat 0 bottom;width:215px;padding:0;}#blq-autosuggest li{padding:7px 10px 7px 8px;font-size:1.2em;border-top:none;color:#333;background:transparent;}#blq-autosuggest li.active{background-color:#575757;color:#fff;}#blq-mast form p{position:absolute;height:22px;border:none;bottom:auto;padding:0;right:0;top:0;width:215px;}#blq-mast form.active p{background:transparent url(../img/suggest_sprite.png) no-repeat 0 0;}#blq-mast form.active #blq-search,#blq-mast form.active #blq-search-btn{background:none;}.blq-gvl-3 #blq-mast #blq-search-btn{width:66px;margin:0;padding:0;position:absolute;right:4px;top:4px;color:#000;cursor:pointer;padding-bottom:2px;background:url(../img/main_sprite.png) 0 -194px no-repeat #fff;height:22px;line-height:1.8;}#blq-nav-main li{display:inline;}#blq-nav-main a{display:block;float:left;height:30px;width:78px;padding-top:20px;text-align:center;color:#ccc;background:left -94px url(../img/main_sprite.png) no-repeat;font-size:.95em;}#blq-nav-w a{width:90px;}#blq-nav-i a,#blq-nav-tr a{width:84px;}#blq-nav-t a{width:56px;}#blq-nav-m a{width:82px;}.blq-lang-cy-GB #blq-nav-i a{padding-top:14px;height:36px;}.blq-lang-cy-GB #blq-mast .blq-tooltip,.blq-lang-cy-GB #blq-mast-home .blq-tooltip{display:none;}.blq-lang-gd-GB #blq-nav-n a{width:104px;}.blq-lang-gd-GB #blq-nav-s a{width:68px;}.blq-lang-gd-GB #blq-nav-w a{width:74px;}.blq-lang-ga-GB #blq-nav-w a{width:75px;}.blq-lang-ga-GB #blq-nav-t a{width:76px;}.blq-lang-ga-GB #blq-nav-i a{width:79px;}.blq-cbeebies #blq-nav-i a{padding-top:14px;height:36px;}.blq-cbbc #blq-nav-n a{width:91px;}.blq-cbbc #blq-nav-s a{width:100px;}.blq-cbbc #blq-nav-w a{width:79px;}.blq-cbbc #blq-nav-i a{width:68px;padding-top:14px;height:36px;}.blq-cbbc #blq-nav-t a{width:51px;padding:14px 5px 0 5px;height:36px;}.blq-cbbc #blq-nav-r a{width:64px;}.blq-cbbc #blq-nav-m a{width:82px;}#blq-nav-m a:hover{background-position:left -240px;}.blq-js .blq-int-nav #blq-nav-links{left:80px;}.blq-int-nav #blq-nav-m a{margin-left:370px;padding-left:10px;width:162px;}#blq-nav{clear:both;font-size:1.1em;line-height:1.3;border-top:1px solid #ccc;background-color:#f9f9f9;}#blq-nav h2{margin:7px 0 7px 14px;font-size:1.3em;}#blq-nav a{text-decoration:none;font-weight:normal;}.blq-js #blq-nav h2{position:absolute;left:-2500px;width:1px;}.blq-js #blq-nav{border:none;}#blq-nav-links{width:486px;border-right:1px solid #ccc;padding-bottom:10px;}.blq-js #blq-nav-links{display:none;width:505px;position:absolute;top:0;left:160px;z-index:999;border:none;}.blq-js #blq-nav-links-inner{padding-top:8px;background-image:url(../img/panel.png);width:100%;}.blq-js #blq-nav-links-inner a{position:relative;}.blq-js #blq-nav-links-inner:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#blq-nav .blq-no-images{border:1px solid #ccc;background-color:#efefef;}#blq-pop a,#blq-az a{position:relative;display:block;color:#000;background:url(../img/main_sprite.png);}#blq-az a{float:right;padding:3px 0 5px 5px;width:146px;margin-top:2px;}#blq-pop a{float:left;width:135px;padding:5px 0 7px 15px;margin-left:10px;}#blq-az a:hover{color:#fff;}#blq-pop{float:left;}#blq-pop li,#blq-az{display:inline;}.blq-js #blq-az a{margin-right:26px;}.blq-js #blq-pop a{padding-bottom:5px;}.blq-js #blq-pop{background:none;}.blq-nav-sub{float:left;width:160px;}.blq-first{clear:both;}.blq-nav-sub li{display:inline;}.blq-nav-sub a,.blq-nav-sub a:link,.blq-nav-sub a:visited{position:relative;display:block;padding:3px 0 4px 5px;margin-left:8px;color:#545454;font-weight:normal;}.blq-nav-sub a:hover{color:#fff;}.blq-js .blq-nav-sub{border-top:none;}.blq-js #blq-nav-links-inner .blq-last{width:159px;}#blq-eng{height:22px;padding:6px 0 0 13px;color:#000;}.blq-js #blq-nav-foot{clear:both;width:100%;height:29px;padding-top:3px;background:url(../img/panel.png) bottom;}#blq-obit{display:none;visibility:hidden;}#blq-mothball{background:url(../img/mothball/bg.jpg) 0 0 repeat-x #fbfbfb;}#blq-mothball a{display:block;height:56px;background:url(../img/mothball/i.gif) 230px 10px no-repeat;color:#666;font-size:2em;text-decoration:none;padding-left:300px;padding-top:17px;}#blq-mothball-sub{display:block;font-size:.5em;padding:10px 0 0 70px;font-weight:bold;}#blq-mothball-sub span{color:#1A75BB;margin-left:5px;}a:hover #blq-mothball-sub span{text-decoration:underline;}.blq-rtl #blq-mast #blq-search{background:url(../img/main_sprite.png) 148px -217px no-repeat #fff;position:absolute;left:70px;top:4px;text-align:right;margin:0;padding:2px 8px 0 5px;}.blq-rtl #blq-mast #blq-search-btn{background:url(../img/main_sprite.png) -2px -217px no-repeat #efefef;position:absolute;left:4px;top:4px;}.blq-rtl #blq-mast-home span.blq-home{text-indent:2000em;bottom:5em;}.blq-rtl #blq-acc{left:auto;right:9px;}.blq-rtl #blq-mast{direction:rtl;}.blq-rtl #blq-nav-main{right:auto;left:227px;background-position:94% 19px;}.blq-rtl #blq-morepanel{right:auto;left:280px;}#blq-container.blq-int-nav #blq-container-inner.blq-rtl #blq-morepanel{left:18px;}.blq-int-nav #blq-nav-m a{margin-left:0;}.blq-rtl #blq-eng{padding:6px 13px 0 0;}.blq-rtl #blq-foot{direction:rtl;}.blq-gvl-3 .blq-rtl #blq-foot #blq-logo{float:right;}.blq-gvl-3 .blq-rtl #blq-foot #blq-disclaim{float:right;clear:right;}.blq-gvl-3 .blq-rtl #blq-footlinks{float:left;}.blq-gvl-3 .blq-rtl #blq-bbclinks{text-align:right;}.blq-rtl #blq-mast-home a{margin:8px 8px 0 0;}.blq-rtl #blq-mast{padding-left:0;padding-right:92px;}.blq-rtl #blq-mast form p{right:auto;left:16px;}.blq-rtl #blq-mast-home a{margin:8px 8px 0 0;}.blq-rtl #blq-mast{padding-left:0;padding-right:92px;}.blq-rtl #blq-mast form p{right:auto;left:16px;}.blq-rtl #blq-acc .blq-hide{direction:rtl;}.blq-rtl #blq-mast form.active p{background:transparent url(../img/suggest_sprite_rtl.png) no-repeat -224px 0;}.blq-tooltip{position:absolute;margin-top:-2.9em;margin-left:-2500px;height:32px;width:30em;z-index:999;text-decoration:none;font-weight:normal;line-height:1.1;}a.blq-tooltipped:hover .blq-tooltip,.blq-tooltipped:focus .blq-tooltip{margin-left:-50px;}a.blq-tooltipped:hover .blq-tipunder,.blq-tooltipped:focus .blq-tipunder{margin-top:1.8em;}a.blq-tooltipped:hover .blq-tipright,.blq-tooltipped:focus .blq-tipright{margin-left:auto;margin-left:-30em;}.blq-tooltip-l{padding:6px 0 12px 13px;color:#000;background:url(../img/tooltip.png) 0 -36px no-repeat;float:left;}.blq-tooltip-r{padding:6px 3px 12px 0;background:url(../img/tooltip.png) right -36px no-repeat;float:left;}.blq-tipunder .blq-tooltip-l{padding:10px 0 14px 13px;background-position:0 0;}.blq-tipunder .blq-tooltip-r{padding:10px 3px 14px 0;background-position:right 0;}.blq-tipright .blq-tooltip-l{padding:5px 8px 14px 0;background-position:right -72px;float:right;}.blq-tipright .blq-tooltip-r{padding:5px 0 14px 11px;background-position:0 -72px;float:right;}.blq-blue #blq-pop a:hover{color:#242B6C;}.blq-blue #blq-pop a,.blq-blue .blq-nav-sub a:hover,.blq-blue #blq-az a{background-color:#4264A7;}.blq-sky #blq-pop a:hover{color:#023F6D;}.blq-sky #blq-pop a,.blq-sky .blq-nav-sub a:hover,.blq-sky #blq-az a{background-color:#057CB5;}.blq-teal #blq-pop a:hover{color:#013E60;}.blq-teal #blq-pop a,.blq-teal .blq-nav-sub a:hover,.blq-teal #blq-az a{background-color:#2591AB;}.blq-lime #blq-pop a:hover{color:#678C00;}.blq-lime #blq-pop a,.blq-lime .blq-nav-sub a:hover,.blq-lime #blq-az a{background-color:#9CBF00;}.blq-green #blq-pop a:hover{color:#1E5900;}.blq-green #blq-pop a,.blq-green .blq-nav-sub a:hover,.blq-green #blq-az a{background-color:#329600;}.blq-aqua #blq-pop a:hover{color:#00574C;}.blq-aqua #blq-pop a,.blq-aqua .blq-nav-sub a:hover,.blq-aqua #blq-az a{background-color:#008A79;}.blq-khaki #blq-pop a:hover{color:#4C482C;}.blq-khaki #blq-pop a,.blq-khaki .blq-nav-sub a:hover,.blq-khaki #blq-az a{background-color:#8A8459;}.blq-magenta #blq-pop a:hover{color:#800143;}.blq-magenta #blq-pop a,.blq-magenta .blq-nav-sub a:hover,.blq-magenta #blq-az a{background-color:#FF0286;}.blq-rose #blq-pop a:hover{color:#6D1448;}.blq-rose #blq-pop a,.blq-rose .blq-nav-sub a:hover,.blq-rose #blq-az a{background-color:#B11F7B;}.blq-purple #blq-pop a:hover{color:#5A266A;}.blq-purple #blq-pop a,.blq-purple .blq-nav-sub a:hover,.blq-purple #blq-az a{background-color:#884593;}.blq-red #blq-pop a:hover{color:#A00000;}.blq-red #blq-pop a,.blq-red .blq-nav-sub a:hover,.blq-red #blq-az a{background-color:#E50000;}.blq-orange #blq-pop a:hover{color:#A64100;}.blq-orange #blq-pop a,.blq-orange .blq-nav-sub a:hover,.blq-orange #blq-az a{background-color:#FF9A1F;}#blq-nav-links #blq-pop a{background-position:-12px -69px;background-repeat:no-repeat;}#blq-nav-links #blq-az a{background-position:-22px -5px;background-repeat:no-repeat;}#blq-nav-links #blq-az a:hover{background-position:-22px -34px;}#blq-foot{clear:both;background-color:#646464;border-top:1px solid #ccc;}#blq-foot p,#blq-foot li,#blq-foot a{font-size:.95em;line-height:1.4;color:#fff;}#blq-foot a{color:#fff;text-decoration:none;}#blq-foot a:hover{color:#d9d9d9;}#blq-footlinks{float:right;width:550px;margin:10px 14px 0 0;}#blq-sitelinks,#blq-bbclinks{text-align:right;background-color:#646464;}#blq-sitelinks{float:left;width:230px;}#blq-bbclinks{float:right;width:320px;}#blq-bbclinks li{float:right;width:160px;}#blq-foot #blq-copy{font-size:1.4em;padding-top:8px;margin-left:13px;width:10em;}#blq-copy img{position:relative;top:5px;}#blq-foot #blq-disclaim{padding:9px 0 12px 0;margin-left:14px;width:19em;}#blq-container .blq-foot-white,.blq-foot-white #blq-sitelinks,.blq-foot-white #blq-bbclinks{background-color:#fff;color:#000;}#blq-container .blq-foot-white a,#blq-container .blq-foot-white p{color:#000;}#blq-container .blq-foot-white a:hover{color:#666;}#blq-container .blq-foot-black,.blq-foot-black #blq-sitelinks,.blq-foot-black #blq-bbclinks{background-color:#000;}#blq-container .blq-foot-black a:hover{color:#b2b2b2;}.skylightTheme #blq-mast-home{background:0 200px #1778B3;}.skylightTheme #blq-acc{border-bottom-color:#45AAE6;}.doveTheme #blq-mast-home{background:0 550px #5B688F;}.doveTheme #blq-acc{border-bottom-color:#7C8EC2;}.tealTheme #blq-mast-home{background:0 100px #2383A3;}.tealTheme #blq-acc{border-bottom-color:#53B5D6;}.aquaTheme #blq-mast-home{background:0 600px #158979;}.aquaTheme #blq-acc{border-bottom-color:#3CBCAB;}.greenTheme #blq-mast-home{background:0 500px #5D891B;}.greenTheme #blq-acc{border-bottom-color:#80BC25;}.violetTheme #blq-mast-home{background:0 50px #6A5789;}.violetTheme #blq-acc{border-bottom-color:#A496BC;}.purpleTheme #blq-mast-home{background:0 300px #823892;}.purpleTheme #blq-acc{border-bottom-color:#B56CC5;}.pinkTheme #blq-mast-home{background:0 350px #9D1767;}.pinkTheme #blq-acc{border-bottom-color:#D04283;}.oliveTheme #blq-mast-home{background:0 450px #7C7854;}.oliveTheme #blq-acc{border-bottom-color:#AFAC92;}.suedeTheme #blq-mast-home{background:0 150px #695C4A;}.suedeTheme #blq-acc{border-bottom-color:#9C896E;}.redTheme #blq-mast-home{background:0 250px #9E2C1D;}.redTheme #blq-acc{border-bottom-color:#D15A4A;}.orangeTheme #blq-mast-home{background:0 400px #C55F16;}.orangeTheme #blq-acc{border-bottom-color:#DC7D2A;}.blackTheme #blq-acc{border-bottom-color:#505153;}.blq_hp #blq-mast-home{background-image:url(../img/mast_colours.png);}.blq_hp #blq-mast-home a,.blq_hp #blq-nav-main a{color:#fff;}.blq_hp #blq-pop .blq-last{display:none;}.bbcdotcomAdvertsResetBottom .blq-dotcom #blq-footlinks{width:550px;}.bbcdotcomAdvertsResetBottom .blq-dotcom #blq-sitelinks{width:230px;}.blq-dotcom #blq-footlinks{width:470px;}.blq-dotcom #blq-sitelinks{width:150px;}@media print{#blq-obit,#blq-mast,#blq-mast p,#blq-nav-main,#blq-nav,#blq-acc-links{display:none;}#blq-acc{border-bottom:1px solid #000;}#blq-foot{border-top:1px solid #000;}}#blq-container.blq-gvl-3{padding:0;}.blq-gvl-3 .blq-rst *,.blq-gvl-3 .blq-rst input,.blq-gvl-3 .blq-rst a:link,.blq-gvl-3 .blq-rst a:visited{font-family:arial,helvetica,sans-serif;}.blq-gvl-3 #blq-pre-mast,.blq-gvl-3 #blq-acc,.blq-gvl-3 #blq-mast,.blq-gvl-3 #blq-main,.blq-gvl-3 #blq-foot,.blq-gvl-3 #blq-nav{font-size:1.3em;line-height:1.6em;font-family:arial,sans-serif;}.blq-gvl-3 #blq-mast.blq-mast-light{background:rgba(0,0,0,0.4);}.blq-gvl-3 #blq-pre-mast,.blq-gvl-3 #blq-container-inner{width:976px;}.blq-gvl-3 #blq-container-inner{padding:40px 9px 0 9px;background:transparent;}.blq-gvl-3 #blq-acc{height:40px;border:none;position:auto;z-index:11;width:92px;left:9px;}.blq-gvl-3 #blq-acc-links{font-size:1.0em;background:none;margin-left:87px;font-size:.923em;position:absolute;z-index:12;width:250px;}.blq-gvl-3 #blq-acc-links li{padding:13px 7px 0;}.blq-gvl-3 #blq-acc-links a{color:#fff;line-height:14px;}.blq-gvl-3 #blq-acc-txt,.blq-gvl-3 #blq-acc-help,.blq-gvl-3 #blq-acc-mobile{top:0;}.blq-gvl-3 #blq-acc-mobile{background:none;line-height:14px;}.blq-gvl-3 #blq-acc-links li{padding:14px 7px 0;}.blq-gvl-3 #blq-acc-links a{color:#fff;line-height:100%;}.blq-gvl-3 #blq-acc-txt,.blq-gvl-3 #blq-acc-help,.blq-gvl-3 #blq-acc-mobile{top:0;}.blq-gvl-3 #blq-acc-mobile{background:none;position:static;float:left;padding:0 0 0 8px;}.blq-gvl-3 #blq-acc-mobile a{color:#fff;padding:14px 8px;display:block;font-size:.923em;}.blq-gvl-3 #blq-acc-txt,.blq-gvl-3 #blq-acc-help{display:none;}.blq-gvl-3 #blq-acc-txt a,.blq-gvl-3 #blq-acc-help a{color:#fff;line-height:1;}.blq-gvl-3 #blq-acc-help{display:none;}.blq-gvl-3 #blq-mast #blq-search{width:175px;padding:4px 4px 5px 7px;height:15px;font-size:.923em;color:#4c4c4c;background-image:none;left:auto;top:8px;right:37px;margin:0;}.blq-gvl-3 #blq-mast #blq-search.focused{color:#bbb;}.blq-gvl-3 #blq-mast #blq-search-btn,.blq-gvl-3 #blq-mast form.active #blq-search-btn{height:24px;width:29px;overflow:hidden;padding:0;border:none;background:#fff url('../img/search_icon.png') no-repeat center center;text-indent:-2000em;left:auto;top:8px;right:8px;}.blq-gvl-3 #blq-mast #blq-search-btn.loaddisableding{background-image:url('../img/autosuggest_loaddisableder.gif');}.blq-gvl-3 #blq-mast form.active #blq-search{background:#fff;}.blq-gvl-3 #blq-mast form.active p{background:#dcdcdc none no-repeat 0 0;color:#fff;}.blq-rtl #blq-mast #blq-search-btn{right:194px;}.blq-rtl #blq-acc-mobile{float:right;padding:0 8px 0 0;}.blq-rtl #blq-acc-mobile a{font-family:Nassim,arial,helvetica,sans-serif;padding-top:12px;padding-bottom:0;font-size:1.154em;}.blq-rtl #blq-mast #blq-search{right:8px;font-size:1.154em;font-weight:bold;font-family:Nassim,arial,helvetica,sans-serif;color:#505050;}.blq-gvl-3 #blq-mast-home{background:transparent;}.blq-gvl-3 #blq-mast-home{top:0;width:auto;height:40px;position:absolute;z-index:5;}.blq-gvl-3 #blq-mast-home a:hover{background:none;}.blq-gvl-3 #blq-mast-home img{height:24px;}.blq-gvl-3 #blq-mast-home .blq-span{bottom:16px;left:534px;position:absolute;display:none;}#blq-nav-main{position:absolute;right:227px;top:0;}.blq-gvl-3 #blq-nav-main a{height:26px;width:auto;padding:14px 7px 0 7px;font-size:.923em;color:#fff;background:url(../img/nav_divider.png) no-repeat right 13px;}.blq-gvl-3 #blq-nav-main #blq-nav-h a{background:none;}.blq-gvl-3 #blq-acc-links a:hover,.blq-gvl-3 #blq-nav-main a:hover,.blq-gvl-3 #blq-acc-mobile a:hover{color:#fff;text-decoration:underline;}.blq-gvl-3 #blq-nav-main #blq-nav-m a{background:none;margin-right:4px;padding-right:24px;background:url(../img/more_arrow.png) no-repeat scroll right 19px;}#blq-container-inner.blq-rtl #blq-nav-m a{background:none;margin-left:4px;padding-left:24px;padding-right:7px;margin-right:0;background:url(../img/more_arrow.png) no-repeat scroll left 19px;}#blq-container-inner.blq-rtl #blq-nav-main.blq-not-uk #blq-nav-m a{font-family:Nassim,arial,helvetica,sans-serif;font-size:1.154em;padding-top:12px;font-weight:normal;}#blq-container-inner.blq-rtl #blq-nav-main.blq-morepanel-shown #blq-nav-m a{background:url("../img/more_arrow.png") no-repeat scroll left -12px #DCDCDC;}.blq-js .blq-overlay{position:absolute;display:none;overflow:visible;}.blq-js .blq-morepanel-shown .overlay{display:block;}.blq-gvl-3 #blq-nav-links{display:block;width:336px;height:120px;font-size:1em;right:9px;border:none;padding:0;}#blq-container.blq-int-nav #blq-container-inner.blq-rtl #blq-nav-links{width:384px;}.blq-gvl-3 .blq-nav-sub{width:auto;}.blq-rtl .blq-nav-sub{text-align:left;}.blq-js .blq-gvl-3 #blq-nav-links-inner .blq-last{width:104px;}.blq-gvl-3 .blq-nav-sub a,.blq-gvl-3 .blq-nav-sub a:link,.blq-gvl-3 .blq-nav-sub a:visited,.blq-gvl-3 #blq-pop li a,.blq-gvl-3 #blq-az a{font-size:1.2em;margin:0;padding:4px 0 4px 8px;line-height:16px;width:104px;color:#333;}.blq-gvl-3 #blq-pop{clear:both;}.blq-gvl-3 #blq-pop li a{color:#000;}.blq-gvl-3 #blq-pop li a,.blq-gvl-3 #blq-nav-links #blq-az a{background:transparent;}#blq-nav-main.blq-morepanel-shown #blq-nav-m a,#blq-nav-main.blq-morepanel-shown #blq-nav-m a:hover{color:#333;margin-top:8px;padding-top:6px;background:#dcdcdc url(../img/more_arrow.png) no-repeat right -12px;}.blq-js .blq-gvl-3 #blq-nav-links{position:absolute;display:none;left:auto;background:#e9e9e9;background:#dcdcdc;}.blq-js .blq-overlay #blq-nav-links{display:block;}.blq-js .blq-gvl-3 #blq-nav-links-inner,.blq-js .blq-gvl-3 #blq-nav-foot{padding:0;background:transparent;height:auto;}.blq-js .blq-gvl-3 #blq-nav #blq-nav-foot a{font-weight:bold;}.blq-js .blq-gvl-3 #blq-nav-foot h3{border-top:#c1c1c1 solid 1px;left:8px;height:1px;width:320px;}.blq-gvl-3 #blq-pop a:hover,.blq-gvl-3 .blq-nav-sub a:hover,.blq-gvl-3 #blq-nav-links #blq-az a:hover{color:#fff;background-color:#333;}.blq-gvl-3 #blq-az a{float:left;}.blq-rtl #blq-az a{float:none;}.blq-gvl-3 #blq-acc li.blq-hide a:focus,.blq-gvl-3 #blq-acc li.blq-hide a:active{position:absolute;top:40px;left:3036px;width:336px;opacity:.9999;font-weight:normal;padding:8px;color:#333;background:#dcdcdc;border:none;}.blq-gvl-3 #blq-main{background:transparent;}#blq-morepanel{top:40px;right:0;}.blq-gvl-3 #blq-foot{clear:both;border:none;backround:none;}.blq-gvl-3 #blq-foot p,.blq-gvl-3 #blq-foot li,.blq-gvl-3 #blq-foot a{font-size:1em;line-height:normal;}.blq-gvl-3 #blq-footlinks{margin:0;}.blq-gvl-3 #blq-bbclinks{background-color:transparent;}.blq-gvl-3 #blq-foot #blq-copy{font-size:1em;padding:0;margin:0;width:auto;}.blq-gvl-3 #blq-foot #blq-disclaim{padding:0;margin:0;width:auto;line-height:normal;}.blq-gvl-3 #bbccom_bottom{margin:0;padding:0;}.blq-gvl-3 #blq-foot{font-size:1.2em;padding:16px 16px 13px 16px;width:944px;}.blq-gvl-3 #blq-foot p,.blq-gvl-3 #blq-foot li{color:#fff;}.blq-gvl-3 #blq-foot a:link,.blq-gvl-3 #blq-foot a:visited,.blq-gvl-3 #blq-foot a:hover,.blq-gvl-3 #blq-foot a:active,.blq-gvl-3 #blq-foot a{text-decoration:none;text-shadow:none;color:#fff;}.blq-gvl-3 #blq-foot a:hover{text-decoration:underline;}.blq-gvl-3 #blq-footlinks{float:right;width:320px;margin:-4px 0 0 0;}.blq-gvl-3 #blq-bbclinks{text-align:left;}.blq-gvl-3 #blq-bbclinks{float:right;width:320px;}.blq-gvl-3 #blq-bbclinks li{float:right;line-height:16px;padding-right:16px;width:144px;}.blq-gvl-3 #blq-foot #blq-copy{font-weight:bold;color:#fff;}.blq-gvl-3 #blq-foot #blq-logo{float:left;height:24px;width:84px;margin-bottom:23px;}.blq-gvl-3 #blq-foot #blq-disclaim{line-height:16px;clear:left;float:left;width:307px;}#blq-container.blq-gvl-3 .blq-foot-transparent{clear:both;font-size:1.2em;padding-left:0;width:960px;background-color:transparent;}#blq-container.blq-gvl-3 .blq-foot-text-dark{border-top:1px solid #4c4c4c;}#blq-container.blq-gvl-3 .blq-foot-text-dark a,#blq-container.blq-gvl-3 .blq-foot-text-dark p,#blq-container.blq-gvl-3 .blq-foot-text-dark #blq-copy{color:#4c4c4c;}#blq-container.blq-gvl-3 .blq-foot-text-light{border-top:1px solid #fff;}#blq-container.blq-gvl-3 .blq-foot-text-light a,#blq-container.blq-gvl-3 .blq-foot-text-light p{color:#fff;}#blq-container.blq-gvl-3 .blq-foot-opaque{background:none repeat scroll 0 0 rgba(0,0,0,0.7);}#blq-container.blq-gvl-3 .blq-foot-black{background-color:black;}.blq-gvl-3 #blq-foot #blq-promo{margin-top:-16px;margin-left:-16px;margin-bottom:16px;}.blq-gvl-3 #blq-foot.blq-foot-transparent #blq-promo{margin-top:0;margin-left:0;margin-bottom:16px;}.blq-gvl-3 #bbccom_bottom{float:left;margin-bottom:8px;margin-top:0;margin-left:16px;width:468px;height:60px;}.blq-gvl-3 #blq-container-inner{padding-top:0;}.blq-gvl-3 #blq-main{padding-top:40px;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/requirejs/0.6.4/sharedmodules/require.js b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/requirejs/0.6.4/sharedmodules/require.js
deleted file mode 100755
index 95e91e697..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/requirejs/0.6.4/sharedmodules/require.js
+++ /dev/null
@@ -1 +0,0 @@
-var require,define;(function(){var version="0.24.0",commentRegExp=/(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg,cjsRequireRegExp=/require\(["']([^'"\s]+)["']\)/g,currDirRegExp=/^\.\//,jsSuffixRegExp=/\.js$/,ostring=Object.prototype.toString,ap=Array.prototype,aps=ap.slice,apsp=ap.splice,isBrowser=!!(typeof window!=="undefined"&&navigator&&document),isWebWorker=!isBrowser&&typeof importScripts!=="undefined",readyRegExp=isBrowser&&navigator.platform==="PLAYSTATION 3"?/^complete$/:/^(complete|loaddisableded)$/,defContextName="_",isOpera=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",reqWaitIdPrefix="_r@@",empty={},contexts={},globalDefQueue=[],interactiveScript=null,isDone=false,useInteractive=false,req,cfg={},currentlyAddingScript,s,head,baseElement,scripts,script,src,subPath,mainScript,dataMain,i,scrollIntervalId,setReadyState,ctx;function isFunction(it){return ostring.call(it)==="[object Function]"}function isArray(it){return ostring.call(it)==="[object Array]"}function mixin(target,source,force){for(var prop in source){if(!(prop in empty)&&(!(prop in target)||force)){target[prop]=source[prop]}}return req}function configurePackageDir(pkgs,currentPackages,dir){var i,location,pkgObj;for(i=0;(pkgObj=currentPackages[i]);i++){pkgObj=typeof pkgObj==="string"?{name:pkgObj}:pkgObj;location=pkgObj.location;if(dir&&(!location||(location.indexOf("/")!==0&&location.indexOf(":")===-1))){location=dir+"/"+(location||pkgObj.name)}pkgs[pkgObj.name]={name:pkgObj.name,location:location||pkgObj.name,lib:pkgObj.lib||"lib",main:(pkgObj.main||"lib/main").replace(currDirRegExp,"").replace(jsSuffixRegExp,"")}}}if(typeof require!=="undefined"){if(isFunction(require)){return }else{cfg=require}}function newContext(contextName){var context,resume,config={waitSeconds:7,baseUrl:s.baseUrl||"./",paths:{},pkgs:{}},defQueue=[],specified={require:true,exports:true,module:true},urlMap={},defined={},loaddisableded={},waiting={},waitAry=[],waitIdCounter=0,managerCallbacks={},plugins={},pluginsQueue={},resumeDepth=0,normalizedWaiting={};function trimDots(ary){var i,part;for(i=0;(part=ary[i]);i++){if(part==="."){ary.splice(i,1);i-=1}else{if(part===".."){if(i===1&&(ary[2]===".."||ary[0]==="..")){break}else{if(i>0){ary.splice(i-1,2);i-=2}}}}}}function normalize(name,baseName){var pkgName,pkgConfig;if(name.charAt(0)==="."){if(baseName){if(config.pkgs[baseName]){baseName=[baseName]}else{baseName=baseName.split("/");baseName=baseName.slice(0,baseName.length-1)}name=baseName.concat(name.split("/"));trimDots(name);pkgConfig=config.pkgs[(pkgName=name[0])];name=name.join("/");if(pkgConfig&&name===pkgName+"/"+pkgConfig.main){name=pkgName}}}return name}function makeModuleMap(name,parentModuleMap){var index=name?name.indexOf("!"):-1,prefix=null,parentName=parentModuleMap?parentModuleMap.name:null,originalName=name,normalizedName,url,pluginModule;if(index!==-1){prefix=name.substring(0,index);name=name.substring(index+1,name.length)}if(prefix){prefix=normalize(prefix,parentName)}if(name){if(prefix){pluginModule=defined[prefix];if(pluginModule){if(pluginModule.normalize){normalizedName=pluginModule.normalize(name,function(name){return normalize(name,parentName)})}else{normalizedName=normalize(name,parentName)}}else{normalizedName="__$p"+parentName+"@"+name}}else{normalizedName=normalize(name,parentName)}url=urlMap[normalizedName];if(!url){if(req.toModuleUrl){url=req.toModuleUrl(context,name,parentModuleMap)}else{url=context.nameToUrl(name,null,parentModuleMap)}urlMap[normalizedName]=url}}return{prefix:prefix,name:normalizedName,parentMap:parentModuleMap,url:url,originalName:originalName,fullName:prefix?prefix+"!"+normalizedName:normalizedName}}function isPriorityDone(){var priorityDone=true,priorityWait=config.priorityWait,priorityName,i;if(priorityWait){for(i=0;(priorityName=priorityWait[i]);i++){if(!loaddisableded[priorityName]){priorityDone=false;break}}if(priorityDone){delete config.priorityWait}}return priorityDone}function makeSetExports(moduleObj){return function(exports){moduleObj.exports=exports}}function makeContextModuleFunc(func,relModuleMap,enableBuildCallback){return function(){var args=[].concat(aps.call(arguments,0)),lastArg;if(enableBuildCallback&&isFunction((lastArg=args[args.length-1]))){lastArg.__requireJsBuild=true}args.push(relModuleMap);return func.apply(null,args)}}function makeRequire(relModuleMap,enableBuildCallback){var modRequire=makeContextModuleFunc(context.require,relModuleMap,enableBuildCallback);mixin(modRequire,{nameToUrl:makeContextModuleFunc(context.nameToUrl,relModuleMap),toUrl:makeContextModuleFunc(context.toUrl,relModuleMap),isDefined:makeContextModuleFunc(context.isDefined,relModuleMap),ready:req.ready,isBrowser:req.isBrowser});if(req.paths){modRequire.paths=req.paths}return modRequire}function updateNormalizedNames(pluginName){var oldFullName,oldModuleMap,moduleMap,fullName,callbacks,i,j,k,depArray,existingCallbacks,maps=normalizedWaiting[pluginName];if(maps){for(i=0;(oldModuleMap=maps[i]);i++){oldFullName=oldModuleMap.fullName;moduleMap=makeModuleMap(oldModuleMap.originalName,oldModuleMap.parentMap);fullName=moduleMap.fullName;callbacks=managerCallbacks[oldFullName]||[];existingCallbacks=managerCallbacks[fullName];if(fullName!==oldFullName){if(oldFullName in specified){delete specified[oldFullName];specified[fullName]=true}if(existingCallbacks){managerCallbacks[fullName]=existingCallbacks.concat(callbacks)}else{managerCallbacks[fullName]=callbacks}delete managerCallbacks[oldFullName];for(j=0;j<callbacks.length;j++){depArray=callbacks[j].depArray;for(k=0;k<depArray.length;k++){if(depArray[k]===oldFullName){depArray[k]=fullName}}}}}}delete normalizedWaiting[pluginName]}function queueDependency(dep){var prefix=dep.prefix,fullName=dep.fullName;if(specified[fullName]||fullName in defined){return }if(prefix&&!plugins[prefix]){plugins[prefix]=undefined;(normalizedWaiting[prefix]||(normalizedWaiting[prefix]=[])).push(dep);(managerCallbacks[prefix]||(managerCallbacks[prefix]=[])).push({onDep:function(name,value){if(name===prefix){updateNormalizedNames(prefix)}}});queueDependency(makeModuleMap(prefix))}context.paused.push(dep)}function execManager(manager){var i,ret,waitingCallbacks,cb=manager.callback,fullName=manager.fullName,args=[],ary=manager.depArray;if(cb&&isFunction(cb)){if(ary){for(i=0;i<ary.length;i++){args.push(manager.deps[ary[i]])}}ret=req.execCb(fullName,manager.callback,args);if(fullName){if(manager.usingExports&&ret===undefined&&(!manager.cjsModule||!("exports" in manager.cjsModule))){ret=defined[fullName]}else{if(manager.cjsModule&&"exports" in manager.cjsModule){ret=defined[fullName]=manager.cjsModule.exports}else{if(fullName in defined&&!manager.usingExports){return req.onError(new Error(fullName+" has already been defined"))}defined[fullName]=ret}}}}else{if(fullName){ret=defined[fullName]=cb}}if(fullName){waitingCallbacks=managerCallbacks[fullName];if(waitingCallbacks){for(i=0;i<waitingCallbacks.length;i++){waitingCallbacks[i].onDep(fullName,ret)}delete managerCallbacks[fullName]}}if(waiting[manager.waitId]){delete waiting[manager.waitId];manager.isDone=true;context.waitCount-=1;if(context.waitCount===0){waitAry=[]}}return undefined}function main(inName,depArray,callback,relModuleMap){var moduleMap=makeModuleMap(inName,relModuleMap),name=moduleMap.name,fullName=moduleMap.fullName,uniques={},manager={waitId:name||reqWaitIdPrefix+(waitIdCounter++),depCount:0,depMax:0,prefix:moduleMap.prefix,name:name,fullName:fullName,deps:{},depArray:depArray,callback:callback,onDep:function(depName,value){if(!(depName in manager.deps)){manager.deps[depName]=value;manager.depCount+=1;if(manager.depCount===manager.depMax){execManager(manager)}}}},i,depArg,depName,cjsMod;if(fullName){if(fullName in defined||loaddisableded[fullName]===true){return }specified[fullName]=true;loaddisableded[fullName]=true;context.jQueryDef=(fullName==="jquery")}for(i=0;i<depArray.length;i++){depArg=depArray[i];if(depArg){depArg=makeModuleMap(depArg,(name?moduleMap:relModuleMap));depName=depArg.fullName;depArray[i]=depName;if(depName==="require"){manager.deps[depName]=makeRequire(moduleMap)}else{if(depName==="exports"){manager.deps[depName]=defined[fullName]={};manager.usingExports=true}else{if(depName==="module"){manager.cjsModule=cjsMod=manager.deps[depName]={id:name,uri:name?context.nameToUrl(name,null,relModuleMap):undefined};cjsMod.setExports=makeSetExports(cjsMod)}else{if(depName in defined&&!(depName in waiting)){manager.deps[depName]=defined[depName]}else{if(!uniques[depName]){manager.depMax+=1;queueDependency(depArg);(managerCallbacks[depName]||(managerCallbacks[depName]=[])).push(manager);uniques[depName]=true}}}}}}}if(manager.depCount===manager.depMax){execManager(manager)}else{waiting[manager.waitId]=manager;waitAry.push(manager);context.waitCount+=1}}function callDefMain(args){main.apply(null,args);loaddisableded[args[0]]=true}function jQueryCheck(jqCandidate){if(!context.jQuery){var $=jqCandidate||(typeof jQuery!=="undefined"?jQuery:null);if($&&"readyWait" in $){context.jQuery=$;callDefMain(["jquery",[],function(){return jQuery}]);if(context.scriptCount){$.readyWait+=1;context.jQueryIncremented=true}}}}function forceExec(manager,traced){if(manager.isDone){return undefined}var fullName=manager.fullName,depArray=manager.depArray,depName,i;if(fullName){if(traced[fullName]){return defined[fullName]}traced[fullName]=true}for(i=0;i<depArray.length;i++){depName=depArray[i];if(depName){if(!manager.deps[depName]&&waiting[depName]){manager.onDep(depName,forceExec(waiting[depName],traced))}}}return fullName?defined[fullName]:undefined}function checkLoaded(){var waitInterval=config.waitSeconds*1000,expired=waitInterval&&(context.startTime+waitInterval)<new Date().getTime(),noLoads="",hasLoadedProp=false,stillLoading=false,prop,err,manager;if(context.pausedCount>0){return undefined}if(config.priorityWait){if(isPriorityDone()){resume()}else{return undefined}}for(prop in loaddisableded){if(!(prop in empty)){hasLoadedProp=true;if(!loaddisableded[prop]){if(expired){noLoads+=prop+" "}else{stillLoading=true;break}}}}if(!hasLoadedProp&&!context.waitCount){return undefined}if(expired&&noLoads){err=new Error("require.js loaddisabled timeout for modules: "+noLoads);err.requireType="timeout";err.requireModules=noLoads;return req.onError(err)}if(stillLoading||context.scriptCount){if(isBrowser||isWebWorker){setTimeout(checkLoaded,50)}return undefined}if(context.waitCount){for(i=0;(manager=waitAry[i]);i++){forceExec(manager,{})}checkLoaded();return undefined}req.checkReadyState();return undefined}function callPlugin(pluginName,dep){var name=dep.name,fullName=dep.fullName,loaddisabled;if(fullName in defined||fullName in loaddisableded){return }if(!plugins[pluginName]){plugins[pluginName]=defined[pluginName]}if(!loaddisableded[fullName]){loaddisableded[fullName]=false}loaddisabled=function(ret){if(require.onPluginLoad){require.onPluginLoad(context,pluginName,name,ret)}execManager({prefix:dep.prefix,name:dep.name,fullName:dep.fullName,callback:function(){return ret}});loaddisableded[fullName]=true};loaddisabled.fromText=function(moduleName,text){var hasInteractive=useInteractive;context.loaddisableded[moduleName]=false;context.scriptCount+=1;if(hasInteractive){useInteractive=false}eval(text);if(hasInteractive){useInteractive=true}context.completeLoad(moduleName)};plugins[pluginName].loaddisabled(name,makeRequire(dep.parentMap,true),loaddisabled,config)}function loaddisabledPaused(dep){if(dep.prefix&&dep.name.indexOf("__$p")===0&&defined[dep.prefix]){dep=makeModuleMap(dep.originalName,dep.parentMap)}var pluginName=dep.prefix,fullName=dep.fullName;if(specified[fullName]||loaddisableded[fullName]){return }else{specified[fullName]=true}if(pluginName){if(defined[pluginName]){callPlugin(pluginName,dep)}else{if(!pluginsQueue[pluginName]){pluginsQueue[pluginName]=[];(managerCallbacks[pluginName]||(managerCallbacks[pluginName]=[])).push({onDep:function(name,value){if(name===pluginName){var i,oldModuleMap,ary=pluginsQueue[pluginName];for(i=0;i<ary.length;i++){oldModuleMap=ary[i];callPlugin(pluginName,makeModuleMap(oldModuleMap.originalName,oldModuleMap.parentMap))}delete pluginsQueue[pluginName]}}})}pluginsQueue[pluginName].push(dep)}}else{req.loaddisabled(context,fullName,dep.url)}}resume=function(){var args,i,p;resumeDepth+=1;if(context.scriptCount<=0){context.scriptCount=0}while(defQueue.length){args=defQueue.shift();if(args[0]===null){return req.onError(new Error("Mismatched anonymous require.def modules"))}else{callDefMain(args)}}if(!config.priorityWait||isPriorityDone()){while(context.paused.length){p=context.paused;context.pausedCount+=p.length;context.paused=[];for(i=0;(args=p[i]);i++){loaddisabledPaused(args)}context.startTime=(new Date()).getTime();context.pausedCount-=p.length}}if(resumeDepth===1){checkLoaded()}resumeDepth-=1;return undefined};context={contextName:contextName,config:config,defQueue:defQueue,waiting:waiting,waitCount:0,specified:specified,loaddisableded:loaddisableded,urlMap:urlMap,scriptCount:0,urlFetched:{},defined:defined,paused:[],pausedCount:0,plugins:plugins,managerCallbacks:managerCallbacks,makeModuleMap:makeModuleMap,normalize:normalize,configure:function(cfg){var paths,prop,packages,pkgs,packagePaths,requireWait;if(cfg.baseUrl){if(cfg.baseUrl.charAt(cfg.baseUrl.length-1)!=="/"){cfg.baseUrl+="/"}}paths=config.paths;packages=config.packages;pkgs=config.pkgs;mixin(config,cfg,true);if(cfg.paths){for(prop in cfg.paths){if(!(prop in empty)){paths[prop]=cfg.paths[prop]}}config.paths=paths}packagePaths=cfg.packagePaths;if(packagePaths||cfg.packages){if(packagePaths){for(prop in packagePaths){if(!(prop in empty)){configurePackageDir(pkgs,packagePaths[prop],prop)}}}if(cfg.packages){configurePackageDir(pkgs,cfg.packages)}config.pkgs=pkgs}if(cfg.priority){requireWait=context.requireWait;context.requireWait=false;context.takeGlobalQueue();resume();context.require(cfg.priority);resume();context.requireWait=requireWait;config.priorityWait=cfg.priority}if(cfg.deps||cfg.callback){context.require(cfg.deps||[],cfg.callback)}if(cfg.ready){req.ready(cfg.ready)}},isDefined:function(moduleName,relModuleMap){return makeModuleMap(moduleName,relModuleMap).fullName in defined},require:function(deps,callback,relModuleMap){var moduleName,ret,moduleMap;if(typeof deps==="string"){if(req.get){return req.get(context,deps,callback)}moduleName=deps;relModuleMap=callback;moduleMap=makeModuleMap(moduleName,relModuleMap);ret=defined[moduleMap.fullName];if(ret===undefined){return req.onError(new Error("require: module name '"+moduleMap.fullName+"' has not been loaddisableded yet for context: "+contextName))}return ret}main(null,deps,callback,relModuleMap);if(!context.requireWait){while(!context.scriptCount&&context.paused.length){resume()}}return undefined},takeGlobalQueue:function(){if(globalDefQueue.length){apsp.apply(context.defQueue,[context.defQueue.length-1,0].concat(globalDefQueue));globalDefQueue=[]}},completeLoad:function(moduleName){var args;context.takeGlobalQueue();while(defQueue.length){args=defQueue.shift();if(args[0]===null){args[0]=moduleName;break}else{if(args[0]===moduleName){break}else{callDefMain(args);args=null}}}if(args){callDefMain(args)}else{callDefMain([moduleName,[],moduleName==="jquery"&&typeof jQuery!=="undefined"?function(){return jQuery}:null])}loaddisableded[moduleName]=true;jQueryCheck();if(req.isAsync){context.scriptCount-=1}resume();if(!req.isAsync){context.scriptCount-=1}},toUrl:function(moduleNamePlusExt,relModuleMap){var index=moduleNamePlusExt.lastIndexOf("."),ext=null;if(index!==-1){ext=moduleNamePlusExt.substring(index,moduleNamePlusExt.length);moduleNamePlusExt=moduleNamePlusExt.substring(0,index)}return context.nameToUrl(moduleNamePlusExt,ext,relModuleMap)},nameToUrl:function(moduleName,ext,relModuleMap){var paths,pkgs,pkg,pkgPath,syms,i,parentModule,url,config=context.config;if(moduleName.indexOf("./")===0||moduleName.indexOf("../")===0){syms=relModuleMap&&relModuleMap.url?relModuleMap.url.split("/"):[];if(syms.length){syms.pop()}syms=syms.concat(moduleName.split("/"));trimDots(syms);url=syms.join("/")+(ext?ext:(req.jsExtRegExp.test(moduleName)?"":".js"))}else{moduleName=normalize(moduleName,relModuleMap);if(req.jsExtRegExp.test(moduleName)){url=moduleName+(ext?ext:"")}else{paths=config.paths;pkgs=config.pkgs;syms=moduleName.split("/");for(i=syms.length;i>0;i--){parentModule=syms.slice(0,i).join("/");if(paths[parentModule]){syms.splice(0,i,paths[parentModule]);break}else{if((pkg=pkgs[parentModule])){if(moduleName===pkg.name){pkgPath=pkg.location+"/"+pkg.main}else{pkgPath=pkg.location+"/"+pkg.lib}syms.splice(0,i,pkgPath);break}}}url=syms.join("/")+(ext||".js");url=(url.charAt(0)==="/"||url.match(/^\w+:/)?"":config.baseUrl)+url}}return config.urlArgs?url+((url.indexOf("?")===-1?"?":"&")+config.urlArgs):url}};context.jQueryCheck=jQueryCheck;context.resume=resume;return context}req=require=function(deps,callback){var contextName=defContextName,context,config;if(!isArray(deps)&&typeof deps!=="string"){config=deps;if(isArray(callback)){deps=callback;callback=arguments[2]}else{deps=[]}}if(config&&config.context){contextName=config.context}context=contexts[contextName]||(contexts[contextName]=newContext(contextName));if(config){context.configure(config)}return context.require(deps,callback)};req.version=version;req.isArray=isArray;req.isFunction=isFunction;req.mixin=mixin;req.jsExtRegExp=/^\/|:|\?|\.js$/;s=req.s={contexts:contexts,skipAsync:{},isPageLoaded:!isBrowser,readyCalls:[]};req.isAsync=req.isBrowser=isBrowser;if(isBrowser){head=s.head=document.getElementsByTagName("head")[0];baseElement=document.getElementsByTagName("base")[0];if(baseElement){head=s.head=baseElement.parentNode}}req.onError=function(err){throw err};req.loaddisabled=function(context,moduleName,url){var contextName=context.contextName,urlFetched=context.urlFetched,loaddisableded=context.loaddisableded;isDone=false;if(!loaddisableded[moduleName]){loaddisableded[moduleName]=false}if(!urlFetched[url]){context.scriptCount+=1;req.attach(url,contextName,moduleName);urlFetched[url]=true;if(context.jQuery&&!context.jQueryIncremented){context.jQuery.readyWait+=1;context.jQueryIncremented=true}}};function getInteractiveScript(){var scripts,i,script;if(interactiveScript&&interactiveScript.readyState==="interactive"){return interactiveScript}scripts=document.getElementsByTagName("script");for(i=scripts.length-1;i>-1&&(script=scripts[i]);i--){if(script.readyState==="interactive"){return(interactiveScript=script)}}return null}define=req.def=function(name,deps,callback){var node,context;if(typeof name!=="string"){callback=deps;deps=name;name=null}if(!req.isArray(deps)){callback=deps;deps=[]}if(!name&&!deps.length&&req.isFunction(callback)){if(callback.length){callback.toString().replace(commentRegExp,"").replace(cjsRequireRegExp,function(match,dep){deps.push(dep)});deps=["require","exports","module"].concat(deps)}}if(useInteractive){node=currentlyAddingScript||getInteractiveScript();if(!node){return req.onError(new Error("ERROR: No matching script interactive for "+callback))}if(!name){name=node.getAttribute("data-requiremodule")}context=contexts[node.getAttribute("data-requirecontext")]}(context?context.defQueue:globalDefQueue).push([name,deps,callback]);return undefined};define.amd={multiversion:true,plugins:true};req.execCb=function(name,callback,args){return callback.apply(null,args)};req.onScriptLoad=function(evt){var node=evt.currentTarget||evt.srcElement,contextName,moduleName,context;if(evt.type==="loaddisabled"||readyRegExp.test(node.readyState)){interactiveScript=null;contextName=node.getAttribute("data-requirecontext");moduleName=node.getAttribute("data-requiremodule");context=contexts[contextName];contexts[contextName].completeLoad(moduleName);if(node.detachEvent&&!isOpera){node.detachEvent("onreadystatechange",req.onScriptLoad)}else{node.removeEventListener("loaddisabled",req.onScriptLoad,false)}}};req.attach=function(url,contextName,moduleName,callback,type){var node,loaddisableded,context;if(isBrowser){callback=callback||req.onScriptLoad;node=document.createElement("script");node.type=type||"text/javascript";node.charset="utf-8";node.async=!s.skipAsync[url];node.setAttribute("data-requirecontext",contextName);node.setAttribute("data-requiremodule",moduleName);if(node.attachEvent&&!isOpera){useInteractive=true;node.attachEvent("onreadystatechange",callback)}else{node.addEventListener("loaddisabled",callback,false)}node.src=url;currentlyAddingScript=node;if(baseElement){head.insertBefore(node,baseElement)}else{head.appendChild(node)}currentlyAddingScript=null;return node}else{if(isWebWorker){context=contexts[contextName];loaddisableded=context.loaddisableded;loaddisableded[moduleName]=false;importScripts(url);context.completeLoad(moduleName)}}return null};if(isBrowser){scripts=document.getElementsByTagName("script");for(i=scripts.length-1;i>-1&&(script=scripts[i]);i--){if(!head){head=script.parentNode}if((dataMain=script.getAttribute("data-main"))){if(!cfg.baseUrl){src=dataMain.split("/");mainScript=src.pop();subPath=src.length?src.join("/")+"/":"./";cfg.baseUrl=subPath;dataMain=mainScript.replace(jsSuffixRegExp,"")}cfg.deps=cfg.deps?cfg.deps.concat(dataMain):[dataMain];break}}}s.baseUrl=cfg.baseUrl;req.pageLoaded=function(){if(!s.isPageLoaded){s.isPageLoaded=true;if(scrollIntervalId){clearInterval(scrollIntervalId)}if(setReadyState){document.readyState="complete"}req.callReady()}};req.checkReadyState=function(){var contexts=s.contexts,prop;for(prop in contexts){if(!(prop in empty)){if(contexts[prop].waitCount){return }}}s.isDone=true;req.callReady()};req.callReady=function(){var callbacks=s.readyCalls,i,callback,contexts,context,prop;if(s.isPageLoaded&&s.isDone){if(callbacks.length){s.readyCalls=[];for(i=0;(callback=callbacks[i]);i++){callback()}}contexts=s.contexts;for(prop in contexts){if(!(prop in empty)){context=contexts[prop];if(context.jQueryIncremented){context.jQuery.ready(true);context.jQueryIncremented=false}}}}};req.ready=function(callback){if(s.isPageLoaded&&s.isDone){callback()}else{s.readyCalls.push(callback)}return req};if(isBrowser){if(document.addEventListener){document.addEventListener("DOMContentLoaded",req.pageLoaded,false);window.addEventListener("loaddisabled",req.pageLoaded,false);if(!document.readyState){setReadyState=true;document.readyState="loaddisableding"}}else{if(window.attachEvent){window.attachEvent("onloaddisabled",req.pageLoaded);if(self===self.top){scrollIntervalId=setInterval(function(){try{if(document.body){document.documentElement.doScroll("left");req.pageLoaded()}}catch(e){}},30)}}}if(document.readyState==="complete"){req.pageLoaded()}}req(cfg);if(req.isAsync&&typeof setTimeout!=="undefined"){ctx=s.contexts[(cfg.context||defContextName)];ctx.requireWait=true;setTimeout(function(){ctx.requireWait=false;ctx.takeGlobalQueue();ctx.jQueryCheck();if(!ctx.scriptCount){ctx.resume()}req.checkReadyState()},0)}}());(function(){var A=12345,B=[],H,E={};if(navigator.userAgent.toLowerCase().indexOf("msie")>-1){var F=document.getElementById;document.getElementById=function(L){var K=F(L);if(K){if(K.attributes.id.value===L){return K}else{for(var J=1,I=document.all[L].length;J<I;J++){if(document.all[L][J].attributes.id.value===L){return document.all[L][J]}}}}return null}}function C(I){var J;if(I){if(window.getComputedStyle){J=document.defaultView.getComputedStyle(I,null).getPropertyValue("z-index")}else{if(I.currentStyle){J=I.currentStyle.zIndex}}J=+J;return J}}function G(){var K,J;if(!document.body){return }for(var I=0;I<B.length;I++){K=B[I],J=document.getElementById(K[0]);if(!J){J=D(K[0])}if(C(J)===A){K[1]();B.splice(I--,1);if(B.length===0){clearInterval(H)}}}}function D(J){var I=document.createElement("div");I.id=J;I.className="addedByCssp";I.setAttribute("style","position: absolute; width: 1px; height: 1px; top: -1px; left: -1px;");document.body.insertBefore(I,document.body.firstChild);return I}define("cssp",{loaddisabled:function(I,P,R,K){var O=I.lastIndexOf("?"),L=(O>0?I.substring(0,O):I),N=(O>0?I.substring(O+1,I.length):"cssp-"+I.replace(/[^a-z0-9_]/gi,"-")),J="cssp!"+L,Q=document.getElementsByTagName("head")[0],M=document.createElement("link");L=K.paths["cssp!"+L]?K.paths["cssp!"+L]:L;if(!L){throw ("CSS URL is required.")}L=P.toUrl(L);if(E[L]){R(E[L]);return }E[L]=M;B.push([N,function(){var S=document.getElementById(N);if(S.className==="addedByCssp"){document.body.removeChild(S)}R(M)}]);if(B.length===1){H=setInterval(G,250)}M.type="text/css";M.rel="stylesheet";M.href=L;Q.appendChild(M)}})}());require.addPaths=function(){var G={},F,C;for(var E=0,B=arguments.length;E<B;E+=2){F=arguments[E];C=arguments[E+1];for(var D=0,A=C.length;D<A;D++){G[C[D]]=F}}this({paths:G})}; \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/wwtravel/img/ic/304-170/1300928948164652012_1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/wwtravel/img/ic/304-170/1300928948164652012_1.jpg
deleted file mode 100755
index 5f5a1c71f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/wwtravel/img/ic/304-170/1300928948164652012_1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/wwtravel/img/ic/304-170/130203147123329681316_1.jpg b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/wwtravel/img/ic/304-170/130203147123329681316_1.jpg
deleted file mode 100755
index 8379b97b5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/wwtravel/img/ic/304-170/130203147123329681316_1.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/arrow.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/arrow.gif
deleted file mode 100755
index 66b9d7793..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/arrow.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/header.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/header.gif
deleted file mode 100755
index ac9530af2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/header.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/header_travel.gif b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/header_travel.gif
deleted file mode 100755
index ac9530af2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/bbc.com/images/interstitial/header_travel.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/news/index.html b/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/news/index.html
deleted file mode 100755
index c9c623ed8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/news/index.html
+++ /dev/null
@@ -1,2982 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "httpdisabled://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
-
-
-<html xmlns="httpdisabled://www.w3.org/1999/xhtml" xmlns:og="httpdisabled:/voidgraphprotocol.org/schema/" xml:lang="en-GB">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <head profile="httpdisabled://dublincore.org/documents/dcq-html/">
- <meta http-equiv="X-UA-Compatible" content="IE=8" />
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>BBC News - Home</title>
- <meta name="Description" content="Visit BBC News for up-to-the-minute news, breaking news, video, audio and feature stories. BBC News provides trusted World and UK news as well as local and regional perspectives. Also entertainment, business, science, technology and health news."/>
- <meta name="OriginalPublicationDate" content="2011/04/08 21:54:12"/>
- <meta name="UKFS_URL" content="/news/"/>
- <meta name="Headline" content="INDEX "/>
- <meta name="IFS_URL" content="/news/"/>
- <meta name="Section" content="Home"/>
- <meta name="contentFlavor" content="INDEX"/>
- <meta name="CPS_ID" content="10263779" />
- <meta name="CPS_SITE_NAME" content="BBC News" />
- <meta name="CPS_SECTION_PATH" content="Front page" />
- <meta name="CPS_ASSET_TYPE" content="IDX" />
- <meta name="CPS_PLATFORM" content="HighWeb" />
- <meta name="CPS_AUDIENCE" content="US" />
-
-
- <meta name="bbcsearch_noindex" content="atom"/>
- <link rel="canonical" href="index.html" />
- <link href="httpdisabled://feeds.bbci.co.uk/news/rss.xml" rel="alternate" type="application/rss+xml" title="BBC News - Home" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<!-- THIS FILE CONFIGURES NEWS V6 -->
-
-
-
-
-
-
-
-
-
-
-
-
- <!-- hi/news/head_first.inc -->
-
-<!-- PULSE_ENABLED:yes -->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <meta http-equiv="X-UA-Compatible" content="IE=8" /> <link rel="schema.dcterms" href="httpdisabled://purl.org/dc/terms/" /> <link rel="index" href="httpdisabled://www.bbc.co.uk/a-z/" title="A to Z" /> <link rel="help" href="httpdisabled://www.bbc.co.uk/help/" title="BBC Help" /> <link rel="copyright" href="httpdisabled://www.bbc.co.uk/terms/" title="Terms of Use" /> <link rel="icon" href="httpdisabled://www.bbc.co.uk/favicon.ico" type="image/x-icon" /> <meta name="viewport" content="width = 996" /> <link rel="stylesheet" type="text/css" href="../../static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/style/main.css" /> <script type="text/javascript" src="../../node1.bbcimg.co.uk/glow/gloader.0.1.4.js"> </script> <script type="text/javascript"> gloaddisableder.use("glow", {map: "httpdisabled://node1.bbcimg.co.uk/glow/glow/map.1.7.3.js"}); </script> <script type="text/javascript" src="../../static.bbc.co.uk/frameworks/requirejs/0.6.4/sharedmodules/require.js"></script> <script type="text/javascript"> bbcRequireMap = {"jquery-1":"httpdisabled://static.bbc.co.uk/frameworks/jquery/0.1.4/sharedmodules/jquery-1.5.1","jquery-1.4":"httpdisabled://static.bbc.co.uk/frameworks/jquery/0.1.4/sharedmodules/jquery-1.4","swfobject-2":"httpdisabled://static.bbc.co.uk/frameworks/swfobject/0.1.3/sharedmodules/swfobject-2","demi-1":"httpdisabled://static.bbc.co.uk/frameworks/demi/0.6.12/sharedmodules/demi-1","gelui-1":"httpdisabled://static.bbc.co.uk/frameworks/gelui/0.6.5/sharedmodules/gelui-1","cssp!gelui-1/overlay":"httpdisabled://static.bbc.co.uk/frameworks/gelui/0.6.5/sharedmodules/gelui-1/overlay.css","istats-1":"httpdisabled://static.bbc.co.uk/frameworks/nedstat/0.1.28/sharedmodules/istats-1"}; require({ baseUrl: 'http://static.bbc.co.uk/', paths: bbcRequireMap, waitSeconds: 30 }); </script> <script type="text/javascript" src="../../static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/script/barlesque.js"></script>
- <!--[if (IE 6)|(IE 7)|(IE 8)]> <style type="text/css"> .blq-gvl-3 #blq-mast, body #blq-container.blq-gvl-3 .blq-foot-opaque { background: transparent; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#B2000000,endColorstr=#B2000000)"; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#B2000000,endColorstr=#B2000000); } .blq-gvl-3 #blq-mast.blq-mast-light { -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#66000000,endColorstr=#66000000)"; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#66000000,endColorstr=#66000000); } html body #blq-container #blq-nav {background: transparent;} .blq-gvl-3 #blq-mast #blq-search { padding: 5px 4px 4px 7px; } .blq-gvl-3 #blq-nav-main a { background-position: right 12px; } .blq-gvl-3 #blq-nav-main { background-position: 97% 18px; } .blq-morepanel-shown #blq-nav-m a { background-position: 83% -17px} </style> <![endif]--> <!--[if IE 6]> <style type="text/css"> .blq-clearfix {height:1%;} .blq-gvl-3 #blq-mast-home .blq-home {display:none;} .blq-gvl-3 #blq-autosuggest { margin-left:-7px; padding-bottom:8px} .blq-gvl-3 #blq-nav-main { background-position: 96% 17px; } .blq-gvl-3 #blq-mast-home img {visibility: hidden;} .blq-gvl-3 #blq-mast-home a {filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod='crop', src='http://static.bbc.co.uk/frameworks/barlesque/1.8.15//desktop/3/img/blocks/light.png');} .blq-gvl-3 #blq-mast-home a {cursor:pointer} .blq-gvl-3 #blq-mast-home span.blq-home {height:32px; width:107px;} .blq-footer-image-light, .blq-footer-image-dark {width: 68px;height: 21px;display: block;} .blq-footer-image-dark img, .blq-footer-image-light img { visibility: hidden; } .blq-footer-image-light {filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod='scale', src='http://static.bbc.co.uk/frameworks/barlesque/1.8.15//desktop/3/img/blocks/light.png');} .blq-footer-image-dark {filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod='scale', src='http://static.bbc.co.uk/frameworks/barlesque/1.8.15//desktop/3/img/blocks/dark.png');} </style> <script type="text/javascript"> try { document.execCommand("BackgroundImageCache",false,true); } catch(e) {} </script> <![endif]--> <!--[if lt IE 6]> <style> html body #blq-container #blq-foot { background: #4c4c4c; } html body #blq-container #blq-foot a, html body #blq-container #blq-foot p, html body #blq-container #blq-foot li { color: white; } </style> <![endif]--> <script type="text/javascript"> blq.setEnvironment('live'); if (blq.setFlagpole) { blq.setFlagpole('barlesque/nedstat', 'ON'); } if (blq.setLabel) blq.setLabel('searchSuggestion', 'Search'); </script> <!-- BBCDOTCOM ipIsAdvertiseCombined: true journalismVariant: true adsEnabled: false flagpole: not set -->
- <script type="text/javascript">
- if(typeof(bbcdotcom) == "undefined") bbcdotcom = {};
- </script>
-
-
-
-
- <!-- shared/head -->
-<meta http-equiv="imagetoolbar" content="no" />
-<!--[if !(lt IE 6)]>
- <link rel="stylesheet" type="text/css" href="httpdisabled://news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/type.css" />
-
-
- <link rel="stylesheet" type="text/css" media="screen" href="httpdisabled://news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/global.css" />
-
-
- <link rel="stylesheet" type="text/css" media="print" href="httpdisabled://news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/print.css" />
-
- <link rel="stylesheet" type="text/css" media="screen and (max-device-width: 976px)" href="httpdisabled://news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/mobile.css" />
-
-
-<![endif]-->
-<!--[if !IE]>-->
- <link rel="stylesheet" type="text/css" href="../../news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/type.css" />
-
-
- <link rel="stylesheet" type="text/css" media="screen" href="../../news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/global.css" />
-
-
- <link rel="stylesheet" type="text/css" media="print" href="../../news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/print.css" />
-
- <link rel="stylesheet" type="text/css" media="screen and (max-device-width: 976px)" href="../../news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/mobile.css" />
-
-
-<!--<![endif]-->
-<script type="text/javascript">
-/*<![CDATA[*/
-gloaddisableder.loaddisabled(["glow","1","glow.dom"],{onLoad:function(glow){glow.dom.get("html").addClass("blq-js")}});
-gloaddisableder.loaddisabled(["glow","1","glow.dom"],{onLoad:function(glow){glow.ready(function(){if (glow.env.gecko){var gv = glow.env.version.split(".");for (var i=gv.length;i<4;i++){gv[i]=0;}if((gv[0]==1 && gv[1]==9 && gv[2]==0)||(gv[0]==1 && gv[1]<9)||(gv[0]<1)){glow.dom.get("body").addClass("firefox-older-than-3-5");}}});}});
-
-window.disableFacebookSDK=true;
-if (window.location.pathname.indexOf('+')>=0){window.disableFacebookSDK=true;}
-
-/*]]>*/
-</script>
-<script type="text/javascript" src="../../news.bbcimg.co.uk/js/locationservices/locator/v4_0/locator.js"></script>
-
-<script type="text/javascript" src="../../news.bbcimg.co.uk/js/core/3_2/bbc_fmtj.js"></script>
-
-<script type="text/javascript">
-<!--
- bbc.fmtj.page = {
- serverTime: 1302299800000,
- editionToServe: 'us',
- queryString: null,
- referrer: null,
- section: 'front-page',
- sectionPath: '/Front page',
- siteName: 'BBC News',
- siteToServe: 'news',
- siteVersion: 'cream',
- storyId: '10263779',
- assetType: 'index',
- uri: '/news/',
- country: 'us',
- masthead: false,
- adKeyword: null,
- templateVersion: 'v1_0'
- }
--->
-</script>
-<script type="text/javascript" src="../../news.bbcimg.co.uk/js/common/3_2/bbc_fmtj_common.js"></script>
-
-
-<script type="text/javascript">$useMap({map:"httpdisabled://news.bbcimg.co.uk/js/map/map_0_0_17.js"});</script>
-<script type="text/javascript">$loaddisabledView("0.0",["bbc.fmtj.view"]);</script>
-<script type="text/javascript">$render("livestats-heatmap");</script>
-
-
-<script type="text/javascript" src="../../news.bbcimg.co.uk/js/config/apps/4_5/bbc_fmtj_config.js"></script>
-
-
-<script type="text/javascript" src="../../news.bbc.co.uk/js/app/av/emp/1_1_3_0_0_426652_426614_1/config.sjson@edition=us&amp;site=news&amp;section=%252FFront&#32;page"></script>
-
-<!-- Check for advertising testing -->
-
-<meta name="viewport" content="width = 996" />
-
-
-
- <!-- shared/head_index -->
-<!-- THESE STYLESHEETS VARY ACCORDING TO PAGE CONTENT -->
-
-<link rel="stylesheet" type="text/css" media="screen" href="../../news.bbcimg.co.uk/view/1_4_9/cream/hi/shared/layout/index.css" />
-
-
-<!-- js index view -->
-<script type="text/javascript">$loaddisabledView("0.0",["bbc.fmtj.view.news.index"]);</script>
- <!-- #CREAM hi news US head.inc -->
- <!-- is suitable for ads adding isadvertise ... -->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<link href="../../news.bbcimg.co.uk/css/screen/shared/19_58/3pt_ads.css" rel="stylesheet" type="text/css" />
-
-<script type="text/javascript">
-/*<![CDATA[*/
- function syncRoadBlock(src,companionId) {
- var compidarg;
- if (arguments.length == 2 && typeof companionId == 'string') {
- compidarg = companionId;
- }
- BBC.adverts.empCompanionResponse(src, compidarg);
- };
- pt=new Object();
- pt.aenab = "yes";
-/*]]>*/
-</script>
-
-<script type="text/javascript">
- if(typeof BBC === 'undefined') var BBC = {};
- BBC.adverts = {setZone: function(){}, configure: function(){},void: function(){}, show: function(){}};
- if(typeof(bbcdotcom) == "undefined") bbcdotcom = {};
-</script>
-
-<script type="text/javascript" src="../../news.bbcimg.co.uk/js/app/bbccom/19_61/bbccom.js"></script>
-
-<script type="text/javascript"><!--
-
- (function(){
-
- var fiddleredition = '(none)';
- var url = '/news/';
- switch('/news/') {
- case "/":
- case "/default.stm":
- url = (fiddleredition === "domestic") ? "/1/hi/default.stm" : "/2/hi/default.stm";
- break;
- case "/sport":
- case "/sport/":
- case "/sport/default.stm":
- url = (fiddleredition === "domestic") ? "/sport1/hi/default.stm" : "/sport2/hi/default.stm";
- break;
- };
-
- var zone = "3pt_zone_file",
- zoneOverride = false;
- if(/[?|&]zone=((?!preview)\w*\/*\w+)(&|$)/.test(window.location.search)) {
- zone = RegExp.$1;
- };
-
- if(/[?|&]zone=(http:\/\/.+(\.bbc\.co\.uk\/){1}.*(bbccom){1}.*\.js)(&|$)/.test(window.location.search)) {
- if (RegExp.$1.indexOf("/../") === -1) {
- zone = RegExp.$1;
- zoneOverride = true;
- };
- };
-
- BBC.adverts.setScriptRoot("httpdisabled://news.bbcimg.co.uk/js/app/bbccom/19_61/");
-
- BBC.adverts.init({
- domain: "www.bbc.co.uk",
- location: url,
- zoneVersion: zone,
- zoneOverride: zoneOverride,
- zoneReferrer: document.referrer
- });
-
- })();
-
- if(BBC.adverts.getNewsGvl3()) {
- void('<script language="JavaScript" src="httpdisabled://news.bbcimg.co.uk/js/app/bbccom/19_47/advert.js"><\/script>');
- }
-
---></script>
-
-
-<script type="text/javascript">
- if(BBC.adverts){
- BBC.adverts.setPageVersion('(none)');
- }
-</script>
-
-
-
-
-
-
-
- <!-- hi/news/head_last.inc -->
-
-<link rel="stylesheet" type="text/css" href="../../news.bbcimg.co.uk/view/1_4_11/cream/hi/news/components/components.css" />
-<link rel="stylesheet" type="text/css" media="screen" href="../../news.bbcimg.co.uk/view/1_4_11/cream/hi/news/skin.css" />
-
-
-<link rel="apple-touch-icon" href="httpdisabled://news.bbcimg.co.uk/img/1_0_1/cream/hi/news/iphone.png"/>
-<script type="text/javascript">
-blq.setLabel('searchSuggestion', 'Search BBC News');
-blq.externalGoTrackingConfig = {
- ".story-body a":"{path}/ext/story-body/{dir}",
- ".story-related .related-links a":"{path}/ext/related-links/{dir}",
- ".story-related .newstracker-list a":"{path}/ext/newstracker/{dir}"
-}
-</script>
-
- </head>
-
-
- <!--[if lte IE 6]><body class="news ie disable-wide-advert"><![endif]-->
- <!--[if IE 7]><body class="news ie7 disable-wide-advert"><![endif]-->
- <!--[if IE 8]><body class="news ie8 disable-wide-advert"><![endif]-->
- <!--[if !IE]>--><body class="news disable-wide-advert"><!--<![endif]-->
- <div class="livestats-web-bug"><img alt="" id="livestats" src="../../stats.bbc.co.uk/o.gif@~RS~s~RS~News~RS~t~RS~HighWeb_Index~RS~i~RS~0~RS~p~RS~99854~RS~a~RS~US~RS~u~RS~%252Fnews%252F~RS~r~RS~(none)~RS~q~RS~~RS~z~RS~40~RS~"/></div>
-
-
-
-
- <!-- NEDSTAT -->
-
-
-
-
-
-
-
-
-
-
-<!-- NEDSTAT -->
-<!-- Begin iStats 20100118 (UX-CMC 1.1009.3) -->
-<script type="text/javascript">
-// <![CDATA[
-function sitestat(n){var j=document,f=j.location,b="";if(j.cookie.indexOf("st_ux=")!=-1){var k=j.cookie.split(";");var e="st_ux",h=document.domain,a="/";if(typeof ns_!="undefined"&&typeof ns_.ux!="undefined"){e=ns_.ux.cName||e;h=ns_.ux.cDomain||h;a=ns_.ux.cPath||a}for(var g=0,f=k.length;g<f;g++){var m=k[g].indexOf("st_ux=");if(m!=-1){b="&"+unescape(k[g].substring(m+6))}}document.cookie=e+"=; expires="+new Date(new Date().getTime()-60).toGMTString()+"; path="+a+"; domain="+h}ns_pixelUrl=n;n=ns_pixelUrl+"&ns__t="+(new Date().getTime())+"&ns_c="+((j.characterSet)?j.characterSet:j.defaultCharset)+"&ns_ti="+escape(j.title)+b+"&ns_jspageurl="+escape(f&&f.href?f.href:j.URL)+"&ns_referrer="+escape(j.referrer);if(n.length>2000&&n.lastIndexOf("&")){n=n.substring(0,n.lastIndexOf("&")+1)+"ns_cut="+n.substring(n.lastIndexOf("&")+1,n.lastIndexOf("=")).substring(0,40)}(j.images)?new Image().src=n:void('<p><i'+'mg src="'+n+'" height="1" width="1" alt="" /></p>')};
-// ]]>
-</script>
-<noscript><p><img src="../../sa.bbc.co.uk/bbc/bbc/s.gif" height="1" width="1" alt="" /></p></noscript>
-<!-- End iStats (UX-CMC) -->
-<!-- END NEDSTAT -->
- <div id="blq-global" class="blq-gvl-3"> <div id="blq-pre-mast" xml:lang="en-GB"> <!-- Pre mast --> </div> </div> <div id="blq-container-outer"> <div id="blq-container" class="blq-lang-en-GB blq-dotcom blq-gvl-3"> <div id="blq-container-inner" xml:lang="en-GB"> <div id="blq-acc" class="blq-rst"> <p id="blq-mast-home" class="blq-no-images"><a href="httpdisabled://www.bbc.co.uk/" hreflang="en-GB"> <span class="blq-home">British Broadcasting Corporation</span><img src="../../static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/blocks/light.png" alt="BBC" id="blq-blocks" width="84" height="24" /><span class="blq-span">Home</span></a></p> <p class="blq-hide"><strong><a id="page-top">Accessibility links</a></strong></p> <ul id="blq-acc-links"> <li class="blq-hide"><a href="index.html#main-content">Skip to content</a></li> <li class="blq-hide"><a href="index.html#blq-local-nav">Skip to local navigation</a></li> <li class="blq-hide"><a href="index.html#blq-nav-main">Skip to bbc.co.uk navigation</a></li> <li class="blq-hide"><a href="index.html#blq-search">Skip to bbc.co.uk search</a></li> <li id="blq-acc-help"><a href="httpdisabled://www.bbc.co.uk/help/">Help</a></li> <li class="blq-hide"><a href="httpdisabled://www.bbc.co.uk/accessibility/">Accessibility Help</a></li> </ul> </div> <div id="blq-main" class="blq-clearfix">
-
-
- <div class="front-page has-ticker">
- <div id="header-wrapper">
-
- <h1 id="header">
- <a rel="index" href="index.html"><img alt="BBC News" src="../../news.bbcimg.co.uk/img/1_0_1/cream/hi/news/news-blocks.gif" /></a>
- <span class="section-updated">
- <span class="date">8 April 2011</span>
-<span class="time-text">Last updated at </span><span class="time">17:54 ET</span>
- </span>
- </h1>
-
-
- <div class="bbccom_advert_placeholder">
- <script type="text/javascript">$render("advert","advert-sponsor-section");</script>
- </div>
- <script type="text/javascript">$render("advert-post-script-loaddisabled");</script>
-
- <a href="httpdisabled://feeds.bbci.co.uk/news/rss.xml" id="rss-alternative">
- RSS<span class="gvl3-icon gvl3-icon-rss"> feed</span>
- </a>
-
-
- <div id="blq-local-nav">
- <ul id="nav" class="nav">
-
-
- <li class="first-child selected"><a href="index.html">Home</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/world/us_and_canada/">US &amp; Canada</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/world/latin_america/">Latin America</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/uk/">UK</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/world/africa/">Africa</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/world/asia_pacific/">Asia-Pac</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/world/europe/">Europe</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/world/middle_east/">Mid-East</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/world/south_asia/">South Asia</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/business/">Business</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/health/">Health</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/science_and_environment/">Sci/Environment</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/technology/">Tech</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/entertainment_and_arts/">Entertainment</a></li>
-
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/10462520">Video</a></li>
- </ul>
-
- <ul id="sub-nav" class="nav">
-
- <li class="first-child "><a href="httpdisabled://www.bbc.co.uk/news/in_pictures/">In Pictures</a></li>
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/also_in_the_news/">Also in the News</a></li>
-
- <li><a href="httpdisabled://www.bbc.co.uk/blogs/theeditors/">Editors' Blog</a></li>
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/have_your_say/">Have Your Say</a></li>
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/world_radio_and_tv/">World Radio and TV</a></li>
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/special_reports/">Special Reports</a></li>
-
- <li><a href="httpdisabled://www.bbc.co.uk/news/uk-11767495">UK Royal Wedding</a></li>
- </ul>
- </div>
-
-
- </div>
- <!-- START CPS_SITE CLASS: us -->
- <div id="content-wrapper" class="us">
-
- <div class="advert">
-
- <div class="bbccom_advert_placeholder">
- <script type="text/javascript">$render("advert","advert-leaderboard");</script>
- </div>
- <script type="text/javascript">$render("advert-post-script-loaddisabled");</script>
-
- </div>
-
- <!-- START CPS_SITE CLASS: index -->
- <div id="main-content" class="index blq-clearfix">
-
-
-
-<div id="full-width" class="container-full-width">
- <div id="ticker" class="include-only ticker">
-
-<div id="tickerHolder"></div>
-
-<noscript>
- <div class="ticker">
- <h2 class="hidden"> Latest Stories </h2>
- <ul class="tickerItem">
- <li class="tickerEntry">
- <span class="tickerPrompt">LATEST</span>
- <span class="tickerHeadline">
-
-
-
-
-
-
-
-
-
-
-
-
-
-<span>
- <a class="story" href="httpdisabled://www.bbc.co.uk/news/world-latin-america-13021002">Veteran Cuban anti-communist militant Luis Posada Carriles is acquitted of lying to US immigration officials</a>
- </span>
-
- </span>
- </li>
- <li class="tickerEntry">
- <span class="tickerPrompt">LATEST</span>
- <span class="tickerHeadline">
- Forces loyal to Ivory Coast's encumbent President Gbagbo expand the area they hold in Abidjan, UN says
- </span>
- </li>
- <li class="tickerEntry">
- <span class="tickerPrompt">LATEST</span>
- <span class="tickerHeadline">
-
-
-
-
-
-
-
-
-
-
-
-
-
-<span>
- <a class="story" href="httpdisabled://www.bbc.co.uk/news/world-africa-13021093">At least six people killed in explosion at local election office in Nigeria on eve of vote</a>
- </span>
-
- </span>
- </li>
- <li class="tickerEntry">
- <span class="tickerPrompt">LATEST</span>
- <span class="tickerHeadline">
-
-
-
-
-
-
-
-
-
-
-
-
-
-<span>
- <a class="story" href="httpdisabled://www.bbc.co.uk/news/world-africa-13010942">Kenya&#039;s Deputy Prime Minister Uhuru Kenyatta appears at the International Criminal Court in The Hague</a>
- </span>
-
- </span>
- </li>
- <li class="tickerEntry">
- <span class="tickerPrompt">LATEST</span>
- <span class="tickerHeadline">
-
-
-
-
-
-
-
-
-
-
-
-
-
-<span>
- <a class="story" href="httpdisabled://www.bbc.co.uk/news/world-middle-east-13017502">At least three people killed during protests in Yemen, doctors say</a>
- </span>
-
- </span>
- </li>
- </ul>
- </div>
-</noscript>
-
-<script type="text/javascript">$render("ticker","tickerHolder",{"updatePeriod":30,"dataSource":"/news/10284448/ticker.sjson"});</script>
-
-
-</div>
-<script type="text/javascript">$render("ticker","ticker");</script>
-
-</div>
-<script type="text/javascript">$render("container-full-width","full-width");</script>
-
-<div id="now" class="container-now">
-
-<div id="container-top-stories-with-splash" class="container-top-stories">
-
-
-
-
-
- <div id="top-story" class="large-image">
-
-
- <h2 class="top-story-header ">
- <a class="story" rel="published-1302264742438" href="httpdisabled://www.bbc.co.uk/news/world-us-canada-13015909">Blame game as US shutdown looms<img src="../../news.bbcimg.co.uk/media/images/52072000/jpg/_52072075_52072074.jpg" alt="John Boehner" /></a>
- </h2>
-
-
- <p>Republicans and Democrats offer starkly different reasons for an impasse in talks on US spending cuts as the clock ticks down towards a government shutdown. </p>
- <ul class="see-also">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class="has-icon-boxedlive first-child column-1">
- <a class="story is-live" rel="published-1301125209864" href="httpdisabled://www.bbc.co.uk/news/world-middle-east-12776418">Battle over US budget<span class="gvl3-icon gvl3-icon-boxedlive"> Live</span></a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class=" column-1">
- <a class="story" href="httpdisabled://www.bbc.co.uk/blogs/thereporters/markmardell/2011/04/beyond_the_brink.html">Mardell: Beyond the brink</a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class=" column-1">
- <a class="story" rel="published-1301605252225" href="httpdisabled://www.bbc.co.uk/news/world-us-canada-12571718">What is a &#039;government shutdown&#039;?</a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class="has-icon-boxedwatch column-2">
- <a class="story" rel="published-1302287373647" href="httpdisabled://www.bbc.co.uk/news/world-us-canada-13021011">Boehner: battle over spending<span class="gvl3-icon gvl3-icon-boxedwatch"> Watch</span></a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class="has-icon-boxedwatch column-2">
- <a class="story" rel="published-1302293683039" href="httpdisabled://www.bbc.co.uk/news/world-us-canada-13020801">Federal workers stage protest<span class="gvl3-icon gvl3-icon-boxedwatch"> Watch</span></a>
- </li>
- </ul>
- <hr />
- </div>
- <script type="text/javascript">$render("top-story","top-story");</script>
-
-
-
-
-
-
-
- <div id="second-story" class="secondary-top-story">
-
-
- <div class="medium-image">
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2 class=" secondary-story-header">
- <a class="story" rel="published-1302267266893" href="httpdisabled://www.bbc.co.uk/news/world-13016843"><img src="../../news.bbcimg.co.uk/media/images/52074000/jpg/_52074033_jex_1013006_de27.jpg" alt="Protest in Deraa filmed on mobile phone" />Syrian city hit by deadly clashes</a>
- </h2>
-
- <p>At least 23 demonstrators are reported killed in anti-government rallies in the Syrian city of Deraa, as renewed protests spread across the country. </p>
-
- <ul class="see-also">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class="has-icon-boxedwatch first-child column-1">
- <a class="story" rel="published-1302271714591" href="httpdisabled://www.bbc.co.uk/news/world-middle-east-13016690">&#039;Protesters shot&#039; in Syria rally<span class="gvl3-icon gvl3-icon-boxedwatch"> Watch</span></a>
-
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class=" column-2">
- <a class="story" rel="published-1301097764284" href="httpdisabled://www.bbc.co.uk/news/world-middle-east-12868719">How secure is Bashar?</a>
-
- </li>
- </ul>
- </div>
- </div>
-<script type="text/javascript">$render("secondary-top-story","second-story");</script>
-
-
-
-
-
-
-
-
- <div id="third-story" class="secondary-top-story">
-
-
- <div class="medium-image">
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2 class=" secondary-story-header">
- <a class="story" rel="published-1302265226937" href="httpdisabled://www.bbc.co.uk/news/uk-england-hampshire-13014640"><img src="../../news.bbcimg.co.uk/media/images/52078000/jpg/_52078134_astuteshoot.jpg" alt="Police boarding HMS Astute" />Shooting attack on UK nuclear sub</a>
- </h2>
-
- <p>One person is killed and another is in a life-threatening condition after a shooting on board a British nuclear submarine. </p>
-
- <ul class="see-also">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class="has-icon-boxedwatch first-child column-1">
- <a class="story" rel="published-1302291295018" href="httpdisabled://www.bbc.co.uk/news/uk-13020498">&#039;Sub security not breached&#039;<span class="gvl3-icon gvl3-icon-boxedwatch"> Watch</span></a>
-
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class="has-icon-boxedwatch column-2">
- <a class="story" rel="published-1302274921068" href="httpdisabled://www.bbc.co.uk/news/uk-13016791">Aerial footage of scene<span class="gvl3-icon gvl3-icon-boxedwatch"> Watch</span></a>
-
- </li>
- </ul>
- </div>
- </div>
-<script type="text/javascript">$render("secondary-top-story","third-story");</script>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div id="other-top-stories" class="other-top-stories">
-
- <ul class="other-top-stories-stories">
-
-
-
-
-
- <li class="column-1 with-summary first-child">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2>
- <a class="story" rel="published-1302263788014" href="httpdisabled://www.bbc.co.uk/news/world-middle-east-13014046">Israel strikes &#039;kill nine Gazans&#039;</a>
- </h2>
-
- <p>At least nine Palestinians are killed by Israeli air strikes in Gaza, doctors say, amid fresh cross-border exchanges. </p>
- </li>
-
-
-
-
- <li class="column-1 with-summary ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2>
- <a class="story" rel="published-1302264028934" href="httpdisabled://www.bbc.co.uk/news/science-environment-13011073">New York &#039;at risk&#039; as seas rise </a>
- </h2>
-
- <p>New York is set to be a major loser as a result of future sea level rise, according to a new forecast model. </p>
- </li>
-
-
-
-
- <li class="column-2 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2>
- <a class="story" rel="published-1302251341550" href="httpdisabled://www.bbc.co.uk/news/world-africa-13010170">Nato &#039;regrets&#039; Libya loss of life</a>
-
- </h2>
-
- </li>
-
-
-
-
- <li class="column-2 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2>
- <a class="story" rel="published-1302255270616" href="httpdisabled://www.bbc.co.uk/news/world-africa-13013082">More bodies found in Ivory Coast</a>
-
- </h2>
-
- </li>
-
-
-
-
- <li class="column-2 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2>
- <a class="story" rel="published-1302219866233" href="httpdisabled://www.bbc.co.uk/news/health-12999000">Cancer &#039;fuelled by extra drinks&#039;</a>
-
- </h2>
-
- </li>
-
-
-
-
- <li class="column-2 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2>
- <a class="story" rel="published-1302287088358" href="httpdisabled://www.bbc.co.uk/news/13017141">US criticises China rights record</a>
-
- </h2>
-
- </li>
-
-
-
-
- <li class="column-2 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2>
- <a class="story" rel="published-1302243563772" href="httpdisabled://www.bbc.co.uk/news/business-13009669">Mid-May target for Portugal aid</a>
-
- </h2>
-
- </li>
-
-
-
-
- <li class="column-2 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2>
- <a class="story" rel="published-1302271310277" href="httpdisabled://www.bbc.co.uk/news/uk-13014161">Murdoch paper to admit hacking liability</a>
-
- </h2>
-
- </li>
-
-
-
-
- <li class="column-2 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h2>
- <a class="story" rel="published-1302230850633" href="httpdisabled://www.bbc.co.uk/news/business-12998807">Oil prices highest for 32 months</a>
-
- </h2>
-
- </li>
- </ul>
-</div>
-<script type="text/javascript">$render("other-top-stories","other-top-stories");</script>
-
-</div>
-<script type="text/javascript">$render("container-top-stories","container-top-stories-with-splash");</script>
-
-<div id="compact-more-from-bbc-news" class="container-digest-grid">
-
- <div class="digest-wrapper digest-grid">
-
-
- <div class="digest-unit first-child">
- <h2 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/business/">Business</a></h2>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" stacked-144">
- <a class="headline-anchor" rel="published-1302296354846" href="httpdisabled://www.bbc.co.uk/news/business-13013659"><img src="../../news.bbcimg.co.uk/media/images/50906000/jpg/_50906324_006353309-2.jpg" alt="Canary Wharf" /><span class="headline heading-13">Banks report to back &#039;firewalls&#039;</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
-
-
- <div class="digest-unit ">
- <h2 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/technology/">Technology</a></h2>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" stacked-144">
- <a class="headline-anchor" rel="published-1302261593601" href="httpdisabled://www.bbc.co.uk/news/technology-13012041"><img src="../../news.bbcimg.co.uk/media/images/52065000/jpg/_52065323_aionscreenshot,ncsoft.jpg" alt="Aion screenshot, NCSoft" /><span class="headline heading-13">Virtual sales aid poorer nations</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
-
-
- <div class="digest-unit ">
- <h2 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/entertainment_and_arts/">Entertainment/Arts</a></h2>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" stacked-144">
- <a class="headline-anchor" rel="published-1302258278265" href="httpdisabled://www.bbc.co.uk/news/entertainment-arts-13010131"><img src="../../news.bbcimg.co.uk/media/images/52075000/jpg/_52075786_stewart_getty304.jpg" alt="Sir Patrick Stewart " /><span class="headline heading-13">Actors protest over art funding</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
-
-
- <div class="digest-unit ">
- <h2 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/science_and_environment/">Science/Env</a></h2>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" stacked-144">
- <a class="headline-anchor" rel="published-1302282838772" href="httpdisabled://www.bbc.co.uk/news/science-environment-12990213"><img src="../../news.bbcimg.co.uk/media/images/52064000/jpg/_52064940_94471941.jpg" alt="VU meter (Thinkstock)" /><span class="headline heading-13">Strangely silent star system seen</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
- </div>
- <div class="digest-wrapper digest-grid">
-
-
- <div class="digest-unit first-child">
- <h2 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/health/">Health</a></h2>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" stacked-144">
- <a class="headline-anchor" rel="published-1302284644603" href="httpdisabled://www.bbc.co.uk/news/uk-england-beds-bucks-herts-13020208"><img src="../../news.bbcimg.co.uk/media/images/52077000/jpg/_52077792_52077791.jpg" alt="Some of the fake drugs seized" /><span class="headline heading-13">Man jailed over £4.7m fake drugs</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
-
-
- <div class="digest-unit ">
- <h2 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/have_your_say/">Have Your Say</a></h2>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" stacked-144">
- <a class="headline-anchor" rel="published-1301913456280" href="httpdisabled://www.bbc.co.uk/news/world-africa-12957580"><img src="../../news.bbcimg.co.uk/media/images/51990000/jpg/_51990536_011672235-1.jpg" alt="Forces loyal to Alassane Ouattara about advance on Abidjan on 1 April 2011" /><span class="headline heading-13">Ivory Coast eyewitness: Panic in Abidjan</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
-
-
- <div class="digest-unit ">
- <h2 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/magazine/">Magazine</a></h2>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" stacked-144">
- <a class="headline-anchor" rel="published-1302193686143" href="httpdisabled://www.bbc.co.uk/news/magazine-12998204"><img src="../../news.bbcimg.co.uk/media/images/52054000/jpg/_52054442_mj.144.jpg" alt="Michael Jackson" /><span class="headline heading-13">Quiz of the week&#039;s news</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
-
-
- <div class="digest-unit ">
- <h2 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/also_in_the_news/">Also In The News</a></h2>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" stacked-144">
- <a class="headline-anchor" rel="published-1302284283617" href="httpdisabled://www.bbc.co.uk/news/world-south-asia-13015768"><img src="../../news.bbcimg.co.uk/media/images/52073000/jpg/_52073406_008253948-1.jpg" alt="Sesame Street characters pose under a &quot;123 Sesame Street&quot; sign, November 2009 in New York City" /><span class="headline heading-13">Sesame Street heads to Pakistan</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
- </div>
- </div>
-<script type="text/javascript">$render("container-compact-section-digests","compact-more-from-bbc-news");</script>
-
-
-
-<div id="featured-other-site---bbc-sport" class="container-featured-other-site">
- <h2 class="container-featured-other-site-heading"><a href="httpdisabled://www.bbc.co.uk/sport2/hi/default.stm">Sport</a></h2>
-
-<div id="featured-site-top-stories---bbc-sport" class="featured-site-top-stories">
-
-
- <ul>
-
-
-
-
- <li class=" medium-image first-child">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3>
- <a class="story" rel="published-1302262215000" href="httpdisabled://www.bbc.co.uk/sport2/hi/golf/9451236.stm"><img src="../../news.bbcimg.co.uk/media/images/52015000/jpg/_52015349_flag_reuters_144.jpg" alt="Masters flag" />Live - 2011 Masters day two</a>
- </h3>
-
- <p>Rory McIlroy leads the Masters by two shots over Australian Jason Day with the second round in full swing at Augusta National.</p>
-
-
-
-
- <hr />
- </li>
-
-
-
-
-
-
- <li class="column-1 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3>
- <a class="story" rel="published-1302289407000" href="httpdisabled://www.bbc.co.uk/sport2/hi/tennis/9452020.stm">Djokovic ruled out of Monte Carlo</a>
- </h3>
-
-
-
-
-
- </li>
-
-
-
-
-
-
- <li class="column-2 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3>
- <a class="story" rel="published-1302260853390" href="httpdisabled://www.bbc.co.uk/sport2/hi/football/13013741.stm">Rooney ref pressurised - Ferguson</a>
- </h3>
-
-
-
-
-
- </li>
-
-
-
-
-
-
- <li class="column-1 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3>
- <a class="story" rel="published-1302190310000" href="httpdisabled://www.bbc.co.uk/sport2/hi/rugby_league/9447492.stm">Wigan 28-47 Catalan Dragons</a>
- </h3>
-
-
-
-
-
- </li>
-
-
-
-
-
-
- <li class="column-2 ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3>
- <a class="story" rel="published-1302169822000" href="httpdisabled://www.bbc.co.uk/sport2/hi/rugby_league/9447490.stm">Huddersfield 29-10 Warrington</a>
- </h3>
-
-
-
-
-
- </li>
-
- </ul>
-</div>
-<script type="text/javascript">$render("featured-site-top-stories","featured-site-top-stories---bbc-sport");</script>
-
-</div>
-<script type="text/javascript">$render("container-featured-other-site","featured-other-site---bbc-sport");</script>
- <div id="geographic-news-digests-no-tabs" class="container-digest-grid">
-
-<div id="compact-geographic-section-digests" class="container-block-grid">
- <h2 class="heading-24">World News</h2>
-
-
- <div class="digest-wrapper digest-grid-list-column">
-
- <div class="digest-unit first-child">
- <h3 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/world/us_and_canada/">US &amp; Canada</a></h3>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" standard-no-image">
- <a class="headline-anchor" rel="published-1302257749429" href="httpdisabled://www.bbc.co.uk/news/technology-13010760">US developing activist technology</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
- <div class="digest-unit ">
- <h3 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/world/latin_america/">Latin America</a></h3>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" standard-no-image">
- <a class="headline-anchor" rel="published-1302291982657" href="httpdisabled://www.bbc.co.uk/news/world-latin-america-13020999">Brazil mourns murdered Rio pupils</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
- <div class="digest-unit ">
- <h3 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/world/africa/">Africa</a></h3>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" standard-no-image">
- <a class="headline-anchor" rel="published-1302289064895" href="httpdisabled://www.bbc.co.uk/news/world-africa-13021093">Bomb hits Nigeria election office</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
- <div class="digest-unit ">
- <h3 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/world/asia_pacific/">Asia-Pacific</a></h3>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" standard-no-image">
- <a class="headline-anchor" rel="published-1302187507701" href="httpdisabled://www.bbc.co.uk/news/world-asia-pacific-13005110">Three dead after Japan aftershock</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
- </div>
- <div class="digest-wrapper digest-grid-list-column">
-
- <div class="digest-unit first-child">
- <h3 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/world/europe/">Europe</a></h3>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" standard-no-image">
- <a class="headline-anchor" rel="published-1302257160809" href="httpdisabled://www.bbc.co.uk/news/world-europe-13011540">Medvedev denounces cyber-attack</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
- <div class="digest-unit ">
- <h3 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/world/middle_east/">Middle East</a></h3>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" standard-no-image">
- <a class="headline-anchor" rel="published-1302275084283" href="httpdisabled://www.bbc.co.uk/news/world-middle-east-13017502">Yemeni forces fire on protesters</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
-
- <div class="digest-unit ">
- <h3 class="heading-16"><a href="httpdisabled://www.bbc.co.uk/news/world/south_asia/">South Asia</a></h3>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<div class=" standard-no-image">
- <a class="headline-anchor" rel="published-1302237618867" href="httpdisabled://www.bbc.co.uk/news/world-south-asia-13009198">India anti-graft protests urged</span></a>
- <br class="ie-clear" />
-</div>
-
- </div>
-
- </div>
- </div>
-
-
-
-</div>
-<script type="text/javascript">$render("container-digest-grid","geographic-news-digests-no-tabs");</script>
-
-
-<div id="digest-from-a-single-section---container" class="container-single-section-digest">
- <h2 class="container-single-section-digest-heading"><a href="httpdisabled://www.bbc.co.uk/news/uk/">UK News</a></h2>
-
-
- <div id="geo-uk-digest" class="geo-digest-region-2">
-<script type="text/javascript">$render("personalisation-panel","geo-uk-digest",{panelId:"personalisation"});</script>
-</div>
-
-
-
- <div id="single-section-digest" class="container-digest-grid">
- <ul class="digest-wrapper digest-grid-text-only">
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class=" digest-unit standard-no-image first-child">
- <a class="headline-anchor" rel="published-1302263207369" href="httpdisabled://www.bbc.co.uk/news/uk-politics-13013250">Osborne downplays bailout impact</span></a>
- <br class="ie-clear" />
-</li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class=" digest-unit standard-no-image ">
- <a class="headline-anchor" rel="published-1302290270060" href="httpdisabled://www.bbc.co.uk/news/business-13020668">Pinewood studios gets £87.8m bid</span></a>
- <br class="ie-clear" />
-</li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class=" digest-unit standard-no-image ">
- <a class="headline-anchor" rel="published-1302281869114" href="httpdisabled://www.bbc.co.uk/news/uk-northern-ireland-13020381">Third man arrested over NI murder</span></a>
- <br class="ie-clear" />
-</li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class=" digest-unit standard-no-image ">
- <a class="headline-anchor" rel="published-1302270359690" href="httpdisabled://www.bbc.co.uk/news/uk-england-13015824">Court rejects deportation appeal</span></a>
- <br class="ie-clear" />
-</li>
-
-
- </ul>
-</div>
-
-</div>
-<script type="text/javascript">$render("container-single-section-digest","digest-from-a-single-section---container");</script>
-
-<div id="special-reports" class="special-reports-component">
-
- <h2 class="special-reports-header">
- Special Reports
- </h2>
-
-
- <div class="special-reports-wrapper">
-
-
-
-
- <div class="top-report">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3>
- <a class="story" rel="published-1289925174387" href="httpdisabled://www.bbc.co.uk/news/uk-11767495"><img src="../../news.bbcimg.co.uk/media/images/50112000/jpg/_50112416_010706746-1.jpg" alt="Kate Middleton&#039;s engagement ring" />Britain&#039;s Royal Wedding</a>
- </h3>
- <p>News and features on the royal engagement</p>
-
-
- <div class="bbccom_advert_placeholder">
- <script type="text/javascript">$render("advert","advert-sponsor-module","special-reports","britains-royal-wedding");</script>
- </div>
- <script type="text/javascript">$render("advert-post-script-loaddisabled");</script>
-
- </div>
-
- <div class="more-special-reports">
- <h3 class="more">More Special Reports:</h3>
- <ul>
- <li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h4>
- <a class="story" rel="published-1300297841012" href="httpdisabled://www.bbc.co.uk/news/world-asia-pacific-12711226">Japan earthquake</a>
- </h4>
- </li>
-
-
- <li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h4>
- <a class="story" rel="published-1297967084658" href="httpdisabled://www.bbc.co.uk/news/world-middle-east-12480844">Libya crisis</a>
- </h4>
- </li>
-
- </ul>
- </div>
- </div>
-
-</div>
-<script type="text/javascript">$render("special-reports","special-reports");</script>
-
-
-
-<div id="featured-other-site---democracy-live" class="container-featured-other-site">
- <div id="featured-site-include---democracy-live" class="include-only featured-site-include">
-
-
-
-<div id="from-bbc-travel" class="container-other-site-promotion ">
- <h2 class="other-site-content-header"><a href="httpdisabled://www.bbc.com/travel/">From BBC Travel</a></h2>
- <div id="other-site-content-1" class="other-site-content first-group">
- <ul class="stacked-content-group stacked-overlay-other-site-promotion ">
- <li class="first-other-promo">
- <h3>
- <a class="story" href="httpdisabled://www.bbc.com/travel/feature/20110407-amsterdam-on-wheels">
- <span class="overlay">
- <strong class="headline">Amsterdam on wheels</strong>
- <span class="summary">Make like a local in the bike capital of Europe</span>
- </span>
- <img alt="Peddling through Amsterdam" src="../../static.bbc.co.uk/wwtravel/img/ic/304-170/130203147123329681316_1.jpg" />
- </a>
- </h3>
- </li>
- </ul>
- </div>
- <div id="other-site-content-2" class="other-site-content ">
- <ul class="stacked-content-group stacked-overlay-other-site-promotion ">
- <li class="first-other-promo">
- <h3>
- <a class="story" href="httpdisabled://www.bbc.com/travel/feature/20110324-40-free-attractions-in-new-york-city">
- <span class="overlay">
- <strong class="headline">Free attractions in New York</strong>
- <span class="summary">Forty things to do without handing over a cent</span>
- </span>
- <img alt="City Hall, New York" src="../../static.bbc.co.uk/wwtravel/img/ic/304-170/1300928948164652012_1.jpg" />
- </a>
- </h3>
- </li>
- </ul>
- </div>
-</div>
-<script type="text/javascript">$render("container-other-site-promotion","from-bbc-travel");</script>
-</div>
-<script type="text/javascript">$render("featured-site-include---democracy-live","featured-site-include---democracy-live");</script>
-</div>
-<script type="text/javascript">$render("container-featured-other-site","featured-other-site---democracy-live");</script>
-
-<div class="languages">
- <h3><a href="httpdisabled://www.bbc.co.uk/worldservice/">BBC World Service</a></h3>
- <h4>News and analysis in 32 languages</h4>
- <ul>
- <li><a href="httpdisabled://www.bbc.co.uk/arabic"><span class="lang-with-image">Arabic</span> <span class="lang-sprite lang-arabic">عربي</span></a></li>
- <li><a href="httpdisabled://www.bbc.co.uk/chinese"><span class="lang-with-image">Chinese</span> <span class="lang-sprite lang-chinese">&#20013;&#25991;</span></a></li>
- </ul>
- <h5>Languages continued (2 of 4)</h5>
- <ul>
- <li><a href="httpdisabled://www.bbcpersian.com/"><span class="lang-with-image">Persian</span> <span class="lang-sprite lang-persian">&#x0641;&#x0627;&#x0631;&#x0633;&#x06cc;</span></a></li>
- <li><a href="httpdisabled://www.bbc.co.uk/portuguese"><span class="lang-with-image">Portuguese</span> <span class="lang-sprite lang-brasil">Brasil</span></a></li>
- </ul>
- <h5>Languages continued (3 of 4)</h5>
- <ul>
- <li><a href="httpdisabled://www.bbc.co.uk/russian"><span class="lang-with-image">Russian</span> <span class="lang-sprite lang-russian">&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081;</span></a></li>
- <li><a href="httpdisabled://www.bbcmundo.com/"><span class="lang-with-image">Spanish</span> <span class="lang-sprite lang-mundo">Mundo</span></a></li>
- </ul>
- <h5>Languages continued (4 of 4)</h5>
- <ul>
- <li><a href="httpdisabled://www.bbcurdu.com/"><span class="lang-with-image">Urdu</span> <span class="lang-sprite lang-urdu">&#x0627;&#x0631;&#x062f;&#x0648;</span></a></li>
- <li><a href="httpdisabled://www.bbc.co.uk/vietnamese"><span class="lang-with-image">Vietnamese</span> <span class="lang-sprite lang-vietnamese">Ti&#x1ebf;ng Vi&#x1ec7;t</span></a></li>
- </ul>
- <div class="languages-footer">
- <a href="httpdisabled://www.bbc.co.uk/worldservice/languages/">More languages</a>
- </div>
-</div>
-
-
-</div>
-<script type="text/javascript">$render("container-now","now");</script>
-
-<div id="best" class="container-best">
-
-<div id="promo-best" class="container-promo-best">
-
-<div class="bbccom_advert_placeholder">
- <script type="text/javascript">$render("advert","advert-mpu-high");</script>
-</div>
-<script type="text/javascript">$render("advert-post-script-loaddisabled");</script>
-
-
-<div id="av-best" class="container-av-best">
-
-
- <div id="av-stories-best" class="av-stories-best">
-
- <h2 class="av-best-header">Watch/Listen</h2>
-
- <div class="list-wrapper">
-
-
- <ul class="av-best-carousel carousel ">
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li class=" first-child">
- <a class="story" rel="published-1302294075339" href="httpdisabled://www.bbc.co.uk/news/world-africa-13020909"><img src="../../news.bbcimg.co.uk/media/images/52078000/jpg/_52078945_jex_1013338_de27-1.jpg" alt="Election posters" />Doubt over fair Nigerian election<span class="gvl3-icon-wrapper"><span class="gvl3-icon gvl3-icon-invert-watch"> Watch</span></span></a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li>
- <a class="story" rel="published-1302263035778" href="httpdisabled://www.bbc.co.uk/news/technology-13012083"><img src="../../news.bbcimg.co.uk/media/images/52068000/jpg/_52068942_jex_1012675_de09-1.jpg" alt="Dutch &#039;super bus&#039;" />Electric &#039;super bus&#039; reaches 250km/h<span class="gvl3-icon-wrapper"><span class="gvl3-icon gvl3-icon-invert-watch"> Watch</span></span></a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li>
- <a class="story" rel="published-1302284070065" href="httpdisabled://www.bbc.co.uk/news/world-south-asia-13020443"><img src="../../news.bbcimg.co.uk/media/images/52077000/jpg/_52077604_jex_1013246_de27-1.jpg" alt="Security forces" />Cleric killed by bomb in Kashmir<span class="gvl3-icon-wrapper"><span class="gvl3-icon gvl3-icon-invert-watch"> Watch</span></span></a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li>
- <a class="story" rel="published-1302291873011" href="httpdisabled://www.bbc.co.uk/news/world-middle-east-13021417"><img src="../../news.bbcimg.co.uk/media/images/52079000/jpg/_52079170_jex_1013354_de30-1.jpg" alt="Amateur video appearing to show protesters in Banias" />Deadly protests sweep across Syria<span class="gvl3-icon-wrapper"><span class="gvl3-icon gvl3-icon-invert-watch"> Watch</span></span></a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li>
- <a class="story" rel="published-1302268171566" href="httpdisabled://www.bbc.co.uk/news/world-africa-13012968"><img src="../../news.bbcimg.co.uk/media/images/52072000/jpg/_52072276_jex_1012855_de27-1.jpg" alt="Plumes of smoke after the Nato attack on rebel forces" />Confusion over Nato Libya strike<span class="gvl3-icon-wrapper"><span class="gvl3-icon gvl3-icon-invert-watch"> Watch</span></span></a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li>
- <a class="story" rel="published-1302286920993" href="httpdisabled://www.bbc.co.uk/news/world-africa-13020575"><img src="../../news.bbcimg.co.uk/media/images/52077000/jpg/_52077993_ivory_coast.jpg" alt="Armed pro-Ouattara forces" />Divided loyalties in Ivory Coast <span class="gvl3-icon-wrapper"><span class="gvl3-icon gvl3-icon-invert-watch"> Watch</span></span></a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li>
- <a class="story" rel="published-1302279220278" href="httpdisabled://www.bbc.co.uk/news/business-13018318"><img src="../../news.bbcimg.co.uk/media/images/52076000/jpg/_52076863_jex_1013152_de27-1.jpg" alt="Toyota car in production" />Toyota production returns to Japan<span class="gvl3-icon-wrapper"><span class="gvl3-icon gvl3-icon-invert-watch"> Watch</span></span></a>
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
-
-<li>
- <a class="story" rel="published-1302215956187" href="httpdisabled://www.bbc.co.uk/newsbeat/13005125"><img src="../../news.bbcimg.co.uk/media/images/52058000/jpg/_52058744_jex_1012144_de27-1.jpg" alt="Pillow fight" />Giant pillow fight - it&#039;s Odd Box<span class="gvl3-icon-wrapper"><span class="gvl3-icon gvl3-icon-invert-watch"> Watch</span></span></a>
- </li>
- </ul>
- </div>
-
- </div>
-
- <script type="text/javascript">$render("av-stories-best","av-stories-best");</script>
-
-
-
-<div id="av-live-streams" class="av-live-streams">
-
-
-
-
- <div class="av-live-streams-include">
- <ul id="news-channel-promotion" class="news-channel-promotion">
- <li class="latest-summary"><h3>Latest summary:</h3> <a href="httpdisabled://www.bbc.co.uk/news/10462520" class="story watch">Watch <span class="gvl3-icon gvl3-icon-boxedwatch"> latest news summary</span></a> <a href="httpdisabled://www.bbc.co.uk/worldservice/includes/1024/screen/audio_console.shtml?stream=news_bullettin" class="story listen">Listen <span class="gvl3-icon gvl3-icon-boxedlisten"> latest news summary</span></a></li>
- <li class="has-icon-boxedlive ">
- <a href="httpdisabled://www.bbc.co.uk/iplayer/console/bbc_world_service" class="story is-live" onclick="javascript: void void('http://www.bbc.co.uk/iplayer/console/bbc_world_service', 'BBC', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=512,height=270,left=0,top=0'); return false;" >BBC World Service <span class="gvl3-icon gvl3-icon-boxedlive">Live</span></a>
- </li>
-</ul>
-<script type="text/javascript">$render("news-channel-promotion","news-channel-promotion");</script>
-
- </div>
- </div>
-<script type="text/javascript">$render("av-live-streams","av-live-streams");</script>
-
-</div>
-<script type="text/javascript">$render("container-av-best","av-best");</script>
-
-<div class="bbccom_advert_placeholder">
- <script type="text/javascript">$render("advert","advert-mpu-low");</script>
-</div>
-<script type="text/javascript">$render("advert-post-script-loaddisabled");</script>
-
-</div>
-<script type="text/javascript">$render("container-promo-best","promo-best");</script>
-
-<div id="features-and-analysis" class="container-features-and-analysis">
- <h2 class="features-header">Features &amp; Analysis</h2>
-
- <ul>
-
-
-
-
-
-
- <!-- Non specific version -->
-
-
-
- <li class="medium-image">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3 class=" feature-header">
- <a class="story" rel="published-1302264356466" href="httpdisabled://www.bbc.co.uk/news/world-middle-east-13013322"><img src="../../news.bbcimg.co.uk/media/images/52069000/jpg/_52069270_011711396-1.jpg" alt="An Iron Dome battery outside Ashkelon (4 April 2011)" />&#039;Iron Dome&#039;</a>
- </h3>
-
- <p>Israel&#039;s missile defence system may be a game changer </p>
-
- <hr />
- </li>
-
-
- <li class="medium-image">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3 class=" feature-header">
- <a class="story" rel="published-1302268714570" href="httpdisabled://www.bbc.co.uk/news/world-asia-pacific-13010757"><img src="../../news.bbcimg.co.uk/media/images/52073000/jpg/_52073764_011717136-1.jpg" alt="A Humboldt penguin swims at a zoo in Lusisenpark, Mannheim, Germany, on 8/4/11" />Day in pictures</a>
- </h3>
-
- <p>Striking images from around the world </p>
-
- <hr />
- </li>
-
-
- <li class="medium-image">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3 class=" feature-header">
- <a class="story" rel="published-1302230709033" href="httpdisabled://www.bbc.co.uk/news/magazine-12986535"><img src="../../news.bbcimg.co.uk/media/images/52058000/jpg/_52058296_holdring_thinks.jpg" alt="Man holding wedding ring" />Ring thing</a>
- </h3>
-
- <p>When did most men start wearing wedding bands? </p>
-
- <hr />
- </li>
-
-
- <li class="medium-image">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3 class=" feature-header">
- <a class="story" rel="published-1302217882578" href="httpdisabled://www.bbc.co.uk/news/world-12992548"><img src="../../news.bbcimg.co.uk/media/images/52057000/jpg/_52057539_arniecomp.jpg" alt="Arnie" />It&#039;s quiz time!</a>
- </h3>
-
- <p>Arnie said he&#039;d be back - but what as? </p>
-
- <hr />
- </li>
-
-
-
-
-
-
-
-
-
-
-
-
- <!-- Non specific version -->
-
-
-
- <li class="no-image">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3 class=" feature-header">
- <a class="story" rel="published-1302254723664" href="httpdisabled://www.bbc.co.uk/news/magazine-12893416">LOL&#039;s triumph</a>
- </h3>
-
- <p>How did a little web acronym spread so fast? </p>
-
- </li>
-
-
- <li class="no-image">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3 class=" feature-header">
- <a class="story" rel="published-1302218200000" href="httpdisabled://www.bbc.co.uk/2/hi/programmes/from_our_own_correspondent/9450807.stm">Driving on ice</a>
- </h3>
-
- <p>No seatbelts allowed on Europe&#039;s longest road over frozen sea <a class="from-external-source" href="httpdisabled://www.bbc.co.uk/1/hi/programmes/from_our_own_correspondent/default.stm">From our own correspondent</a>
- </p>
-
- </li>
-
-
- <li class="no-image">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3 class=" feature-header">
- <a class="story" rel="published-1302217339004" href="httpdisabled://www.bbc.co.uk/news/world-south-asia-13001640">Unloved US</a>
- </h3>
-
- <p>Rage against America breaks out in Afghanistan and Pakistan </p>
-
- </li>
-
-
-
-
-
-
- </ul>
-</div>
-<script type="text/javascript">$render("container-features-and-analysis","features-and-analysis");</script>
-
- <div id="special-event-promotion-best-promo-module-hyper" class="include-only special-event-promotion-best">
-
-
-
-
-
- <div class="hyperpuff">
- <div id="promotional-content" class="hyper-promotional-content">
-
- <h2>Elsewhere on BBC News</h2>
-
- <ul>
-
-
-
- <li class="medium-image first-child">
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3>
- <a class="story" rel="published-1302259690526" href="httpdisabled://www.bbc.co.uk/news/business-13000883"><img src="../../news.bbcimg.co.uk/media/images/52063000/jpg/_52063276_52063272.jpg" alt="Apps" />An app for that</a>
- </h3>
- <p>In a competitive, developing marketplace will apps remain a feature of business?</p>
- </li>
- </ul>
-
- <div class="bbccom_advert_placeholder">
- <script type="text/javascript">$render("advert","advert-sponsor-module","hyper-promotional-content","an-app-for-that");</script>
- </div>
- <script type="text/javascript">$render("advert-post-script-loaddisabled");</script>
-
-</div>
-<script type="text/javascript">$render("hyper-promotional-content","promotional-content");</script>
-
-
- </div>
-
-</div>
-<script type="text/javascript">$render("special-event-promotion-best-promo-module-hyper","special-event-promotion-best-promo-module-hyper");</script>
- <div id="market-data-include" class="include-only market-data-include">
- <div class="market-data">
-<h2><a href="httpdisabled://www.bbc.co.uk/news/business/market_data/overview/default.stm">Market Data</a></h2>
-<p class="mkt-last-updated">Last Updated at 17:56 ET</p>
-
-<table class="mkt-table">
- <tbody>
- <tr class="table-headers">
- <th id="mkt-index">Market index</th>
- <th id="mkt-current">Current value</th>
- <th id="mkt-trend">Trend</th>
- <th id="mkt-var">Variation</th>
- <th id="mkt-percent">% variation</th>
- </tr>
-
- <tr class="mkt-down">
- <td headers="mkt-index" class="mkt-index"><a href="httpdisabled://www.bbc.co.uk/news/business/market_data/stockmarket/2/default.stm">Dow Jones</a></td>
- <td headers="mkt-current">12380.05</td>
- <td headers="mkt-trend" class="mkt-trend"><span class="mkt-trend-image">Down</span></td>
- <td headers="mkt-var">-29.44</td>
- <td headers="mkt-percent" class="mkt-percent">-0.24%</td>
- </tr>
-
- <tr class="mkt-down">
- <td headers="mkt-index" class="mkt-index"><a href="httpdisabled://www.bbc.co.uk/news/business/market_data/stockmarket/12122/default.stm">Nasdaq</a></td>
- <td headers="mkt-current">2780.41</td>
- <td headers="mkt-trend" class="mkt-trend"><span class="mkt-trend-image">Down</span></td>
- <td headers="mkt-var">-15.72</td>
- <td headers="mkt-percent" class="mkt-percent">-0.56%</td>
- </tr>
-
- <tr class="mkt-down">
- <td headers="mkt-index" class="mkt-index"><a href="httpdisabled://www.bbc.co.uk/news/business/market_data/stockmarket/11826/default.stm">S&amp;P 500</a></td>
- <td headers="mkt-current">1328.17</td>
- <td headers="mkt-trend" class="mkt-trend"><span class="mkt-trend-image">Down</span></td>
- <td headers="mkt-var">-5.34</td>
- <td headers="mkt-percent" class="mkt-percent">-0.40%</td>
- </tr>
-
- <tr class="mkt-up">
- <td headers="mkt-index" class="mkt-index"><a href="httpdisabled://www.bbc.co.uk/news/business/market_data/stockmarket/3/default.stm">FTSE 100</a></td>
- <td headers="mkt-current">6055.75</td>
- <td headers="mkt-trend" class="mkt-trend"><span class="mkt-trend-image">Up</span></td>
- <td headers="mkt-var">48.38</td>
- <td headers="mkt-percent" class="mkt-percent">0.81%</td>
- </tr>
-
- <tr class="mkt-up">
- <td headers="mkt-index" class="mkt-index"><a href="httpdisabled://www.bbc.co.uk/news/business/market_data/stockmarket/18/default.stm">Dax</a></td>
- <td headers="mkt-current">7217.02</td>
- <td headers="mkt-trend" class="mkt-trend"><span class="mkt-trend-image">Up</span></td>
- <td headers="mkt-var">38.24</td>
- <td headers="mkt-percent" class="mkt-percent">0.53%</td>
- </tr>
-
- <tr class="mkt-up">
- <td headers="mkt-index" class="mkt-index"><a href="httpdisabled://www.bbc.co.uk/news/business/market_data/stockmarket/29954/default.stm">BBC Global 30</a></td>
- <td headers="mkt-current">5727.44</td>
- <td headers="mkt-trend" class="mkt-trend"><span class="mkt-trend-image">Up</span></td>
- <td headers="mkt-var">2.06</td>
- <td headers="mkt-percent" class="mkt-percent">0.02%</td>
- </tr>
-
- </tbody>
-</table>
-
-<div class="mkt-footer">
-
-<p><a href="httpdisabled://www.bbc.co.uk/news/business/market_data/ticker/markets/default.stm" class="mkt-ticker">Marketwatch ticker</a></p>
-
-<p class="mkt-data-delayed">Data delayed by 15 mins</p>
-</div>
-</div>
-
-
- <div class="bbccom_advert_placeholder">
- <script type="text/javascript">$render("advert","advert-sponsor-module","market-data-include","market-data-include");</script>
- </div>
- <script type="text/javascript">$render("advert-post-script-loaddisabled");</script>
-
-</div>
-<script type="text/javascript">$render("market-data-include","market-data-include");</script>
-
-<div id="most-popular-promotion" class="container-most-popular-promotion">
-
-<div class="bbccom_advert_placeholder">
- <script type="text/javascript">$render("advert","advert-partner-button");</script>
-</div>
-<script type="text/javascript">$render("advert-post-script-loaddisabled");</script>
-
-
-<div id="most-popular" class="livestats livestats-tabbed tabbed most-popular">
-
- <h2 class="livestats-header">Most Popular</h2>
-
-
- <h3 class="void"><a href="index.html#">Shared</a></h3>
-
- <div class="void">
- <ol>
- <li
- class="first-child ol1">
- <a
- href="httpdisabled://www.bbc.co.uk/news/health-12999000"
- class="story">
- <span
- class="livestats-icon livestats-1">1: </span>Cancer 'fuelled by extra drinks'</a>
-</li>
-<li
- class="ol2">
- <a
- href="httpdisabled://www.bbc.co.uk/news/science-environment-13011073"
- class="story">
- <span
- class="livestats-icon livestats-2">2: </span>New York 'at risk' as seas rise </a>
-</li>
-<li
- class="ol3">
- <a
- href="httpdisabled://www.bbc.co.uk/news/science-environment-13009718"
- class="story">
- <span
- class="livestats-icon livestats-3">3: </span>Stars' structure revealed by 'music'</a>
-</li>
-<li
- class="ol4">
- <a
- href="httpdisabled://www.bbc.co.uk/news/uk-england-hampshire-13014640"
- class="story">
- <span
- class="livestats-icon livestats-4">4: </span>Nuclear submarine man shot dead</a>
-</li>
-<li
- class="ol5">
- <a
- href="httpdisabled://www.bbc.co.uk/news/magazine-12893416"
- class="story">
- <span
- class="livestats-icon livestats-5">5: </span>Why did LOL infiltrate the language?</a>
-</li>
- </ol>
- </div>
-
- <h3 class="tab "><a href="index.html#">Read</a></h3>
-
- <div class="panel ">
- <ol>
- <li
- class="first-child ol1">
- <a
- href="httpdisabled://www.bbc.co.uk/news/uk-england-hampshire-13014640"
- class="story">
- <span
- class="livestats-icon livestats-1">1: </span>Nuclear submarine man shot dead</a>
-</li>
-<li
- class="ol2">
- <a
- href="httpdisabled://www.bbc.co.uk/news/world-us-canada-13015909"
- class="story">
- <span
- class="livestats-icon livestats-2">2: </span>Blame game as US shutdown looms</a>
-</li>
-<li
- class="ol3">
- <a
- href="httpdisabled://www.bbc.co.uk/news/science-environment-13011073"
- class="story">
- <span
- class="livestats-icon livestats-3">3: </span>New York 'at risk' as seas rise </a>
-</li>
-<li
- class="ol4">
- <a
- href="httpdisabled://www.bbc.co.uk/news/health-12999000"
- class="story">
- <span
- class="livestats-icon livestats-4">4: </span>Cancer 'fuelled by extra drinks'</a>
-</li>
-<li
- class="ol5">
- <a
- href="httpdisabled://www.bbc.co.uk/news/world-asia-pacific-13010757"
- class="story">
- <span
- class="livestats-icon livestats-5">5: </span>Day in pictures</a>
-</li>
-<li
- class="ol6">
- <a
- href="httpdisabled://www.bbc.co.uk/news/world-us-canada-12571718"
- class="story">
- <span
- class="livestats-icon livestats-6">6: </span>What does 'government shutdown' mean?</a>
-</li>
-<li
- class="ol7">
- <a
- href="httpdisabled://www.bbc.co.uk/news/science-environment-12990213"
- class="story">
- <span
- class="livestats-icon livestats-7">7: </span>Strangely silent star system seen</a>
-</li>
-<li
- class="ol8">
- <a
- href="httpdisabled://www.bbc.co.uk/news/world-middle-east-13013322"
- class="story">
- <span
- class="livestats-icon livestats-8">8: </span>Israeli new missile defence in action</a>
-</li>
-<li
- class="ol9">
- <a
- href="httpdisabled://www.bbc.co.uk/news/world-13016843"
- class="story">
- <span
- class="livestats-icon livestats-9">9: </span>Syrian city hit by deadly clashes</a>
-</li>
-<li
- class="ol10">
- <a
- href="httpdisabled://www.bbc.co.uk/news/magazine-12986535"
- class="story">
- <span
- class="livestats-icon livestats-10">10: </span>Without this ring, I thee wed</a>
-</li>
- </ol>
- </div>
-
- <h3 class="tab "><a href="index.html#">Video/Audio</a></h3>
-
- <div class="panel ">
- <ol>
- <li
- class="first-child has-icon-watch ol1">
- <a
- href="httpdisabled://www.bbc.co.uk/news/technology-13012083"
- class="story">
- <span
- class="livestats-icon livestats-1">1: </span>Electric 'super bus' reaches 250km/h<span
- class="gvl3-icon gvl3-icon-watch"> Watch</span></a>
-</li>
-<li
- class="has-icon-watch ol2">
- <a
- href="httpdisabled://www.bbc.co.uk/news/uk-13020498"
- class="story">
- <span
- class="livestats-icon livestats-2">2: </span>'Submarine security was not breached'<span
- class="gvl3-icon gvl3-icon-watch"> Watch</span></a>
-</li>
-<li
- class="has-icon-watch ol3">
- <a
- href="httpdisabled://www.bbc.co.uk/news/world-us-canada-12994270"
- class="story">
- <span
- class="livestats-icon livestats-3">3: </span>US government shutdown - what next?<span
- class="gvl3-icon gvl3-icon-watch"> Watch</span></a>
-</li>
-<li
- class="has-icon-watch ol4">
- <a
- href="httpdisabled://www.bbc.co.uk/news/health-13010512"
- class="story">
- <span
- class="livestats-icon livestats-4">4: </span>Alcohol can increase cancer risk<span
- class="gvl3-icon gvl3-icon-watch"> Watch</span></a>
-</li>
-<li
- class="has-icon-watch ol5">
- <a
- href="httpdisabled://www.bbc.co.uk/news/world-middle-east-13016690"
- class="story">
- <span
- class="livestats-icon livestats-5">5: </span>'Protesters shot' in Syria rally<span
- class="gvl3-icon gvl3-icon-watch"> Watch</span></a>
-</li>
-<li
- class="has-icon-watch ol6">
- <a
- href="httpdisabled://www.bbc.co.uk/news/video_and_audio/"
- class="story">
- <span
- class="livestats-icon livestats-6">6: </span>One-minute World News<span
- class="gvl3-icon gvl3-icon-watch"> Watch</span></a>
-</li>
-<li
- class="has-icon-watch ol7">
- <a
- href="httpdisabled://www.bbc.co.uk/news/world-us-canada-13020801"
- class="story">
- <span
- class="livestats-icon livestats-7">7: </span>Protest over US budget stalemate<span
- class="gvl3-icon gvl3-icon-watch"> Watch</span></a>
-</li>
-<li
- class="has-icon-watch ol8">
- <a
- href="httpdisabled://www.bbc.co.uk/news/science-environment-13009718"
- class="story">
- <span
- class="livestats-icon livestats-8">8: </span>Stars' structure revealed by 'music'<span
- class="gvl3-icon gvl3-icon-watch"> Watch</span></a>
-</li>
-<li
- class="has-icon-watch ol9">
- <a
- href="httpdisabled://www.bbc.co.uk/news/uk-13020502"
- class="story">
- <span
- class="livestats-icon livestats-9">9: </span>'I wrestled the gunman to the ground'<span
- class="gvl3-icon gvl3-icon-watch"> Watch</span></a>
-</li>
-<li
- class="has-icon-watch ol10">
- <a
- href="httpdisabled://www.bbc.co.uk/news/world-us-canada-13021011"
- class="story">
- <span
- class="livestats-icon livestats-10">10: </span>Boehner's battle over spending<span
- class="gvl3-icon gvl3-icon-watch"> Watch</span></a>
-</li>
- </ol>
- </div>
-
- <div class="bbccom_advert_placeholder">
- <script type="text/javascript">$render("advert","advert-sponsor-module","most-popular","most-popular");</script>
- </div>
- <script type="text/javascript">$render("advert-post-script-loaddisabled");</script>
-
-</div>
-
-<script type="text/javascript">$render("most-popular","most-popular");</script>
-
-</div>
-<script type="text/javascript">$render("container-most-popular-promotion","most-popular-promotion");</script>
- <div id="programmes-promotion" class="include-only programmes-promotion">
-
-
-
-
-
- <div class="hyperpuff">
-
-
-
-
-<div id="container-programme-promotion" class="container-programme-promotion">
- <h2 class="programmes-header">Programmes</h2>
-
-
-
- <ul class="programmes-standard">
-
-
-
- <li class="medium-image first-item">
-
-
-
-
-
-
-
-
-
-
-
-
-
-<h3 class=" programme-header">
- <a class="story" rel="published-1302263131000" href="httpdisabled://www.bbc.co.uk/2/hi/programmes/click_online/9451425.stm"><img src="../../news.bbcimg.co.uk/media/images/52072000/jpg/_52072121_-3.jpg" alt="A scientist monitors radiation" />Click<span class="gvl3-icon-wrapper"><span class="gvl3-icon gvl3-icon-invert-listen"> Listen</span></span></a>
- </h3>
- <p>How radiation level readings from Japan are being crowd-sourced</p>
- <hr />
- </li>
-</ul>
-
- <div id="data-feed-best" class="include-only data-feed-best">
- <h3><a href="httpdisabled://www.bbc.co.uk/worldservice/programmes/">BBC World Service</a></h3>
- <ul><li class="no-image"><h4 class="has-icon-listen programme-header"><a class="story" href="httpdisabled://www.bbc.co.uk/iplayer/episode/b00zxn8x/From_Our_Own_Correspondent_02_04_2011/">From Our Own Correspondent<span xmlns:ion="httpdisabled://bbc.co.uk/2008/iplayer/ion" class="gvl3-icon gvl3-icon-invert-boxedlisten"> Listen</span></a></h4><p>Kate Adie hosts stories from reporters around the world.</p></li><li class="no-image"><h4 class="has-icon-listen programme-header"><a class="story" href="httpdisabled://www.bbc.co.uk/iplayer/episode/p00fvlfm/Newshour_07_04_2011_(2000_GMT)/">Newshour<span xmlns:ion="httpdisabled://bbc.co.uk/2008/iplayer/ion" class="gvl3-icon gvl3-icon-invert-boxedlisten"> Listen</span></a></h4><p>Who bombed Libyan rebels? Brazil school shooting; George Washington's belongings auctioned</p></li></ul>
-</div>
-<script type="text/javascript">$render("data-feed-best","data-feed-best");</script>
- </div>
-<script type="text/javascript">$render("container-programmes-promotion","container-programme-promotion");</script>
-
- </div>
-
-</div>
-<script type="text/javascript">$render("programmes-promotion","programmes-promotion");</script>
-
-<div class="bbccom_advert_placeholder">
- <script type="text/javascript">$render("advert","advert-google-adsense");</script>
-</div>
-<script type="text/javascript">$render("advert-post-script-loaddisabled");</script>
-
-</div>
-<script type="text/javascript">$render("container-best","best");</script>
-
- <!-- END #MAIN-CONTENT & CPS_ASSET_TYPE CLASS: index -->
- </div>
-<!-- END CPS_AUDIENCE CLASS: us -->
-
-</div>
-<div id="related-services" class="footer">
- <div id="news-services">
- <h2>Services</h2>
- <ul>
- <li id="service-feeds"><a href="httpdisabled://www.bbc.co.uk/news/10628494"><span class="gvl3-feeds-icon-large services-icon">&nbsp;</span>News feeds</a></li>
- <li id="service-mobile" class="first-child"><a href="httpdisabled://www.bbc.co.uk/news/help-10801499"><span class="gvl3-mobile-icon-large services-icon">&nbsp;</span>Mobile</a></li>
- <li id="service-podcasts"><a href="httpdisabled://www.bbc.co.uk/podcasts/"><span class="gvl3-podcast-icon-large services-icon">&nbsp;</span>Podcasts</a></li>
- <li id="service-alerts"><a href="httpdisabled://www.bbc.co.uk/news/10628323"><span class="gvl3-alerts-icon-large services-icon">&nbsp;</span>Alerts</a></li>
- <li id="service-email-news"><a href="httpdisabled://newsvote.bbc.co.uk/email"><span class="gvl3-email-icon-large services-icon">&nbsp;</span>E-mail news</a></li>
- </ul>
- </div>
- <div id="news-related-sites">
- <h2>About BBC News</h2>
- <ul>
- <li class="column-1"><a href="httpdisabled://www.bbc.co.uk/blogs/theeditors/">Editors' blog</a></li>
- <li class="column-1"><a href="httpdisabled://www.bbc.co.uk/journalism/">BBC College of Journalism</a></li>
- <li class="column-1"><a href="httpdisabled://www.bbc.co.uk/news/10621655">News sources</a></li>
- <li class="column-1"><a href="httpdisabled://www.bbc.co.uk/worldservice/trust/">World Service Trust</a></li>
- </ul>
- </div>
-</div>
-</div><!-- close front-page -->
-
-
-
-
-
-
- </div> <div id="blq-mast" class="blq-rst blq-mast-light blq-new-nav" xml:lang="en-GB"> <div id="blq-acc-mobile"><a href="httpdisabled://www.bbc.co.uk/news/mobile/">Mobile</a></div> <form method="get" action="httpdisabled://search.bbc.co.uk/search" accept-charset="utf-8"> <p> <input type="hidden" name="go" value="toolbar" /> <input type="hidden" value="httpdisabled://www.bbc.co.uk/news/" name="uri" /> <input type="hidden" name="scope" value="news" /> <label for="blq-search" class="blq-hide">Search term:</label> <input id="blq-search" type="text" name="q" value="" maxlength="128" /> <input id="blq-search-btn" type="submit" value="Search" /> </p> </form> <h2 class="blq-hide">bbc.co.uk navigation</h2> <ul id="blq-nav-main" class="blq-not-uk"> <li id="blq-nav-n"><a href="index.html" hreflang="en-GB">News</a></li> <li id="blq-nav-s"><a href="httpdisabled://news.bbc.co.uk/sport/" hreflang="en-GB">Sport</a></li> <li id="blq-nav-w"><a href="httpdisabled://news.bbc.co.uk/weather/" hreflang="en-GB">Weather</a></li> <li id="blq-nav-tr"> <a href="httpdisabled://www.bbc.com/travel/" hreflang="en-GB">Travel</a> </li> <li id="blq-nav-t"><a href="httpdisabled://www.bbc.co.uk/tv/" hreflang="en-GB">TV</a></li> <li id="blq-nav-r"><a href="httpdisabled://www.bbc.co.uk/radio/" hreflang="en-GB">Radio</a></li> <li id="blq-nav-m"><a href="index.html#blq-nav">More</a></li> </ul> </div> <div id="blq-nav" class="blq-orange blq-rst"> <div id="blq-nav-links" class="blq-clearfix" xml:lang="en-GB"> <div id="blq-nav-links-inner"> <ul class="blq-nav-sub blq-first"> <li><a href="httpdisabled://www.bbc.co.uk/cbbc/">CBBC</a></li> <li><a href="httpdisabled://www.bbc.co.uk/cbeebies/">CBeebies</a></li> <li><a href="httpdisabled://www.bbc.co.uk/comedy/">Comedy</a></li> <li><a href="httpdisabled://www.bbc.co.uk/food/">Food</a></li> <li><a href="httpdisabled://www.bbc.co.uk/health/">Health</a></li> </ul> <ul class="blq-nav-sub"> <li><a href="httpdisabled://www.bbc.co.uk/history/">History</a></li> <li><a href="httpdisabled://www.bbc.co.uk/learning/">Learning</a></li> <li><a href="httpdisabled://www.bbc.co.uk/music/">Music</a></li> <li><a href="httpdisabled://www.bbc.co.uk/science/">Science</a></li> <li><a href="httpdisabled://www.bbc.co.uk/nature/">Nature</a></li> </ul> <ul class="blq-nav-sub blq-last"> <li><a href="httpdisabled://www.bbc.co.uk/local/">Local</a></li> <li><a href="httpdisabled://www.bbc.co.uk/northernireland/">Northern Ireland</a></li> <li><a href="httpdisabled://www.bbc.co.uk/scotland/">Scotland</a></li> <li><a href="httpdisabled://www.bbc.co.uk/wales/">Wales</a></li> <li id="blq-az"><a href="httpdisabled://www.bbc.co.uk/a-z/">Full A-Z<span class="blq-hide"> of BBC sites</span></a></li> </ul> </div> </div> </div> <div id="blq-foot" xml:lang="en-GB" class="blq-rst blq-clearfix blq-foot-transparent blq-foot-text-dark"> <div id="blq-footlinks"> <h2 class="blq-hide">BBC links</h2> <ul id="blq-bbclinks"> <li> <a href="httpdisabled://www.bbc.co.uk/aboutthebbc/">About the BBC</a> </li> <li> <a href="httpdisabled://www.bbc.co.uk/help/">BBC Help</a> </li> <li> <a href="httpdisabled://news.bbc.co.uk/newswatch/ifs/hi/feedback/default.stm">Contact Us</a> </li> <li> <a href="httpdisabled://www.bbc.co.uk/accessibility/">Accessibility Help</a> </li> <li> <a href="httpdisabled://www.bbc.co.uk/terms/">Terms of Use</a> </li> <li> <a href="httpdisabled://www.bbc.co.uk/jobs/">Jobs</a> </li> <li> <a href="httpdisabled://www.bbc.co.uk/privacy/">Privacy &amp; Cookies</a> </li> <li> <a href="httpdisabled://www.bbc.co.uk/bbc.com/furtherinformation/">Advertise With Us</a> </li> </ul> </div> <p id="blq-logo" class="blq-footer-image-dark"><img src="../../static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/img/blocks/dark.png" width="84" height="24" alt="BBC" /></p> <p id="blq-disclaim"><span id="blq-copy">BBC &copy; 2011</span> <a href="httpdisabled://www.bbc.co.uk/help/web/links/">The BBC is not responsible for the content of external sites. Read more.</a></p> <div id="blq-obit"><p><strong>This page is best viewed in an up-to-date web browser with style sheets (CSS) enabled. While you will be able to view the content of this page in your current browser, you will not be able to get the full visual experience. Please consider upgrading your browser software or enabling style sheets (CSS) if you are able to do so.</strong></p></div> </div> </div> <div id="bbccomWebBug" class="bbccomWebBug"></div>
-<script type="text/javascript">
-bbcdotcom.stats = {
- "adEnabled" : "yes",
- "contentType" : "HTML",
- "audience" : "us"
-};
-</script>
-
-<script type="text/javascript" src="../../js.revsci.net/gateway/gw.js@csid=J08781"></script>
-<script type="text/javascript">
- DM_tag();
-</script>
-<!-- Start Quantcast tag -->
-<script type="text/javascript">
- _qoptions={
- qacct:"p-ccrmZLtMqYB8w"
- };
-</script>
-<script type="text/javascript" src="../../edge.quantserve.com/quant.js"></script>
-<noscript>
- <div>
- <img src="../../pixel.quantserve.com/pixel/p-ccrmZLtMqYB8w.gif" style="display: none;" height="1" width="1" alt="Quantcast"/>
- </div>
-</noscript>
-<!-- End Quantcast tag -->
-
-<!-- SiteCatalyst code version: H.21.
-Copyright 1996-2010 Adobe, Inc. All Rights Reserved
-More info available at http://www.omniture.com -->
-<script type="text/javascript" src="../../news.bbcimg.co.uk/js/app/bbccom/19_52/s_code.js"></script>
-<script type="text/javascript"><!--
-/* You may give each page an identifying name, server, and channel on
-the next lines. */
-
-/************* DO NOT ALTER ANYTHING BELOW THIS LINE ! **************/
-var s_code=s.t();if(s_code)void(s_code)//--></script>
-<script type="text/javascript"><!--
-if(navigator.appVersion.indexOf('MSIE')>=0)void(unescape('%3C')+'\!-'+'-')
-//--></script><noscript><div><a href="httpdisabled://www.omniture.com" title="Web Analytics"><img
-src="../../bbc.112.2o7.net/b/ss/bbcwglobalprod/1/H.21--NS/0@AQB=1&amp;pccr=true&amp;AQE=1"
-height="1" width="1" alt="" /></a></div></noscript><!--/DO NOT REMOVE/-->
-<!-- End SiteCatalyst code version: H.21. -->
-
-
-
-<!-- Begin comScore Tag -->
-<script type="text/javascript">
- void(unescape("%3Cscript src='" + (document.location.protocol == "httpdisabledsdisabled:" ? "httpdisabledsdisabled://sb" : "httpdisabled://b") + ".scorecardresearch.com/beacon.js' %3E%3C/script%3E"));</script>
-<script type="text/javascript">
- COMSCORE.beacon({
- c1:2,
- c2:"6035051",
- c3:"",
- c4:"www.bbc.co.uk/news/",
- c5:"",
- c6:"",
- c15:""
- });
-</script>
-<noscript>
- <div>
- <img src="../../b.scorecardresearch.com/b2@c1=2&amp;c2=6035051&amp;c3=&amp;c4=www.bbc.co.uk%252Fnews%252F&amp;c5=&amp;c6=&amp;c15=&amp;cv=1.3&amp;cj=1.html" style="display:none" width="0" height="0" alt="" />
- </div>
-</noscript>
-<!-- End comScore Tag -->
-
-
-
-
-
-
-
-
-
-
- </div> </div>
-
-
-<!-- shared/foot -->
-<script type="text/javascript">
- bbc.fmtj.common.removeNoScript({});
- bbc.fmtj.common.tabs.createTabs({});
-</script>
-<!-- hi/news/foot.inc -->
-<!-- shared/foot_index -->
-<!-- #CREAM hi news international foot.inc -->
-
-
-</body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/blst.msn.com/as/wea3/i/en-us/law/30.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/blst.msn.com/as/wea3/i/en-us/law/30.gif
deleted file mode 100755
index 992699f4d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/blst.msn.com/as/wea3/i/en-us/law/30.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/23/6B8E88315584A40B04E32D89551E.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/23/6B8E88315584A40B04E32D89551E.jpg
deleted file mode 100755
index e37353323..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/23/6B8E88315584A40B04E32D89551E.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/2F/9EFAECEC174B21FB83D10C82522D2.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/2F/9EFAECEC174B21FB83D10C82522D2.jpg
deleted file mode 100755
index a2dd41298..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/2F/9EFAECEC174B21FB83D10C82522D2.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/38/FAF3346E94CF4579ECAB641703868.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/38/FAF3346E94CF4579ECAB641703868.jpg
deleted file mode 100755
index 4b3ccca52..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/38/FAF3346E94CF4579ECAB641703868.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/5B/CC662FC6233C7449D9C7F9796801D.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/5B/CC662FC6233C7449D9C7F9796801D.jpg
deleted file mode 100755
index 53cf4bdbb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/5B/CC662FC6233C7449D9C7F9796801D.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/76/CAF5FAB7F245F96327F2B4C806D.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/76/CAF5FAB7F245F96327F2B4C806D.jpg
deleted file mode 100755
index c9aa55971..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/76/CAF5FAB7F245F96327F2B4C806D.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/80/82E2A652E4A790B140675E74293AD6.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/80/82E2A652E4A790B140675E74293AD6.jpg
deleted file mode 100755
index 75bd58519..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/80/82E2A652E4A790B140675E74293AD6.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/B7/EB75D45B8948F72EE451223E95A96.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/B7/EB75D45B8948F72EE451223E95A96.gif
deleted file mode 100755
index d316f8451..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/B7/EB75D45B8948F72EE451223E95A96.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/CE/19F603C3122D48B6554BBD495195.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/CE/19F603C3122D48B6554BBD495195.jpg
deleted file mode 100755
index d65e93190..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/CE/19F603C3122D48B6554BBD495195.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/CF/59B3CB34EF11B221719175143187.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/CF/59B3CB34EF11B221719175143187.jpg
deleted file mode 100755
index dd51c1c30..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/CF/59B3CB34EF11B221719175143187.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/D8/41FF8CA0A47CC8208E684FA1BE6D6.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/D8/41FF8CA0A47CC8208E684FA1BE6D6.jpg
deleted file mode 100755
index 8f8798743..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/D8/41FF8CA0A47CC8208E684FA1BE6D6.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/E2/37BA92E210D341BFDBF4126422A3D2.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/E2/37BA92E210D341BFDBF4126422A3D2.gif
deleted file mode 100755
index 3abac737e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/E2/37BA92E210D341BFDBF4126422A3D2.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/EA/9BECE90994978BFAE6F38561515E8.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/EA/9BECE90994978BFAE6F38561515E8.jpg
deleted file mode 100755
index b499cbd70..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/EA/9BECE90994978BFAE6F38561515E8.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/FF/6B3EB94D554DA0488C66DC31482D48.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/FF/6B3EB94D554DA0488C66DC31482D48.jpg
deleted file mode 100755
index 0505af37b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stb.s-msn.com/i/FF/6B3EB94D554DA0488C66DC31482D48.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/gbl/lg/csl/favicon.ico b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/gbl/lg/csl/favicon.ico
deleted file mode 100755
index a7e042d65..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/gbl/lg/csl/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/css/1d/b0ebeba5ed4ca3c158e6d6059f5074.css b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/css/1d/b0ebeba5ed4ca3c158e6d6059f5074.css
deleted file mode 100755
index 86da9d146..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/css/1d/b0ebeba5ed4ca3c158e6d6059f5074.css
+++ /dev/null
@@ -1 +0,0 @@
-#wrapper .w12,#wrapper.w12{min-width:972px;width:81em}.pa{margin:0 auto;padding:1em .5em}.pa #content,.pa #area1,.pa #area2,.pa #area3{float:left}.pa #subfoot{clear:both}.pa #area2,.pa #area3{margin-left:1em}.pa #page:after{clear:both;content:".";display:block;height:0;visibility:hidden}#wrapper{padding:1em 0;text-align:left;margin:0 auto}#wrapper .w1{min-width:70px;width:5.833em}#wrapper .w2{min-width:152px;width:12.667em}#wrapper .w3{min-width:234px;width:19.5em}#wrapper .w3 .w50{min-width:111px;width:9.25em}#wrapper .w4{min-width:316px;width:26.333em}#wrapper .w4 .w33{min-width:97px;width:8.083em}#wrapper .w4 .ce3.w33{min-width:98px;width:8.167em}#wrapper .w5{min-width:398px;width:33.167em}#wrapper .w5 .w33{min-width:124px;width:10.333em}#wrapper .w5 .ce2.w33,#wrapper .w5 .ce3.w33{min-width:125px;width:10.417em}#wrapper .w5 .w50{min-width:193px;width:16.083em}#wrapper .w6{min-width:480px;width:40em}#wrapper .w7{min-width:562px;width:46.833em}#wrapper .w7 .w33{min-width:179px;width:14.917em}#wrapper .w7 .ce3.w33{min-width:180px;width:15em}#wrapper .w7 .w50{min-width:275px;width:22.917em}#wrapper .w8{min-width:644px;width:53.667em}#wrapper .w8 .w33{min-width:206px;width:17.167em}#wrapper .w8 .ce1.w33,#wrapper .w8 .ce3.w33{min-width:206px;width:17.167em}#wrapper .w9{min-width:726px;width:60.5em}#wrapper .w9 .w50{min-width:357px;width:29.75em}#wrapper .w10{min-width:808px;width:67.333em}#wrapper .w10 .w33{min-width:261px;width:21.75em}#wrapper .w10 .ce3.w33{min-width:262px;width:21.833em}#wrapper .w11{min-width:890px;width:74.167em}#wrapper .w11 .w33{min-width:288px;width:24em}#wrapper .w11 .ce2.w33,#wrapper .w11 .ce3.w33{min-width:289px;width:24.083em}#wrapper .w11 .w50{min-width:439px;width:36.583em}#wrapper .w12{min-width:972px;width:81em}#head{min-width:972px;background:transparent}#page{min-width:972px;background:#fff}#nav{min-width:972px;background:transparent}#content{background:transparent}#foot{min-width:972px;background:transparent}#wrapper .wings{background-color:#009ad9;height:1.667em;min-width:81em;width:100%}a.more,div.br *,.cotb *,.coss *{font-family:arial,sans-serif}@media print{form,object{display:none}}a,a:link,a:visited{color:#333;text-decoration:none}a:hover,a:hover span{color:#000;text-decoration:underline}a img{border:none}input,select,textarea{font-size:15px;line-height:normal}big,div.h2,div.h3,h1,h2,h3,h4,h5,h6,small{font-family:arial,sans-serif;font-size:100%;margin:0;padding:0}.cf:after,ul.cf li:after,.ro:after{clear:both;content:".";display:block;height:0;visibility:hidden}.none{display:none}#wrapper .grsep{border-bottom:solid 1px #e1e1e1}#wrapper .headerbar2,#wrapper .breaknews1,#wrapper .ad1,#wrapper .alert1,#wrapper .hotmail1,#wrapper .spotlight1,#wrapper .msnfoot1,#wrapper #area2 .linkedimg1{margin:.667em}#wrapper .money1,#wrapper .sponad1{margin:0 0 0 .667em}#wrapper .shopping1 ul.linklist22 li.last{border-bottom:solid 1px #e1e1e1}#wrapper .local1 .simple8 div.loclist ul li{clear:both;float:none}body{background:transparent url(../../i/1a/57011fe37f98be0ee74ce87a62ba9b.png) no-repeat top center;color:#333;font-family:arial,sans-serif;font-size:75%;line-height:1.33em;margin:0;padding:0;text-align:center}#wrapper #hotmail{margin:.457em .667em 2.33em}#wrapper #content #stgsearch{margin-top:-.21em}#wrapper #content #gendermodule{margin-top:1.418em}.exphd .wlcard1 ul li.tolatino{float:right;border-left:none;border-right:1px solid #999;padding-right:5px}.localshopping h3.cf{border-bottom:1px solid #d7d7d7;padding-bottom:.8333em}.dating1 .complex1 fieldset.last input{padding-top:.167em;padding-bottom:.167em}.dating1 .complex1 fieldset.last input.button{background-color:#009ad9}.dating1 .complex1 fieldset.last input.button:hover{background-color:#33aee1;cursor:pointer}.dating1 .complex1 fieldset.last label,.dating1 .complex1 fieldset.last select{margin-top:.167em}.dating1 .br2 .complex1 label{color:#333}.dating1 .linkedimglinklist8 span{color:#666}.dating1 #cff1 select{height:21px;width:108px}.dating1 #agemin,.dating1 #agemax{height:21px;width:46px}#wrapper #area2 .dating1 .linkedimg1{margin-left:0;margin-right:0}.dating1 .complex1 fieldset.last #txtlocation{margin-right:.667em;width:4.333em}.dating1 .complex1 fieldset.last .button{width:8.333em}.w12 .generic1 div.br{margin:0}.w12 .generic1 .linkedimg1 img{vertical-align:top}.dating1 .br3 img{vertical-align:bottom}.dating1 .complex1 fieldset.last label{margin-right:.667em}#wrapper #tg{background:transparent url(../../i/62/b5797d19976f0955d6d5d5c87ec996.jpg) no-repeat top center}#stk_head .single2{margin:.6em 0 0 .4em}#stk_data .simple8 input.text{color:#666;margin:0 .167em 0 .083em}#stk_data .simple8 div div{padding:0 .083em .083em}#stk_data .simple8 .image{vertical-align:bottom}#wrapper .ce .sponad1{margin:0}.sponad1 .richtext p{margin:.583em 0 0}.sponad1 .m16{margin:.667em 0}#stk_data .linklist16{margin-top:-.5em}#stk_data .linklist16 li{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2236px;padding:.333em 0 .333em 1.583em}.headerbar_us .websearch2 .opt,.headerbar_us .websearch2 span{color:#666}.dating1 .linkedimglinklist8,.dating1 .br2,.dating1 .br3{margin-left:.333em}.dating1 .h3{background-color:#fff;padding-bottom:.5em}#nav .pa{padding-top:0}.headerbar_us .pgopt1{float:none}#page .menunavbar1{margin:0 auto .667em}#page .menunavbar1 .ntier1{background-color:#009ad9}.scp1 .headline .first .richtext{margin-top:1.167em}div.hlcpm1 .hcpep3 li{display:inline-block;float:none;vertical-align:top}.hlcpm1 .hcpep3 li,.hlcpm1 .hcpep3 li.media{line-height:1.5em;padding-top:.25em}.scp1 .npane span a,.scp1 .linkedimg span a{display:block}#wrapper .exphd{margin:0 0 22px}.exphd .wlcard1 ul li.first{border-left:0;line-height:20px}.exphd .wlcard1 ul li{border-left:solid 1px #999;display:inline;float:left;line-height:20px;margin-left:5px;padding-left:5px}.expblu .exphd .wlcard1 ul li,.expblu .exphd .wlcard1 ul li.myhp a{border-color:#fff}#wrapper .exphd .wlcard1 a{color:#999}.exphd .wlcard1 ul li.last{border-left:none;float:right}.exphd .wlcard1 ul{width:93%}.exphd .wlcard1 ul li.myhp a{padding-right:5px;border-right:solid 1px #999;font-weight:bold}.exphd .wlcard1 div{font-size:100%;float:left;margin-left:5px;padding-top:1px;line-height:16px}#wrapper #head .exphd .br4{clear:none;margin:0;padding-left:.417em;padding-top:1.25em}#wrapper #head .exphd .br2{display:block;float:left;min-width:16.7em;padding-top:0;width:200px}#wrapper .exphd .br1{width:100%;display:block;padding-bottom:.3em}#wrapper #head .exphd .br3{min-width:600px;padding-top:.9em;width:50em}.exphd .websearch2 .bi{padding:0 0 0 5px}#wrapper .exphd .websearch2 input.text{margin-top:7px;width:396px}.expfoot{min-width:600px;padding-top:.9em;width:50em}.expfoot .websearch2 .bi{padding:0 0 0 5px}#wrapper .expfoot .websearch2 input.text{margin-top:7px;width:396px}body.expht{background:none}.expht #wrapper{padding-top:0}.expht .headerbg,#wrapper #tg{background:transparent url(../../i/94/8b0fe9bcd1399077fdc9374e5f314d_1.png) no-repeat 0 0}.expht .exphd{padding-top:1em}.expht #head .ro .ce{position:relative;z-index:51}.expht .exphd .imgloaddisabledla{position:absolute;z-index:-1;top:0;left:0}.expht .exphd .br5{margin:5px 0 0 21.2%}.expht .exphd .br5 .richtext p{background:transparent url(../../i/11/999518480e3c07301320f84f4bd855.png) no-repeat scroll 0 0;padding-left:20px;margin:0}.thumb_h ul{padding-left:0;width:100%;height:6.2em;margin:0}.thumb_h ul li{background-color:#f1f1f1;margin:3px 2px 0 0;list-style:none;width:23%;float:left;padding:.44em;min-height:60px}.thumb_h ul .last{margin-right:0}.thumb_h a p{margin:0;height:5em}.thumb_h a img{float:left;margin-right:10px}.thumb_h ul li.selected{border:1px solid #009ad9;border-top-width:3px;margin-top:0;height:4.9em;background-color:#fff}.tfh .scp1 .npane li img{padding-bottom:8px}.tfh .scp1 .npane ul li{margin:3px 9px 0 0}.tfh .scp1 .npane ul .last{margin-right:0}.tfh .scp1 .npane ul a{font-size:1.2em;font-weight:bold;padding-bottom:1px}.tfh .scp1 .headline ul{padding-left:1.6em}.tfh .scp1 .npane,.tfh .scp1 .linkedimg{text-align:center}.tfh .co1b1{min-height:191px}.thumb_h ul li a{height:5em;display:block;color:#666}.thumb_h ul li.selected a{color:#333}.thumb_h ul li.selected a:hover span,.thumb_h ul li.selected a:hover{text-decoration:none}.thumb_v{float:left;margin-right:.75em}.thumb_v ul{padding:0;margin:0;width:100%}.thumb_v ul li{list-style:none;height:5em;min-height:60px;margin:0 0 1px 2px;background:#f1f1f1;width:17.9em;border:1px solid #f1f1f1}.thumb_v ul li a{height:5em;display:block;color:#666}.thumb_v ul li a span{display:block;padding-top:1.1em}.thumb_v ul li.selected a:hover span,.thumb_v ul li.selected a:hover{text-decoration:none}.thumb_v ul li.selected a{color:#333}.thumb_v ul .selected{border:1px solid #009ad9;border-left-width:3px;margin-left:0;background-color:#fff}.thumb_v ul li img{float:left;margin-right:.75em}.tfv .scp1 .npane li img{padding-bottom:8px}.tfv .scp1 .npane ul li{margin-right:10px}.tfv .scp1 .npane ul .last{margin-right:0}.tfv .scp1 .npane ul a{font-size:1.2em;font-weight:bold;text-align:left}.tfv .scp1 .headline ul{padding-left:20.6em}.tfv .scp1 .linkedimg .richtext{margin-bottom:3px}.tfv .scp1 .npane.n3{text-align:left}.tfv .scp1 .headline li{padding-top:0}.tfv .scp1 .linkedimg{margin-left:19em}#wrapper #content .cogr{margin:.6em 0 1.2em .4em}.tfv .headline div a,.tfh .headline div a{float:left}.tfv .headline div p a,.tfh .headline div p a{float:none}#infopane_hc .tfh div.co,#infopane_vc .tfv div.co{display:none}#infopane_hc .cof div.co,#infopane_vc .cof div.co{display:block}#wrapper #head .expsh{margin-bottom:17px}#wrapper #head .ro .expsh .br4{display:none;margin:0 auto;min-width:582px;padding:0 0 0 1.5em;width:50.4em}#wrapper #head .expsh .br3{margin-bottom:3px}#wrapper .expsh .br4 .richtext p{float:left;margin-bottom:0;margin-right:2px}#wrapper .expsh .br4 .prefix{float:left;margin-right:3px}#wrapper .expsh .br4 .resultlist{margin:0;padding:0}#wrapper .expsh .br4 .resultlist li{float:left;list-style:none}#wrapper .expsh .br4 .resultlist li.last{float:right}#wrapper .expsh .br4 .resultlist li.last a{color:#666}#wrapper .expsh .br4 .resultlist li a,#wrapper .headerbar2 .br5 .richtext p a{text-decoration:none}#wrapper .expsh .br4 .resultlist li a:hover,#wrapper .headerbar2 .br5 .richtext p a:hover{color:#000;text-decoration:underline}#wrapper .exphd .websearch2 .opt{position:absolute;margin-left:0}#wrapper .exphd .websearch2 .opt a{margin:0 3px}#wrapper .exphd .websearch2 .opt a.first{margin:0}#mq1 #msd{float:left;margin:-6.215em 0 0 17.8em}#mq1 br{display:none}#mq1 .br4{float:none;margin:-4.75em 0 0 35.2em}#mq1 .br3 .simple8 input.text{color:#666;width:12.55em;margin-left:6px}#mq1 .br3 .co3b1 .br2{float:left;margin-top:1.65em}#mq1 .br3 .co3b1 .br3{clear:none;float:left;margin-top:1.3em}#mq1 .br1 table{width:15.3em}#mq1 .br1 table td{line-height:1.16em;width:4.4em}#mq1 .br1 td.siidx{font-weight:bold;padding:0 0 .25em;width:auto}#mq1 .br1 td.silast{width:auto}#mq2 .br4{margin-left:.67em;margin-top:-6.92em}#mq2 .indices1 table{width:25.08em}#mq2 .indices1 td{margin:0;padding:0;width:6.17em}#mq2 .indices1 .siidx{font-weight:bold;width:6.58em}#mq2 .simple8 input.text{color:#666;margin-left:6px;width:22.42em}#mq2 .br3 .co3b1 .br2{float:left;margin-top:1.42em}#mq2 .br3 .co3b1 .br3{clear:none;margin-top:.58em}#mq1 .h2,#mq2 .h2{margin:0 0 .65em;width:98.8%}#mq1 .linklist16 li,#mq2 .linklist16 li{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2236px;display:list-item;line-height:1.98em;margin:0;padding:.083em 0 .083em 19px}#mq1 .simple8 div div,#mq2 .simple8 div div{border-color:#ccc;height:24px;padding:0}#mq1 .br2 .richtext,#mq2 .br2 .richtext{color:#707070;font-size:83%}#mq1 .br3 .co3b1 .br2 .richtext,#mq2 .br3 .co3b1 .br2 .richtext{color:#333;font-size:100%;padding-right:.4em}#mq1 .br3 .co3b1 .br2 .richtext{font-size:79%}#mq1 .simple8 input.image,#mq2 .simple8 input.image{margin-right:1px}#mq1 .linklist16 li span.media,#mq2 .linklist16 li span.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2351px;display:block;margin-left:-19px}#mq1 .linklist16 li span.media a,#mq2 .linklist16 li span.media a{display:block;margin-left:19px}.bottomline{border-bottom:solid 1px #bcbcbc}#wrapper div.scrollhead{background-color:#fff;min-width:972px;position:fixed;top:0;width:81em;z-index:60}.scrollheadheight{padding-top:14em}.scrollhead #nav .ro div.ce{position:static}.msnvideooverlayplayer{z-index:16777271}#heroplayer1internalgallerydiv_content object{visibility:visible!important}#popsrchnew .coa2 div.hr{margin:.7em 0}#popsrchnew .alist1 div.br2 h3,#popsrchnew .alist1 div.br3 h3,#popsrchnew .alist1 div.br4 h3{margin-bottom:0}#popsrchnew .hlcp2 .sec img.landscape{margin-bottom:.35em}#head .shortersrch #q{width:316px}.shortersrch .search{margin-top:1.4em}#wrapper .minihead{background-color:#009ad9;left:0;padding:.6em 0 1em;position:fixed;top:0;width:100%;z-index:60}#wrapper .minihead #tg{background:none}.minihead .headerbar_us{height:auto;min-height:0;width:81em;min-width:972px;margin:0 auto}.minihead .headerbar_us .br1,.minihead .headerbar_us .br2,.minihead .headerbar_us .scopes,.minihead .headerbar_us .br4 img,.minihead .headerbar_us .opt,.minihead .condbanner1{display:none}.minihead .headerbar_us .br4 a{background:transparent url(../../i/61/def0ebad64d00fda0702cb7b8179ea.png) no-repeat scroll 0 -132px;display:block;height:34px;width:77px}.minihead .headerbar_us .br3{height:0}.minihead .headerbar_us .br3 a{color:#fff;display:block;font-weight:normal;margin-top:10px}.minihead .headerbar_us .br3 a:link{font-weight:normal}.minihead .headerbar_us .br4{min-width:179px;padding-top:0;width:179px}.miniheadpageheight{padding-top:9.8em}#wrapper .minihead .w12{width:100%}#wrapper .minihead .headerbar_us .br5{padding-top:0;width:auto}#headl .headerbar_us .br4{padding-top:0;margin-bottom:.5em}#headl .headerbar_us .br5{margin:0}.lhemhp,.lhe{background-color:#009ad9;height:5.6em;left:0;position:fixed;top:0;width:100%;z-index:60}.lhe{height:4.5em}#wrapper .lhemhp #tg,#wrapper .lhe #tg{background:none}.lhemhp .headerbar_us,.lhe .headerbar_us{height:auto;margin:0 auto;min-height:0;min-width:972px;width:81em}.lhemhp .headerbar_us .br1,.lhemhp .headerbar_us .br2,.lhemhp .headerbar_us .br3,.lhemhp .headerbar_us .scopes,.lhemhp .headerbar_us .br4 img,.lhemhp .headerbar_us .opt,.lhemhp #nav,.lhe .headerbar_us .br1,.lhe .headerbar_us .br2,.lhe .headerbar_us .br3,.lhe .headerbar_us .scopes,.lhe .headerbar_us .br4 img,.lhe .headerbar_us .opt,.lhe #nav,.scrollhead .expandbuttoncontainer,.scrollhead .msnheadlogo,.scrollhead .mkhmhead a,.scrollhead #nav .ro,.lhe .condbanner1{display:none}.lhemhp #nav .ntier1,.lhe #nav .ntier1{background-color:transparent;display:none}.lhemhp .headerbar_us .br4,.lhe .headerbar_us .br4{margin-top:.5em;min-width:0;width:12em}.lhemhp .headerbar_us .br4{margin:1.2em 0 1.7em 0;padding-top:0}#wrapper .lhemhp .w12,#wrapper .lhe .w12{width:100%}.lhemhp .headerbar_us .br5{padding-top:0;margin-top:1.23em}.lhemhp .headerbar_us a.expandnavigation,.lhe .headerbar_us a.expandnavigation{border:solid 1px #fff;color:#fff;display:block;float:left;padding:6px 17px;margin-top:7px}.lhemhp .mhexpandhead{min-height:8px;margin-top:-.2em;padding-top:.8em}.lhemhp .headerbar_us .mhexpandhead a{color:#fff;display:block;font-weight:normal}.lhemhp .msnheadlogo,.lhemhp .headerbar_us .br4 a,.lhe .msnheadlogo,.lhe .headerbar_us .br4 a{background:transparent url(../../i/61/def0ebad64d00fda0702cb7b8179ea.png) no-repeat scroll 0 -132px;display:block;height:34px;width:77px}.lhe .headerbar_us .br5{margin-top:.6em}.expandbuttoncontainer{float:right;margin-right:.5em}.lhe .expandbuttoncontainer{margin-top:.5em}#subfoot .bingpulse1{margin-bottom:2.917em;overflow:hidden;padding-top:.833em}.bingpulse1 .br{display:inline;float:left;margin-left:10px;min-width:237px;width:19.75em}.bingpulse1 .br2,.bingpulse1 .br3{min-width:236px;width:19.667em}.bingpulse1 .br2,.bingpulse1 .br3,.bingpulse1 .br4{margin-left:0}.bingpulse1 .linklist1 li{background:url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2241px;color:#333;line-height:1.333em;margin-bottom:0;padding:0 0 .333em 12px}.bingpulse1 .linklist1 li.first{background:none;font-weight:bold;font-size:130%;margin-bottom:.416em;margin-left:-13px;padding-top:0}#subfoot .bingpulse1 .h2{margin-bottom:.5em;min-width:956px;width:79.667em}.srchhs{width:610px}.srchhs span{color:#333;float:left;font-weight:bold;margin-bottom:1.08em;padding-top:.21em}.srchhs ul{list-style:none outside none;margin:0;padding:0}.srchhs li{color:#333;float:left;margin:.23em 0 0 5px}.srchhs ul .last{float:right}.minihead .websearch2 .srchhs{margin-top:0;padding-top:4px}.minihead .websearch2 .srchhs span{margin:0}.minihead .headerbar_us .srchhs a,.minihead .websearch2 .srchhs span,.minihead .headerbar_us .srchhs li,.minihead .headerbar_us .srchhs a:hover{color:#fff}.srchhs.husearchbox,.minihead .srchhs.hlockedheader{display:none}.minihead div.srchhs{display:block}#head .headerbar_us{margin-top:0}.coa2.coc1 .h2,.cogr ul.cotb.coc1 li.tabsel span,.cogr ul.cotb.coc1{border-color:#009ad9}.coa2.coc1 div.hr,.coa3.coc1 div.hr,.coa3.coc1 .h2,.coa3.coc1 .h3{border-color:#ccebf7}.coa2.coc2 .h2,.cogr ul.cotb.coc2 li.tabsel span,.cogr ul.cotb.coc2{border-color:#89c655}.coa2.coc2 div.hr,.coa3.coc2 div.hr,.coa3.coc2 .h2,.coa3.coc2 .h3{border-color:#e2f1d4}.coa2.coc3 .h2,.cogr ul.cotb.coc3 li.tabsel span,.cogr ul.cotb.coc3{border-color:#bdbdbd}.coa2.coc3 div.hr,.coa3.coc3 div.hr,.coa3.coc3 .h2,.coa3.coc3 .h3{border-color:#e3e3e3}.m1{margin:.667em 0 0 0}.m2{margin:0 .5em 0 0}.m3{margin:0 0 .667em 0}.m4{margin:0 0 0 .5em}.m5{margin:.667em 0 .667em 0}.m6{margin-bottom:0;margin-top:0}.m7{margin:0 .5em 0 .5em}.m8{margin-left:0;margin-right:0}.m9{margin:.667em 0 0 .5em}.m10{margin:.667em .5em 0 0}.m11{margin:0 0 .667em .5em}.m12{margin:0 .5em .667em 0}.m13{margin:0 .5em .667em .5em}.m14{margin:.667em 0 .667em .5em}.m15{margin:.667em .5em 0 .5em}.m16{margin:.667em .5em .667em 0}.m17{margin:.667em .5em .667em .5em}.coa2.ruled{border-bottom:solid 1px #e1e1e1}.coa2 .h3{color:#333;font-weight:bold;line-height:1.43em;margin:0 0 .833em 0}.coa2 .h2 a,.coa2 .h2 a:link,.coa2 .h2 a:visited{color:#333}.coa2 .h2 a:hover,.coa2 .h2 a:active{color:#000}.coa2 .h3 a,.coa2 .h3 a:link,.coa2 .h3 a:visited{color:#333}.coa2 .h3 a:hover,.coa2 .h3 a:active{color:#000}.coa2 .h2 span.icon,.cogr ul.cotb li span.icon,.cogr ul.cotb li.tabsel span.icon{padding-left:.333em}.coa2 .h2 a span,.coa2 .h2 span span{padding:0}.coa2 .h2 a,.coa2 .h2 span{display:block;float:left;padding:0 0 .333em 0}#wrapper .coa2 .attr{border:0;bottom:-3px;float:right;position:relative}#wrapper .coa2 .attr,#wrapper .coa2 a.attr:link,#wrapper .coa2 a.attr:visited,#wrapper .coa2 a.more,#wrapper .coa2 a.more:link,#wrapper .coa2 a.more:visited{color:#666;font-size:92%;font-weight:normal}#wrapper .coa2 a.attr:hover,#wrapper .coa2 a.attr:active,#wrapper .coa2 a.more:hover,#wrapper .coa2 a.more:active{color:#333}.coa2 div.hr{border-top:solid 2px;margin:.833em 0}.cogr ul.cotb,.coa2 .h2{clear:both;font-weight:bold;line-height:normal;list-style-type:none;margin:0 0 .833em 0;padding:0;width:100%}.coa2 .h2{border-bottom:solid 3px;color:#333;font-weight:bold;line-height:normal}.cogr ul.cotb{border-bottom:solid 1px;background-color:#f1f1f1}.cogr ul.cotb li{float:left;list-style-type:none}.cogr ul.cotb li a,.cogr ul.cotb li span{display:block;float:left;font-size:100%;line-height:normal}.cogr ul.cotb li span span,.cogr ul.cotb li.tabsel span span,.cogr ul.cotb li a span{border:0;bottom:0;padding:0;margin:0;top:0}.cogr ul.cotb li span span span,.cogr ul.cotb li.tabsel span span span,.cogr ul.cotb li a span span{padding-left:.333em}.cogr ul.cotb li a{background-color:#f1f1f1;border-width:0 1px;border-color:#fff;border-style:solid;padding:.5em 1.333em .25em 1.333em;text-decoration:none}.cogr ul.cotb li a,.cogr ul.cotb li a:link,.cogr ul.cotb li a:visited{color:#666}.cogr .js ul.cotb li a:hover{color:#666;text-decoration:none}.cogr ul.cotb li a:hover,.cogr ul.cotb li a:active{color:#333;text-decoration:none}.cogr .js ul.cotb li a.hover{color:#333;text-decoration:none}.cogr ul.cotb li.tabsel span{background-color:#fff;border-style:solid;border-width:4px 1px 0 1px;bottom:-1px;color:#333;cursor:default;margin-left:-1px;margin-top:-4px;padding:.417em 1.333em .417em 1.333em;position:relative}.coa2 .h2 a span,.coa2 .h3 a span,.cogr ul.cotb li span{cursor:pointer}.cogr ul.cotb li.first a{border-left:0}.cogr ul.cotb li.last a{border-right:0}.cogr ul.cotb li a.hover,.cogr ul.cotb li a:hover{text-decoration:none}.coa2 .h2 img,.cogr ul.cotb li img{display:block;float:left;margin-bottom:.083em}.coa3.ruled{border-bottom:solid 1px #e1e1e1}.coa3 .h2,.coa3 .h3{border-style:solid;line-height:normal}.coa3 .h2{border-width:0 0 2px 0;font-weight:bold;font-size:117%}.coa3 .h3{border-width:0 0 1px 0;font-weight:normal}.coa3 .h2 a,.coa3 .h3 a,.coa3 .h2 span,.coa3 .h3 span{display:block;float:left}.coa3 .h2 span span,.coa3 .h2 a span,.coa3 .h3 span span,.coa3 .h3 a span{padding:0}.coa3 .h2 a,.coa3 .h2 span{padding:.47em 0}.coa3 .h3 a,.coa3 .h3 span{padding:.8em 0}#wrapper .coa3 .attr,#wrapper .coa3 a.attr:link,#wrapper .coa3 a.attr:visited{color:#666;font-size:86%;font-weight:normal;float:right}#wrapper .coa3 a.attr:hover,#wrapper .coa3 a.attr:active{color:#333}.coa3 a.more{display:block;float:none;padding:.58em 0 0 0}.coa3 div.hr{border-top:solid 2px;margin:.833em 0}.coa3 .h2 a span,.coa3 .h3 a span{cursor:pointer}.coa3 .h2 a,.coa3 .h2 a:link,.coa3 .h2 a:visited,.coa3 .h2 span{color:#333}.coa3 .h3 a,.coa3 .h3 a:link,.coa3 .h3 a:visited,.coa3 .h3 span{color:#333}.coa3 .more,.coa3 a.more,.coa3 a.more:link,.coa3 a.more:visited{color:#333}.coa3 .h2 a:hover,.coa3 .h2 a:active{color:#000}.coa3 .h3 a:hover,.coa3 .h3 a:active{color:#000}.coa3 a.more:hover,.coa3 a.more:active{color:#000}.coa4.ruled{border-bottom:solid 1px #e1e1e1}.coa4 .h2,.coa4 .h3{line-height:normal}.coa4 .h2 a,.coa4 .h3 a,.coa4 .h2 span,.coa4 .h3 span{display:block;float:left;padding:.5em .86em .286em .86em}.coa4 .h2 a,.coa4 .h2 span{font-weight:normal}.coa4 .h3 a,.coa4 .h3 span{padding:0;font-weight:normal}#wrapper .coa4 .attr{font-size:92%;font-weight:normal;float:right}.coa4 a.more{display:block;float:none}.coa4 div.hr{border-top:solid 2px;margin:.833em 0}.coa4 .h2 a span,.coa4 .h3 a span{cursor:pointer}#wrapper .headerbar2 .br2{clear:none;padding-left:.417em}#wrapper .headerbar2 .br2,#wrapper .headerbar2 .br3{padding-top:1.25em;margin:0}.headerbar2 .br3 .wlcard1{margin-left:1.833em}#wrapper .headerbar2 .br4{clear:both;float:none}.headerbar2 .websearch2 input.text{width:350px}.co4b11 .b3{display:none}.co4b11 .br{display:block;float:left}.co4b11 .br2{clear:left}.co4b11 .more{clear:both}.co4b11 .br .more{clear:none}#sw_as{display:none;position:relative;z-index:100}input.text{-webkit-appearance:none;-webkit-border-radius:0}.websearch2 h2,.websearch2 label.hide{display:none}.websearch2 form{margin:0}.websearch2 input.image{border:0;cursor:pointer;display:block;float:left;margin:0;margin-left:3px;padding:0;text-align:right}.websearch2 input.text,.websearch2 select.dd{border:0;color:#333;display:block;float:left;margin:0;margin-top:7px;outline:none;padding:0;text-align:left;width:429px}.websearch2 input.txt1{border:solid 1px #c0c0c0;padding:5px 0 3px 3px;margin:1px 1px 0 -3px}.websearch2 input.txt2{border:solid 1px #c0c0c0;padding:5px 0 3px 3px;margin:1px 0 0 1px}.websearch2 select.dd{border:solid 1px #c0c0c0;border-top:solid 1px #a0a0a0;margin:1px 0 1px 1px;padding:3px 3px 3px 0}.websearch2 .opt,.websearch2 .scopes{font-family:verdana,sans-serif;font-size:100%}.websearch2 a,.websearch2 a:link,.websearch2 a:visited,.websearch2 a:hover,.websearch2 a:active,.websearch2 label,.websearch2 span,.websearch2 a:hover span{color:#fff}.websearch2 a:hover span{text-decoration:underline}.websearch2 span.bi{background-color:#fff;border:1px solid #2e6ba5;display:block;float:left;padding:0 0 0 1px}.websearch2 span.bo{border:2px solid #c7d9e9;clear:both;display:block;float:left}.websearch2 .opt{clear:both;color:#fff;margin-top:5px}.websearch2 .opt a,.websearch2 .opt label{margin:0 2px}.websearch2 .opt label{margin-left:5px;margin-right:11px}.websearch2 .opt a.first{margin:0}.websearch2 .opt input{margin:0 0 4px 0;padding:0;vertical-align:middle}.websearch2 .opt .delimited{display:inline}.websearch2 .opthide input,.websearch2 .opthide label{display:none}.websearch2 .scopes a{display:block;float:left;padding:2px 6px 4px 6px}.websearch2 .scopes a.selected,.websearch2 .scopes a.selected:hover{background:transparent url(../../i/07/617475cf39bf6f5c0bd6ecb985335c.gif) no-repeat 53% bottom;margin-bottom:0;padding-bottom:6px}.websearch2 .scopes a.selected,.websearch2 .scopes a.selected:hover,.websearch2 .scopes a.selected span,.websearch2 .scopes a.selected:hover span{color:#faae32;cursor:default;font-weight:bold;position:relative;text-decoration:none}.websearch2 .scopes span{display:inline;float:left;margin-top:1px}.websearch2 .scopes a span{display:inline-block;float:none;font-size:100%;margin-top:0;cursor:pointer}.websearch2 .scopes a span.icon1{background:transparent url(../../i/50/f63ed0301e8b02a8a42d8590a46291.gif) no-repeat right center;padding-right:30px}.websearch2 .scopes a span.icon2{background:transparent url(../../i/50/f63ed0301e8b02a8a42d8590a46291.gif) no-repeat right center;padding-right:30px}.websearch2 .scopes a span.icon3{background:transparent url(../../i/50/f63ed0301e8b02a8a42d8590a46291.gif) no-repeat right center;padding-right:30px}.websearch2 .scopes a span.icon4{background:transparent url(../../i/50/f63ed0301e8b02a8a42d8590a46291.gif) no-repeat right center;padding-right:30px}.websearch2 .scopes a span.icon5{background:transparent url(../../i/50/f63ed0301e8b02a8a42d8590a46291.gif) no-repeat right center;padding-right:30px}.wlcard1 div{font-size:117%;line-height:normal;text-align:right}.wlcard1 ul{float:left;list-style-type:none;margin:0;padding:0}.wlcard1 ul li{padding:0}.wlcard1 ul li.first{padding:0 0 .417em 0}.wlcard1 a,.wlcard1 a:link,.wlcard1 a:visited{color:#666}.wlcard1 a:hover,.wlcard1 a:active{color:#333}.wlcard1 ul li a span{color:#74a0c9}.linkedimglinklist8{list-style-type:none;margin:0;padding:0}.linkedimglinklist8 a{float:left}.linkedimglinklist8 a:hover{text-decoration:none}.linkedimglinklist8 img{border:none;margin-bottom:.4em}.linkedimglinklist8 li{float:left;margin:0 auto;padding:0 .5em;text-align:center}.linkedimglinklist8 a span{display:block}.richtext a,.richtext a:link,.richtext a:visited{text-decoration:underline}.richtext cite,.richtext dfn{font-style:normal}.richtext h4{margin:0 0 3px 0}.richtext p{margin:0 0 1em 0}.richtext code,.richtext samp,.richtext kbd{font-family:"courier new",courier,monospace;vertical-align:baseline}.ro{clear:left}.ro .ce{float:left;margin-left:.5em;margin-right:.5em;min-width:70px;width:5.833em}#wrapper .ro .ce1{margin-left:0}#wrapper .ro .cel{margin-right:0}.ro.m1,.ro .ce.m1{margin-top:1em}.ro.m3,.ro .ce.m3{margin-bottom:1em}.ro.m5,.ro .ce.m5{margin-bottom:1em;margin-top:1em}#wrapper .cogr .co{margin:0}#wrapper .cogr{margin:.667em}#wrapper .llmsg{text-align:center;padding-top:5em}#wrapper #page div.cotc{margin-bottom:18em}#wrapper div.tab h2{float:left}#wrapper div.tab div.tabchild{display:none;left:0;position:absolute;padding-top:.833em;top:2.167em}#wrapper div.cof div.tabchild{display:block}#wrapper div.cotc.cotch:hover div.cof div.tabchild{display:none}#wrapper div.cotc.cotch div.tab:hover div.tabchild{display:block}#wrapper div.cotc{background-color:#f1f1f1;border-bottom:1px solid;border-color:#009ad9;border-top:1px solid #f1f1f1;padding:.417em 0;position:relative}#wrapper div.cotc div.tab h2 span,#wrapper div.cotc.cotch:hover div.cof h2 span{background-color:#f1f1f1;border-color:#fff;border-style:solid;border-width:0 1px;bottom:-1px;padding:.5em 1.333em .25em;position:relative}#wrapper div.cotc div.cof h2 span,#wrapper div.cotc.cotch div.tab:hover h2 span{background-color:#fff;border-color:#009ad9;border-style:solid;border-width:4px 1px 0;bottom:-1px;color:#333;cursor:default;padding:.45em 1.333em;position:relative}#wrapper div.cotc div.tab h2 span span,#wrapper div.cotc.cotch:hover div.cof h2 span span,#wrapper div.cotc div.tab.cof h2 span span,#wrapper div.cotc.cotch div.tab:hover h2 span span{border:0 none;bottom:0;margin:0;margin-right:1px;padding:0;top:0}#wrapper #content .cossf{margin-bottom:3.33em}#wrapper #content .cossf .coss{margin-bottom:-25px}.cogr .coss ul{list-style-type:none;margin:0;padding:1px 0 0 0}.cogr .coss ul li{float:left;list-style-type:none}.cogr .coss ul li a{border:solid 1px #fff;display:block;height:19px;padding:0;text-decoration:none;width:18px}.cogr .coss ul li a.prev{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -730px}.cogr .coss ul li a.prev:hover{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -849px}.cogr .coss ul li a.next{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -968px}.cogr .coss ul li a.next:hover{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -1087px}.cogr .coss ul li a.pause{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -1206px;border-width:1px 0 1px 0;width:17px}.cogr .coss ul li a.pause:hover{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -1325px}.cogr .coss ul li a.play{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -1444px;border-width:1px 0 1px 0;width:17px}.cogr .coss ul li a.play:hover{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -1563px}.cogr .coss ul li a span{display:none;left:-10000px;position:relative}.cogr .coss ul li.last{color:#666;line-height:normal;padding:2px 0 4px;padding-left:12px}.ssa .as{background-color:#fff;left:54.5em;position:absolute;top:0;width:100%;z-index:1}.ssa .cof{left:0;z-index:2}.ssa{position:relative;overflow:hidden}.ssa .asn{left:0;position:absolute;z-index:3}.ssa .act{z-index:2}.ssa .nact{z-index:1}.date1{line-height:1.25em;margin:1.333em .667em .667em .667em}.date1 a,.date1 a:link,.date1 a:visited{color:#666}.date1 a:hover,.date1 a:active{color:#333}.blowoutmod1 .blowout1 h3{margin:0}.blowout1{border-bottom:solid 1px #ccc;padding:0 2em 1.333em 2em}.blowout1 div div{text-align:center}.blowout1 div div div{padding:.583em 0 0 0}.blowout1 h2{font-size:133%;line-height:1.13em;margin:0 0 .188em 0}.blowout1 h3{font-size:267%;font-weight:bold;line-height:1.09em}.blowout1 h3 a,.blowout1 h3 a:link,.blowout1 h3 a:visited{color:#333}.blowout1 h3 a:hover,.blowout1 h3 a:active{color:#000}.blowout1 p{color:#ccc;line-height:1.5em;margin:0;padding:0}.blowout1 ul{list-style-type:none;margin:.833em 0;padding:0}.blowout1 ul li{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -3683px;line-height:1.5em;padding:0 0 0 .75em}.breaknews1{font-size:133%;line-height:normal;padding:.625em .75em;text-align:center;margin:0 0 .667em}.breaknews1,.breaknews1 .richtext a,.breaknews1 .richtext a:link,.breaknews1 .richtext a:visited,.breaknews1 .richtext h4,.breaknews1 .richtext p,.breaknews1 .richtext span.custom{background-color:#ba1010;color:#fff;font-weight:bold}.breaknews1 .richtext h4{display:inline;margin:0 1em 0 0}.breaknews1 .richtext p{display:inline;margin:0}.navbar2 .br1 .menubar2{margin:0 0 0 8px}.navbar2 .br2 .menubar2{margin:0 0 0 9px}.navbar2 .br2 .menubar2 li.first{min-width:202px;width:16.833em}.navbar2 .br2 .menubar2 li.last{min-width:102px;width:8.5em}#wrapper .navbar2 .br2{min-width:316px;width:auto}.navbar2 .br2 .menubar2 li li.first,.navbar2 .br2 .menubar2 li li.last{min-width:142px;width:11.83em}.navbar2 .br2 .menubar2 li.fluid:hover ul,.navbar2 .br2 .menubar2 ul.js #hover.fluid ul{min-width:302px;width:25.167em}.navbar2 .br2 .menubar2 li.fluid ul li{min-width:0}.navbar2 .br2 .menubar2 li.fluid ul.mod2 li{width:50%}.navbar2 .br2 .menubar2 li.fluid ul.mod3 li{width:33.3%}.navbar2 .br2 .menubar2 li.fluid ul.mod4 li{width:25%}.navbar2 .br2 .menubar2 li.fluid ul.mod5 li{width:20%}.navbar2 .br2 .menubar2 li.fluid li a,.navbar2 .br2 .menubar2 li.fluid li a:link,.navbar2 .br2 .menubar2 li.fluid li a:hover,.navbar2 .br2 .menubar2 li.fluid li a:active,.navbar2 .br2 .menubar2 li.fluid li a:visited{font-size:100%;padding:.5em .25em .5em .571em}.co2b1 .br{float:left}.co2b1 .more{clear:both}.co2b1 .br .more{clear:none}.menubar2 ul,.menubar2 li{display:block;float:left;list-style:none;position:relative}.menubar2 ul{margin:0;padding:0;z-index:50}.menubar2 li{background-color:transparent;margin-right:1px;text-align:center}.menubar2 .snap li{min-width:102px;width:8.5em}.menubar2 .snap li.last{min-width:105px;width:8.75em}.menubar2 ul li.fluid:hover ul,.menubar2 ul.js #hover.fluid ul{left:auto;right:0;min-width:616px;width:51.333em}.menubar2 li a{outline:none}.menubar2 a:link,.menubar2 a:visited,.menubar2 a:active,.menubar2 a:hover,.menubar2 span{border-bottom:solid 4px;display:block;font-size:117%;font-weight:bold;line-height:normal;padding:.5em .571em}.menubar2 a:active,.menubar2 a:hover,.menubar2 a:hover span,.menubar2 span{text-decoration:none}.menubar2 span{cursor:default}.menubar2 li ul,.menubar2 ul.js li:hover ul,.menubar2 li ul li,.menubar2 .snap ul li.last{min-width:142px;width:11.833em}.menubar2 li ul,.menubar2 ul.js li:hover ul,.menubar2 ul.js li.last:hover ul{left:-999em;position:absolute;z-index:50}.menubar2 li ul{background-color:#fff;border:solid 1px}.menubar2 li li,.menubar2 .snap li li{margin:0;min-width:142px;position:static;text-align:left;width:11.833em}.menubar2 ul li:hover ul,.menubar2 ul.js #hover ul{left:0}.menubar2 li li:hover,.menubar2 ul.js li #hover,.menubar2 ul.js li li.focus{background-color:#e5e5e5}.menubar2 li li a:link,.menubar2 li li a:visited,.menubar2 li li a:active,.menubar2 li li a:hover{border:solid 1px #fff;font-weight:normal}.menubar2 li li span{font-weight:normal}.menubar2 .coc1 li a,.menubar2 .coc1 li span,.menubar2 .coc2 li a,.menubar2 .coc2 li span,.menubar2 .coc3 li a,.menubar2 .coc3 li span,.menubar2 .coc4 li a,.menubar2 .coc4 li span,.menubar2 .coc5 li a,.menubar2 .coc5 li span,.menubar2 .coc6 li a,.menubar2 .coc6 li span,.menubar2 .coc7 li a,.menubar2 .coc7 li span,.menubar2 .coc8 li a,.menubar2 .coc8 li span{color:#525151}.menubar2 .coc1 a,.menubar2 .coc1 span{border-color:#f57325;color:#f57325}.menubar2 .coc2 a,.menubar2 .coc2 span{border-color:#e44097;color:#e44097}.menubar2 .coc3 a,.menubar2 .coc3 span{border-color:#6a439c;color:#6a439c}.menubar2 .coc4 a,.menubar2 .coc4 span{border-color:#0253a2;color:#0253a2}.menubar2 .coc5 a,.menubar2 .coc5 span{border-color:#0191ce;color:#0191ce}.menubar2 .coc6 a,.menubar2 .coc6 span{border-color:#00aeff;color:#0296db}.menubar2 .coc7 a,.menubar2 .coc7 span{border-color:#58de81;color:#43ac63}.menubar2 .coc8 a,.menubar2 .coc8 span{border-color:#89c655;color:#73a846}.menubar2 .coc1 ul{border-color:#fde5d6}.menubar2 .coc2 ul{border-color:#ecd7e2}.menubar2 .coc3 ul{border-color:#e3dcec}.menubar2 .coc4 ul{border-color:#cfdfed}.menubar2 .coc5 ul{border-color:#cfeaf6}.menubar2 .coc6 ul{border-color:#cff0ff}.menubar2 .coc7 ul{border-color:#d5f7df}.menubar2 .coc8 ul{border-color:#cff4ec}.menubar2 ul ul span.custom{color:#333}.menubar2 li.last:hover ul,.menubar2 ul.js #hover.last ul{left:auto;right:0}.menubar2 .snap a:link,.menubar2 .snap a:visited,.menubar2 .snap a:active,.menubar2 .snap a:hover{padding:.5em 0}.menubar2 a span{padding:0;border:0;cursor:pointer;font-size:100%}.menubar2 .snap li li a:link,.menubar2 .snap li li a:visited,.menubar2 .snap li li a:active,.menubar2 .snap li li a:hover{padding:.5em .571em}.menubar2 li.fluid li a:link,.menubar2 li.fluid li a:visited,.menubar2 li.fluid li a:active,.menubar2 li.fluid li a:hover{border-top:none;border-left:none}.menubar2 li.fluid ul{padding-top:1px;padding-left:1px}.menubar2 li ul.mod2 li,.menubar2 .snap li ul.mod2 li.last{min-width:0;width:50%}.menubar2 li ul.mod3 li,.menubar2 .snap li ul.mod3 li.last{min-width:0;width:33.3%}.menubar2 li ul.mod4 li,.menubar2 .snap li ul.mod4 li.last{min-width:0;width:25%}.menubar2 li ul.mod5 li,.menubar2 .snap li ul.mod5 li.last{min-width:0;width:20%}.menubar2 li li.new a{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -232px}.menubar2 li li.beta a{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -344px}.menubar2 li li.new a,.menubar2 .snap li li.new a:link,.menubar2 .snap li li.new a:visited,.menubar2 .snap li li.new a:hover,.menubar2 .snap li li.new a:active{padding-right:33px}.menubar2 li li.beta a,.menubar2 .snap li li.beta a:link,.menubar2 .snap li li.beta a:visited,.menubar2 .snap li li.beta a:hover,.menubar2 .snap li li.beta a:active{padding-right:33px}.searchbar1{text-align:left}#wrapper .searchbar1 .br{margin:0;width:628px}.searchbar2{clear:both;text-align:center}#wrapper .searchbar2 .br{margin:0 auto;width:550px}.msnfoot1{border-top:solid 1px #cdcdcd;font-size:92%;line-height:normal;margin:1.083em .667em .667em .667em;padding:.5em 0 0 0}.msnfoot1 a,.msnfoot1 a:link,.msnfoot1 a:visited{color:#999}.msnfoot1 a:hover,.msnfoot1 a:active{color:#333}.msnfoot1 .primary li{float:left;display:block;padding:0 .833em}.msnfoot1 .primary li.first{padding-left:0}.msnfoot1 .secondary{text-align:right}.msnfoot1 .secondary a{white-space:pre}.msnfoot1 .secondary li{float:right;display:block;padding:0 .833em}.msnfoot1 .secondary li.first{padding-right:0}.msnfoot1 ul{list-style-type:none;margin:0;padding:0}.msnfoot1 .copyright{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right 0;clear:right;color:#999;float:right;margin:1.5em 0 0 0}.msnfoot1 .copyright span{border-right:solid 1px #999;display:block;line-height:20px;margin-right:133px;padding-right:10px}.ad1 .adfb a,.ad1 .adfb a:link,.ad1 .adfb a:visited{color:#666;font-size:83%;line-height:1.5em}.ad1 .adfb a:hover,.ad1 .adfb a:active{color:#333}.adfb.left span,.adfb.left a.adch{float:left}.adfb.left a,.adfb.right a.adch{float:right}.adfb{color:#666;text-align:center;width:100%}.alert1 a,.alert1 a:link,.alert1 a:visited{color:#333}.alert1 a:hover,.alert1 a:active{color:#000}.linkedimglink1{display:block;margin:0;padding:0}.linkedimglink1 a{clear:right;display:block;float:left}.linkedimglink1 a span{cursor:pointer;float:left;padding-top:8px}.linkedimglink1 img{border:none;float:left;margin-right:6px}.linkedimglink2{margin:0;padding:0}.linkedimglink2 a{display:block}.linkedimglink2 a span{cursor:pointer;float:right;text-align:right;padding-top:8px}.linkedimglink2 img{border:none;margin-left:6px;float:right}.hlcp2 .pri .piped,.hlcp2 .pri a,.hlcp2 .pri a:link,.hlcp2 .pri a:visited{color:#333;font-size:150%;line-height:1.22em}.hlcp2 .pri a:hover,.hlcp2 .pri a:active{color:#000}.hlcp2 .sec .piped,.hlcp2 .sec a,.hlcp2 .sec a:link,.hlcp2 .sec a:visited{color:#333;font-size:117%;line-height:1.07em}.hlcp2 .sec a:hover,.hlcp2 .sec a:active{color:#000}#wrapper .hlcp2 p a,#wrapper .hlcp2 p a:link,#wrapper .hlcp2 p a:visited,#wrapper .hlcp2 p a:hover,#wrapper .hlcp2 p a:active{font-size:100%;line-height:100%;text-decoration:underline}.hlcp2 .pri .piped a,.hlcp2 .pri .piped a:link,.hlcp2 .pri .piped a:hover,.hlcp2 .pri .piped a:visited,.hlcp2 .pri .piped a:active,.hlcp2 .sec .piped a,.hlcp2 .sec .piped a:link,.hlcp2 .sec .piped a:hover,.hlcp2 .sec .piped a:visited,.hlcp2 .sec .piped a:active{font-size:100%;line-height:100%}.hlcp2 .pri div{margin:.833em 0 0 0}.hlcp2 .cf{margin:0 0 .583em}.hlcp2 .pri div div,.hlcp2 .pri .first{margin:0}.hlcp2 img{border:0;display:block}.hlcp2 .pri img.landscape{margin:0 0 .333em 0}.hlcp2 .sec img.landscape{margin:0 .833em .833em 0}.hlcp2 ul.right .sec img{float:right}.hlcp2 ul.left .sec img{float:left}.hlcp2 .richtext p{margin:0}.hlcp2 .pri .richtext{margin:.333em 0 0 0}.hlcp2 .sec .richtext{margin:.083em 0 0 0}.hlcp2 ul{list-style-type:none;margin:0;padding:0}.hlcp2 li.sec{display:inline-block;padding:0 0 1.167em 0}.hlcp2 li.sec.last{padding:0 0 1.167em}.hlcp2 li.ter,.hlcp2 li.media{border-top:solid 1px #e1e1e1;display:list-item;line-height:1.25em;margin:0;padding:.583em 0}.hlcp2 li.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2347px;padding-left:19px}.hlcp2 span.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2355px}.hlcp2 .pri span.media{background-image:none}.hlcp2 .pri span.piped span.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2351px}.hlcp2 .pri span.media a{margin-left:0}.hlcp2 span.media a,.hlcp2 .pri span.piped span.media a{margin-left:19px}.hlcp2 .date{color:#999;clear:both;float:left;padding:.938em 0 1.667em 0}.hlcp2 span.icon{display:inline-block;font-size:75%;margin-left:.25em;text-decoration:none}.hlcp2 .pri .piped span.icon{font-size:50%}.hlcp2 span.new{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:12px;padding-top:.417em}.hlcp2 span.fresh1{background:transparent url(../../i/d7/fb6441a4c45cb3a3b2f592d914a3cd.gif) no-repeat right center;padding-right:31px;padding-top:.417em}.hlcp2 span.fresh2{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:12px;padding-top:.417em}.hlcp2 span.fresh3{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:12px;padding-top:.417em}.hlcp2 span.photo{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:12px;padding-top:.417em}.hlcp2 span.dest1{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:10px;padding-top:.417em}.hlcp2 span.dest2{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:10px;padding-top:.417em}.hlcp2 span.dest3{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:10px;padding-top:.417em}.hlcp2 .pri span.new{padding-top:.667em}.hlcp2 .pri span.fresh1{padding-top:.667em}.hlcp2 .pri span.fresh2{padding-top:.667em}.hlcp2 .pri span.fresh3{padding-top:.667em}.hlcp2 .pri span.photo{padding-top:.667em}.hlcp2 .pri span.dest1{padding-top:.667em}.hlcp2 .pri span.dest2{padding-top:.667em}.hlcp2 .pri span.dest3{padding-top:.667em}.menunavbar1{height:3.5em;margin-top:-1.667em;position:relative;width:100%}.menunavbar1 ul,.menunavbar1 li{display:block;float:left;list-style:none}.menunavbar1 ul{margin:0;padding:0;width:100%}.menunavbar1 li{text-align:center}.menunavbar1 ul li a{display:block;outline:none}.menunavbar1 a:link,.menunavbar1 a:visited,.menunavbar1 a:active{color:#fff;display:block;font-size:100%;font-weight:bold;line-height:normal;padding:.25em .8em;text-decoration:none}.menunavbar1 .ntier2 li{height:1.8em}.menunavbar1 ul .ntier2 li a{padding:0 .5em;color:#666;display:block}.menunavbar1 .ntier1 .ntier2{background-color:#fff;padding:0 1.5em 1.083em 0;padding-bottom:.3em;padding-top:.25em;width:79.5em}.menunavbar1 li ul,.menunavbar1 ul li:hover ul,.menunavbar1 ul li.last:hover ul{left:-999em;position:absolute}.menunavbar1 li li a:link,.menunavbar1 li li a:visited,.menunavbar1 li li a:hover,.menunavbar1 li li a:active{font-size:145%;font-weight:normal}.menunavbar1 ul.js li .showsm{display:block;z-index:10}.menunavbar1 ul.js li .hidesm{display:none;z-index:0}.menunavbar1 ul.js ul.notier li a{display:none}.menunavbar1 .ntier1 li:hover .ntier2,.menunavbar1 ul.js li.hover .ntier2,.menunavbar1 .ntier1 li.selected .ntier2{left:0;z-index:0}.menunavbar1 .js li:hover .ntier2{left:-999em}.menunavbar1 .ntier1 li:hover .ntier2{z-index:10}.menunavbar1 .ntier1 li:hover a,.menunavbar1 ul.js li.hover a,.menunavbar1 ul.ntier1 li.selected a{background-color:#fff;color:#666;outline:0}.menunavbar1 .js li:hover a{background-color:transparent;color:#fff}.menunavbar1 .js li:hover .ntier2 li a{background-color:#fff;color:#666}.menunavbar1 .ntier1 li .ntier2 li:hover a,.menunavbar1 ul.js li.hover .ntier2 li.focus a,.menunavbar1 .ntier1 li.selected .ntier2 li.highlighted a,.menunavbar1 .ntier1 li.selected .ntier2 li.focus a{color:#000;outline:0}.menunavbar1 .js li .ntier2 li:hover a{color:#666}.co4b5 .b3{display:none}.headlinelist2 div{float:left}.headlinelist2 ul{margin:0;padding:0}.headlinelist2 ul li{display:list-item;list-style-type:none;margin:0;padding:.417em 0}.headlinelist2 ul li.first{border-top:none;padding-top:0}.headlinelist2 ul li a{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2241px;display:block;line-height:1.25em;padding:0;padding-left:18px}.headlinelist2 span.media a{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2355px}.headlinelist3 div{float:left}.headlinelist3 ul{margin:0;padding:0}.headlinelist3 ul li{display:list-item;list-style-type:none;margin:0;padding:.417em 0}.headlinelist3 ul li.first{border-top:none;padding-top:0}.headlinelist3 ul li.first a{background-image:none;font-size:117%;font-weight:bold;padding-left:0}.headlinelist3 ul li a{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2241px;display:block;line-height:1.25em;padding:0;padding-left:18px}.headlinelist3 span.media a{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2355px}.imglinkabs1 img{float:left;margin-bottom:3px;margin-right:10px}.imglinkabs1 .media{display:inline}.imglinkabs1 p{margin:.2em 0 0 0}.imglinkabslist1{list-style-type:none;margin:0;padding:0}.imglinkabslist1 img{float:left;margin:0;margin-bottom:3px;margin-right:6px}.imglinkabslist1 li{margin:0 0 .9em 0}.imglinkabslist1 li.last{margin:0}.imglinkabslist1 .media{display:inline}.imglinkabslist1 div.richtext{margin:.2em 0 0 0}.imglinkabslist1 div.richtext p{margin:0}.imglinkabslist2{list-style-type:none;margin:0;padding:0}.imglinkabslist2 img{float:right;margin:0;margin-bottom:3px;margin-left:6px}.imglinkabslist2 li{margin:0 0 .9em 0}.imglinkabslist2 li.last{margin:0}.imglinkabslist2 div.richtext{margin:.2em 0 0 0}.imglinkabslist2 div.richtext p{margin:0}.imglinkabslist3{list-style-type:none;margin:0;padding:0}.imglinkabslist3 img{float:left;margin:0;margin-bottom:3px;margin-right:6px}.imglinkabslist3 li{margin:0 0 .9em 0}.imglinkabslist3 li.last{margin:0}.imglinkabslist3 .media{display:inline}.imglinkabslist3 div.richtext{border-top:solid 1px #ace;margin:.2em 0 0 0;padding:.3em 0 0 0}.imglinkabslist3 div.richtext p{margin:0}.imglinkabslist4{list-style-type:none;margin:0;padding:0}.imglinkabslist4 img{float:right;margin:0;margin-bottom:3px;margin-left:6px}.imglinkabslist4 li{margin:0 0 .9em 0}.imglinkabslist4 li.last{margin:0}.imglinkabslist4 div.richtext{border-top:solid 1px #ace;margin:.2em 0 0 0;padding:.3em 0 0 0}.imglinkabslist4 div.richtext p{margin:0}.imglinkabslist5{list-style-type:none;margin:0;padding:0}.imglinkabslist5 a,.imglinkabslist5 img{display:block;margin:0 0 3px 0}.imglinkabslist5 li{margin:0 0 .9em 0}.imglinkabslist5 li.last{margin:0}.imglinkabslist5 a{display:inline}.imglinkabslist5 div.richtext p{margin:0}.imglinkabslist6{list-style-type:none;margin:0;padding:0}.imglinkabslist6 a,.imglinkabslist6 img{display:block;margin:0 0 3px 0}.imglinkabslist6 li{margin:0 0 .9em 0}.imglinkabslist6 li.last{margin:0}.imglinkabslist6 div.richtext{border-top:solid 1px #ace;margin:0;padding:.3em 0 0 0}.imglinkabslist6 div.richtext a{display:inline}.imglinkabslist6 div.richtext p{margin:0}.imglinkabslist7{list-style-type:none;margin:0;padding:0}.imglinkabslist7 img{float:left;margin:0;margin-bottom:3px;margin-right:6px}.imglinkabslist7 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;width:47%}.imglinkabslist7 .media{display:inline}.imglinkabslist7 div.richtext{margin:.2em 0 0 0}.imglinkabslist7 div.richtext p{margin:0}.imglinkabslist8{list-style-type:none;margin:0;padding:0}.imglinkabslist8 img{float:right;margin:0;margin-bottom:3px;margin-left:6px}.imglinkabslist8 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;width:47%}.imglinkabslist8 div.richtext{margin:.2em 0 0 0}.imglinkabslist8 div.richtext p{margin:0}.imglinkabslist9{list-style-type:none;margin:0;padding:0}.imglinkabslist9 img{float:left;margin:0;margin-bottom:3px;margin-right:6px}.imglinkabslist9 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;width:47%}.imglinkabslist9 .media{display:inline}.imglinkabslist9 div.richtext{border-top:solid 1px #ace;margin:.2em 0 0 0;padding:.3em 0 0 0}.imglinkabslist9 div.richtext p{margin:0}.imglinkabslist10{list-style-type:none;margin:0;padding:0}.imglinkabslist10 img{float:right;margin:0;margin-bottom:3px;margin-left:6px}.imglinkabslist10 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;width:47%}.imglinkabslist10 div.richtext{border-top:solid 1px #ace;margin:.2em 0 0 0;padding:.3em 0 0 0}.imglinkabslist10 div.richtext p{margin:0}.imglinkabslist11{list-style-type:none;margin:0;padding:0}.imglinkabslist11 a,.imglinkabslist11 img{display:block;margin:0 0 3px 0}.imglinkabslist11 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;width:47%}.imglinkabslist11 div.richtext a{display:inline}.imglinkabslist11 div.richtext p{margin:0}.imglinkabslist12{list-style-type:none;margin:0;padding:0}.imglinkabslist12 a,.imglinkabslist12 img{display:block;margin:0 0 3px 0}.imglinkabslist12 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;width:47%}.imglinkabslist12 div.richtext{border-top:solid 1px #ace;margin:0;padding:.3em 0 0 0}.imglineabslist12 div.richtext a{display:inline}.imglinkabslist12 div.richtext p{margin:0}.imglinkabslist13{list-style-type:none;margin:0;padding:0}.imglinkabslist13 img{float:left;margin:0;margin-bottom:3px;margin-right:6px}.imglinkabslist13 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:28%}.imglinkabslist13 .media{display:inline}.imglinkabslist13 div.richtext{margin:.2em 0 0 0}.imglinkabslist13 div.richtext p{margin:0}.imglinkabslist14{list-style-type:none;margin:0;padding:0}.imglinkabslist14 img{float:right;margin:0;margin-bottom:3px;margin-left:6px}.imglinkabslist14 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:28%}.imglinkabslist14 div.richtext{margin:.2em 0 0 0}.imglinkabslist14 div.richtext p{margin:0}.imglinkabslist15{list-style-type:none;margin:0;padding:0}.imglinkabslist15 img{float:left;margin:0;margin-bottom:3px;margin-right:6px}.imglinkabslist15 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:28%}.imglinkabslist15 .media{display:inline}.imglinkabslist15 div.richtext{border-top:solid 1px #ace;margin:.2em 0 0 0;padding:.3em 0 0 0}.imglinkabslist15 div.richtext p{margin:0}.imglinkabslist16{list-style-type:none;margin:0;padding:0}.imglinkabslist16 img{float:right;margin:0;margin-bottom:3px;margin-left:6px}.imglinkabslist16 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:28%}.imglinkabslist16 div.richtext{border-top:solid 1px #ace;margin:.2em 0 0 0;padding:.3em 0 0 0}.imglinkabslist16 div.richtext p{margin:0}.imglinkabslist17{list-style-type:none;margin:0;padding:0}.imglinkabslist17 a,.imglinkabslist17 img{display:block;margin:0 0 3px 0}.imglinkabslist17 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:28%}.imglinkabslist17 div.richtext a{display:inline}.imglinkabslist17 div.richtext p{margin:0}.imglinkabslist18{list-style-type:none;margin:0;padding:0}.imglinkabslist18 img{display:block;margin:0 0 3px 0}.imglinkabslist18 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:28%}.imglinkabslist18 div.richtext{border-top:solid 1px #ace;margin:0;padding:.3em 0 0 0}.imglinkabslist18 div.richtext p{margin:0}.imglinkabslist19{list-style-type:none;margin:0;padding:0}.imglinkabslist19 img{float:left;margin:0;margin-bottom:3px;margin-right:6px}.imglinkabslist19 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:21%}.imglinkabslist19 .media{display:inline}.imglinkabslist19 div.richtext{margin:.2em 0 0 0}.imglinkabslist19 div.richtext p{margin:0}.imglinkabslist20{list-style-type:none;margin:0;padding:0}.imglinkabslist20 img{float:right;margin:0;margin-bottom:3px;margin-left:6px}.imglinkabslist20 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:21%}.imglinkabslist20 div.richtext{margin:.2em 0 0 0}.imglinkabslist20 div.richtext p{margin:0}.imglinkabslist21{list-style-type:none;margin:0;padding:0}.imglinkabslist21 img{float:left;margin:0;margin-bottom:3px;margin-right:6px}.imglinkabslist21 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:21%}.imglinkabslist21 .media{display:inline}.imglinkabslist21 div.richtext{border-top:solid 1px #ace;margin:.2em 0 0 0;padding:.3em 0 0 0}.imglinkabslist21 div.richtext p{margin:0}.imglinkabslist22{list-style-type:none;margin:0;padding:0}.imglinkabslist22 img{float:right;margin:0 0 3px 0;margin-left:6px}.imglinkabslist22 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:21%}.imglinkabslist22 div.richtext{border-top:solid 1px #ace;margin:.2em 0 0 0;padding:.3em 0 0 0}.imglinkabslist22 div.richtext p{margin:0}.imglinkabslist23{list-style-type:none;margin:0;padding:0}.imglinkabslist23 a,.imglinkabslist23 img{display:block;margin:0 0 3px 0}.imglinkabslist23 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;min-width:90px;width:21%}.imglinkabslist23 div.richtext a{display:inline}.imglinkabslist23 div.richtext p{margin:0}.imglinkabslist24{list-style-type:none;margin:0;padding:0}.imglinkabslist24 a,.imglinkabslist24 img{display:block;margin:0 0 3px 0}.imglinkabslist24 li{display:block;float:left;margin:0;margin-bottom:.9em;margin-right:3%;width:21%}.imglinkabslist24 div.richtext{border-top:solid 1px #ace;margin:0;padding:.3em 0 0 0}.imglinkabslist24 div.richtext a{display:inline}.imglinkabslist24 div.richtext p{margin:0}.linkedimglinklist13{list-style-type:none;margin:0;padding:0}.linkedimglinklist13 li{display:block;float:left;margin-bottom:.9em;margin-right:3%;position:relative;width:47%}.linkedimglinklist13 a{display:block}.linkedimglinklist13 a:after{content:".";clear:both;display:block;height:0;visibility:hidden}.linkedimglinklist13 img{border:none;float:left;margin-bottom:.4em;margin-right:.4em}.linkedimglinklist13 a span{cursor:pointer;padding-top:6px}.linklist9{list-style-type:none;margin:0;padding:0}.linklist9 a{white-space:pre}.linklist9 li{background:transparent url(../../i/f8/614595fba50d96389708a4135776e4.gif) repeat-y 100% 0;float:left;margin:0 0 2px 0;margin-right:.7em;padding:0;padding-right:.7em}.linklist9 li.last{background-image:none;margin:0;padding:0}.linklist16{list-style-type:none;margin:0;padding:0}.linklist16 li{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -3681px;margin:0;padding:.25em 0 .2em 9px}.linkimgabs1 a{display:block;margin:0 0 .4em 0}.linkimgabs1 br{display:none}.linkimgabs1 div.richtext br{display:inline}.linkimgabs1 img{display:block;float:left;margin-bottom:3px;margin-right:6px}.linkimgabs1 div.richtext a{display:inline}.conban1{position:relative}.conban1 .close{left:980px;top:0}.headerbar_us{height:9.833em;min-height:118px}.headerbar_us .pageoptions1 .welcome{text-align:right}.headerbar_us a,.headerbar_us a:link,.headerbar_us a:visited,.headerbar_us a:hover,.headerbar_us a:active,.headerbar_us label,.headerbar_us span,.headerbar_us a:hover span,.headerbar_us .br2 .welcome{color:#666}.headerbar_us .br1{float:left;width:54em}.headerbar_us .br1 .linklist1 li{float:left;padding:.25em 1.5em .2em 0}.headerbar_us .br2{float:right}.headerbar_us .br3{float:right;margin-right:.5em}.headerbar_us .br4{clear:both;float:left;min-width:208px;padding-top:.5em;width:17.33em}.headerbar_us .br5{float:left}.headerbar_us .br3 a,.headerbar_us .br3 a:link,.headerbar_us .br2 .welcome{font-weight:bold}.headerbar_us .m2{margin-top:.25em}.rstkq1 .rstockq1 h4{float:left;margin-right:.333em}.rstkq1 a,.rstkq1 a:link,.rstkq1 a:visited{color:#666}.co3b5 .br{float:left}.co3b5 .br2{clear:right;float:right}.co3b5 .br3,.co3b5 .more{clear:left}.co3b5 .br .more{clear:none}.co3b6 .br{clear:right;float:right}.co3b6 .br1{float:left}.co3b6 .more{clear:both;float:none}.co3b6 .br .more{clear:none}.co4b1 .br{float:left}.co4b1 .br2{clear:right}.co4b1 .br3{clear:left}.co4b1 .more{clear:both}.co4b1 .br .more{clear:none}.co4b1 .b3{display:block}.co4b2 .b3{display:none}.co4b2 .br{float:left}.co4b2 .more{clear:both}.co4b2 .br .more{clear:none}.co4b8 .b3{display:none}.co4b8 .br{float:left}.co4b8 .br3,.co4b8 .br4{clear:both;display:block;float:none}.co4b8 .more{clear:both}.co5b9 .b3,.co5b9 .b4{display:none}.co6b1 .b3,.co6b1 .b5{display:none}.co6b1 .b4{display:block}.co6b1 .br{float:left}.co6b1 .br4{clear:left}.co6b1 .more{clear:left}.co6b1 .br .more{clear:none}.hlcp1 .pri .piped,.hlcp1 .pri a,.hlcp1 .pri a:link,.hlcp1 .pri a:visited{color:#333;font-size:150%;line-height:1.22em}.hlcp1 .pri a:hover,.hlcp1 .pri a:active{color:#000}.hlcp1 .sec .piped,.hlcp1 .sec a,.hlcp1 .sec a:link,.hlcp1 .sec a:visited{color:#333;font-size:117%;line-height:1.07em}.hlcp1 .sec a:hover,.hlcp1 .sec a:active{color:#000}#wrapper .hlcp1 p a,#wrapper .hlcp1 p a:link,#wrapper .hlcp1 p a:visited,#wrapper .hlcp1 p a:hover,#wrapper .hlcp1 p a:active{font-size:100%;line-height:100%;text-decoration:underline}.hlcp1 .pri .piped a,.hlcp1 .pri .piped a:link,.hlcp1 .pri .piped a:hover,.hlcp1 .pri .piped a:visited,.hlcp1 .pri .piped a:active,.hlcp1 .sec .piped a,.hlcp1 .sec .piped a:link,.hlcp1 .sec .piped a:hover,.hlcp1 .sec .piped a:visited,.hlcp1 .sec .piped a:active{font-size:100%;line-height:100%}.hlcp1 .pri div{margin:.833em 0 0 0}.hlcp1 .cf{margin:0 0 .583em}.hlcp1 .pri div div,.hlcp1 .pri .first{margin:0}.hlcp1 img{border:0;display:block}.hlcp1 .pri img.landscape{margin:0 0 .333em 0}.hlcp1 .sec img.landscape{margin:0 .833em .833em 0}.hlcp1 ul.right .sec img{float:right}.hlcp1 ul.left .sec img{float:left}.hlcp1 .richtext p{margin:0}.hlcp1 .pri .richtext{margin:.333em 0 0 0}.hlcp1 .sec .richtext{margin:.083em 0 0 0}.hlcp1 ul{list-style-type:none;margin:0;padding:0}.hlcp1 li.sec{display:inline-block;padding:0 0 1.167em 0}.hlcp1 li.sec.last{padding:0 0 1.167em}.hlcp1 li.ter,.hlcp1 li.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2236px;display:list-item;line-height:1.333em;margin:0;padding:.333em 0 .333em 1.583em}.hlcp1 li.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2350px}.hlcp1 span.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2355px}.hlcp1 .pri span.media{background-image:none}.hlcp1 .pri span.piped span.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2351px}.hlcp1 .pri span.media a{margin-left:0}.hlcp1 span.media a,.hlcp1 .pri span.piped span.media a{margin-left:19px}.hlcp1 .date{color:#999;clear:both;float:left;padding:.938em 0 1.667em 0}.hlcp1 span.icon{display:inline-block;font-size:75%;margin-left:.25em;text-decoration:none}.hlcp1 .pri .piped span.icon{font-size:50%}.hlcp1 span.new{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:12px;padding-top:1px}.hlcp1 span.fresh1{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:12px;padding-top:1px}.hlcp1 span.fresh2{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:12px;padding-top:1px}.hlcp1 span.fresh3{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:12px;padding-top:1px}.hlcp1 span.photo{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:10px;padding-top:.25em}.hlcp1 span.dest1{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:12px;padding-top:.25em}.hlcp1 span.dest2{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:12px;padding-top:.25em}.hlcp1 span.dest3{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:12px;padding-top:.25em}.hlcp1 .pri span.new{padding-top:.667em}.hlcp1 .pri span.fresh1{padding-top:.667em}.hlcp1 .pri span.fresh2{padding-top:.667em}.hlcp1 .pri span.fresh3{padding-top:.667em}.hlcp1 .pri span.photo{padding-top:.667em}.hlcp1 .pri span.dest1{padding-top:.667em}.hlcp1 .pri span.dest2{padding-top:.667em}.hlcp1 .pri span.dest3{padding-top:.667em}.imgmap1 img{border:none}.linklist1{list-style-type:none;margin:0;padding:0}.linklist1 li{margin:0;padding:.25em 0 .2em 0}.linklist2{list-style-type:square;margin:0;margin-left:18px;padding:0}.linklist2 li{margin:0;padding:.25em 0 .2em 0}.linklist13{list-style-type:none;margin:0;padding:0}.linklist13 li{display:block;float:left;margin:0;margin-right:1%;padding:.25em 0 .2em 0;width:29%}.linklist14{list-style-type:none;margin:0;padding:0}.linklist14 li{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -3681px;display:block;float:left;margin:0 1% 0 0;padding:.25em 0 .2em 9px;width:44%}.linklist15{list-style-type:none;margin:0;padding:0}.linklist15 li{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -3681px;display:block;float:left;margin:0 1% 0 0;padding:.25em 0 .2em 9px;width:27%}.condbanner1 a.close{display:inline;padding:0 32px 32px 0;position:absolute;margin:0 0 0 -32px}.condbanner1 a.white{background:0 -466px transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat}.condbanner1 a.black{background:0 -598px transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat}.pgopt1{float:right;clear:both}.pgopt1 .opt,.pgopt1 .signin{display:inline;float:left;font-size:83.33%;line-height:1.6em;height:1.6em;min-height:16px}.pgopt1 li a,.pgopt1 li span{border-bottom:solid 2px #fff}.pgopt1 li li a,.pgopt1 li li span{border-bottom:none}.pgopt1 .opt ul{font-size:120%;line-height:1.333em;top:1.333em}.pgopt1 .user ul{top:1.417em}.pgopt1 .user div a,.pgopt1 .user div span{font-size:100%;font-weight:bold}.pgopt1 .user div ul a{font-weight:normal}.pgopt1 ul,.pgopt1 li{display:block;margin:0;padding:0;text-align:right;list-style:none}.pgopt1 li li{background-color:#fff;display:block;width:100%;text-align:left}.pgopt1 li a,.pgopt1 .js li:hover a{border-color:#fff}.pgopt1 li a span,.pgopt1 li a:link,.pgopt1 li a:visited,.pgopt1 li a:active,.pgopt1 li a:visited,.pgopt1 .js li:hover a:link,.pgopt1 .js li:hover a:visited,.pgopt1 .js li:hover a:hover,.pgopt1 .js li:hover a:active{text-decoration:none}.pgopt1 .pipe{border-left:solid 1px #999;margin-left:.417em;padding-left:.417em}.pgopt1 li.signin:hover a,.pgopt1 .js li#hover.signin a:hover{text-decoration:underline}.pgopt1 li.signin:hover a,.pgopt1 li.signin a:hover,.pgopt1 .js li#hover.signin a{border-bottom-color:#fff}.pgopt1 li:hover a,.pgopt1 li a:hover,.pgopt1 .js #hover a{border-bottom-color:#666}.pgopt1 ul li:hover ul,.pgopt1 ul.js #hover ul{left:auto;right:0;z-index:110}.pgopt1 li li:hover,.pgopt1 .js li li#hover,.pgopt1 li li.focus{background-color:#f1f1f1}.pgopt1 li:hover li a,.pgopt1 li#hover li a{border:none}.pgopt1 .user div,.pgopt1 .opt div{position:relative}.pgopt1 li ul,.pgopt1 ul.js li:hover ul{left:-999em;right:auto;z-index:auto}.pgopt1 .user ul,.pgopt1 .opt ul{background-color:#fff;border:solid 1px #666;position:absolute}.pgopt1 li li a,.pgopt1 ul.js li li a{display:block;float:none;padding:.417em 1.417em;min-width:132px;white-space:nowrap}.pgopt1 li li a.checked{background:transparent url(../../i/ff/290e7f0b12fa8a201581c74c1ae75a.gif) no-repeat .417em center}.pgopt1 li li.separator#hover,.pgopt1 li li.separator:hover{background-color:transparent}.pgopt1 li li.separator{font-size:10%;height:1px;line-height:1px;min-height:1px;position:absolute;z-index:100}.pgopt1 li li.separator div{border:none;border-top:1px solid #666;height:1px;margin:0 17px}.rstockq1 a,.rstockq1 h4,.rstockq1 span{margin:0;padding:0}.esbm,.esb{display:none}.esh .esbm{display:block}.esh .esb{background:#b2bdc4;display:block;font-size:12px}.esh #head .ro .ce{position:inherit}.esh #srchfrm{position:relative;z-index:110}.esh .scopes a{color:#fff}.esh #srchfrm .opt{display:none}.headerbar_us .esbc span,.headerbar_us .esbc a:hover span{color:#fff}.esbm{background:#333;height:100%;position:absolute;width:100%;z-index:110}.esbtn{background-image:url("../../i/61/379589e51e05637f600f129f305b52.png");cursor:pointer;height:23px;position:absolute;right:-23px;top:0;width:23px}.esbc{background-color:#b2bdc4;position:relative}.esbc ul,.esbc ul{list-style:none outside none;margin:0;padding:0}.esbc .cbg{line-height:0}.esbc .mbg{background:none repeat scroll 0 0 #000;height:100%;position:absolute;width:100%;z-index:1}.esbc .mlogo{background:0 0 url(../../i/61/def0ebad64d00fda0702cb7b8179ea.png) no-repeat;float:left;height:32px;margin:14px 0 2px 14px;width:90px}.esbc .cmenu{height:100%;position:absolute;top:0;width:113px}.menus{top:48px;position:absolute;z-index:10}.esh .menus li a{color:#fff}.menus li a{display:block;padding:10px 14px}.menus li .sc_pc{background:#333;border:1px solid #777;display:block;left:105px;padding:.5em;position:absolute;margin-top:-45px;width:22em;white-space:nowrap}.menus li.col3 .sc_pc{margin-top:-55px}.menus li.col4 .sc_pc{margin-top:-65px}.menus li a span{background-color:#fff;display:block;height:26px;left:0;margin-top:-6px;position:absolute;width:100%}.menus .sc_pc a{padding:2px 5px}.menus .sc_pc h3{color:#999;padding:5px}.menus li .sc_pca{color:#fff;padding-top:10px}.menus li .sc_pca a{display:inline;padding:5px}.sl_sh{font-size:13px}.sh_hto{background:none repeat scroll 0 0 #000;height:37px;padding:1px;width:37px}.sh_hs p{color:#fff;margin:0 0 5px}.sh_hto div{border:1px solid #fff;float:left;height:35px;width:35px}.sh_hst{position:absolute;z-index:5}a.sh_hs{cursor:pointer;display:block;line-height:1.4em;padding:5px 5px 5px 10px;position:absolute;width:219px;z-index:15}a.sh_hs:hover{text-decoration:none}.sh_ho{background:none repeat scroll 0 0 #000;left:0;padding:1px;position:absolute;top:0;width:100%;z-index:-1}.sh_ho div{border:1px solid #fff}.sh_hq{text-decoration:underline}.sh_hs span.sh_hi,a.sh_hs:hover span.sh_hi{color:#ffa500;text-decoration:none}.sh_rdiv{bottom:10px;font-size:11px;position:absolute;right:5px}.sh_rdiv a{cursor:default;display:block;float:left;margin:0 3px;outline:medium none;position:relative;text-decoration:none}#head .sh_rdiv a:hover span{display:block;text-decoration:none}.sc_light{border:1px solid;cursor:pointer;display:block;text-indent:3px;height:18px;width:17px}.dis .sc_light{cursor:default}#head .sc_msg{color:#000}.sc_msg{background:none repeat scroll 0 0 #fff;border:1px solid #555;bottom:2em;display:none;padding:.2em .5em;position:absolute;right:.18em;white-space:nowrap}.sh_rdiv .copy{font-size:14px}.sh_rdiv .sh_igc{margin:1px 2px 0 5px}.sh_igc .sc_msg{bottom:1.82em;white-space:normal;width:300px}.esbf{background:none repeat scroll 0 0 #d0d9dd;padding:14px 4px 10px}.esbf h3{color:#737373;font-size:16px;font-weight:200;margin-left:6px}.esbf ul{margin:0;padding:9px 0 0;list-style:none outside none}.esbf li{float:left;font-size:14px;font-weight:700}.esb .esbf li a{color:#000}.esbf a,.esbf a:hover{line-height:1.2em;font-weight:200;margin:0 6px}.es2 .menus li a{padding:7px 14px}.es2 .menus .sc_pc a{padding:2px 5px}.esh .es2 #sa_drw li{padding:7px}.dating1{background-color:#f7f7f7;padding:0;margin:.667em 0 .667em .333em}#wrapper .dating1 .h2{border-bottom:none;margin:0 0 .83em;background-color:#fff;padding-bottom:.4em}.dating1 br{display:none}#wrapper .dating1 .br2{padding-top:0}.dating1 .linkedimglinklist8 img{margin-bottom:0}.dating1 .linkedimglinklist8 li{padding:0 .333em 0 0;margin:0;text-align:left}.dating1 .linkedimglinklist8 li.last{padding:0}.w4 .dating1 .linkedimglinklist8 li{width:6.32em}.w4 .dating1 .linkedimglinklist8 li.last{width:5em}.dating1 .linkedimglinklist8 a span{font-size:92%;line-height:1em}.dating1 .complex1 .dddiv1,.dating1 .complex1 .dddiv2{float:left}.dating1 .complex1 .dddiv1 select,.dating1 .complex1 .dddiv2 select,.dating1 .complex1 .dddiv3,.dating1 .complex1 .dddiv5{clear:left}.dating1 .complex1 .dddiv2{margin-left:1.5em}.dating1 .complex1 .dddiv3,.dating1 .complex1 .dddiv5{padding-top:.583em}.dating1 .complex1 .dddiv4{margin-top:0}.dating1 .complex1 .dddiv1 label,.dating1 .complex1 .dddiv2 label{margin-bottom:.25em}.dating1 .complex1 .dddiv3 label,.dating1 .complex1 .dddiv4 label,.dating1 .complex1 .dddiv5 label{margin-top:.167em}.dating1 .complex1 label,.dating1 .complex1 select{color:#666;margin-right:1.25em;margin-bottom:0}.dating1 .complex1 label{margin-top:0}.dating1 .complex1 .button{background-color:#36b701;border:solid 1px #92b0dd;color:#fff;font-weight:bold}#wrapper .dating1 .br4{padding-top:1.25em}.dating1 fieldset #mygender{clear:left}.dating1 fieldset #theirgenderlbl{float:none}.dating1 fieldset#cff1 label{margin-right:7.9em;margin-top:0}.dating1 fieldset#cff1 select{margin-right:1.667em}.dating1 fieldset{padding:.5em 0 0}.dating1 fieldset.last{padding-bottom:.5em}.dating1 fieldset.last select{width:auto}.dating2{background-color:#fff0fb;padding:0}#wrapper .dating2 .h2{border-bottom:0;margin:0 0 0 .641em}.dating2 br{display:none}.dating2 .br1,.dating2 .br2{padding:0 0 0 .75em}#wrapper .dating2 .br2{padding-top:0}.dating2 .linkedimglinklist8 li{padding:0 1.222em 0 0;margin:0;text-align:left}.dating2 .linkedimglinklist8 li.last{padding:0}.w4 .dating2 .linkedimglinklist8 li{width:5em}.w4 .dating2 .linkedimglinklist8 li.last{width:5em}.dating2 .linkedimglinklist8 a span{font-size:92%;line-height:1em}.dating2 .complex1 .dddiv1,.dating2 .complex1 .dddiv2{float:left}.dating2 .complex1 .dddiv1 select,.dating2 .complex1 .dddiv2 select,.dating2 .complex1 .dddiv3,.dating2 .complex1 .dddiv5{clear:left}.dating2 .complex1 .dddiv2{margin-left:1.5em}.dating2 .complex1 .dddiv3,.dating2 .complex1 .dddiv5{padding-top:.583em}.dating2 .complex1 .dddiv4{margin-top:0}.dating2 .complex1 .dddiv1 label,.dating2 .complex1 .dddiv2 label{margin-bottom:.25em}.dating2 .complex1 .dddiv3 label,.dating2 .complex1 .dddiv4 label,.dating2 .complex1 .dddiv5 label{margin-top:.167em}.dating2 .complex1 label,.dating2 .complex1 select{color:#666;margin-right:.667em;margin-bottom:0}.dating2 .complex1 .button{background-color:#36b701;border:solid 1px #92b0dd;color:#fff;font-weight:bold}#wrapper .dating2 .br4{padding-top:1.25em}.dating2 fieldset #mygender{clear:left}.dating2 fieldset #theirgenderlbl{float:none}.dating2 fieldset#cff1 label{margin-right:5.2em}.dating2 fieldset#cff1 select{margin-right:2.2em}.dating2 fieldset{padding:.5em 0 0}.dating2 fieldset.last{padding-bottom:.5em}.complex1,.complex1 p{margin:0;padding:0}.complex1 fieldset{border:none;clear:both}.complex1 fieldset.last div{margin-top:0}.complex1 cite{display:block;font-style:normal}.complex1 label,.complex1 select,.complex1 input,.complex1 textarea{float:left;margin-right:.2em}.complex1 cite,.complex1 div{margin-top:.4em}.complex1 select{font-size:100%}.complex1 input{font-size:100%;line-height:1.25em}.complex1 input.alt{float:right}.linkedimg1 a:hover{text-decoration:none}.dhppromo1 .adfb{color:#666;text-align:center;width:100%}.co5b18 .b3,.co5b18 .b4{display:none}.co5b18 .br{float:left}.co5b18 .br1,.co5b18 .br5{clear:both;display:block;float:none}.co5b18 .more{clear:both;float:none}#wrapper .hotmail1{margin:.667em .667em 1.667em .667em}#wrapper .hotmail1 .h2{margin:0}.hminbox1 .expands{display:none}.hminbox1 p{line-height:1.333em;margin:.833em 0}.hminbox1 table{border-collapse:collapse;border-bottom:solid 2px #ccebf7;width:100%}.hminbox1 caption,.hminbox1 thead{display:none}.hminbox1 td{border-bottom:solid 1px #e1e1e1;padding:6px 0}.hminbox1 td.rec{text-align:right}.hminbox1 td.msg{padding-left:27px}.hminbox1 tr.unread td.msg{font-weight:bold;background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2461px}.hminbox1 tr.unread td.rec span.date{font-weight:bold}.hminbox1 tr.read td.msg{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2573px}.hminbox1 tr.replied td.msg{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -1674px}.hminbox1 tr.forwarded td.msg{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -1785px}.hminbox1 tr.attached td.msg{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -1897px}.hminbox1 tr.msn td.msg{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2009px}.hminbox1 tr.courier td.msg{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2121px}.hminbox1 tr.prilow td.msg{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 5px -3461px}.hminbox1 tr.prihigh td.msg{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 6px -3571px}.hminbox1 td.msg span,.hminbox1 td.rec span.time{display:block;font-weight:normal;margin-top:.5em}.hminbox1 td.rec span.date{color:#333}.hminbox1 td.rec span.time{color:#999;line-height:1.5em;white-space:nowrap}.hminbox1 ul.greet{border-bottom:solid 2px #ccebf7;margin:0;padding:.417em 0}.hminbox1 p.teaser{border-top:solid 1px #e1e1e1;margin-top:0;padding:.583em 0 0 0}.hminbox1 div.logo{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -116px;float:none;height:30px;width:90px}.hminbox1 ul.actions{float:right;margin:.54em 0;padding:0}.hminbox1 div.hr{margin-top:0}.hminbox1 li{border-right:solid 1px #e1e1e1;display:block;float:left;margin:0;padding:0 1.083em}.hminbox1 li.last{border-right:none;padding-right:0}.hminbox1 li.first{padding-left:0}.hminbox1 ul.greet li{border-right:none;padding:0;width:50%}.hminbox1 ul.greet li.last{text-align:right}.hminbox1 ul.actions li a.hide{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -3032px;padding-right:15px}.hminbox1 ul.actions li a.hide:hover{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -3141px}.hminbox1 ul.actions li a.show{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -3250px;padding-right:15px}.hminbox1 ul.actions li a.show:hover{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -3359px}.hminbox1 ul.greet li.first a,.hminbox1 ul.greet li.first a:link,.hminbox1 ul.greet li.first a:visited{color:#333;font-size:117%;line-height:1.43em}.hminbox1 ul.greet li.first a:visited,.hminbox1 ul.greet li.first a:active{color:#000}.hminbox1 td.msg a,.hminbox1 td.msg a:link,.hminbox1 td.msg a:visited{color:#333}.hminbox1 td.msg a:hover,.hminbox1 td.msg a:active{color:#000;cursor:pointer}.hminbox1 ul.greet li.first a span{font-size:86%;line-height:1.333em;padding:.25em}.hminbox1 p.error a,.hminbox1 p.error a:link,.hminbox1 p.error a:visited{color:#333}.hminbox1 p.error a:hover,.hminbox1 p.error a:active{color:#000}.hminbox1 ul.greet li a span,.hminbox1 ul.greet li a:link span,.hminbox1 ul.greet li a:visited span,.hminbox1 td.msg a span,.hminbox1 td.msg a:link span,.hminbox1 td.msg a:visited span{color:#333}.hminbox1 ul.greet li a:hover span,.hminbox1 ul.greet li a:active span,.hminbox1 td.msg a:hover span,.hminbox1 td.msg a:active span{color:#000}.hminbox1 ul a,.hminbox1 ul a:link,.hminbox1 ul a:visited{color:#666}.hminbox1 ul a:hover,.hminbox1 ul a:active{color:#333}.ht1{margin:0;padding:0;text-align:left}.ht1 .sub{color:#666;line-height:2.333em}.ht1 .sub a:link{color:#666}.ht1 .topicitem{width:26.333em;min-width:316px;border-top:solid 1px #e1e1e1;padding:0}.ht1 .atopicitem{width:24.833em;min-width:298px}.ht1 .first{display:inline-block;border-top:none;margin-bottom:.833em;padding:0;vertical-align:top}.ht1 .num,.ht1 .first .topic{color:#666;font-size:116.7%;font-weight:bold;line-height:1.333em}.ht1 .first p{color:#999;font-weight:normal;line-height:1.333em;margin:0;padding:0}.ht1 .down{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2685px}.ht1 .up{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2799px}.ht1 .side{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2913px}.ht1 .downflush{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2690px}.ht1 .upflush{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2804px}.ht1 .sideflush{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2918px}.ht1 .first .content{margin-right:136px;padding-right:.833em}.ht1 .media{float:right}.ht1 .media img{display:block}.ht1 .arrow{padding-left:1.5em}.ht1 .rank{float:left;text-align:right;width:1.25em;display:inline}.ht1 .first .rank{width:1.071em}.ht1 .content{padding-left:1.667em}#marchmadness .br3 img,#marchmadness .br2{display:none}#marchmadness .br3 noscript p{padding:5em 10em 0}#marchmadness .hlcp1 .pri a,#marchmadness .hlcp1 .pri a:link,#marchmadness .hlcp1 .pri a:visited{font-size:117%}#marchmadness .m2{margin-right:1em}.co3b1 .br{float:left}.co3b1 .more{clear:left}.co3b1 .br .more{clear:none}.co3b2 .br{float:left}.co3b2 .br1{clear:both;display:block;float:none}.co3b2 .more{clear:left}.co3b2 .br .more{clear:none}.co3b3 .br{float:left}.co3b3 .br3{clear:both;display:block;float:none}.co3b3 .more{clear:both}.srchh1 div.loaddisableding{font-weight:bold;margin:.66em 0;padding:0 0 .33em 0;text-align:center}.srchh1 div.logo{background:transparent url(../../i/61/def0ebad64d00fda0702cb7b8179ea.png) no-repeat 0 -263px;height:19px;width:37px}.srchh1 div.shupsell{margin-bottom:.33em;padding-bottom:0}.srchh1 div.results,.srchh1 div.shupsell,.srchh1 div.loaddisableding{border-bottom:solid 2px #ccebf7}.srchh1 div.results{margin-bottom:.33em;padding:0}.srchh1 ul.resultlist{list-style-type:none;margin:0;padding:0}.srchh1 ul.resultlist li{border-bottom:solid 1px #e1e1e1;display:list-item;line-height:1.25em;padding:.58em 0}.srchh1 ul.resultlist li.first{padding-top:0}.srchh1 ul.logobar{float:right;margin:.1em 0;padding:0}.srchh1 ul.logobar li{float:left;list-style-type:none;margin:0;padding:0 1.08em}.srchh1 ul.logobar li.first{border-right:solid 1px #e1e1e1;padding-left:0}.srchh1 ul.logobar li.last{border-right-style:none;padding-right:0}.srchh1 ul.logobar li a.hide{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -3032px;padding-right:15px}.srchh1 ul.logobar li a.hide:hover{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -3141px}.srchh1 ul.logobar li a.show{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -3250px;padding-right:15px}.srchh1 ul.logobar li a.show:hover{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -3359px}.srchh1 ul a,.srchh1 ul a:link,.srchh1 ul a:visited{color:#666}.srchh1 ul a:hover,.srchh1 ul a:active{color:#333}.eula1 h2.h2 span,.eula1 div.h2 span{display:none}.eula1{display:none;left:0;height:100%;text-align:center;top:0;position:absolute;width:100%;z-index:110}.eula1 h2.h2,.eula1 div.h2{background:transparent url(../../i/09/4ebdf19a1ce03cce12e11926256422.gif) repeat 0 0;height:100%;left:0;position:absolute;text-align:center;width:100%}#wrapper .eula1 .br1{background:#f5f9fb;border:solid 2px #9c9c9c;margin:0 auto;position:relative;top:180px;width:37.2em;z-index:111}.eula1 .richtext{padding:6px 10px;text-align:left}.eula1 .custom2{display:block;font-weight:bold;margin:6px auto;text-align:center}.eula1 .custom2 a{background-color:#eb7c00;border:solid 1px #ffa615;color:#fff;padding:2px 7px}.actfeed1 .ac-head{margin-top:-5px;border-bottom:2px solid #ccebf7;width:100%}.actfeed1 .ac-greet{float:left}.actfeed1 .ac-greettext{font-size:117%;padding:4px 0 7px 0}.actfeed1 .ac-upsell,.actfeed1 .ac-errortext{float:left;padding:5px 0 6px 0}.actfeed1 .ac-errortext{padding-top:5px}.actfeed1 .ac-signinlink,.actfeed1 .ac-signout{float:right;margin-top:5px}.actfeed1 .ac-signinlink.fbsignin{margin-top:1px}.actfeed1 .ac-signinlink.fbsignin a span{background:url(../../i/16/9798fea395258497f598bba500bf83.png) repeat 0% -263px #5f78ab;border-bottom:1px solid #1a356e;border-top:1px solid #879ac0;color:#fff;display:block;font-family:"lucida grande",tahoma,verdana,arial,sans-serif;font-weight:bold;margin:1px 1px 0 21px;padding:2px 6px 3px;text-decoration:none}.actfeed1 .ac-signinlink a{padding:3px 0 5px 23px}.actfeed1 .ac-signinlink.fbsignin a{margin:0;padding:0;background:url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 0% -229px #29447e;cursor:pointer;display:inline-block;outline:medium none;text-decoration:none;font-size:92%;line-height:14px}.actfeed1 .wlsignin{background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 0% -149px}.actfeed1 .twsignin{background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 0% -120px}.actfeed1 .ac-list,.actfeed1 .ac-item{list-style-type:none;margin:0;padding:0}.actfeed1 .ac-item{padding:10px 0 0 0;border-bottom:1px solid #e1e1e1}.actfeed1 .ac-itemauthorpicdiv{width:26px;float:left}.actfeed1 .ac-itemauthorpic{width:26px;height:26px}.actfeed1 .ac-itemmain{margin:-3px 0 0 0;float:right;width:88%;padding:0;overflow:hidden}.actfeed1 .ac-itemauthorname{display:inline;font-weight:bold}.actfeed1 .ac-itemfoot{padding-left:0;padding-bottom:8px;margin-left:0}.actfeed1 .ac-itemfoot li.first{background:none;padding-left:0}.actfeed1 .ac-itemfoot li{list-style-type:disc;list-style:none;background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat -1.4em -170px;padding:0 8px 0 11px;margin-top:3px;float:left}.actfeed1 .ac-noitems a:link,.actfeed1 .ac-noitems a:visited,.actfeed1 .ac-list a:link,.actfeed1 .ac-list a:visited,.actfeed1 .ac-errortext a:link,.actfeed1 .ac-errortext a:visited,.actfeed1 .ac-foot .ac-footlefthide a:link,.actfeed1 .ac-foot .ac-footlefthide a:visited{color:#000}.actfeed1 .ac-noitems a:hover,.actfeed1 .ac-noitems a:active,.actfeed1 .ac-list a:hover,.actfeed1 .ac-list a:active,.actfeed1 .ac-errortext a:hover,.actfeed1 .ac-errortext a:active,.actfeed1 .ac-foot .ac-footlefthide a:hover,.actfeed1 .ac-foot .ac-footlefthide a:active{color:#000}.actfeed1 .ac-statustext.ac-statustextcurrent,.actfeed1 .ac-commentinput.ac-statustextcurrent,.actfeed1 .ac-signout a:link,.actfeed1 .ac-signout a:visited,.actfeed1 .ac-foot a:link,.actfeed1 .ac-foot a:visited,.actfeed1 .ac-commenttime,.actfeed1 .ac-liketext,.actfeed1 .ac-liketext a:link,.actfeed1 .ac-liketext a:visited,.actfeed1 .ac-itemfoot a:link,.actfeed1 .ac-itemfoot a:visited,.actfeed1 .ac-allcomments a:link,.actfeed1 .ac-allcomments a:visited{color:#666}.actfeed1 .ac-statustext,.actfeed1 .ac-commentinput,.actfeed1 .ac-signout a:hover,.actfeed1 .ac-signout a:active,.actfeed1 .ac-foot a:hover,.actfeed1 .ac-foot a:active,.actfeed1 .ac-itemfoot a:hover,.actfeed1 .ac-itemfoot a:active,.actfeed1 .ac-liketext a:hover,.actfeed1 .ac-liketext a:active,.actfeed1 .ac-allcomments a:hover,.actfeed1 .ac-allcomments a:active{color:#333}.actfeed1 .ac-itemtext{display:inline;margin:0;padding:0}.actfeed1 .ac-itembody{padding-top:5px}.actfeed1.facebook .ac-itembasic{overflow:hidden;line-height:1.34em;max-height:13.4em}.actfeed1.facebook .ac-itembodymain{max-height:9.3em;line-height:1.34em;overflow:hidden}.actfeed1 .ac-itembodypicdiv{float:left;margin-right:9px}.actfeed1 .ac-noitems{padding:10px 0 10px 0;border-bottom:1px solid #e1e1e1}.actfeed1 .ac-status{margin:0;padding:11px 0 12px 0;border-bottom:2px solid #ccebf7;height:26px}.actfeed1 .ac-statusform{height:26px}.actfeed1 .ac-status .ac-statusmsgs{margin-top:6px}.actfeed1 .ac-statustext,.actfeed1 .ac-commentinput{padding:5px}.actfeed1 .ac-statustext{width:65.3%;float:left}.actfeed1 .ac-commentinput{width:92%;float:right;margin-top:2px}.actfeed1 .ac-commentsubmit{float:right;margin:7px 0 3px 0}.actfeed1 .ac-poststatus{float:right;margin-top:3px;padding:1px 0 0 0;width:27%}.actfeed1 input{font-size:100%;line-height:1.25em}.actfeed1 .ac-foot{padding:6px 0 7px 0;border-bottom:1px solid #e1e1e1}.actfeed1 .ac-footleftshow,.actfeed1 .ac-footlefthide{float:left}.actfeed1 .ac-footright{float:right}.actfeed1 .ac-hidelink{padding-right:15px;background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 100% 3px}.actfeed1 a:hover.ac-hidelink{background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 100% -16px}.actfeed1 .ac-showlink{padding-right:15px;background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 100% -79px}.actfeed1 a:hover.ac-showlink{background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 100% -98px}.actfeed1 .ac-refreshpic{background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 100% -36px;padding-right:17px}.actfeed1 a:hover.ac-refreshpic{background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 100% -58px}.actfeed1 .ac-updatestatus{width:283px;height:91px;text-align:center;vertical-align:middle;padding-top:192px}.actfeed1 .ac-loaddisabled{background:transparent url(../../i/fb/f017d9e8cc630c5e02659b6eaf35fa.gif) no-repeat 0 0}.actfeed1 .ac-comments .ac-commentsform{display:inline}.actfeed1 .ac-comments{list-style-type:none;padding:0;margin:0}.actfeed1 .ac-comments li{list-style:none;padding:10px 0;border-top:1px solid #e1e1e1}.actfeed1 .ac-comments .ac-liketext,.actfeed1 .ac-comments .ac-allcomments{padding:7px 0}.actfeed1 .ac-comments .ac-liketext span,.actfeed1 .ac-comments .ac-allcomments a{padding:0 0 0 30px}.actfeed1 .ac-liketext span{background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 0% -189px}.actfeed1 .ac-allcomments a{background:transparent url(../../i/16/9798fea395258497f598bba500bf83.png) no-repeat 0% -208px}.actfeed1 .ac-comment .ac-itemmain{width:86.5%}.actfeed1 .ac-selfcomment{padding:10px 0 0 0}.actfeed ac-commentinput{width:78%}#wrapper #content .generic1{margin:0 0 1em}.generic1 div.br{margin:0 0 .833em}.generic1 .link{text-align:left}.generic1 .link a{color:#333;font-family:arial;font-size:1.499em;font-weight:normal}.generic1 .richtext p{color:#333;font-family:arial;font-size:.996em;font-weight:normal;line-height:1.333em;text-align:left}.co6b7 .b3,.co6b7 .b4,.co6b7 .b5{display:none}.simple1,.simple1 p{margin:0;padding:0}.simple1 cite{font-style:normal}.simple1 cite,.simple1 label{display:block}.simple1 cite,.simple1 div{margin:.5em 0 0 0}.simple1 input{font-size:100%;line-height:1.25em;outline:none}.simple1 input.button{margin:0;margin-left:.2em}.simple2,.simple2 p{margin:0;padding:0}.simple2 cite{font-style:normal;margin:.5em 0 0;margin-left:-.9em}.simple2 cite,.simple2 label{display:block}.simple2 div{margin:.5em 0 0;margin-left:.9em}.simple2 input{font-size:100%;line-height:1.25em;outline:none}.simple2 input.button{margin:0;margin-left:.2em}.simple3,.simple3 p{margin:0;padding:0}.simple3 cite{font-style:normal;margin:.5em 0 0;margin-left:-.9em}.simple3 cite,.simple3 input,.simple3 label{display:block}.simple3 div{margin:.5em 0 0;margin-left:.9em}.simple3 input{font-size:100%;line-height:1.25em;outline:none}.simple3 input.button{margin:.2em 0 0 0}.simple4,.simple4 p{margin:0;padding:0}.simple4 cite{font-style:normal;margin:0;margin-left:.6em}.simple4 div{margin:.5em 0}.simple4 input{font-size:100%;line-height:1.25em;outline:none}.simple4 input.button{margin:0;margin-left:.2em}.simple5,.simple5 p{margin:0;padding:0}.simple5 cite{display:block;font-style:normal}.simple5 cite,.simple5 div{margin:.5em 0 0 0}.simple5 input{font-size:100%;line-height:1.25em;outline:none}.simple5 input.button{margin:0;margin-left:.2em}.simple6,.simple6 p{margin:0;padding:0}.simple6 cite{display:block;font-style:normal}.simple6 cite,.simple6 div{margin:.5em 0 0 0}.simple6 input{font-size:100%;line-height:1.25em;outline:none}.simple6 input.image{margin:0;margin-left:.2em;vertical-align:bottom}.simple7,.simple7 p{margin:0;padding:0}.simple7 cite{font-style:normal}.simple7 cite,.simple7 input,.simple7 label{clear:left;display:block}.simple7 cite,.simple7 div{margin:.5em 0 0 0}.simple7 input{font-size:100%;line-height:1.25em;outline:none}.simple7 input.button{margin:.2em 0 0 0}.simple8{margin:0;padding:0;position:relative}.simple8 cite,.simple8 p{display:none}.simple8 div{clear:left}.simple8 div div{border:solid 1px #bcbcbc;clear:none;float:left;padding:3px 3px 0 3px}.simple8 input.image{margin:1px 0 0 0}.simple8 input.text{border-width:0;font-size:100%;line-height:1.25em;outline:none;padding:4px 3px 0 0;vertical-align:top}.simple8 label{color:#666;display:block}.hlcp1 .pri .last{float:left}.hlcpm1 .hlcp1 .pri .piped,.hlcpm1 .hlcp1 .pri a,.hlcpm1 .hlcp1 .pri a:link,.hlcpm1 .hlcp1 .pri a:visited,.hlcpm1 .hlcp2 .pri .piped,.hlcpm1 .hlcp2 .pri a,.hlcpm1 .hlcp2 .pri a:link,.hlcpm1 .hlcp2 .pri a:visited{font-size:150%}.hcpep1 ul{list-style-type:none;margin:0;padding:0}.hcpep1 li,.hcpep1 li.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2236px;display:block;line-height:1.25em;margin:0;padding:.5em 0 .5em 19px}.hcpep1 li.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2350px}.hcpep1 span.piped span.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2354px;padding:.083em 0 .083em 19px}.hcpep1 .date{color:#999;clear:both;padding:.333em 0 1.667em 0}.hcpep1 span.icon{display:inline-block;font-size:75%;text-decoration:none}.hcpep1 span.new{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:14px;padding-top:1px}.hcpep1 span.fresh1{background:transparent url(../../i/d7/fb6441a4c45cb3a3b2f592d914a3cd.gif) no-repeat right center;padding-right:33px;padding-top:1px}.hcpep1 span.fresh2{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:14px;padding-top:1px}.hcpep1 span.fresh3{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:14px;padding-top:1px}.hcpep1 span.photo{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:1px}.hcpep1 span.dest1{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:3px}.hcpep1 span.dest2{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:3px}.hcpep1 span.dest3{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:3px}.hcpep2 ul{list-style-type:none;margin:0;padding:0}.hcpep2 li,.hcpep2 li.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2236px;display:block;float:left;line-height:1.25em;margin:0 7px 0 8px;padding:.5em 0 .5em 19px;width:42%}.hcpep2 li.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2350px}.hcpep2 span.piped span.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2354px;padding:.083em 0 .083em 19px}.hcpep2 .date{color:#999;clear:both;padding:.333em 0 1.667em 0}.hcpep2 span.icon{display:inline-block;font-size:75%;text-decoration:none}.hcpep2 span.new{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:14px;padding-top:1px}.hcpep2 span.fresh1{background:transparent url(../../i/d7/fb6441a4c45cb3a3b2f592d914a3cd.gif) no-repeat right center;padding-right:33px;padding-top:1px}.hcpep2 span.fresh2{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:14px;padding-top:1px}.hcpep2 span.fresh3{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:14px;padding-top:1px}.hcpep2 span.photo{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:1px}.hcpep2 span.dest1{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:3px}.hcpep2 span.dest2{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:3px}.hcpep2 span.dest3{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:3px}.hcpep3 ul{list-style-type:none;margin:0;padding:0}.hcpep3 li,.hcpep3 li.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2236px;display:block;float:left;line-height:1.25em;margin:0 7px 0 8px;padding:.5em 0 .5em 19px;width:27%}.hcpep3 li.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2350px}.hcpep3 span.piped span.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2354px;padding:.083em 0 .083em 19px}.hcpep3 .date{color:#999;clear:both;padding:.333em 0 1.667em 0}.hcpep3 span.icon{display:inline-block;font-size:75%;text-decoration:none}.hcpep3 span.new{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:14px;padding-top:1px}.hcpep3 span.fresh1{background:transparent url(../../i/d7/fb6441a4c45cb3a3b2f592d914a3cd.gif) no-repeat right center;padding-right:33px;padding-top:1px}.hcpep3 span.fresh2{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:14px;padding-top:1px}.hcpep3 span.fresh3{background:transparent url(../../i/77/b23a82d78a0605243aad8f44e8c079.gif) no-repeat right center;padding-right:14px;padding-top:1px}.hcpep3 span.photo{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:1px}.hcpep3 span.dest1{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:3px}.hcpep3 span.dest2{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:3px}.hcpep3 span.dest3{background:transparent url(../../i/b9/ab98403e7de9ce52839e5de99d27e5.gif) no-repeat right center;padding-right:11px;padding-top:3px}.local1 .br5 h3{font-size:100%;font-weight:normal;line-height:1.67em}.local1 .simple8{margin-top:8px}.local1 input{width:237px}.local1 .simple8 div div{float:none;width:262px}.local1 .simple8 div.loclist{background-color:#fff;border:1px solid #bcbcbc;clear:left;margin:10px 0 0 0;padding:0;position:absolute;width:268px}.local1 .simple8 div.loclist a.cancel{border:solid 1px #bcbcbc;float:right;padding:0 3px;margin:2px 2px 0 0}.local1 .simple8 div.loclist.down{top:45px}.local1 .simple8 div.loclist.up{bottom:28px}.local1 .simple8 div.loclist ul{list-style-type:none;margin:0;padding:0}.local1 .simple8 div.loclist ul li a{display:block;padding:5px 10px}.local1 .simple8 div.loclist ul li a:hover,.local1 .simple8 div.loclist ul li a:active{color:#333;background-color:#e5e5e5}.local1 .simple8 div.loclist ul li p{display:block;font-weight:normal;margin:0;padding:5px 10px}.local1 .simple8 .image{cursor:pointer}.weather1{line-height:1.25em}.weather1 .selected a,.weather1 .selected a:link,.weather1 .selected a:visited,.weather1 h4 a,.weather1 h4 a:link,.weather1 h4 a:visited,.weather1 .temp,.weather1 .conditions,.weather1 ul.degreetype li a:hover,.weather1 ul.forecasts a:hover,.weather1 div.today a:hover,.weather1 div.today a:hover span{color:#333}.weather1 .selected a:hover,.weather1 .selected a:active,.weather1 h4 a:hover,.weather1 h4 a:active,.weather1 ul.forecasts a:hover,.weather1 div.conditions a:hover,.weather1 .today li a:hover,.weather1 ul.degreetype li a:hover{color:#333}.weather1 h4 a:hover,.weather1 div.temp a:hover{color:#000}.weather1 .h3{line-height:1.4em;margin-bottom:.31em}.weather1 .h3 a{color:#666;float:left;font-size:117%;font-weight:bold}.weather1 .h3 span a.mapit{color:#333;font-size:83%;font-weight:normal;text-align:right;width:100%}.weather1 .h3 span{float:right}.weather1 div.data{float:left;padding-left:1.35em}.weather1 div.conditions{padding-bottom:1.75em}.weather1 div.msgbox{padding-top:.833em}.weather1 div.temp{font-size:150%;font-weight:bold;line-height:normal;padding:.2em 0 .35em 0}.weather1 div.today{height:1em;padding-bottom:.667em;width:100%}.weather1 div.today a,.weather1 div.today a:link,.weather1 div.today a:visited,.weather1 ul.degreetype li,.weather1 ul.degreetype li a{color:#666}.weather1 div.today ul,.weather1 ul{list-style-type:none;margin:0;padding:0}.weather1 div.weaheading{padding-bottom:.63em}.weather1 h4,.weather1 img{float:left}.weather1 div.weahr{border-top:solid 1px;color:#e1e1e1;margin-bottom:.7em}.weather1 ul.degreetype{float:right;text-align:right;width:20%}.weather1 ul.degreetype li{display:inline;padding:0}.weather1 ul.degreetype li.celsius{padding:0 0 0 1.417em}.weather1 ul.degreetype li.selected{font-weight:bold;color:#333}.weather1 ul.forecasts a,.weather1 ul.forecasts a:link,.weather1 ul.forecasts a:visited,.weather1 ul.degreetype li.selected a{color:#333}.weather1 div.conditions a{color:#666}.weather1 ul.forecasts li,.weather1 div.today ul li{border-right:solid 1px #333;float:left;font-size:100%;padding:0 .917em;text-align:right}.weather1 ul.forecasts li.first,.weather1 div.today ul li.first{padding-left:0}.weather1 ul.forecasts li.last,.weather1 div.today ul li.last{border:none}.weather1 h3.h3{font-size:117%}.weather1 h3.h3 a{font-size:100%}.weather1 .weaheading h4{font-size:100%}.weather1 div.temp a{font-weight:bold;line-height:1em}.weather1 ul.forecasts a:hover,.weather1 div.conditions a:hover,.weather1 .today li a:hover,.weather1 ul.degreetype li a:hover,.weather1 .h3 span a:hover{color:#333}.weather1 ul.forecasts a:hover,.weather1 ul.degreetype li.selected a:hover,.weather1 .h3 span a:hover,.weather1 h3.h3 span a:hover,.weather1 h4 a:hover{color:#000}.weather2 .location{border-right:1px solid #333;float:left;margin-top:.417em;padding:0 .333em}.weather2 .forecast{float:left}.weather2 .forecast .weatherimage{float:left;margin:.25em .25em 0 .2em}.weather2 .forecast .minidata{float:left;margin-top:.417em}.weather2 .forecast .minidata .weaheading{float:left}.weather2{float:right;margin:.66em}.weather2 .weaheading ul.degreetype li{display:inline;padding:.083em .25em .083em .083em}.weather2 .h3{line-height:1.4em;margin-bottom:.31em}.weather2 .h3 a{color:#333;float:left;font-size:100%;font-weight:bold}.weather2 ul.degreetype li.selected{color:#333;font-weight:bold}.weather2 ul.forecasts a,.weather2 ul.forecasts a:link,.weather2 ul.forecasts a:visited,.weather2 ul.degreetype li.selected a{color:#333}.weather2 div.today{display:inline;float:left;height:1em;padding-bottom:.667em}.weather2 div.today ul,.weather2 ul{display:inline;list-style-type:none;margin-left:.417em;padding:0}.weather2 div.today ul li{float:left;font-size:100%;padding:0 .917em;text-align:right}.weather2 ul.degreetype li.celsius{padding:0}.hideminiweather{visibility:hidden}.weather2 .degreetype li a,.weather2 .degreetype li a:link{color:#666}.weather2 .degreetype li.selected a,.weather2 .degreetype li.selected a:link{color:#333}.locnews1 ul{list-style-type:none;margin:0;padding:0}.locnews1 ul li{border-bottom:solid 1px #e1e1e1;line-height:1.25em;padding:.583em 0}.locnews1 ul.msg li{border-top:0;border-bottom:0}.locnews1 ul li.first{border-top:solid 1px #e1e1e1;margin:.583em 0 0 0}.locnews1 p.msg{line-height:1.33em;margin:0 0 5.417em 0}.locnews1 .seemore{font-style:italic;line-height:1.25em;padding:.583em 0 0 0;text-align:right}.locnews1 .hideseemore{display:none}.locnews1 ul li.last{border-bottom:none}.locevents1 ul{list-style-type:none;margin:0;padding:0}.locevents1 ul li{border-bottom:solid 1px #e1e1e1;line-height:1.25em;padding:.583em 0}.locevents1 ul li.first{border-top:solid 1px #e1e1e1;margin:.583em 0 0 0}.locevents1 p.msg{line-height:1.33em;margin:0 0 5.417em 0}.locevents1 .seemore{font-style:italic;line-height:1.25em;padding:.583em 0 0 0;text-align:right}.locevents1 .hideseemore{display:none}.locevents1 ul li.last{border-bottom:none}.locsports1 ul{list-style-type:none;margin:0;padding:0}.locsports1 ul li{border-bottom:solid 1px #e1e1e1;line-height:1.25em;padding:.583em 0}.locsports1 ul.msg li{border-top:0;border-bottom:0}.locsports1 ul li.first{border-top:solid 1px #e1e1e1;margin:.583em 0 0 0}.locsports1 p.msg{line-height:1.33em;margin:0 0 5.417em 0}.locsports1 .seemore{font-style:italic;line-height:1.25em;padding:.583em 0 0 0;text-align:right}.locsports1 .hideseemore{display:none}.locsports1 ul li.last{border-bottom:none}.lmlsf1 .findmore{border-bottom:solid 1px #e1e1e1;height:1%;line-height:1.43em;padding:0 0 .833em;overflow:hidden}.lmlsf1 .findmore div{float:left}.lmlsf1 .findmore ul li.first{padding:0 .8em 0 .583em}.lmlsf1 .findmore strong{font-size:100%}.lmlsf1 .simpleform p{display:block;font-size:100%;font-weight:bold;line-height:1.43em;margin:.833em 0}.linklist22{list-style-type:none;margin:0;padding:0}.linklist22 li{border-top:solid 1px #e1e1e1;line-height:1.25em;padding:.583em 0}#wrapper .money1 .br2{margin:0}#wrapper .money1 .br1{float:none}.money1 .indices1 table{border-collapse:collapse;border-spacing:0;width:91%}.money1 .simple8 input.text{width:20.583em}.money1 .siidx{font-weight:bold}.indices1 a,.indices1 a:link,.indices1 a:visited{color:#333}.indices1 a:hover,.indices1 a:active{color:#000}.indices1 caption,.indices1 thead{display:none}.indices1 td{color:#333;padding:0 0 0 .833em;line-height:1.25em;text-align:right}.indices1 td.neg{color:#c30505}.indices1 td.pos{color:#090}.indices1 td.siidx{padding:0 1em 0 0;text-align:left}.indices1 .sitime{text-align:left;color:#999;padding-bottom:.333em}.co4b3 .b3{display:none}.co4b3 .br{float:left}.co4b3 .br1{clear:both;display:block;float:none}.co4b3 .more{clear:both}.co4b3 .br .more{clear:none}.co4b4 .b3{display:none}.co4b4 .br{float:left}.co4b4 .br4{clear:both;display:block;float:none}.co4b4 .more{clear:both}.co4b6 .b3{display:none}.co4b6 .br{clear:right}.co4b6 .br1{float:left}.co4b6 .br2,.co4b6 .br3,.co4b6 .br4{float:right}.co4b6 .more{clear:both;float:none}.co4b6 .br .more{clear:none}.co4b7 .b3{display:none}.co4b7 .br1{float:right}.co4b7 .more{clear:left}.co4b7 .br .more{clear:none}.co4b9 .b3{display:none}.co4b9 .br{float:left}.co4b9 .br1,.co4b9 .br2{clear:both;display:block;float:none}.co4b9 .more{clear:both}.co4b9 .br .more{clear:none}.co4b10 .b3{display:none}.co4b10 .br{float:left}.co4b10 .br1,.co4b10 .br4{clear:both;display:block;float:none}.co4b10 .more{clear:both}.co4b10 .br .more{clear:none}div.hlcp3 li.ter{background:transparent url(../../i/0c/c57bc2a7d38843d7c4aa8028fc9f82.gif) no-repeat scroll 0 center;padding:.167em .6em;white-space:nowrap}div.hlcp3 li.ter .piped a{background:transparent url(../../i/0c/c57bc2a7d38843d7c4aa8028fc9f82.gif) no-repeat scroll 0 center;margin-left:-.2em;padding-left:.7em}div.hlcp3 li.ter span{color:#fff}.headlinelist1 div{float:left}.headlinelist1 ul{display:block;margin:0;padding:0}.headlinelist1 ul li{border-top:solid 1px #e1e1e1;display:list-item;line-height:1.25em;list-style-type:none;margin:0;padding:.583em 0}.headlinelist1 ul li.first{border-top:none;padding-top:0}.headlinelist1 span.media{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2355px;display:inline-block}.headlinelist1 span.media a{margin-left:19px}.adserved1 ul{margin:0;padding:0 0 0 .833em}.adserved1 ul li{border-top:solid 1px #e1e1e1;display:list-item;line-height:1.25em;list-style-type:none;margin:0;padding:.583em 0}.adserved1 ul li.first{border-top:none;padding-top:0}.slupsell1 .appbar .detail{position:absolute;height:326px;width:520px}.slupsell1 .appbar .detail .hidden{left:-9000px;top:0;position:absolute}.single2 .linklist22 li.first{border-top:none;padding-top:0}.single2 .orderedlist1{margin:0 0 0 1.5em}.single2 .imglinkabslist23 li a{font-size:150%}.w4 .single2 .imglinkabslist17 li,.w4 .single2 .linkedimgabslist7 li,.w4 .single2 .linkedimglinklist14 li,.w4 .single2 .linkedimglinklist17 li{margin:0 1.75em 0 0;min-width:86px;padding:0;width:7.167em}.w8 .single2 .imglinkabslist17 li,.w8 .single2 .linkedimgabslist7 li,.w8 .single2 .linkedimglinklist14 li,.w8 .single2 .linkedimglinklist17 li{margin:0 2.16em 0 0;min-width:192px;padding:0;width:16em}.w4 .single2 .linklist15 li{margin:0 1.75em 0 0;min-width:77px;padding:.25em 0 .25em .75em;width:7.167em}.w8 .single2 .linklist15 li{margin:0 1.333em 0 0;min-width:183px;padding:.25em 0 .5em .75em;width:15.25em}.w4 .single2 .imglinkabslist23 li,.w4 .single2 .linkedimglinklist18 li{margin:0 1.667em 0 0;min-width:60px;padding:0;width:5em}.w8 .single2 .imglinkabslist23 li,.w8 .single2 .linkedimglinklist18 li{margin:0 2.25em 0 0;min-width:136px;padding:0;width:11.333em}.w4 .single2 .imglinkabslist17 li.last,.w4 .single2 .linkedimgabslist7 li.last,.w4 .single2 .linkedimglinklist14 li.last,.w4 .single2 .linkedimglinklist17 li.last,.w4 .single2 .linklist15 li.last,.w8 .single2 .imglinkabslist17 li.last,.w8 .single2 .linkedimgabslist7 li.last,.w8 .single2 .linkedimglinklist14 li.last,.w8 .single2 .linkedimglinklist17 li.last,.w8 .single2 .linklist15 li.last,.w4 .single2 .imglinkabslist23 li.last,.w4 .single2 .linkedimglinklist18 li.last,.w8 .single2 .imglinkabslist23 li.last,.w8 .single2 .linkedimglinklist18 li.last{margin:0}.single2 .linkedimglinklist16 a{text-align:left}.w4 .single2 .linkedimglinklist16 li{margin-right:.833em;width:12.083em}.single2 .linkedimglinklist16 li.last{margin-right:0}.complex2,.complex2 p{margin:0;padding:0}.complex2 fieldset{border:none;clear:both}.complex2 fieldset.last div{display:block}.complex2 cite,.complex2 label{display:block;font-style:normal}.complex2 cite,.complex2 div{margin-top:.4em}.complex2 select{font-size:100%}.complex2 input{font-size:100%;line-height:1.25em}.complex2 label,.complex2 select{margin-bottom:.2em}.complex2 input.alt{float:right}.linkedimgabslist7{list-style-type:none;margin:0;padding:0}.linkedimgabslist7 img{border:solid 1px #333;float:left;margin-bottom:3px;margin-right:6px}.linkedimgabslist7 li{display:block;float:left;margin-bottom:.9em;margin-right:1%;width:29%}.linkedimglinklist1{list-style-type:none;margin:0;padding:0}.linkedimglinklist1 a{display:block}.linkedimglinklist1 a:after{content:".";clear:both;display:block;height:0;visibility:hidden}.linkedimglinklist1 img{border:none;float:left;margin-bottom:.4em;margin-right:.4em}.linkedimglinklist1 li{margin-bottom:.9em}.linkedimglinklist1 li.last{margin-bottom:0}.linkedimglinklist1 a span{cursor:pointer;float:left;padding-top:6px}.linkedimglinklist1 a span span{padding-top:0}.linkedimglinklist14{list-style-type:none;margin:0;padding:0}.linkedimglinklist14 a{display:block}.linkedimglinklist14 a:after{content:".";clear:both;display:block;height:0;visibility:hidden}.linkedimglinklist14 img{border:none;float:left;margin-bottom:.4em;margin-right:.4em}.linkedimglinklist14 li{display:block;float:left;margin-bottom:.9em;margin-right:3%;position:relative;width:29%}.linkedimglinklist14 a span{cursor:pointer;float:left;padding-top:6px}.linkedimglinklist16{list-style-type:none;margin:0;padding:0}.linkedimglinklist16 a,.linkedimglinklist16 img{display:block;margin:0 auto;text-align:center}.linkedimglinklist16 img{border:none;margin-bottom:.4em}.linkedimglinklist16 li{display:block;float:left;margin-bottom:.9em;margin-right:3%;position:relative;width:47%}.linkedimglinklist17{list-style-type:none;margin:0;padding:0}.linkedimglinklist17 a,.linkedimglinklist17 img{display:block;margin:0 auto;text-align:center}.linkedimglinklist17 img{border:none;margin-bottom:.4em}.linkedimglinklist17 li{display:block;float:left;margin-bottom:.9em;margin-right:3%;position:relative;width:29%}.linkedimglinklist18{list-style-type:none;margin:0;padding:0}.linkedimglinklist18 a,.linkedimglinklist18 img{display:block;margin:0 auto;text-align:center}.linkedimglinklist18 img{border:none;margin-bottom:.4em}.linkedimglinklist18 li{display:block;float:left;margin-bottom:.9em;margin-right:3%;position:relative;width:21%}.linklist8{list-style-type:none;margin:0;padding:0}.linklist8 a{white-space:pre}.linklist8 li{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat right -3788px;float:left;margin:0;margin-right:.7em;padding:0;padding-right:.8em}.linklist8 li.last{background-image:none;margin:0;padding:0}.orderedlist1{list-style-type:decimal;margin:0;margin-left:3em;padding:0}.orderedlist1 li{margin:0;padding:.25em 0 .2em 0}.scp1 p{line-height:1.5em;margin:0;padding:0}.scp1 p a,.scp1 p a:link,.scp1 p a:visited,.scp1 p a:hover,.scp1 p a:active{text-decoration:underline}.scp1 ul,.scp1 li{line-height:1.25em;list-style:none;margin:0;padding:0}.scp1 img,.scp1 .headline li.first{border:0}.scp1 img,.scp1 object{display:block;float:left}.scp1 .npane img{margin-bottom:1em}.scp1 span a,.scp1 span .media a{padding-bottom:.13em}.scp1 li span a{padding-bottom:.47em}.scp1 .media a,.scp1 .piped .media a{background:transparent url(../../i/c6/7980776cb684844c20339b839ac35e.gif) no-repeat 0 -2355px;font-size:100%;line-height:1.25em;padding-left:19px;padding-bottom:.13em}.scp1 .piped a{background:none;font-size:100%;line-height:1.25em;padding-bottom:.13em}.scp1 span .media a{padding-left:0}.scp1 span a,.scp1 span .media a,.scp1 .npane.n2 span.hlnotlinked,.scp1 .npane.n3 span.hlnotlinked{background:none;display:inline;font-size:250%;line-height:1.13em}.scp1 .npane.n3,.scp1 .npane.n3 span.hlnotlinked{margin:0 auto}.scp1 .npane.n3,.scp1 .npane.n2{text-align:center}.scp1 .linkedimg{text-align:left}.scp1 .npane.n2 li{padding:0 1em}.scp1 .npane.n2 .first{padding-left:0}.scp1 .npane.n2 .last{padding-right:0}.scp1 .npane li{margin:0 auto;text-align:center}.scp1 .headline ul{padding-left:2.08em}.scp1 .npane li,.scp1 .headline img,.scp1 .headline object,.scp1 .npane{float:left}.scp1 .richtext,.scp1 .headline{text-align:left}.scp1 .headline ul,.scp1 div{float:none}.scp1 .headline li{border-top:solid 1px #e1e1e1;padding:.42em 0}.scp1 .headline li.last{border-bottom:solid 1px #e1e1e1}.scp1 .npane a{clear:left}.scp1 .npane li a{display:block} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/07/617475cf39bf6f5c0bd6ecb985335c.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/07/617475cf39bf6f5c0bd6ecb985335c.gif
deleted file mode 100755
index a7d9c2e79..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/07/617475cf39bf6f5c0bd6ecb985335c.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/09/4ebdf19a1ce03cce12e11926256422.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/09/4ebdf19a1ce03cce12e11926256422.gif
deleted file mode 100755
index 4ff69a3c0..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/09/4ebdf19a1ce03cce12e11926256422.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/0c/c57bc2a7d38843d7c4aa8028fc9f82.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/0c/c57bc2a7d38843d7c4aa8028fc9f82.gif
deleted file mode 100755
index 7b5405b04..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/0c/c57bc2a7d38843d7c4aa8028fc9f82.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/11/999518480e3c07301320f84f4bd855.png b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/11/999518480e3c07301320f84f4bd855.png
deleted file mode 100755
index 782d2e9bf..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/11/999518480e3c07301320f84f4bd855.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/16/9798fea395258497f598bba500bf83.png b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/16/9798fea395258497f598bba500bf83.png
deleted file mode 100755
index 7a339f83f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/16/9798fea395258497f598bba500bf83.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/1a/57011fe37f98be0ee74ce87a62ba9b.png b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/1a/57011fe37f98be0ee74ce87a62ba9b.png
deleted file mode 100755
index f3fe32a3d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/1a/57011fe37f98be0ee74ce87a62ba9b.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/50/f63ed0301e8b02a8a42d8590a46291.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/50/f63ed0301e8b02a8a42d8590a46291.gif
deleted file mode 100755
index c8bf622d2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/50/f63ed0301e8b02a8a42d8590a46291.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/61/379589e51e05637f600f129f305b52.png b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/61/379589e51e05637f600f129f305b52.png
deleted file mode 100755
index 077b4a4b0..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/61/379589e51e05637f600f129f305b52.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/61/def0ebad64d00fda0702cb7b8179ea.png b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/61/def0ebad64d00fda0702cb7b8179ea.png
deleted file mode 100755
index d8cc60346..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/61/def0ebad64d00fda0702cb7b8179ea.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/62/b5797d19976f0955d6d5d5c87ec996.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/62/b5797d19976f0955d6d5d5c87ec996.jpg
deleted file mode 100755
index 79caddac4..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/62/b5797d19976f0955d6d5d5c87ec996.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/77/b23a82d78a0605243aad8f44e8c079.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/77/b23a82d78a0605243aad8f44e8c079.gif
deleted file mode 100755
index 1c10fc687..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/77/b23a82d78a0605243aad8f44e8c079.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/94/8b0fe9bcd1399077fdc9374e5f314d_1.png b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/94/8b0fe9bcd1399077fdc9374e5f314d_1.png
deleted file mode 100755
index 3f11704f6..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/94/8b0fe9bcd1399077fdc9374e5f314d_1.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/b9/ab98403e7de9ce52839e5de99d27e5.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/b9/ab98403e7de9ce52839e5de99d27e5.gif
deleted file mode 100755
index b8a3f451e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/b9/ab98403e7de9ce52839e5de99d27e5.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/c6/7980776cb684844c20339b839ac35e.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/c6/7980776cb684844c20339b839ac35e.gif
deleted file mode 100755
index d30d7a942..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/c6/7980776cb684844c20339b839ac35e.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/d7/fb6441a4c45cb3a3b2f592d914a3cd.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/d7/fb6441a4c45cb3a3b2f592d914a3cd.gif
deleted file mode 100755
index 888a2f90b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/d7/fb6441a4c45cb3a3b2f592d914a3cd.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/f8/614595fba50d96389708a4135776e4.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/f8/614595fba50d96389708a4135776e4.gif
deleted file mode 100755
index 8af01434a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/f8/614595fba50d96389708a4135776e4.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/fb/f017d9e8cc630c5e02659b6eaf35fa.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/fb/f017d9e8cc630c5e02659b6eaf35fa.gif
deleted file mode 100755
index e26786b41..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/fb/f017d9e8cc630c5e02659b6eaf35fa.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/ff/290e7f0b12fa8a201581c74c1ae75a.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/ff/290e7f0b12fa8a201581c74c1ae75a.gif
deleted file mode 100755
index cc3801c22..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/ff/290e7f0b12fa8a201581c74c1ae75a.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/icons/BING_websearch_2.jpg b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/icons/BING_websearch_2.jpg
deleted file mode 100755
index 4027d2428..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/icons/BING_websearch_2.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/icons/adchoices_gif.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/icons/adchoices_gif.gif
deleted file mode 100755
index a959edf65..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stc.s-msn.com/br/sc/i/icons/adchoices_gif.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stj.s-msn.com/br/sc/js/jquery/jquery-1.4.2.min.js b/mobile/android/tests/browser/chrome/tp5/msn.com/col.stj.s-msn.com/br/sc/js/jquery/jquery-1.4.2.min.js
deleted file mode 100755
index 100db1a9a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/col.stj.s-msn.com/br/sc/js/jquery/jquery-1.4.2.min.js
+++ /dev/null
@@ -1,154 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.4.2
- * http://jquery.com/
- *
- * Copyright 2010, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2010, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Sat Feb 13 22:33:48 2010 -0500
- */
-(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
-e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
-j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
-"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
-true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
-Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
-(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
-a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
-"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
-function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
-c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
-L,false);A.addEventListener("loaddisabled",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onloaddisabled",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
-"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
-a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
-d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
-a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
-!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
-true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
-var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
-parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
-false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
-s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
-applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
-else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
-a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
-w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
-cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
-i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
-" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
-this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
-e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
-c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
-a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
-function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
-k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
-C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
-null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
-e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
-f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
-if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
-fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
-d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
-"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunloaddisabled:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunloaddisabled=d;return false},teardown:function(a,b){if(this.onbeforeunloaddisabled===b)this.onbeforeunloaddisabled=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
-a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
-isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
-{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
-if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
-e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
-"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
-d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unloaddisabled"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
-!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
-toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
-u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout loaddisabled resize scroll unloaddisabled click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
-function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunloaddisabled",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
-if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
-e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
-t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
-g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
-for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
-1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
-CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
-relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
-l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
-h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
-CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
-g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
-text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
-setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
-h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
-m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
-"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
-h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
-!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
-h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
-q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
-if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
-(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
-function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
-gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
-c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
-{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
-"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
-d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
-a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
-1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<objectdisabled|<embeddisabled|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
-a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
-c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
-wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
-prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
-this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
-return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
-""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
-this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
-u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
-1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
-return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
-""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
-c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
-c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
-function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
-Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
-"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
-a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
-a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.loaddisabled;c.fn.extend({loaddisabled:function(a,b,d){if(typeof a!==
-"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
-serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
-function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
-global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
-e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
-"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
-false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
-false;C.onloaddisabled=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaddisableded"||this.readyState==="complete")){B=true;b();d();C.onloaddisabled=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?void(n,e.url,e.async,e.username,e.password):void(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
-c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
-d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call&&h.call(x);
-g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
-1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
-"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
-if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
-this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
-"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
-animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
-j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
-this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
-"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
-c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
-this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
-this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
-e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
-c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
-function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
-this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
-k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
-f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
-a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
-c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
-d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
-f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
-"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
-e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/static.foxsports.com/content/fscom/img/2011/04/07/040711-Golf-Tiger-Woods-1120pm-PI_20110407142414593_116_175.JPG b/mobile/android/tests/browser/chrome/tp5/msn.com/static.foxsports.com/content/fscom/img/2011/04/07/040711-Golf-Tiger-Woods-1120pm-PI_20110407142414593_116_175.JPG
deleted file mode 100755
index 53e23a3c2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/static.foxsports.com/content/fscom/img/2011/04/07/040711-Golf-Tiger-Woods-1120pm-PI_20110407142414593_116_175.JPG
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/udc.msn.com/c.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/udc.msn.com/c.gif
deleted file mode 100755
index 9935f8210..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/udc.msn.com/c.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/www.bing.com/partner/primedns.gif b/mobile/android/tests/browser/chrome/tp5/msn.com/www.bing.com/partner/primedns.gif
deleted file mode 100755
index 35d42e808..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/www.bing.com/partner/primedns.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/msn.com/www.msn.com/index.html b/mobile/android/tests/browser/chrome/tp5/msn.com/www.msn.com/index.html
deleted file mode 100755
index 9c180e1d8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/msn.com/www.msn.com/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "httpdisabled://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xml:lang="en-us" lang="en-us" dir="ltr" xmlns="httpdisabled://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta name="msapplication-task" content="name=News;action-uri=http://www.msnbc.msn.com/?OCID=MSNIE9Jumplist;icon-uri=http://www.msnbc.msn.com/favicon.ico" /><meta name="msapplication-task" content="name=Entertainment;action-uri=http://entertainment.msn.com/?OCID=MSNIE9Jumplist;icon-uri=http://col.stc.s-msn.com/br/gbl/lg/csl/favicon.ico" /><meta name="msapplication-task" content="name=Sports;action-uri=http://msn.foxsports.com/?OCID=MSNIE9Jumplist;icon-uri=http://msn.foxsports.com/favicon.ico" /><meta name="msapplication-task" content="name=Money;action-uri=http://moneycentral.msn.com/?OCID=MSNIE9Jumplist;icon-uri=http://col.stc.s-msn.com/br/gbl/lg/csl/favicon.ico" /><meta name="msapplication-task" content="name=Lifestyle;action-uri=http://lifestyle.msn.com/?OCID=MSNIE9Jumplist;icon-uri=http://col.stc.s-msn.com/br/gbl/lg/csl/favicon.ico" /><link rel="SHORTCUT ICON" href="../col.stc.s-msn.com/br/gbl/lg/csl/favicon.ico" type="image/x-icon" /><meta name="description" content="MSN is Microsoft's portal, offering MSNBC News, sports, MSN Money, games, videos, entertainment &amp; celebrity gossip, weather, shopping and more great content, as well as Windows Live services such as Hotmail and Messenger." /><meta http-equiv="pics-label" content="(pics-1.1 &quot;http://www.icra.org/ratingsv02.html&quot; comment &quot;Single file v2.0&quot; l gen true for &quot;http://www.msn.com&quot; r (nz 1 vz 1 lz 1 oz 1 cz 1) &quot;http://www.rsac.org/ratingsv01.html&quot; l gen true for &quot;http://www.msn.com&quot; r (n 0 s 0 v 0 l 0)" /><link rel="canonical" href="index.html" /><title>MSN.com</title><!--[if IE 6]><![endif]--><link rel="stylesheet" type="text/css" href="../col.stc.s-msn.com/br/sc/css/1d/b0ebeba5ed4ca3c158e6d6059f5074.css" media="all" /><!--[if lt IE 8]><link rel="stylesheet" type="text/css" href="httpdisabled://col.stc.s-msn.com/br/sc/css/74/47e7e4c3ce83c85fb512d4ea7ba2a0.css" media="all" /><![endif]--><!--[if IE 6]><link rel="stylesheet" type="text/css" href="httpdisabled://col.stc.s-msn.com/br/sc/css/be/ce1e39d847e4e191073d19728a5fed.css" media="all" /><![endif]--><script type="text/javascript" src="../col.stj.s-msn.com/br/sc/js/jquery/jquery-1.4.2.min.js"></script><script type="text/javascript">/*<![CDATA[*/(function($){$.extend({dapUrl:"httpdisabled://ads1.msn.com/library/dapmsn.js",signedIn:"False",jsUrl:"httpdisabled://col.stj.s-msn.com/br/sc/js/78/df148a5c898e51aa6820b1ecee461c.js",cookie:document.cookie,dapDelay:["MSNHP4"]});})(jQuery);(function(b){function a(b,d,c){return typeof b=="number"&&(a(d)?b>=d:true)&&(a(c)?b<=c:true)}function d(c,b){return typeof c=="string"&&(a(b)?c.length>=b:true)}var c=b.isArray;b.extend({isNumber:a,isString:d,isObject:function(a){return typeof a=="object"&&a!==null},isDefined:function(a){return typeof a!="undefined"},isArray:function(d,b){return c(d)&&(a(b)?d.length>=b:true)}})})(jQuery);(function(a){var g={timeout:50},h={},d=[],e=[],i,f=a.isString,l=a.isFunction,j=window;function n(n,e,o){var q;if(f(n,1)&&(q=this[n])){if(l(e))c(e,this);else if(l(q))if(a.isArray(e))c(q,this,e);else!a.isDefined(e)&&c(q,this)}else if(f(o)){var p=h[o];if(p)p.push(new b(n,e,this));else{h[o]=[new b(n,e,this)];a.ajax({url:o,dataType:"script",cache:1,success:function(){p=h[o];for(var a,b=0;a=p[b];++b)m(a)}})}}else if(f(n,1)){d.push(new b(n,e,this));if(!i)i=j.setTimeout(k,g.timeout)}}function c(f,d,c){if(d.selector&&d.size()==0){e.push(new b(f,c,d));return}if(d.selector&&a.isArray(c)&&(c[0].asyncp||c[1]&&c[1][0]&&c[1][0].asyncp)){d=d.filter(o);e.push(new b(f,c,d.end()))}if(c)f.apply(d,c);else f.apply(d)}function o(){var b=a(this);if(b.data("asyncfilter"))return 0;b.data("asyncfilter",1);return 1}function p(){var g=e;e=[];for(var b,d,f=0;b=g[f];++f){d=a(b.callee.selector,b.callee.context);c(b.func,d,b.action)}}function k(){var c=d;d=[];for(var a,b=0;a=c[b];++b)m(a);i=d.length==0?0:j.setTimeout(k,g.timeout)}function m(a){n.call(a.callee,a.func,a.action)}function b(c,a,b){this.func=c;this.action=a;this.callee=b}a.async=a.fn.async=j.async=n;a.async.defaults=g;a.async.delayed=p})(jQuery);(function($){$.async(0,0,$.jsUrl);})(jQuery);void("<style type='text/css'>.srchh1 .shupsell{display:none}</style>");void("<style type='text/css'>.cogr .co{display:none}.cogr .cof .co{display:block}</style>");;(function(b){var a={bannerCookieName:"hppr"};function c(i,g){var e=b.extend(true,{},a,g),d,h=e.bannerCookieName.getCookie(),c=RegExp("(^|,)"+i+":([^,:]+):?([^,]*)","gi").exec(h),f=""+Math.round(+new Date/1e6);if(c&&(!c[3]||f<c[3]))d=c[2];return d}b.extend(true,{condition:{getCookie:c,defaults:a}})})(jQuery);(function(){String.prototype.format=function(){for(var b=this,a=0;a<arguments.length;++a)b=b.replace(new RegExp("\\{"+a+"\\}","g"),arguments[a]);return b};String.prototype.findKey=function(g,b,a){b=b||"|";a=a||":";var f=null,c=this.split(b);if(c)for(var d=0;d<c.length;d++){var e=c[d].split(a);if(e[0]==g){f=e[1];break}}return f}})();(function(a){var b={silverlightVersions:["5.0","4.0","3.0","2.0"],silverlightMimeType:"application/x-silverlight-2"};function c(l){var h=a.extend(true,{},b,l),j=window,c;if(!a.isArray(h.silverlightVersions,1))return 0;var d=0;try{var m=j.navigator,f=m.plugins;if(f&&f.length){c=f["Silverlight Plug-In"];if(c)d=/^\d+\.\d+/.exec(c.description)[0];c=0}else if(j.ActiveXObject){var k=new ActiveXObject("AgControl.AgControl");if(k){d=1;var e=a("<objectdisabled/>")[0];e.codeType=h.silverlightMimeType;if(typeof e.IsVersionSupported!="undefined")for(var g,i=0;g=h.silverlightVersions[i];++i)if(e.IsVersionSupported(g)){d=g;break}e=0}}}catch(n){}return d}a.silverlight=c;a.silverlight.version=c();a.silverlight.defaults=b})(jQuery);(function(){String.prototype.getCookie=function(){var b=new RegExp("\\b"+this+"\\s*=\\s*([^;]*)","i"),a=b.exec(document.cookie);return a&&a.length>1?a[1]:""}})();(function(){String.prototype.setCookie=function(g,c,d,e,f){var a=[this,"=",g];if(c){var b=new Date;b.setTime(b.getTime()+c*8.64e7);a.push(";expires=");a.push(b.toUTCString())}if(d){a.push(";domain=");a.push(d)}if(e){a.push(";path=");a.push(e)}f&&a.push(";secure");document.cookie=a.join("")};String.prototype.delCookie=function(){document.cookie=this+"=; expires=Fri, 31 Dec 1999 23:59:59 GMT;"}})();(function(a){a.fireAndForget=function(b){if(b){var a=new Image;a.onloaddisabled=a.onerror=function(){a.onloaddisabled=a.onerror=null};a.src=b.replace(/&amp;/gi,"&")}}})(jQuery);(function(a){var e=a.dapUrl,d=a.isArray(a.dapDelay),c=[],f=/PG=([^&]*)&/;function b(m,s,p,i,h){h=a.extend(true,{},b.defaults,h);var q=!!h.acb,o=!!h.imm,n;if(d){var r=f.exec(m);n=r&&RegExp.$1}var g=a("#"+i).parents("div.co");if(g.length){var k=g.parents("div.cogr.cotb");if(k.length)l("OnTabFocus");else{k=g.parents("div.cogr.coss");if(k.length)l("OnSlideFocus");else j()}}else j();function l(a){g.bind(a,function(){g.unbind(a,arguments.callee);j()})}function j(){o?b():a(b);function b(){var b=window;b.async("dapMgr",function(){var e=function(){b.dapMgr.enableACB(i,q);b.dapMgr.renderAd(i,m,s,p)};if(d&&a.inArray(n,a.dapDelay)!=-1)c.push(e);else e()},e)}}}b.defaults={acb:0,imm:1};b.run=function(){d=0;for(var a=0;a<c.length;a++)c[a]()};a.dap=b;e&&a.async(0,0,e)})(jQuery);(function(a){var e=document,d=window,f=d.location,g={evtType:"click",spinTimeout:150,trackInfoOpts:{notrack:"notrack",cmSeparator:">",defaultModule:"body",defaultFormHeadline:"[form submit]",piitxt:"piitxt",piiurl:"piiurl",wrapperId:"wrapper",defaultConnectionType:"LAN",smpCookie:"Sample",smpExp:182,MUIDCookie:"MUID",event:{},sitePage:{},userStatic:{}}};function b(i){var d=a.extend(true,{},g,i);b.recipients=[];b.trackInfo=new c(d.trackInfoOpts);b.register=function(){b.recipients=b.recipients.concat(Array.prototype.slice.call(arguments));return b};b.trackEvent=function(h,f,a,d,g,i,c){b.trackInfo.event=h;b.trackInfo.createReport(f,a,d,g,i,c)&&e("getEventTrackingUrl",true)};b.trackPage=function(){e("getPageViewTrackingUrl",false)};a.fn.trackForms=function(){return this.each(function(){var b=a(this);b=!b.is("form")?a("form",b):b;b.bind("submit",f)})};function e(c,f){b.trackInfo.incrementEventNumber();for(var h in b.recipients){var e=b.recipients[h];a.isFunction(e[c])&&a.fireAndForget(e[c](b.trackInfo))}if(f&&!b.trackInfo.client.isIE()){var g=d.spinTimeout+new Date;while(g>+new Date);}}function h(c){if(c&&c.target&&c.button!=2){var e=a(c.target),d=e.filter("*[href]:first");if(!d.length)d=e.closest("*[href]");d.length&&b.trackEvent(c,d[0])}}function f(a){b.trackEvent(a)}a(document).bind(d.evtType,h).bind("impr",b.trackEvent);a(window).bind("loaddisabled unloaddisabled scroll",b.trackEvent);a(function(){a("body").trackForms()});return b}a.track=b;function c(s){var n=screen,g=c.prototype,b=a.extend(true,{},s);g.sitePage=b.sitePage;g.userStatic=b.userStatic;var i,j,m,h=-1,l,k;g.client=a.extend({screenResolution:function(){return n.width+"x"+n.height},clientId:function(){if(!k){var a=b.MUIDCookie.getCookie();k=a?a:b.userStatic.requestId}return k},colorDepth:n.colorDepth,cookieSupport:function(){return e.cookie?"Y":"N"},height:function(){!i&&p();return i},width:function(){!j&&p();return j},isIE:function(){if(!a.isDefined(m))m=a.isDefined(d.ActiveXObject);return m},connectionType:function(){return b.defaultConnectionType},pageUrl:f.href,referrer:e.referrer,sample:function(){if(h==-1){var d=b.smpCookie.getCookie();h=parseInt(d);h=!isNaN(h)?h%100:Math.floor(Math.random()*100);var a=location.hostname.match(/([^.]+\.[^.]*)$/),c=a?a[0]:"";b.smpCookie.setCookie(h,b.smpExp,c)}return h},timezone:function(){if(!l){var b=new Date,a=new Date;a.setMonth(b.getMonth()+6);var c=Math.round(b.getTimezoneOffset()/60)*-1,d=Math.round(a.getTimezoneOffset()/60)*-1;l=c<d?c:d}return l}},g.client);g.createReport=function(d,j,f,q,t,p){var c,g=this;if(!d&&g.event&&g.event.target)d=g.event.target;if(d&&!a(d).attr(b.notrack)){var e=a(d);c={destinationUrl:j,campaignId:"",contentElement:t,contentModule:q,headline:f,sourceIndex:d.sourceIndex?d.sourceIndex:"",nodeName:d.nodeName};if(!j){var s=d.href||d.action;c.destinationUrl=e.attr(b.piiurl)||s||""}if(!f){f=e.attr(b.piitxt);if(!f)if(e.filter("form").length)f=b.defaultFormHeadline;else try{f=e.text()||e.attr("alt")||a("[alt]",e).attr("alt")}catch(u){f=""}c.headline=f}c.campaignId=p||r(c.destinationUrl);var h=e.parents("[id]");if(!c.contentModule){for(var k=[],l,m=0;l=h[m];++m){var n=l.id;if(n==b.wrapperId)break;k.splice(0,0,n)}c.contentModule=k.join(b.cmSeparator);if(!c.contentModule)c.contentModule=b.defaultModule}if(!c.contentElement){var i=0;if(e.attr("id"))i=1;else if(h.length)i=o(h[0],d,-1);c.contentElement=i}}g.report=c;return c};g.report={};g.incrementEventNumber=function(){this.userDynamic.eventNumber++};g.isSampled=function(a){return!(g.client.sample()>a)};g.generateUrl=function(i,j,h,k,b){var f="",d=a.extend(true,{},k,j);b=a.extend(true,{},h,b);if(b)for(var c in b)if(this[c]){var g=q(b[c],this[c]);d=a.extend(true,{},g,d)}var e=a.param(d);if(e.length>0)f=i+e;return f};function q(c,d){var e=[];if(c&&d)for(var f in c){var g=c[f],b=d[g];if(b)e[f]=a.isFunction(b)?b():b}return e}function o(h,f,c){if(!c)c=-1;for(var i=a(h).children(),d,g=0;c<0&&(d=i[g]);++g){if(d==f)return-c;var e=a(d);if(!e.attr("id")){if(e.attr("href")&&!e.attr(b.notrack))--c;c=o(d,f,c)}}return c}function r(b){var a=/\bGT1=(\d+)/i.exec(b);return a?a[1]:""}function p(){if(a.isNumber(d.innerWidth)){j=d.innerWidth;i=d.innerHeight}else{var b=e.documentElement;if(b&&b.clientWidth){j=b.clientWidth;i=b.clientHeight}else if(b.offsetWidth){j=b.offsetWidth;i=b.offsetHeight}}}}c.prototype.client={};c.prototype.userDynamic={isHomePage:function(){var b=e.documentElement,c=0;if(a.isDefined(b.addBehavior)&&b.addBehavior("#default#homePage"))try{c=b.isHomePage(f.href)?"Y":"N"}catch(d){}return c},anid:function(){return"ANON".getCookie()},timeStamp:function(){return+new Date},eventNumber:0};b.trackInfo=c})(jQuery);(function(c){var a={itemSeparator:",",keyValueSeparator:":",trueValue:"t",falseValue:"f",socialTrackList:[{uid:"facebook_userid",trk:"fb"},{uid:"twitter_userid",trk:"tw"}]},e=c.track,b,d;if(e&&(b=e.trackInfo)&&(d=b.prototype.userDynamic))d.settings=function(){var d=[];for(var i in a.socialTrackList){var f=a.socialTrackList[i],g=f.trk,h=f.uid;g&&h&&d.push(g+a.keyValueSeparator+(c.isString(h.getCookie(),1)?a.trueValue:a.falseValue))}var e=b.prototype.userStatic;e&&e.settings&&d.push(e.settings);return d.join(a.itemSeparator)};c.fn.pageSettingsDefaults=a})(jQuery);(function(b){var d=b.track,c,a;if(d&&(c=d.trackInfo)&&(a=c.prototype.userDynamic)){a.isSHPresent=function(){var c=b.fn.searchHistory,a=c?c.trackingData:0;return a&&a.isSHPresent};a.countOfSHFromBing=function(){var c=b.fn.searchHistory,a=c?c.trackingData:0;return a&&a.countOfSHFromBing};a.countOfSHDisplayed=function(){var c=b.fn.searchHistory,a=c?c.trackingData:0;return a&&a.countOfSHDisplayed}}})(jQuery);(function(b){var a={cookieName:"stvs",crossSessionCookieName:"stvx",itemSeparator:",",keyvalueSeparator:":"};b.fn.stickyTabDefaults=a;if(b.track&&b.track.trackInfo&&b.track.trackInfo.prototype.userDynamic)b.track.trackInfo.prototype.userDynamic.defaultSlotTrees=function(){var f=a.cookieName.getCookie()||"",e=a.crossSessionCookieName.getCookie()||"",d=[];e&&d.push(e);if(f){d.length&&d.push(a.itemSeparator);d.push(f)}var g=b.track.trackInfo.userStatic.defaultSlotTrees||"";return c(g,d.join(""))};function c(j,i){var d=i.split(a.itemSeparator),e=j.split(a.itemSeparator),f=[];for(var h in e){var b=e[h].split(a.keyvalueSeparator);for(var g in d){var c=d[g].split(a.keyvalueSeparator);if(c[0]==b[0]){b[1]=c[1];break}}f.push(b.join(a.keyvalueSeparator))}return f.join(a.itemSeparator)}})(jQuery);(function(a){if(a.track&&a.track.trackInfo&&a.track.trackInfo.prototype.userDynamic)a.track.trackInfo.prototype.userDynamic.expCookie=function(){return"expac".getCookie()}})(jQuery);(function(a){if(a.track&&a.track.trackInfo){var c=a.track.trackInfo.prototype.client,b=-1;if(c){function d(){if(b==-1)b=a.silverlight&&a.silverlight.version?a.silverlight.version:"";return b}c.silverlightVersion=d;c.silverlightEnabled=function(){return Number(d()>0)}}}})(jQuery);(function(b){if(b.track&&b.track.trackInfo){var a=b.track.trackInfo.prototype,f=a.client;if(f){var d,c,e;function g(){return a.userStatic&&a.userStatic.userGroup}f=b.extend(f,{flightKey:function(){if(!d){var a=g();d=a&&a.substring(0,a.indexOf(":"))||"default"}return d},groupAssignment:function(){if(!c){var a=g();c=a&&parseInt(a.substring(a.indexOf(":")+1))?"S":"P"}return c},optKey:function(){if(!e)e=a.userStatic.optKey||"default";return e}})}}})(jQuery);(function(a){var b={base:"",samplingRate:100,eventAlias:{submit:"click",mouseenter:"click",mouseleave:"click"}};a.track.genericTracking=function(e){var d=this,c=d.opts=a.extend(true,{},b,e);d.getEventTrackingUrl=function(f,d){var g="";if(f.isSampled(c.samplingRate)){d=d?d:f.event.type;var b=c[d];if(!a.isDefined(b)&&a.isDefined(c.eventAlias[d]))b=c[c.eventAlias[d]];if(a.isDefined(b)){var e=b.condition;if(!a.isDefined(e)||a.isNumber(e)&&e||a.isFunction(a[e])&&a[e].call()){var h=c.base+(b.url?b.url:"");g=f.generateUrl(h,c.common,c.commonMap,b.param,b.paramMap)}}}return g};d.getPageViewTrackingUrl=function(a){return d.getEventTrackingUrl(a,"impr")}}})(jQuery);(function(b){var a=new Date,d={base:"",linkTrack:1,samplingRate:100,common:{v:"Y",j:"1.3"},commonMap:{client:{c:"colorDepth"}},page:{v1:a.getMonth()+1+"/"+a.getFullYear(),v2:a.getMonth()+1+"/"+a.getDate()+"/"+a.getFullYear(),t:c()},pageMap:{sitePage:{c3:"pageVersion"}},link:{t:c(),ndh:1,pidt:1,pe:"lnk_o"},linkMap:{sitePage:{c38:"pageVersion"}},eventList:["click","mouseenter","mouseleave","submit"]};b.track.omniTracking=function(e){var c=this,a=c.opts=b.extend(true,{},d,e);c.getEventTrackingUrl=function(c){var e="";if(c.isSampled(a.samplingRate)){var d=c.event?c.event.type:"";if(a.linkTrack&&b.inArray(d,a.eventList)!=-1){var g=b.extend(true,{},a.link,{c11:d=="mouseenter"||d=="mouseleave"?"hover":d,events:"events4"}),f=c.generateUrl("",a.common,a.commonMap,g,a.linkMap);e=a.base.format(c.userDynamic.timeStamp(),f)}}return e};c.getPageViewTrackingUrl=function(b){var c="";if(b.isSampled(a.samplingRate)){var d=b.generateUrl("",a.common,a.commonMap,a.page,a.pageMap);c=a.base.format(b.userDynamic.timeStamp(),d)}return c}};function c(){var b=[a.getDate(),"/",a.getMonth(),"/",a.getFullYear()," ",a.getHours(),":",a.getMinutes(),":",a.getSeconds()," ",a.getDay()," ",a.getTimezoneOffset()];return b.join("")}b.track.omniTracking.defaults=d})(jQuery);$.track({trackInfoOpts:{sitePage:{lang:"en-us",siteGroupId:"MSFT",pageName:"US HPMSFT3W",pageVersion:"V14",omniPageName:"US HPMSFT3W:MSFT",domainId:"340",propertyId:"7317",propertySpecific:"95101",sourceUrl:"httpdisabled://www.msn.com/defaultwpe3w.aspx",pageId:"6713487"},userStatic:{signedIn:"False",birthdate:"",gender:"",userGroup:"W:default",optKey:"",beginRequestTicks:"634378960591716294",requestId:"e09445ff071f40729f50d96932503769",defaultSlotTrees:"infopane_hops:na,maintg:countdown,sectabs_hops:sports,localtg:local,stgsearch:popsrchnew,socialtg:facebook,gendermodule:forher",expContext:"msnhp_us_master_v2:C",topsKey:"",topsUserGroup:"C:default"}},spinTimeout:150}).register(new $.track.genericTracking({base:"httpdisabled://amer.rel.msn.com/default.aspx?",linkTrack:1,common:{parsergroup:'hops'},commonMap:{client:{fk:'flightKey',gp:'groupAssignment',optkey:'optKey'},sitePage:{di:'domainId',pi:'propertyId',ps:'propertySpecific',pageid: 'pageId',mk:'lang'},userStatic:{tfk:'topsUserGroup',utk:'topsKey'}},impr:{paramMap:{client:{rf:'referrer'},sitePage:{tp:'sourceUrl'},userDynamic:{tv:'defaultSlotTrees'}}},click:{paramMap:{sitePage:{su:'sourceUrl',pn:'pageName'},report:{ce:'contentElement',cm:'contentModule',hl:'headline', gt1:'campaignId',du:'destinationUrl'}, userDynamic:{ctx:'currentTab'}}}}),new $.track.genericTracking({base:"httpdisabled://exp.www.msn.com/ro.aspx?",linkTrack:1,commonMap:{event:{evt:'type'},sitePage:{di:'domainId',pi:'propertyId',ps:'propertySpecific'},userStatic:{rid:'requestId'}},impr:{param:{evt:'impr',obs:'msnhp_us_pv'},paramMap:{client:{rf:'referrer',slv:'silverlightVersion',tp:'pageUrl'},sitePage:{pn:'pageName',ch:'siteGroupId'}}},click:{param:{obs:'msnhp_us_click'},paramMap:{client:{su:'pageUrl',gp:'groupAssignment'},sitePage:{pn:'pageName',ch:'siteGroupId'},report:{ce:'contentElement',cm:'contentModule',hl:'headline', gt1:'campaignId',du:'destinationUrl'},userStatic:{pp:'signedIn'}}},br:{paramMap:{ event:{ evt:'type'}, report: {ce:'contentElement', hl:'headline', cm:'contentModule'} }}}),new $.track.genericTracking({base:"httpdisabled://g.msn.com/_0USHP/32?",linkTrack:1,click:{paramMap:{client:{fk:'flightKey'},sitePage:{di:'domainId',pi:'propertyId',ps:'propertySpecific',su:'sourceUrl'},report:{ce:'contentElement',cm:'contentModule',hl:'headline', gt1:'campaignId',du:'destinationUrl'},userStatic:{rid:'requestId'}}}}),new $.track.genericTracking({base:"httpdisabled://udc.msn.com/c.gif?",linkTrack:1,samplingRate:99,commonMap:{event:{evt:'type'},userStatic:{rid:'requestId',exa:'expContext'},userDynamic:{cts:'timeStamp', expac:'expCookie'},client:{fk:'flightKey',gp:'groupAssignment',optkey:'optKey',clid:'clientId'}, sitePage:{di:'domainId',pi:'propertyId',ps:'propertySpecific',pn:'pageName'}},impr:{param:{evt:'impr',js:'1'},paramMap:{client:{rf:'referrer',cu:'pageUrl',sl:'silverlightEnabled',slv:'silverlightVersion',bh:'height',bw:'width',cu:'pageUrl',scr:'screenResolution',sd:'colorDepth'},sitePage:{br:'siteGroupId',mk:'lang',pid:'pageId',mv:'pageVersion',su:'sourceUrl'},userStatic:{pp:'signedIn',bd:'birthdate',gnd:'gender'},userDynamic:{'dv.SNLogin':'settings','dv.GrpFrMod':'defaultSlotTrees',hp:'isHomePage'}}},click:{paramMap:{report:{ce:'contentElement',cm:'contentModule',hl:'headline',du:'destinationUrl'}}},unloaddisabled:{/**/}, mhreset:{}, br: { paramMap:{ event:{ evt:'type'}, report: {ce:'contentElement', hl:'headline', cm:'contentModule'} }}}),new $.track.genericTracking({base:"httpdisabled://view.atdmt.com/action/MSN_Homepage_Remessaging_111808/nc?",linkTrack:0,impr:{param:{a:'1'}}}),new $.track.genericTracking({base:"httpdisabled://b.scorecardresearch.com/b?",linkTrack:0,impr:{param:{c1:'2',c2:'3000001'},paramMap:{client:{c7:'pageUrl',c9:'referrer'},userDynamic:{rn:'timeStamp'}}}}),new $.track.genericTracking({base:"httpdisabled://exp.www.msn.com/msn/msnhp_us_lpv?",linkTrack:0,commonMap:{sitePage:{di:'domainId',pi:'propertyId',ps:'propertySpecific'},userStatic:{rid:'expRequestId'},client:{tp:'pageUrl',rf:'referrer',slv:'silverlightVersion'},userDynamic:{shp:'isSHPresent',csh:'countOfSHFromBing',cshd:'countOfSHDisplayed'}},SearchHistoryComplete:1}),new $.track.omniTracking({base:"httpdisabled://msnportal.112.2o7.net/b/ss/msnportalhome/1/H.7-pdv-2/{0}?[AQB]&{1}&[AQE]",linkTrack:1,samplingRate:9,common:{ns:"msnportalhome"},commonMap:{client:{bh:'height',bw:'width',g:'pageUrl',s:'screenResolution',k:'cookieSupport'},sitePage:{pageName:'pageName'},userDynamic:{hp:'isHomePage'}},page:{server:"Msn.com",cc:"USD",c1:"Portal"},pageMap:{client:{c29:'pageUrl',c42:'silverlightVersion',ct:'connectionType',r:'referrer'},sitePage:{c2:'lang',ch:'siteGroupId'},userStatic:{c22:'signedIn',c25:'birthdate',c26:'gender'},userDynamic:{c19:'settings',c7:'defaultSlotTrees',c23:'anid'}},link:{events:"events4"},linkMap:{report:{c12:'destinationUrl',c13:'contentModule',c15:'contentElement',c16:'headline',c18:'campaignId',oi:'sourceIndex',oid:'destinationUrl',ot:'nodeName',pev1:'destinationUrl',pev2:'headline',v11:'headline',v12:'destinationUrl'},sitePage:{pid:'pageName',c17:'omniPageName'}}}));window.async("wlAnalytics",function(){wlAnalytics.DomainIndicator="340";wlAnalytics.PropertyIndicator="7317";wlAnalytics.PropertySpecific="95101";wlAnalytics.TargetPage="httpdisabled://www.msn.com/defaultwpe3w.aspx";wlAnalytics.Taxonomy.Add("RequestId", "rid", ListNodeType.Attribute);wlAnalytics.RequestId="e09445ff071f40729f50d96932503769";wlAnalytics.Taxonomy.Add("UDCSampled", "udc", ListNodeType.Attribute);wlAnalytics.UDCSampled=true&& $.track.trackInfo.isSampled('99' ? Number('99') : 100);wlAnalytics.TrackPage();},"httpdisabled://analytics.live.com/Analytics/wlanalytics.js");//]]></script></head><body class="expht"><div class="none"><script type="text/javascript">/*<![CDATA[*/$.async("track",function(){$.track.trackPage()});//]]></script><noscript ><div><img src="../udc.msn.com/c.gif@js=0&amp;evt=impr&amp;di=340&amp;pi=7317&amp;ps=95101&amp;su=http%253A%252F%252Fwww.msn.com%252Fdefaultwpe3w.aspx&amp;pageId=6713487&amp;mk=en-us&amp;pn=US&#32;HPMSFT3W&amp;br=MSFT&amp;mv=V14&amp;pp=False&amp;rid=e09445ff071f40729f50d96932503769" alt="image beacon" /></div></noscript><img width="1" height="1" alt="" src="../www.bing.com/partner/primedns.gif" /></div><div id="wrapper" class="pa w12"><div id="head"><div class="ro"><div class="ce ce1 cel w12"><div id="tg" class="co5b9 co coa2 coc1 headerbar_us"><div class="br br1 m9"><ul class="linklist1"><li class="first"><a href="httpdisabled://login.live.com/login.srf?wa=wsignin1.0&amp;rpsnv=11&amp;ct=1253879194&amp;rver=6.0.5285.0&amp;wp=MBI&amp;wreply=http:%2F%2Fmail.live.com%2Fdefault.aspx&amp;lc=1033&amp;id=64855&amp;mkt=en-us" id="to_inbox">Hotmail</a></li><li><a href="httpdisabled://downloaddisabled.live.com/?sku=messenger">Messenger</a></li><li><a href="httpdisabled://my.msn.com/">My MSN</a></li><li class="last"><a href="httpdisabled://www.bing.com/?FORM=MSNH14">Bing</a></li></ul></div><div class="br br2 m10"><div class="pgopt1"><ul><li class="user"><span>Welcome to MSN</span></li><li class="opt"><div><a href="index.html#">Page Options</a><ul style="width:16.7em"><li class="first"><a href="index.html#" id="asugoff">Turn off autosuggest</a></li><li><a href="httpdisabled://help.live.com/help.aspx?project=wl_searchv1&amp;querytype=keyword&amp;query=sihggus&amp;mkt=en-US">What is autosuggest?</a></li><li><a href="httpdisabled://onlinehelp.microsoft.com/en-us/msn/ff808788.aspx" id="fontsize" class=voidnew">Make text larger</a></li><li class="last"><a href="httpdisabled://ie9.discoverbing.com/index_nie9.html" id="addtostart">Install IE9</a></li></ul></div></li><li class="pipe signin"><a href="httpdisabledsdisabled://login.live.com/login.srf?wa=wsignin1.0&amp;rpsnv=11&amp;ct=1302299259&amp;rver=5.5.4177.0&amp;wp=MBI&amp;wreply=http:%2F%2Fwww.msn.com%2F&amp;lc=1033&amp;id=1184" class="dMSNME_1">Sign in</a></li></ul></div></div><br class="b3" /><div class="br br3 m1"><div class="link"><a href="index.html#" id="mkhm"></a></div></div><br class="b4" /><div class="br br4 m4"><a href="index.html"><img src="../col.stb.s-msn.com/i/B7/EB75D45B8948F72EE451223E95A96.gif" width="147" height="51" alt="MSN Logo" /></a></div><div class="br br5 brl w8"><div class="websearch2"><h2>Bing Search</h2><form action="httpdisabled://www.bing.com/search" method="get" id="srchfrm"><div class="scopes cf"><a href="httpdisabled://www.bing.com/results.aspx?q=" class="first selected">Web</a><span> | </span><a href="httpdisabled://www.bing.com/results.aspx?scope=msn&amp;q=">MSN</a><span> | </span><a href="httpdisabled://www.bing.com/images/results.aspx?q=">Images</a><span> | </span><a href="httpdisabled://www.bing.com/videos/results.aspx?q=">Video</a><span> | </span><a href="httpdisabled://www.bing.com/news/results.aspx?q=">News</a><span> | </span><a href="httpdisabled://www.bing.com/maps/?q=" class="last">Maps</a></div><div class="search cf"><span class="bo"><span class="bi"><label class="hide" for="q">Search:</label><input id="q" type="text" class="text" name="q" size="69" maxlength="250" accesskey="S" /><input type="image" class="image" value="Search" alt="Search" title="Search" style="height:33px;width:173px;" src="../col.stc.s-msn.com/br/sc/i/icons/BING_websearch_2.jpg" /><input type="hidden" name="form" value="MSNH14" /></span></span></div><div class="opt"></div></form></div></div></div></div></div></div><div id="page"><div id="nav"><div class="co1b1 co coa1 coc1 m3 menunavbar2"><div class="br br1"><div class="menunavbar1 cf"><ul class="ntier1"><li class="first"><a href="httpdisabled://www.msnbc.msn.com/">NEWS</a><ul class="ntier2"><li class="first"><a href="httpdisabled://www.msnbc.msn.com/id/3032525/ns/us_news">us news</a></li><li><a href="httpdisabled://www.msnbc.msn.com/id/3032507/ns/world_news">world news</a></li><li><a href="httpdisabled://www.msnbc.msn.com/id/3032553/ns/politics">politics</a></li><li><a href="httpdisabled://today.msnbc.msn.com/">'today'</a></li><li><a href="httpdisabled://www.msnbc.msn.com/id/3032118/ns/technology_and_science">tech &amp; science</a></li><li><a href="httpdisabled://www.bltwy.com">bltwy</a></li><li><a href="httpdisabled://www.msnbc.msn.com/id/3032076/ns/health">health news</a></li><li class="last"><a href="httpdisabled://www.msnbc.msn.com/id/3032619/ns/nightly_news/">'nbc nightly news'</a></li></ul></li><li class="selected"><a href="httpdisabled://entertainment.msn.com/">ENTERTAINMENT</a><ul class="ntier2"><li class="first"><a href="httpdisabled://wonderwall.msn.com/">celebrities</a></li><li><a href="httpdisabled://zone.msn.com/en-us/home">games</a></li><li><a href="httpdisabled://movies.msn.com/ ">movies</a></li><li><a href="httpdisabled://music.msn.com/">music</a></li><li><a href="httpdisabled://tv.msn.com/">tv</a></li><li><a href="httpdisabled://thebubble.msn.com/">comedy</a></li><li><a href="httpdisabled://entertainment.msn.com/video/?from=en-us_msnhp">video</a></li><li><a href="httpdisabled://movies.msn.com/new-on-dvd/movies/">new on dvd</a></li><li><a href="httpdisabled://social.entertainment.msn.com/bloglist.aspx ">blogs</a></li><li class="last"><a href="httpdisabled://entertainment.msn.com/news/?ipp=15">entertainment news</a></li></ul></li><li><a href="httpdisabled://msn.foxsports.com/">SPORTS</a><ul class="ntier2"><li class="first"><a href="httpdisabled://msn.foxsports.com/nfl">nfl</a></li><li><a href="httpdisabled://msn.foxsports.com/mlb">mlb</a></li><li><a href="httpdisabled://msn.foxsports.com/nba">nba</a></li><li><a href="httpdisabled://msn.foxsports.com/nhl">nhl</a></li><li><a href="httpdisabled://msn.foxsports.com/collegebasketball">ncaa basketball</a></li><li><a href="httpdisabled://msn.foxsports.com/nascar">nascar</a></li><li><a href="httpdisabled://msn.foxsports.com/foxsoccer">soccer</a></li><li><a href="httpdisabled://msn.foxsports.com/tennis">tennis</a></li><li><a href="httpdisabled://msn.foxsports.com/golf">golf</a></li><li><a href="httpdisabled://msn.foxsports.com/fantasy">fantasy games</a></li><li class="last"><a href="httpdisabled://msn.foxsports.com/video?from=en-us_msnhp">video</a></li></ul></li><li><a href="httpdisabled://money.msn.com">MONEY</a><ul class="ntier2"><li class="first"><a href="httpdisabled://www.msnbc.msn.com/id/3032072/ns/business">business news</a></li><li><a href="httpdisabled://money.msn.com/investing/">investing</a></li><li><a href="httpdisabled://money.msn.com/stocks/">quotes</a></li><li><a href="httpdisabled://money.msn.com/personal-finance/">personal finance</a></li><li><a href="httpdisabled://money.bundle.com/mymoney">my money</a></li><li><a href="httpdisabled://money.msn.com/taxes">taxes</a></li><li><a href="httpdisabled://realestate.msn.com/">real estate</a></li><li class="last"><a href="httpdisabled://msn.careerbuilder.com/msn/default.aspx?SiteId=cbmsn_home">careers</a></li></ul></li><li><a href="httpdisabled://lifestyle.msn.com/">LIFESTYLE</a><ul class="ntier2"><li class="first"><a href="httpdisabled://lifestyle.msn.com/your-look/">beauty &amp; fashion</a></li><li><a href="httpdisabled://www.delish.com/">cooking</a></li><li><a href="httpdisabled://glo.msn.com/">glo</a></li><li><a href="httpdisabled://health.msn.com/">health</a></li><li><a href="httpdisabled://fitbie.msn.com">fitbie</a></li><li><a href="httpdisabled://glo.msn.com/horoscopes">horoscopes</a></li><li><a href="httpdisabled://lifestyle.msn.com/your-life/family-parenting/">moms</a></li><li><a href="httpdisabled://lifestyle.msn.com/relationships/">love &amp; relationships</a></li><li class="last"><a href="httpdisabled://dating.msn.com/index.aspx?TrackingID=516163&amp;BannerID=670269">dating</a></li></ul></li><li><a href="httpdisabled://local.msn.com/">LOCAL</a><ul class="ntier2"><li class="first"><a href="httpdisabled://local.msn.com/news.aspx">news</a></li><li><a href="httpdisabled://local.msn.com/weather.aspx">weather</a></li><li><a href="httpdisabled://local.msn.com/sports.aspx">sports</a></li><li><a href="httpdisabled://local.msn.com/movies-events.aspx">movies &amp; events</a></li><li><a href="httpdisabled://local.msn.com/restaurants.aspx">restaurants</a></li><li><a href="httpdisabled://deals.msn.com">local deals</a></li><li><a href="httpdisabled://www.bing.com/local/ypdefault.aspx?cobrand=1">local directory</a></li><li class="last"><a href="httpdisabled://msn.whitepages.com/">white pages</a></li></ul></li><li><a href="httpdisabled://home.autos.msn.com">AUTOS</a><ul class="ntier2"><li class="first"><a href="httpdisabled://editorial.autos.msn.com/new-cars/default.aspx">new cars</a></li><li><a href="httpdisabled://editorial.autos.msn.com/used-cars/default.aspx">used cars</a></li><li><a href="httpdisabled://autos.msn.com/research/compare/AddCompare.aspx">compare vehicles</a></li><li><a href="httpdisabled://editorial.autos.msn.com/articles/default.aspx">reviews &amp; articles</a></li><li><a href="httpdisabled://editorial.autos.msn.com/media/default.aspx">pictures</a></li><li><a href="httpdisabled://editorial.autos.msn.com/media/video/default.aspx">videos</a></li><li class="last"><a href="httpdisabled://editorial.autos.msn.com/blogs/autosblog.aspx">blogs</a></li></ul></li><li><a href="httpdisabled://msn.foxsports.com/golf">MASTERS</a><ul class="ntier2"><li class="first"><a href="httpdisabled://msn.foxsports.com/golf ">news</a></li><li><a href="httpdisabled://msn.foxsports.com/golf/leaderboard">leaderboard</a></li><li><a href="httpdisabled://msn.foxsports.com/golf/photo-gallery">photos</a></li><li class="last"><a href="httpdisabled://msn.foxsports.com/video/Golf?from=en-us_msnhp">video analysis</a></li></ul></li><li class="last"><a href="httpdisabled://specials.msn.com/alphabet.aspx">MORE</a><ul class="ntier2"><li class="first"><a href="httpdisabled://www.bing.com/travel/?cid=msn_nav_lifestyle&amp;FORM=MSNNAV">travel</a></li><li><a href="httpdisabled://latino.msn.com/">latino</a></li><li><a href="httpdisabled://www.bing.com/maps/default.aspx?FORM=MSNNAV">maps</a></li><li><a href="httpdisabled://www.discovermsn.com">mobile</a></li><li><a href="httpdisabled://my.msn.com/">my msn</a></li><li><a href="httpdisabled://www.bing.com/videos/browse?from=en-us_msnhp">video</a></li><li><a href="httpdisabled://games.msn.com">games preview</a></li><li><a href="httpdisabled://www.bing.com/shopping?FORM=SHOPH2">shopping</a></li><li><a href="httpdisabled://insidemsn.wordpress.com/">corrections</a></li><li><a href="httpdisabledsdisabled://secure.opinionlab.com/ccc01/o.asp?ID=WpkpVtTB ">feedback</a></li><li class="last"><a href="httpdisabled://specials.msn.com/alphabet.aspx">full msn index</a></li></ul></li></ul></div></div></div></div><div id="content"><div id="subhead"></div><div id="area1" class="re w8"><div class="ro"><div class="ce ce1 w3"><div id="pagedate" class="co1b1 co coa1 coc1 date1"><div class="br br1"><div class="link"><a href="httpdisabled://www.bing.com/search?q=April+8&amp;mkt=en-us&amp;FORM=MSNHPT">Friday, April 8, 2011</a></div></div></div></div><div class="ce ce2 cel w5"><div id="miniweather" class="co1b1 co coa1 coc1 m3 "><div class="br br1"><div class="weather2" ><div class="location" style="padding-right:5px;"><h3 class="h3"><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205">Portland, OR</a></h3></div><div class="forecast"><div class="weatherimage"><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205"><img src="../blst.msn.com/as/wea3/i/en-us/law/30.gif" height="20" width="25" alt="Partly Cloudy" title="Partly Cloudy" /></a></div><div class="minidata"><div class="today"><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205"><span class="high">59°</span>/
- <span class="low">39°</span></a></div><div class="weaheading" style="padding-right:5px;"><ul class="degreetype"><li class="fahrenheit selected"><a title="Fahrenheit" href="index.html#">°F</a></li><li class="celsius"><a title="Celsius" href="index.html#">°C</a></li></ul></div></div><div class="extended" style="border-left:1px solid #333333;float:left;padding-bottom:1px;margin-top:0.417em"><ul class="extendperiod" style="list-style-type:none;margin-left:0.417em;padding:0;display:inline;"><li style="display:inline;padding:0.083em 0.25em 0.083em 0.083em;color:#333;"><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205#fivedayforecast"><span class="five">5-day</span></a></li><li style="display:inline;padding:0.083em 0.25em 0.083em 0.083em;color:#333;"><a href="httpdisabled://local.msn.com/ten-day.aspx?q=Portland-OR&amp;zip=97205"><span class="ten">10-day</span></a></li></ul></div></div></div></div></div></div></div><div class="ro"><div class="ce ce1 cel w8"><div class="cogr coss coj" id="infopane_hops"><div id="slide1" class="cof"><div id="headlinepane1" class="co1b1 co coa2 coc1"><div class="br br1"><div class="scp1 cf"><div class="npane n3"><span><a href="httpdisabled://firstread.msnbc.msn.com/_news/2011/04/08/6433568-gop-dem-huddles-fail-to-yield-progress-on-budget-deal/?GT1=43001">Latest: Budget Talks, Sudden Departure, More</a></span><ul><li style="width:206px;" class="first"><a href="httpdisabled://firstread.msnbc.msn.com/_news/2011/04/08/6433568-gop-dem-huddles-fail-to-yield-progress-on-budget-deal/?GT1=43001"><img src="../col.stb.s-msn.com/i/CE/19F603C3122D48B6554BBD495195.jpg" title="Image: (From left) Senate Majority Leader Harry Reid &amp; House Speaker John Boehner (Photos © J. Scott Applewhite/AP)" width="206" height="144" alt="Image: (From left) Senate Majority Leader Harry Reid &amp; House Speaker John Boehner (Photos © J. Scott Applewhite/AP)" /></a><a href="httpdisabled://firstread.msnbc.msn.com/_news/2011/04/08/6433568-gop-dem-huddles-fail-to-yield-progress-on-budget-deal/?GT1=43001">Tempers flare, clock ticks</a></li><li style="width:206px;"><a href="httpdisabled://msn.foxsports.com/mlb/story/Slugger-Manny-Ramirez-retires-amid-mlb-drug-policy-issues-040811/?GT1=39002"><img src="../col.stb.s-msn.com/i/23/6B8E88315584A40B04E32D89551E.jpg" title="Image: Manny Ramirez of the Tampa Bay Rays (© Tom DiPace/Sports Illustrated/Getty Images)" width="206" height="144" alt="Image: Manny Ramirez of the Tampa Bay Rays (© Tom DiPace/Sports Illustrated/Getty Images)" /></a><a href="httpdisabled://msn.foxsports.com/mlb/story/Slugger-Manny-Ramirez-retires-amid-mlb-drug-policy-issues-040811/?GT1=39002">Manny Ramirez quits MLB</a></li><li style="width:206px;" class="last"><a href="httpdisabled://wonderwall.msn.com/music/naomi-wynonna-judd-we-were-sexually-abused-too-1613238.story?GT1=28135"><img src="../col.stb.s-msn.com/i/D8/41FF8CA0A47CC8208E684FA1BE6D6.jpg" title="Image: (From left) Wynonna &amp; Naomi Judd (© Frazer Harrison/Getty Images for ACM)" width="206" height="144" alt="Image: (From left) Wynonna &amp; Naomi Judd (© Frazer Harrison/Getty Images for ACM)" /></a><a href="httpdisabled://wonderwall.msn.com/music/naomi-wynonna-judd-we-were-sexually-abused-too-1613238.story?GT1=28135">More abuse reports for Judds</a></li></ul></div></div></div></div></div><div id="slide2"><div id="headlinepane2" class="co1b1 co coa2 coc1"> </div></div><div id="slide3"><div id="headlinepane3" class="co1b1 co coa2 coc1"> </div></div><div id="slide4"><div id="headlinepane4" class="co1b1 co coa2 coc1"> </div></div><div id="slide5"><div id="headlinepane5" class="co1b1 co coa2 coc1"> </div></div></div></div></div><div class="ro"><div class="ce ce1 cel w8"><div id="todays_picks" class="co1b1 co coa2 coc1 m3 hlcpm1"><h2 class="h2 cf"><span>EDITORS' PICKS</span></h2><div class="br br1"><div class="hcpep3 cf"><ul><li><a href="httpdisabled://www.msnbc.msn.com/id/42497862/ns/weather/?GT1=43001">Deadly pileup after sandstorm</a></li><li><a href="httpdisabled://www.msnbc.msn.com/id/42492782/ns/world_news-europe/?GT1=43001">People shot on British sub</a></li><li><a href="httpdisabled://msn.foxsports.com/mlb/story/109-year-old-woman-throws-out-first-pitch-at-minor-league-baseball-game-040811?GT1=39002">Woman, 109, throws 1st pitch</a></li><li><a href="httpdisabled://www.delish.com/food/recalls-reviews/pizza-topped-with-face-of-jesus-auctioned-on-ebay?GT1=47001">'Jesus' pizza sells at auction</a></li><li><a href="httpdisabled://msn.foxsports.com/foxsoccer/latinamerica/story/Brazilian-soccer-star-Neymar-is-ejected-for-celebrating-with-face-mask-040711/?gt1=39002">Player ejected for celebration</a></li><li><a href="httpdisabled://msn.foxsports.com/mlb/story/Barry-Bonds-perjury-trial-jury-begins-deliberations-040811/?GT1=39002">Bonds jury deliberating</a></li><li><a href="httpdisabled://money.msn.com/home-loans/article.aspx?post=06a7a70e-1e8e-4b24-8331-48aa100c6075&amp;gt1=33032">How to 'steal' a house</a></li><li><a href="httpdisabled://wonderwall.msn.com/movies/celebs-gone-royal-12022.gallery?GT1=28135">Which celebs are also royals?</a></li><li><a href="httpdisabled://realestate.msn.com/article.aspx?cp-documentid=28280145&amp;GT1=35006">What all tenants should know</a></li></ul></div></div></div></div></div><div class="ro"><div class="ce ce1 cel w8"><div class="cogr cotb cogrst coj" id="maintg"><div id="latest_hops"><div class="co1b1 co coa2 coc1 m3 hlcpm1"><h2 class="h2 cf"><span>MUST-SEE</span></h2></div></div><div id="news"><div class="co1b1 co coa2 coc1 hlcpm1"><h2 class="h2 cf"><span>NEWS</span></h2></div></div><div id="video"><div class="co1b1 co coa2 coc1 m3 hlcp1"><h2 class="h2 cf"><span>VIDEO</span></h2></div></div><div id="health"><div class="co1b1 co coa2 coc1 m3 hlcp1"><h2 class="h2 cf"><span>HEALTH</span></h2></div></div><div id="countdown" class="cof"><div class="co3b6 cf co coa2 coc1 m3 en-us1"><h2 class="h2 cf"><span>GOVERNMENT SHUTDOWN</span></h2><div class="br br1 w4"><div style="clear:both;" class="hlcp1 cf"><div class="pri" style="float:left;width:303px"><div class="first"><div><a href="httpdisabled://money.msn.com/taxes/latest.aspx?post=f980ad10-50ca-418d-8925-997d2fc859a7&amp;gt1=33005"><img class="landscape" src="../col.stb.s-msn.com/i/76/CAF5FAB7F245F96327F2B4C806D.jpg" title="Image: U.S. Capitol (© Jim Young/Reuters)" width="303" height="117" alt="Image: U.S. Capitol (© Jim Young/Reuters)" /></a></div><div><a href="httpdisabled://money.msn.com/taxes/latest.aspx?post=f980ad10-50ca-418d-8925-997d2fc859a7&amp;gt1=33005">Could shutdown derail economy?</a><div class="richtext"><p>Some analysts fear that a government closure could <a href="httpdisabled://money.msn.com/taxes/latest.aspx?post=f980ad10-50ca-418d-8925-997d2fc859a7&amp;gt1=33005">dampen consumer confidence &amp; spending</a>.</p></div></div></div></div></div></div><div class="br br2"><div class="flashlinkedimg" id="f_countdown"><a href="httpdisabled://www.msnbc.msn.com/id/42350517/ns/politics/?GT1=43001"><img src="../col.stb.s-msn.com/i/5B/CC662FC6233C7449D9C7F9796801D.jpg" width="311" height="72" alt="Image: The White House (© Murat Taner/Getty Images)" /></a><script type="text/javascript">jQuery("#f_countdown").async("createFlash",[{version:9,attr:{id:'f_countdownObj',width:311,height:76},param:{movie:'http://col.stb.s-msn.com/i/D3/3894AD869183D2FA8BA6BCCEB519C.swf'}}]);</script></div></div><div class="br br3 brl w4"><ul class="linklist16"><li class="first"><a href="httpdisabled://firstread.msnbc.msn.com/_news/2011/04/08/6433138-boehner-joins-lawmakers-pledging-to-return-pay-in-event-of-shutdown-?GT1=43001">Some lawmakers volunteer to forgo pay</a></li><li><a href="httpdisabled://www.bing.com/travel/content/search?q=National+Parks%2c+Museums+Face+Looming+Shutdown&amp;cid=msn1183652&amp;form=TRVCON&amp;gt1=41000">Parks, museums around US could shutter</a></li><li><a href="httpdisabledsdisabled://www.facebook.com/#!/msn">Sound off on the shutdown on Facebook</a></li><li><a href="httpdisabled://msnbc.newsvine.com/_question/2011/04/08/6431363-do-you-think-the-us-government-will-shut-down-at-midnight?gt1=43001">Vote: Do you think government will close?</a></li><li class="last"><a href="httpdisabled://specials.msn.com/A-List/Money/Government-shutdown.aspx?cp-documentid=28275815&amp;imageindex=1">Search: See what's at stake if a deal isn't reached</a></li></ul></div></div></div></div></div></div><div class="ro" id="stk_heading"><div class="ce ce1 cel w8 m3"><div id="stk_head" class="co1b1 co coa2 coc1 single2"><h2 class="h2 cf"><span>MARKET UPDATE</span></h2><div id="stk_off" class="br br1"></div></div></div></div><div class="ro" id="stk_data"><div class="ce ce1 w33"><div id="stk" class="co2b1 cf co coa2 coc1 money1"><div class="br br1 m3"><div class="indices1"><div class="sitime">Updated: 04/08/2011 04:40 ET</div><table summary="Market update"><caption>Market update</caption><thead><tr><th abbr="Symbol" id="siindex">Symbol</th><th abbr="Last" id="silast">Last</th><th abbr="Change" id="sichange">Change</th></tr></thead><tbody><tr class="first"><td class="siidx" headers="siindex"><a href="httpdisabled://investing.money.msn.com/investments/stock-price?Symbol=$INDU">DOW</a></td><td class="silast" headers="silast">12,380.05</td><td headers="sichange" class="neg">-29.44</td></tr><tr><td class="siidx" headers="siindex"><a href="httpdisabled://investing.money.msn.com/investments/stock-price?Symbol=$COMPX">NASDAQ</a></td><td class="silast" headers="silast">2,780.42</td><td headers="sichange" class="neg">-15.72</td></tr><tr class="last"><td class="siidx" headers="siindex"><a href="httpdisabled://investing.money.msn.com/investments/stock-price?Symbol=$INX">S&amp;P</a></td><td class="silast" headers="silast">1,328.17</td><td headers="sichange" class="neg">-5.34</td></tr></tbody></table></div></div><div class="br br2 brl m3"></div></div></div><div class="ce ce2 w33 m3" id="stk_form"><div class="co1b1 co coa1 coc1 m3 generic1"><div class="br br1"><form action="httpdisabled://moneycentral.msn.com/detail/stock_quote" method="get" class="simple8 cf"><p>legend</p><div><label for="idlblsearch">Get a stock quote</label><div><input id="idlblsearch" type="text" class="text" name="symbol" size="25" maxlength="255" /><input type="image" class="image" alt="" title="" value="" style="height:22px;width:22px;" src="../col.stb.s-msn.com/i/E2/37BA92E210D341BFDBF4126422A3D2.gif" /></div></div></form></div></div><div class="co2b1 cf co coa2 coc1 sponad1"><div class="br br1"><div class="richtext"><p>Brought to you by:</p></div></div><div class="br br2 brl"><div class="advertisement"><div id="SponsorAd"><script type="text/javascript">$.dap("&amp;PG=MSNHQ2&amp;AP=1402",73,14,"SponsorAd");</script></div></div></div></div></div><div class="ce ce3 cel w33"><div id="stk_linklist" class="co1b1 co coa2 coc1 single2"><div class="br br1"><ul class="linklist16"><li class="first"><a href="httpdisabled://money.msn.com/market-news/post.aspx?post=46377f6d-466f-47c3-9c5a-0355cfb08b9a">Dow falls 29; oil tops $112</a></li><li><a href="httpdisabled://money.msn.com/how-to-invest/article.aspx?post=a86ac614-4428-403e-8e2e-4899c3f3638a">How Clorox is cleaning up</a></li><li class="last"><a href="httpdisabled://money.msn.com/market-news/default.aspx?feat=0ba6fe64-a5a5-4091-af1d-f710464b7fa5&amp;_nwpt=1">Gold hits another record</a></li></ul></div></div></div></div><div class="ro"><div class="ce ce1 cel w8"><div class="cogr cotb cogrst coj" id="sectabs_hops"><div id="entertainment"><div class="co1b1 co coa2 coc1 m3 hlcpm1"><h2 class="h2 cf"><span>CELEBS &amp; GOSSIP</span></h2></div></div><div id="sports" class="cof"><div class="co1b1 co coa2 coc1 hlcp1"><h2 class="h2 cf"><span>SPORTS</span></h2><div class="br br1"><div style="clear:both;" class="hlcp1 cf"><div class="pri" style="float:left;width:303px"><div class="first" style="clear:right;"><div style="float:right;width:116px"><a href="httpdisabled://msn.foxsports.com/golf/story/Masters-Round-2-live-blog-040811"><img class="portrait" src="../static.foxsports.com/content/fscom/img/2011/04/07/040711-Golf-Tiger-Woods-1120pm-PI_20110407142414593_116_175.JPG" width="116" height="175" alt="Image: Tiger Woods (© Jamie Squire/Getty Images)" /></a></div><div style="margin-right:116px; padding-right: 10px;"><a href="httpdisabled://msn.foxsports.com/golf/story/Masters-Round-2-live-blog-040811">In progress: Tiger back for Round 2</a><div class="richtext"><p>voiding the Masters with a 71, Tiger Woods needs to hustle to make up ground and catch the tournament leaders. Plus: <a href="httpdisabled://msn.foxsports.com/golf/leaderboard">Round 2 leaderboard</a></p></div></div></div></div><ul style="margin-left: 303px; padding-left: 25px;"><li class="ter"><a href="httpdisabled://msn.foxsports.com/nba/story/Getting-to-know-the-real-Maverick-Carter-LeBron-James-business-manager-childhood-friend-040711">Whitlock: Meet the man behind LeBron James</a></li><li class="ter"><a href="httpdisabled://msn.foxsports.com/cbk/story/St-Johns-Red-Storm-coach-Steve-Lavin-has-prostate-cancer-040811">Successful Big East basketball coach has cancer</a></li><li class="ter"><a href="httpdisabled://msn.foxsports.com/mlb/story/Boston-Red-Sox-defeat-New-York-Yankees-040811">Red Sox earn first victory at Yankees' expense</a></li><li class="ter"><a href="httpdisabled://msn.foxsports.com/nba/story/new-jersy-nets-fined-50000-for-jay-zs-kentucky-locker-room-visit-040911">Nets fined for rap star's Kentucky locker room visit</a></li><li class="ter"><a href="httpdisabled://msn.foxsports.com/nascar/story/NASCAR-Denny-Hamlin-to-drive-kid-created-March-of-Dimes-paint-scheme">NASCAR heavyweight to use children's design</a></li><li class="ter"><a href="httpdisabled://msn.foxsports.com/nba/story/Former-NBA-MVP-Allen-Iverson-lets-loose-against-Atlanta-police-040811">Former NBA MVP gets snippy with Atlanta police</a></li><li class="ter"><a href="httpdisabled://rutgers.scout.com/2/1062634.html">Video: Rutgers football team gets surprise visitor</a></li></ul></div></div></div></div><div id="realestate"><div class="co1b1 co coa2 coc1 m3 hlcpm1"><h2 class="h2 cf"><span>REAL ESTATE</span></h2></div></div><div id="weirdnews"><div class="co1b1 co coa2 coc1 m3 hlcp1"><h2 class="h2 cf"><span>WEIRD NEWS</span></h2></div></div></div></div></div><div class="ro"><div class="ce ce1 w4"><div class="cogr cotb cogrst" id="localtg"><div id="local" class="cof"><div class="co6b7 co coa2 coc1 m5 local1"><h2 class="h2 cf"><span>LOCAL</span></h2><div class="br br1 brl m3"><div class="weather1" ><h3 class="h3 cf"><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205">Portland, OR</a><span><a class="voidnew" href="httpdisabled://www.bing.com/maps/?where1=Portland, OR&amp;FORM=MSNHPM">Get Directions</a></span></h3><div class="weahr"> </div><div class="weaheading cf"><h4><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205">Local Weather</a></h4><ul class="degreetype"><li class="fahrenheit selected"><a title="Fahrenheit" href="index.html#">°F
- </a></li><li class="celsius"><a title="Celsius" href="index.html#">°C
- </a></li></ul></div><div class="forecast cf"><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205"><img src="../blst.msn.com/as/wea3/i/en-us/law/30.gif" height="45" width="55" alt="Partly Cloudy" title="Partly Cloudy" /></a><div class="data"><div class="today"><ul><li class="first"><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205">Friday</a></li><li class="last"><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205"><span class="high">High 59°</span>/
- <span class="low">Low 39°</span></a></li></ul></div><div class="temp"><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205">55°</a></div><div class="conditions"><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205">Partly Cloudy</a></div><ul class="forecasts"><li class="first"><a href="httpdisabled://local.msn.com/hourly.aspx?q=Portland-OR&amp;zip=97205">Hourly</a></li><li><a href="httpdisabled://local.msn.com/weather.aspx?q=Portland-OR&amp;zip=97205#fivedayforecast">5-day</a></li><li class="last"><a href="httpdisabled://local.msn.com/ten-day.aspx?q=Portland-OR&amp;zip=97205">10-day</a></li></ul></div></div></div></div><div class="hr"></div><div class="br br2 m3"><div class="locnews1"><h3 class="h3 cf"><a href="httpdisabled://local.msn.com/news.aspx?zip=97220&amp;q=97220">Local News</a></h3><div><ul>
- <li class="first"><a href="httpdisabled://www.msnbc.msn.com/id/42500254/ns/local_news-portland_or/">OR lawmakers look to expand bottle bill</a></li>
- <li><a href="httpdisabled://www.msnbc.msn.com/id/42499610/ns/local_news-portland_or/">Wash. cop awarded for sword attack rescue</a></li>
- <li class="last"><a href="httpdisabled://www.msnbc.msn.com/id/42482989/ns/local_news-portland_or/">Suspect indicted in Vaughn death for murder with firearm</a></li>
-</ul></div><div class="hideseemore"><a href="httpdisabled://local.msn.com/news.aspx?zip=97220&amp;q=97220">Find more local news</a></div></div></div><div class="hr"></div><br class="b3" /><div class="br br3 m3"><div class="locsports1"><h3 class="h3 cf"><a href="httpdisabled://local.msn.com/sports.aspx?zip=97220&amp;q=97220">Local Sports</a></h3><div><ul>
- <li class="first"><a href="httpdisabled://msn.foxsports.com/mlb/story/Seattle-prepares-for-emotional-voider-47907243">Seattle prepares for emotional voider</a></li>
- <li><a href="httpdisabled://msn.foxsports.com/nba/story/gerald-wallace-leads-portland-trail-blazers-past-utah-jazz-040711-">Wallace, Batum pace Trail Blazers</a></li>
- <li class="last"><a href="httpdisabled://msn.foxsports.com/nba/story/LakersTrail-Blazers-Preview-87822291">Lakers-Trail Blazers Preview</a></li>
-</ul></div><div class="hideseemore"><a href="httpdisabled://local.msn.com/sports.aspx?zip=97220&amp;q=97220">Find more local sports</a></div></div></div><div class="hr"></div><br class="b4" /><div class="br br4 m3"><div class="locevents1"><h3 class="h3 cf"><a href="httpdisabled://local.msn.com/movies-events.aspx?zip=97220&amp;q=97220">Local Events</a></h3><div><ul><li class="first"><a href="httpdisabled://www.bing.com/events/search?q=events near 97220&amp;p1=[Events+source=&quot;vertical&quot;+qzeventid=&quot;z172934165&quot;]&amp;form=MSNLAP">A Rocket To The Moon</a></li><li><a href="httpdisabled://www.bing.com/events/search?q=events near 97220&amp;p1=[Events+source=&quot;vertical&quot;+qzeventid=&quot;z173806065&quot;]&amp;form=MSNLAP">Shuffleboard Tournament</a></li><li class="last"><a href="httpdisabled://www.bing.com/events/search?q=events near 97220&amp;p1=[Events+source=&quot;vertical&quot;+qzeventid=&quot;z173818465&quot;]&amp;form=MSNLAP">Redneck Summer Games</a></li></ul></div><div class="hideseemore"><a href="httpdisabled://local.msn.com/movies-events.aspx?zip=97220&amp;q=97220">Find more local events</a></div></div></div><div class="hr"></div><br class="b5" /><div class="br br5 m3"><div class="lmlsf1 cf"><div class="findmore"><div><strong>Find more local:</strong></div><div><ul class="linklist9 cf"><li class="first"><a href="httpdisabled://local.msn.com/news.aspx?zip=97220&amp;q=97220">News</a></li><li><a href="httpdisabled://local.msn.com/sports.aspx?zip=97220&amp;q=97220">Sports</a></li><li class="last"><a href="httpdisabled://local.msn.com/movies-events.aspx?zip=97220&amp;q=97220">Events</a></li></ul></div></div><div class="simpleform"><form action="httpdisabled://local.msn.com/news.aspx" method="get" class="simple8 cf" id="newsid"><p>Change your location</p><div><label for="txtZipCode"><strong>Enter US ZIP or city</strong></label><div><input id="txtZipCode" type="text" class="text" name="zip" size="30" maxlength="30" /><input type="image" class="image" alt="" title="" value="" style="height:22px;width:22px;" src="../col.stb.s-msn.com/i/E2/37BA92E210D341BFDBF4126422A3D2.gif" /></div></div></form></div></div></div><div class="hr"></div><div class="br br6 brl m3"><h3 class="h3 cf"><a href="httpdisabled://deals.msn.com/">Local Shopping</a></h3><div style="clear:both;" class="hlcp1 cf"><ul><li class="sec last"><div style="float:left;width:128px"><a href="httpdisabled://deals.msn.com/"><img class="landscape" src="../col.stb.s-msn.com/i/EA/9BECE90994978BFAE6F38561515E8.jpg" title="Image: Women window-shopping (© Nisian Hughes/Getty Images)" width="128" height="73" alt="Image: Man &amp; woman with hat (© MM Productions/Getty Images)" /></a></div><div style="margin-left:128px; padding-left: 10px"><a href="httpdisabled://deals.msn.com/"><strong>Top off your look</strong></a><div class="richtext"><p>Save on accessories, home décor, cameras &amp; more to get a jump on spring.</p></div></div></li></ul></div></div></div></div><div id="movies"><div class="co2b2 co coa2 coc1 movies1"><h2 class="h2 cf"><span>MOVIES</span></h2></div></div><div id="jobs"><div class="co2b2 co coa2 coc1 jobs1"><h2 class="h2 cf"><span>JOBS</span></h2></div></div><div id="maps"><div class="co2b2 co coa2 coc1 movies1"><h2 class="h2 cf"><span>TRAVEL</span></h2></div></div></div></div><div class="ce ce2 cel w4"><div class="co1b1 co coa2 coc1 ad1"><div class="br br1"><div class="advertisement" style="width:300px"><div id="Ad300x60"><script type="text/javascript">$.dap("&amp;PG=MSNIF1&amp;AP=1455",300,60,"Ad300x60");</script></div><div class="adfb cf right"><a href="httpdisabled://g.msn.com/AIPRIV/en-us" class="adch"><img src="../col.stc.s-msn.com/br/sc/i/icons/adchoices_gif.gif" alt="Ad Choice" title="Ad Choice" height="12" width="68" /></a></div></div></div></div><div class="cogr"><div id="shpcob15" class="cof"><div id="shopping" class="co4b5 co coa2 coc1 shopping1"><h2 class="h2 cf"><span>SHOPPING</span></h2><div class="br br1 m3"><form action="httpdisabled://www.bing.com/shopping/search" method="get" class="simple8 cf"><p>legend</p><div><label for="idQuickSearch">Shop fitness equipment</label><div><input id="idQuickSearch" type="text" class="text" name="q" size="30" maxlength="30" /><input type="hidden" name="form" value="MSNSSB" /><input type="image" class="image" alt="" title="" value="" style="height:22px;width:22px;" src="../col.stb.s-msn.com/i/E2/37BA92E210D341BFDBF4126422A3D2.gif" /></div></div></form></div><div class="br br2"><ul class="linklist22"><li class="first"><a href="httpdisabled://www.bing.com/shopping/spring-shoe-trends/r/169?FORM=SHOPH1&amp;crea=040811shoes">What are the hottest shoe trends for spring?</a></li><li><a href="httpdisabled://www.bing.com/shopping/digital-cameras/search?q=digita%20camera&amp;p1=%5bCommerceService%20scenario%3d%22f%22%20a%3d%22ra%22%20r%3d%22pricelow%7c60%2cpricehigh%7c150%2cleafcategoryid%7c4362%2cbrandid%7c1213%22%5d&amp;FORM=SHOPH1&amp;crea=040811cameras">Canon digital cameras under $150</a></li><li class="last"><a href="httpdisabled://www.bing.com/shopping/sheets/c/4934?q=cotton+bedding&amp;FORM=SHOPH1&amp;crea=040811sheets">Crisp, cool cotton sheets for spring</a></li></ul></div><br class="b3" /><div class="br br3 m1"><ul class="linklist9 cf"><li class="first"><a href="httpdisabled://www.bing.com/shopping?form=SHOPH1&amp;crea=shoppingpipe">Shop now</a></li><li class="last"><a href="httpdisabled://www.bing.com/shopping/sunless-tanners/c/4346?q=sunless+tanners&amp;s=ra&amp;FORM=SHOPH1&amp;crea=040811tanners">Top-rated sunless tanners</a></li></ul></div><div class="hr"></div><div id="ad" class="br br4 brl"><h3 class="h3 cf">ADVERTISEMENTS</h3><div class="headlinelist1 cf"><div style="width: 70px;"><a href="httpdisabledsdisabled://www.lendgo.com/lam/?tg_ref=ms_hp&amp;camp_id=tl1&amp;rate=2.6&amp;keyword=shoc2&amp;lt=31&amp;rt=v" class=voidnew"><img src="../col.stb.s-msn.com/i/CF/59B3CB34EF11B221719175143187.jpg" title="Click here!" width="70" height="70" alt="Click here!" /></a></div><ul style="margin-left: 80px;"><li class="first"><a href="httpdisabledsdisabled://www.lendgo.com/lam/?tg_ref=ms_hp&amp;camp_id=tl1&amp;rate=2.6&amp;keyword=shoc2&amp;lt=31&amp;rt=v" class=voidnew"><strong>2.6% Mortgage: $160K loan $659mo</strong></a></li><li><a href="httpdisabled://ib.adnxs.com/seg?add=111553,108836,108837&amp;redir=http%3A%2F%2Ftracking.servedbyy.com%2Faff_c%3Foffer_id%3D237%26aff_id%3D1%26source%3DMSNHPTL%26url_id%3D484" class=voidnew">Half Off highly rated wines</a></li><li><a href="httpdisabled://deals.msn.com/default.aspx?m=4LSWSD" class=voidnew">4 Local stores – Shocking deals</a></li><li class="last"><a href="httpdisabled://clk.atdmt.com/AST/go/307318345/direct/01/" class=voidnew">L.L.Bean Free Shipping</a></li></ul></div></div><div class="hr"></div></div></div></div><div id="spotlight" class="co1b1 co coa2 coc1 spotlight1"><div class="br br1"><h3 class="h3 cf"><a href="httpdisabled://specials.msn.com/alphabet.aspx">MSN SPOTLIGHT</a></h3><div class="headlinelist1 cf"><div style="width: 75px;"><a href="httpdisabled://businessonmain.msn.com/browseresources/slideshows/smallbusinesstrends.aspx?cp-documentid=26870779&amp;source=msneditorial&amp;gt1=25049"><img src="../col.stb.s-msn.com/i/80/82E2A652E4A790B140675E74293AD6.jpg" title="Image: Jennifer Lopez (© Charles Sykes/AP)" width="75" height="128" alt="Image: Jennifer Lopez (© Charles Sykes/AP)" /></a></div><ul style="margin-left: 85px;"><li class="first"><a href="httpdisabled://businessonmain.msn.com/browseresources/slideshows/smallbusinesstrends.aspx?cp-documentid=26870779&amp;source=msneditorial&amp;gt1=25049">J.Lo finds a new way to be hot </a></li><li><span class="media"><a href="httpdisabled://businessonmain.msn.com/videos/newsonmain.aspx?cp-documentid=27678565&amp;source=msneditorial&amp;from=en-us_msnhp&amp;gt1=25049">Meet a real-life Willy Wonka </a></span></li><li><a href="httpdisabled://businessonmain.msn.com/browseresources/articles/firststeps.aspx?cp-documentid=28039284&amp;source=msneditorial&amp;gt1=25049">How to start a biz with 50 bucks </a></li><li><span class="media"><a href="httpdisabled://businessonmain.msn.com/videos/newsonmain.aspx?cp-documentid=27844438&amp;source=msneditorial&amp;gt1=25049">2 indie theaters take on big boys </a></span></li><li class="last"><a href="httpdisabled://businessonmain.msn.com/browseresources/articles/innovationstories.aspx?cp-documentid=28039658&amp;source=msneditorial&amp;gt1=25049">They throw zombie parties for a living </a></li></ul></div></div></div></div></div></div><div id="area2" class="re w4"><div class="ro"><div class="ce ce1 cel w4"><div class="co1b1 co coa2 coc1 ad1"><div class="br br1"><div class="advertisement" style="width:300px"><div id="idShowcaseAd" style="min-height:250px"><script type="text/javascript">$.dap("&amp;PG=MSNREC&amp;AP=1089",300,250,"idShowcaseAd");</script></div><div class="adfb cf left"><a href="httpdisabled://g.msn.com/AIPRIV/en-us" class="adch"><img src="../col.stc.s-msn.com/br/sc/i/icons/adchoices_gif.gif" alt="Ad Choice" title="Ad Choice" height="12" width="68" /></a><a href="httpdisabled://ccc01.opinionlab.com/o.asp?id=swHtlTXj">Ad Feedback</a></div></div></div></div></div></div><div class="ro"><div class="ce ce1 cel w4"><div class="co1b1 co coa1 coc1 alert1"><div class="br br1"><div class="link"><a href="httpdisabled://ie9.discoverbing.com/?form=MFEHPG&amp;publ=MSN&amp;crea=STND_MFEHPG_MSNinprod_alert_br0304_1x1" class=voidnew"><strong>Upgrade to the faster Internet Explorer 9 – FREE </strong></a></div></div></div></div></div><div class="ro"><div class="ce ce1 cel w4"><div class="cogr coj"></div></div></div><div class="ro"><div class="ce ce1 cel w4"><div class="cogr cotb" id="stgsearch"><div id="popsrchnew" class="cof"><div class="co4b5 co coa2 coc1 alist1"><h2 class="h2 cf"><span>POPULAR SEARCHES</span></h2><div id="pop1_hops" class="br br1"><div style="clear:both;" class="hlcp2 cf"><ul><li class="sec last"><div style="float:left;width:128px"><a href="httpdisabled://specials.msn.com/A-List/Lifestyle/Weirdest-mug-shots.aspx?cp-documentid=27403042 "><img class="landscape" src="../col.stb.s-msn.com/i/FF/6B3EB94D554DA0488C66DC31482D48.jpg" title="Image: Booking photo of Michelle Allen (Courtesy of Middletown Police Dept.)" width="128" height="73" alt="Image: Booking photo of Michelle Allen (Courtesy of Middletown Police Dept.)" /></a></div><div style="margin-left:128px; padding-left: 10px"><a href="httpdisabled://specials.msn.com/A-List/Lifestyle/Weirdest-mug-shots.aspx?cp-documentid=27403042 "><strong>Weirdest mug shots</strong></a><div class="richtext"><p>While their acts got them in trouble, some suspects' <a href="httpdisabled://specials.msn.com/A-List/Lifestyle/Weirdest-mug-shots.aspx?cp-documentid=27403042 ">arrest photos</a> were quite odd.</p></div></div></li></ul></div></div><div class="hr"></div><div id="pop2_hops" class="br br2"><h3 class="h3 cf">On Bing</h3><div style="clear:both;" class="hlcp1 hlcp3 cf"><ul><li class="ter"><a href="httpdisabled://www.bing.com/search?q=Peyton+Manning+twins&amp;form=msnhpm">Peyton Manning</a><span class="piped"> | <a href="httpdisabled://www.bing.com/search?q=christie+brinkley&amp;form=msnwis">Christie Brinkley</a> | <a href="httpdisabled://www.bing.com/search?q=sarah+palin+shutdown&amp;form=msnhpm">Sarah Palin</a></span></li><li class="ter"><a href="httpdisabled://www.bing.com/search?q=tiger+woods+video+game&amp;form=msnhpm">Tiger Woods</a><span class="piped"> | <a href="httpdisabled://www.bing.com/search?q=kelly+clarkson+ellen&amp;form=msnhpm">Kelly Clarkson</a> | <a href="httpdisabled://www.bing.com/search?q=hanna+movie&amp;form=msnhpm">'Hanna'</a></span></li><li class="ter"><a href="httpdisabled://www.bing.com/search?q=carrie+underwood&amp;form=msnwis">Carrie Underwood</a><span class="piped"> | <a href="httpdisabled://www.bing.com/news/search?q=greta+gerwig&amp;FORM=msnhpm">Greta Gerwig</a> | <a href="httpdisabled://www.bing.com/search?q=gabrielle+giffords+shuttle&amp;form=msnhpm">Gabrielle Giffords</a></span></li><li class="ter"><a href="httpdisabled://www.bing.com/search?q=blue+bird+school+buses+fire+risk&amp;form=msnhpm">School bus recall</a><span class="piped"> | <a href="httpdisabled://www.bing.com/search?q=john+boehner&amp;form=msnwis">John Boehner</a> | <a href="httpdisabled://www.bing.com/search?q=patty+duke+social+security&amp;FORM=msnhpm">Patty Duke</a></span></li><li class="ter"><a href="httpdisabled://www.bing.com/news/search?q=planned+parenthood&amp;FORM=msnhpm">Planned Parenthood</a><span class="piped"> | <a href="httpdisabled://www.bing.com/search?q=johnson+%26+johnson+settles&amp;form=msnhpm">Johnson &amp; Johnson</a> | <a href="httpdisabled://www.bing.com/search?q=military+pay&amp;form=msnhpm">Military pay</a></span></li></ul></div></div><div class="hr"></div><br class="b3" /><div id="pop3_hops" class="br br3"><h3 class="h3 cf">Popular Pages</h3><div style="clear:both;" class="hlcp1 hlcp3 cf"><ul><li class="ter"><a href="httpdisabled://specials.msn.com/A-List/Movies/Natalie-Portman-on-Black-Swan-controversy.aspx?cp-documentid=28301675">Portman on 'Swan' dispute</a><span class="piped"> | <a href="httpdisabled://specials.msn.com/A-List/TV/Bill-Cosby-slams-Trump.aspx?cp-documentid=28292430">Bill Cosby slams Trump</a></span></li><li class="ter"><a href="httpdisabled://specials.msn.com/A-List/Lifestyle/Commodore-64-is-back.aspx?cp-documentid=28291495">A new Commodore 64?</a><span class="piped"> | <a href="httpdisabled://specials.msn.com/A-List/sports/Big-Ben-to-wed.aspx?cp-documentid=28299660">'Big Ben' confirms wedding</a></span></li><li class="ter"><a href="httpdisabled://specials.msn.com/A-List/Entertainment/Iggy-Pop-stuns-Idol-audience.aspx?cp-documentid=28302289">Iggy Pop performs on 'Idol'</a><span class="piped"> | <a href="httpdisabled://specials.msn.com/A-List/Lifestyle/Surprise-plea-in-Dugard-case.aspx?cp-documentid=28292186">Plea in Dugard case</a></span></li><li class="ter"><a href="httpdisabled://specials.msn.com/A-List/Movies/Hailee-Steinfeld-in-Romeo-and-Juliet.aspx?cp-documentid=28299589">Hailee Steinfeld in talks for new role</a><span class="piped"> | <a href="httpdisabled://specials.msn.com/A-List/TV/A-Glee-spin-off.aspx?cp-documentid=28301295">'Glee' spin-off?</a></span></li></ul></div></div><div class="hr"></div><div id="pop4_hops" class="br br4 brl"><h3 class="h3 cf">In Case You Missed It</h3><div style="clear:both;" class="hlcp1 hlcp3 cf"><ul><li class="ter"><a href="httpdisabled://specials.msn.com/A-List/TV/Eva-Longoria-has-on-air-wardrobe-malfunction.aspx?cp-documentid=28287950">Longoria's shirt void </a><span class="piped"> | <a href="httpdisabled://specials.msn.com/A-List/sports/LeBron-James-mom-arrested.aspx?cp-documentid=28287065">LeBron's mom arrested</a></span></li><li class="ter"><a href="httpdisabled://specials.msn.com/A-List/Lifestyle/Mariska-Hargitay-adopts.aspx?cp-documentid=28291248">Mariska Hargitay adopts baby</a><span class="piped"> | <a href="httpdisabled://specials.msn.com/A-List/Health/The-17-day-diet-goes-viral.aspx?cp-documentid=28289344">17 Day Diet goes viral</a></span></li></ul></div></div><div class="hr"></div></div></div></div></div></div><div class="ro" id="apps"><div class="ce ce1 cel w4"><div id="hotmail" class="co1b1 co coa2 coc1 hotmail1"><h2 class="h2 cf"><span>HOTMAIL</span></h2><div id="htup" class="br br1"><div class="hminbox1" ><noscript><p>This module requires scripting to be enabled in your browser.</p></noscript><div class="actions"><a href="httpdisabledsdisabled://login.live.com/login.srf?wa=wsignin1.0&amp;rpsnv=11&amp;ct=1302299259&amp;rver=5.5.4177.0&amp;wp=MBI&amp;wreply=http:%2F%2Fwww.msn.com%2F&amp;lc=1033&amp;id=1184" class="dMSNME_1">Sign in</a></div></div></div></div><div class="cogr cotb cogrst" id="socialtg"><div id="windowslive"><div class="co1b1 co coa2 coc1 activitiesmodule1"><h2 class="h2 cf"><span>MESSENGER</span></h2><div class="br br1"><div class="actfeed1 windowslive"><noscript><p>This module needs JavaScript to be enabled on your browser</p></noscript><div class="ac-head ac-error cf none"><div class="ac-errortext">Unable to show activities. <a href="index.html#" class="ac-refreshlink">Please try again.</a></div><div class="ac-signout"><a class="ac-link dMSNME_1" href="httpdisabledsdisabled://login.live.com/login.srf?wa=wsignin1.0&amp;rpsnv=11&amp;ct=1302299259&amp;rver=5.5.4177.0&amp;wp=MBI&amp;wreply=http:%2F%2Fwww.msn.com%2F&amp;lc=1033&amp;id=1184" rel="False">Sign out</a></div></div><div class="ac-head ac-signin none cf"><div class="ac-upsell">Sign in to see your social updates.</div><div class="ac-signinlink"><a class="ac-link wlsignin dMSNME_1" href="httpdisabledsdisabled://login.live.com/login.srf?wa=wsignin1.0&amp;rpsnv=11&amp;ct=1302299259&amp;rver=5.5.4177.0&amp;wp=MBI&amp;wreply=http:%2F%2Fwww.msn.com%2F&amp;lc=1033&amp;id=1184" rel="False">Sign in</a></div></div></div><div class="ac-loaddisabled none ac-updatestatus">Please wait.<br />This may take a few seconds</div><div class="ac-error none ac-head ac-errortext">Unable to show activities. Please try again later.</div></div></div></div><div id="facebook" class="cof"><div class="co1b1 co coa2 coc1 facebook1"><h2 class="h2 cf"><span>FACEBOOK</span></h2><div class="br br1"><div class="actfeed1 facebook"><noscript><p>This module needs JavaScript to be enabled on your browser</p></noscript><div class="ac-head ac-error cf none"><div class="ac-errortext">Unable to show activities. <a href="index.html#" class="ac-refreshlink">Please try again.</a></div><div class="ac-signout"><a class="ac-link ac-signinoutpopup" href="httpdisabled://www.msn.com/scp/AuthServiceFacebookLogOff.aspx?redirectTo=0&amp;mkt=en-us&amp;format=Homepage">Logout</a></div></div><div class="ac-head ac-signin ac-upsellfb none cf"><div class="ac-upsell">Login to see your News Feed.</div><div class="ac-signinlink fbsignin"><a class="ac-link ac-signinoutpopup" rel="facebook_480_440" href="httpdisabled://www.msn.com/scp/AuthServiceFacebook.aspx?redirectTo=0&amp;mkt=en-us&amp;format=Homepage"><span>Login</span></a></div></div></div><div class="ac-loaddisabled none ac-updatestatus">Please wait.<br />This may take a few seconds</div><div class="ac-error none ac-head ac-errortext">Unable to show activities. Please try again later.</div></div></div></div><div id="twitter"><div class="co1b1 co coa2 coc1 twitter1"><h2 class="h2 cf"><span>TWITTER</span></h2><div class="br br1"><div class="actfeed1 twitter"><noscript><p>This module needs JavaScript to be enabled on your browser</p></noscript><div class="ac-head ac-error cf none"><div class="ac-errortext">Unable to show activities. <a href="index.html#" class="ac-refreshlink">Please try again.</a></div><div class="ac-signout"><a class="ac-link ac-signinoutajax" href="httpdisabled://www.msn.com/scp/AuthServiceTwitterLogOff.aspx?redirectTo=0&amp;mkt=en-us&amp;format=Homepage">Sign out</a></div></div><div class="ac-head ac-signin none cf"><div class="ac-upsell">Want to see your Tweets?</div><div class="ac-signinlink"><a class="ac-link ac-signinoutpopup twsignin" rel="twitter_800_390" href="httpdisabled://www.msn.com/scp/AuthServiceTwitter.aspx?redirectTo=0&amp;mkt=en-us&amp;format=Homepage">Sign in</a></div></div></div><div class="ac-loaddisabled none ac-updatestatus">Please wait.<br />This may take a few seconds</div><div class="ac-error none ac-head ac-errortext">Unable to show activities. Please try again later.</div></div></div></div></div></div></div><div class="ro"><div class="ce ce1 cel w4"><div class="cogr cotb cogrsx coj" id="gendermodule"><div id="forher" class="cof"><div class="co1b1 co coa2 coc1 m3 hlcpm1"><h2 class="h2 cf"><span>FOR HER</span></h2><div class="br br1"><div style="clear:both;" class="hlcp1 cf"><ul><li class="sec last"><div style="float:right;width:128px"><a href="httpdisabled://bodyodd.msnbc.msn.com/_news/2011/04/05/6413263-pop-songs-reflect-our-me-me-me-attitudes-study-says?gt1=43001"><img class="landscape" src="../col.stb.s-msn.com/i/38/FAF3346E94CF4579ECAB641703868.jpg" title="Image: Rihanna &amp; Kanye West (© Lucy Nicholson/Reuters)" width="128" height="73" alt="Image: Rihanna &amp; Kanye West (© Lucy Nicholson/Reuters)" /></a></div><div style="margin-right:128px; padding-right: 10px"><a href="httpdisabled://bodyodd.msnbc.msn.com/_news/2011/04/05/6413263-pop-songs-reflect-our-me-me-me-attitudes-study-says?gt1=43001"><strong>Study: Pop songs all about 'me me me'</strong></a><div class="richtext"><p>Music seems a lot more narcissistic than days gone by. <a href="httpdisabled://bodyodd.msnbc.msn.com/_news/2011/04/05/6413263-pop-songs-reflect-our-me-me-me-attitudes-study-says?gt1=43001">Do you agree</a>?</p></div></div></li><li class="ter"><a href="httpdisabled://www.theroot.com/views/good-sports-encouraging-black-female-athletes?auto=true&amp;gt1=38002">Black female athletes are good role models for girls</a></li><li class="ter media"><a href="httpdisabled://www.msnbc.msn.com/id/21134540/vp/42485020#42485020?from=en-us_msnhp&amp;gt1=43001">Woman accused of shutting down country’s Internet</a></li><li class="ter"><a href="httpdisabled://www.bing.com/search?q=Recommended+Self-help+Books&amp;form=msnspe&amp;gt1=36010">Bing: Recommended self-help books</a></li><li class="ter"><a href="httpdisabled://www.bing.com/search?q=Family+Camping+Checklist&amp;form=msnspe&amp;gt1=36010">Search: Family camping checklist</a></li><li class="ter"><a href="httpdisabled://www.bing.com/browse?g=cat_breeds&amp;form=msnspe&amp;gt1=36010#toc=3">Find: Gallery of easy-going cat breeds</a></li></ul></div></div></div></div><div id="forhim"><div class="co1b1 co coa2 coc1 m3 hlcpm1"><h2 class="h2 cf"><span>FOR HIM</span></h2><div class="br br1"><div style="clear:both;" class="hlcp1 cf"><ul><li class="sec last"><div style="float:right;width:128px"><a href="httpdisabled://money.msn.com/auto-insurance/article.aspx?post=91a93e53-2c02-426a-905a-3c2a175abc11&amp;GT1=33033"><img class="landscape" src="../col.stb.s-msn.com/i/2F/9EFAECEC174B21FB83D10C82522D2.jpg" title="Image: Couple in car (© Caroline von Tuempling/Getty Images)" width="128" height="73" alt="Image: Couple in car (© Caroline von Tuempling/Getty Images)" /></a></div><div style="margin-right:128px; padding-right: 10px"><a href="httpdisabled://money.msn.com/auto-insurance/article.aspx?post=91a93e53-2c02-426a-905a-3c2a175abc11&amp;GT1=33033"><strong>Date a safe driver, save on insurance</strong></a><div class="richtext"><p>Relationship benefits: Love, companionship &amp; ... extra cash? Find out <a href="httpdisabled://money.msn.com/auto-insurance/article.aspx?post=91a93e53-2c02-426a-905a-3c2a175abc11&amp;GT1=33033">how it works</a>.</p></div></div></li><li class="ter"><a href="httpdisabled://digitallife.today.com/_news/2011/04/06/6421524-10-ridiculous-products-to-outsmart-thieves/?gt1=43001">10 ridiculous products to outsmart thieves</a></li><li class="ter"><a href="httpdisabled://realestate.msn.com/blogs/listedblogpost.aspx?post=ed79c32b-2ecc-4cb7-94c9-bfca06f7727c&amp;GT1=35010">Make some cash, turn your home into a giant ad</a></li><li class="ter"><a href="httpdisabled://www.bing.com/browse?g=hdtvs&amp;form=msnspe&amp;gt1=36010#toc=5">Bing: Gallery of top 50- to 52-inch HDTVs</a></li><li class="ter"><a href="httpdisabled://www.bing.com/search?q=Unusual+Sports&amp;form=msnspe&amp;gt1=36010">Find: Most unusual sports around the world</a></li><li class="ter"><a href="httpdisabled://www.bing.com/search?q=best+chefs+in+america&amp;go=&amp;form=msnspe&amp;gt1=36010">Search: Best chefs in America</a></li></ul></div></div></div></div></div></div></div><div class="ro"><div class="ce ce1 cel w4"><div class="cogr coj"></div></div></div><div class="ro"><div class="ce ce1 cel w4"><div class="co1b1 co coa1 coc1 m3 ad1"><div class="br br1"><div class="advertisement" style="width:300px"><div id="publicis_ad"><script type="text/javascript">$.dap("&amp;PG=MSNHP4&amp;AP=1455",300,120,"publicis_ad");</script></div><div class="adfb cf right"><a href="httpdisabled://g.msn.com/AIPRIV/en-us" class="adch"><img src="../col.stc.s-msn.com/br/sc/i/icons/adchoices_gif.gif" alt="Ad Choice" title="Ad Choice" height="12" width="68" /></a></div></div></div></div></div></div><div class="ro"><div class="ce ce1 cel w4"><div class="co1b1 co coa1 coc1 m3 ad1"><div class="br br1"><div class="advertisement"><div id="dap_survey"><script type="text/javascript">$.dap("&amp;PG=MSNSUR&amp;AP=1089",1,1,"dap_survey");</script></div></div></div></div></div></div></div><div id="area3" class="none"></div><div id="subfoot"><div class="co1b1 co coa1 coc1 m3 searchbar2"><div class="br br1 expfoot expsrch"><div class="websearch2"><h2>Bing Search</h2><form action="httpdisabled://www.bing.com/search" method="get" id="footersrchfrm"><div class="search cf"><span class="bo"><span class="bi"><label class="hide" for="qf">Search:</label><input id="qf" type="text" class="text" name="q" size="69" maxlength="250" accesskey="S" /><input type="image" class="image" value="Search" alt="Search" title="Search" style="height:33px;width:173px;" src="../col.stc.s-msn.com/br/sc/i/icons/BING_websearch_2.jpg" /><input type="hidden" name="form" value="MSNH14" /></span></span></div><div class="opt"></div></form></div></div></div></div></div></div><div id="foot"><div class="co1b1 co coa1 coc1 m3 "><div class="br br1"><div class="msnfoot1 cf"><ul class="primary"><li class="first"><a href="httpdisabled://go.microsoft.com/fwlink/?LinkId=74170">MSN Privacy</a></li><li><a href="httpdisabled://g.msn.com/0TO_/enus">Legal</a></li><li><a href="httpdisabled://advertising.microsoft.com/home/home">Advertise</a></li><li class="last"><a href="httpdisabled://www.msn.com/worldwide.aspx">MSN Worldwide</a></li></ul><ul class="secondary"><li class="first"><a href="httpdisabled://rss.msn.com/default.aspx">RSS</a></li><li><a href="httpdisabledsdisabled://careers.microsoft.com/">Jobs</a></li><li><a href="httpdisabled://moneycentral.msn.com/inc/Attributions.asp">Data Providers</a></li><li><a class=voidnew" href="httpdisabledsdisabled://secure.opinionlab.com/ccc01/o.asp?ID=WpkpVtTB">Feedback</a></li><li><a href="httpdisabled://onlinehelp.microsoft.com/en-us/msn/thebasics.aspx">Help</a></li><li class="last"><a href="httpdisabled://g.msn.com/AIPRIV/en-us">About our ads</a></li></ul><div class="copyright"><span>© 2011 Microsoft</span></div></div></div></div></div></div><script type="text/javascript">/*<![CDATA[*/(function(a){var d="body",b="scrollBind";a(window).unbind("scroll",a.track.trackEvent);function e(){a.async("asyncCanary",function(){var d="#to_inbox";c.sm("start");a("#head").scrollHead({withNav:false,scrollHeadFormCode:"MSNL14",animate:1,sSpeed:400,bannerClassName:"generic1"});a("#q").uberFocus();c.sm("sb_uf");a("#infopane_hops a, #todays_picks a").heroPlayer({widgetParams:{flashvars:{configName:"divoverlayplayer",configCsid:"msnvideo"}}});a("div.menunavbar1").menuNavBar({animate:1,fromOpacity:.3});try{a("#addtostart, .addtostart a").async("addToStartMenu",[{LinkText:"Add MSN to Start menu"}])}catch(g){}a("#hp_spotlight_notebook,#hp_spotlight_desktop,#hp_spotlight,#cp_spotlight_desktop,#cp_spotlight_notebook").async("contentRotation",[{dataUrl:"/ajax/hpcStub.aspx",innerSel:".imglinkabslist1"}]);a.cobrandmoduletracking();a("div.cogr.coss").slideshow({delay:7e3,hpad:6,animate:1});a("div.cogr.cotb").scrollBind("tabGroup",[{hover:{delay:300},animate:1}]);a("div.headerbar_us a#mkhm").setHomepage({txt:"Make MSN my homepage"});a("#cobrandeula").async("cobrandeula");a("div.menubar2").menuBar({delay:void:500,close:50}});a("#srchfrm").scrollBind("bindDualSearch",[{scope2:{altImageSrc:"icons/BING_MSN_search_2.jpg",altImageWidth:175,altImageHeight:33},scope3:{altImageSrc:"icons/BING_image_search_2.jpg",altImageWidth:185,altImageHeight:33},scope4:{altImageSrc:"icons/BING_video_search_2.jpg",altImageWidth:182,altImageHeight:33},scope5:{altImageSrc:"icons/BING_news_search_2.jpg",altImageWidth:181,altImageHeight:33},scope6:{altImageSrc:"icons/BING_map_search_2.jpg",altImageWidth:171,altImageHeight:33}}]);a(".websearch2 form").scrollBind("bindSearch");var e="www";switch(a.track.trackInfo.sitePage.siteGroupId){case "DELL":e="dell";break;case "QWEST":e="qwest";break;case "VERIZON":e="verizon";break;case "MSNMEMBER":e="msnmember";break;case "ASUS":case "LENOVO":case "ACER":case "COMPAQ-DESKTOP":case "COMPAQ-NOTEBOOK":case "GATEWAY":case "EMACHINES":case "PACKARDBELL":case "SAMSUNG":case "TOSHIBA":case "MSI":case "MEDION":case "SONY":case "HP-COMM":case "HP-NOTEBOOK":case "HP-DESKTOP":e="us"}a("#stk_heading div").css("margin-bottom","0");a("#marchmadness .br3").async(b,["MarchMadness",[{params:{source:"httpdisabled://col.stc.s-msn.com/br/sc/xap/03182011_1/MarchMadness.xap",initparams:{targetname:"_blank"}}}]]);a.extend(true,{hotmail:{defaults:{proxyurl:"httpdisabled://hotmailproxy.{0}.msn.com/pm/v1.0/getheaders.aspx".format(e)}}});a("div.hminbox1").scrollBind("previewInbox",[{tsrttextOn:0,signinMsg:"Windows Live Hotmail: E-mail made simple. Fight spam with Microsoft SmartScreen technology."}]);a("div.headerbar_us").scrollBind("previewlivescorecard",[{hotmail:d,hmtemplate:"({0})"}]);a.autoSuggest({resources:{js:"httpdisabled://www.bing.com/s/as/863238/en.js"},inputId:"q",delayBind:0,sharedCk:{cn:"_SS",ru:"httpdisabled://www.msn.com/sck.aspx",delay:2},config:{nw:"true",u:" http://api.bing.com/qsonhs.aspx?form=MSN005",mkt:"en-US",tPN:"Popular Now",eHS:1,ePN:1,f:"srchfrm",lh:"httpdisabled://onlinehelp.microsoft.com/en-us/bing/ff808490.aspx",lmh:"httpdisabled://www.bing.com/profile/history"}});c.sm("sb_as");setTimeout(function(){a("#q").trigger("focus");c.sm("sb_f")},0);a(d).scrollBind(voidPopup",[{features:"width=1224,height=768,menubar=1,scrollbars=1,resizable=1,top=0px,left=1,location=1,toolbar=yes,directories=yes"}]);a("#idlblsearch,#txtZipCode, #sc-TWITTERstatus,#idQuickSearch,#shloc,#s_rawwords,#where1").async(b,["bindHinting",[{asyncp:1}]]);a("#srchfrm, #footersrchfrm")voidNew();a(window).loaddisabled(a.dap.run);setTimeout(f,1e3);c.sm("end")},a.jsUrl)}function f(){var f="httpdisabled://local.msn.com/sports.aspx?zip={0}&q={0}",e="httpdisabled://local.msn.com/movies-events.aspx?zip={0}&q={0}",c="ajax/spseventsstub.aspx",d="socialActivityList";a("div.pgopt1").async(b,["pageOptions",[{delay:void:100,close:100}}]]);a("div.pgopt1 #locsrch").async(b,["srchfrm"]);a("div.facebook").async(b,[d,[{serviceName:"facebook",tabSet:"wft"}]]);a("div.twitter").async(b,[d,[{serviceName:"twitter",tabSet:"wft"}]]);a("div.windowslive").async(b,[d,[{serviceName:"windowslive",tabSet:"wft",PassportReturnUrl:"httpdisabled://www.msn.com"}]]);a("#newsid").async(b,["localmodule",[{disambiguationBaseUrl:"ajax/wealocdisambiguatorstub.aspx?weasearchstr="}]]);a("div.weather1").async("weatherForecast",[{weaBaseUrl:"ajax/weadatastub2.aspx?wealocations={0}&weadegreetype={1}",spsUrl:c}]);a("div.locnews1").async(b,["localnews",[{feedUrl:"ajax/localnews.aspx?NewsProviderId=",providerUrl:"ajax/lssproxy.aspx?keyword=",localNewsUrl:" http://local.msn.com/news.aspx?zip={0}&q={0}",spsUrl:c}]]);a("div.locevents1").async(b,["localevents",[{eventsStubURL:"ajax/loceventsstub.aspx?zipcode=",evenstURL:e,spsUrl:c}]]);a("div.locsports1").async(b,["localsports",[{sportsStubURL:"ajax/localsports.aspx?SportsArea=",sportsURL:f,spsUrl:c,ldsStubURL:"ajax/localdata.aspx?zip="}]]);a("div.lmlsf1").async(b,["localMoreLinksSimpleForm",[{link1Text:"News",link2Text:"Sports",link3Text:"Events",link1Url:"httpdisabled://local.msn.com/news.aspx?zip={0}&q={0}",link2Url:f,link3Url:e}]]);a("voidnew").async(b,[voidNew",[{asyncp:1}]]);a("#foot .secondary a").eq(4)voidNew();a("#bing_dsp a")voidNew();a("#dhp1").dhpPromo();a(".exphd .wlcard1 ul li.last").before("<li class='tolatino'><a href='http://latino.msn.com'>Latino</a></li>");a("#srchfrm, #footersrchfrm, .wlcard1 li:eq(2) a").scrollBind("appendQueryParam",[{pc:/^[A-Za-z0-9]{1,10}$/g}])}var c={sm:function(){}};if(location.href.match(/[?&]ll=0(&|$)/i))c.sm=function(b){a.fireAndForget("httpdisabled://col.stj.s-msn.com/br/sc/i/f8/614595fba50d96389708a4135776e4.gif?loc="+b+"&ts="+(new Date).getTime())};c.sm("ab1");a(window).loaddisabled(function(){c.sm("onloaddisabled");setTimeout(function(){c.sm("ab2")},2e3)});a("#makebing").click(function(a){try{window.external.AddSearchProvider("httpdisabled://www.bing.com/s/osd3.xml");a.preventDefault()}catch(b){}});a(d).bind("LLError",function(c,e){a(d).unbind("LLError");var b="LL Error ";switch(e){case 1:b+="Ajax";break;case 2:b+="Parse";break;case 3:b+="Timeout";break;case 4:b+="Content";break;default:b+="Undefined"}a.track.trackEvent(c,0,0,b)});a("#q").attr("autocomplete","off");a(function(){c.sm("dom_r");e()});c.sm("cbc_end");var g="mh".getCookie();if(g=="ASUS"&&/^[^?#]*www\.msn\.com[/?#]/.test(location)){"mh".setCookie("MSFT",30,".msn.com","/");a(d).bind("mhreset",a.track.trackEvent).trigger("mhreset")}})(jQuery)//]]></script><script type="text/javascript">/*<![CDATA[*/(function(a){var c="domcomp",b="cbcomp";if(a.track&&a.track.trackEvent){a(document).bind(c,a.track.trackEvent).trigger(c);a(function(){a.async("asyncCanary",function(){a(document).bind(b,a.track.trackEvent).trigger(b)})})}})(jQuery);//]]></script></body></html>
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/images/loader.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/images/loader.gif
deleted file mode 100755
index 31220d267..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/images/loader.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/images/twitter_logo_header.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/images/twitter_logo_header.png
deleted file mode 100755
index f681f040e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/images/twitter_logo_header.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/javascripts/lib/jquery.tipsy.min.js@1302114648 b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/javascripts/lib/jquery.tipsy.min.js@1302114648
deleted file mode 100755
index 2ff318143..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/javascripts/lib/jquery.tipsy.min.js@1302114648
+++ /dev/null
@@ -1,3 +0,0 @@
-//Licensed under The MIT License
-//Copyright (c) 2008 Jason Frame (jason@onehackoranother.com)
-(function($){$.fn.tipsy=function(g){g=$.extend({fade:false,gravity:'n'},g||{});if(!g['offsetTop']){g['offsetTop']=0}if(!g['offsetLeft']){g['offsetLeft']=0}if(!g['header']){g['header']=''}if(!g['footer']){g['footer']=''}if(!g['hideTimeout']){g['hideTimeout']=100}if(!g['showTimeout']){g['hideTimeout']=0}if(!g['additionalCSSClass']){g['additionalCSSClass']=''}var h=false;var i=null,cancelHide=false;this.hover(function(){var a=$(this).text();var b=g['header'].replace('%{link}',a);var c=g['footer'].replace('%{link}',a);$.data(this,'cancel.tipsy',true);var d=$.data(this,'active.tipsy');if(!d){$('.tipsy').hide();d=$('<div class="tipsy '+g['additionalCSSClass']+'"><div class="tipsy-inner">'+b+$(this).attr('title')+c+'</div></div>');d.css({position:'absolute',zIndex:100000});$(this).attr('title','');$.data(this,'active.tipsy',d)}else if($(this).attr('title')!=''){d.find('.tipsy-inner').html($(this).attr('title'));$(this).attr('title','')}var e=$.extend({},$(this).offset(),{width:this.offsetWidth,height:this.offsetHeight});e.top=e.top+g['offsetTop'];e.left=e.left+g['offsetLeft'];$('.tipsy').hide();d.remove().css({top:0,left:0,visibility:'hidden',display:'block'}).appendTo(document.body);var f=d[0].offsetWidth,actualHeight=d[0].offsetHeight;switch(g.gravity.charAt(0)){case'n':d.css({top:e.top+e.height,left:e.left+e.width/2-f/2}).addClass('tipsy-north');break;case'l':d.css({top:e.top+e.height,left:e.left+e.width/2-18}).addClass('tipsy-north');break;case's':d.css({top:e.top-actualHeight,left:e.left+e.width/2-f/2}).addClass('tipsy-south');break;case'e':d.css({top:e.top+e.height/2-actualHeight/2,left:e.left-f}).addClass('tipsy-east');break;case'w':d.css({top:e.top+e.height/2-actualHeight/2,left:e.left+e.width}).addClass('tipsy-west');break}function show(){if(g.fade){d.css({opacity:0,display:'block',visibility:'visible'}).animate({opacity:1})}else{d.css({visibility:'visible'})}}if(g['showTimeout']){h=setTimeout(show,g['showTimeout'])}else{show()}},function(){clearTimeout(h);$.data(this,'cancel.tipsy',false);var b=this;setTimeout(function(){if($.data(this,'cancel.tipsy'))return;var a=$.data(b,'active.tipsy');if(g.fade){a.stop().fadeOut(function(){$(this).remove()})}else{a.remove()}},g['hideTimeout'])})}})(jQuery);
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/javascripts/lib/mustache.js@1302114648 b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/javascripts/lib/mustache.js@1302114648
deleted file mode 100755
index 7072caa30..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/a/1302214109/javascripts/lib/mustache.js@1302114648
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- mustache.js — Logic-less templates in JavaScript
-
- See http://mustache.github.com/ for more info.
-*/
-
-var Mustache = function() {
- var Renderer = function() {};
-
- Renderer.prototype = {
- otag: "{{",
- ctag: "}}",
- pragmas: {},
- buffer: [],
- pragmas_implemented: {
- "IMPLICIT-ITERATOR": true,
- "TRANSLATION-HINT": true
- },
- context: {},
-
- render: function(template, context, partials, in_recursion) {
- // reset buffer & set context
- if(!in_recursion) {
- this.context = context;
- this.buffer = []; // TODO: make this non-lazy
- }
-
- // fail fast
- if(!this.includes("", template)) {
- if(in_recursion) {
- return template;
- } else {
- this.send(template);
- return;
- }
- }
-
- // Branching or moving down the partial stack, save any translation mode info.
- if (this.pragmas['TRANSLATION-HINT']) {
- context['_TRANSLATION-HINT_mode'] = this.pragmas['TRANSLATION-HINT'].mode;
- }
-
- // get the pragmas together
- template = this.render_pragmas(template);
-
- // handle all translations
- template = this.render_i18n(template, context, partials);
-
- // render the template
- var html = this.render_section(template, context, partials);
-
- // render_section did not find any sections, we still need to render the tags
- if (html === false) {
- html = this.render_tags(template, context, partials, in_recursion);
- }
-
- if (in_recursion) {
- return html;
- } else {
- this.sendLines(html);
- }
- },
-
- /*
- Sends parsed lines
- */
- send: function(line) {
- if(line != "") {
- this.buffer.push(line);
- }
- },
-
- sendLines: function(text) {
- if (text) {
- var lines = text.split("\n");
- for (var i = 0; i < lines.length; i++) {
- this.send(lines[i]);
- }
- }
- },
-
- /*
- Looks for %PRAGMAS
- */
- render_pragmas: function(template) {
- // no pragmas
- if(!this.includes("%", template)) {
- return template;
- }
-
- var that = this;
- var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
- this.ctag);
- return template.replace(regex, function(match, pragma, options) {
- if(!that.pragmas_implemented[pragma]) {
- throw({message:
- "This implementation of mustache doesn't understand the '" +
- pragma + "' pragma"});
- }
- that.pragmas[pragma] = {};
- if(options) {
- var opts = options.split("=");
- that.pragmas[pragma][opts[0]] = opts[1];
- }
- return "";
- // ignore unknown pragmas silently
- });
- },
-
- /*
- Tries to find a partial in the curent scope and render it
- */
- render_partial: function(name, context, partials) {
- name = this.trim(name);
- if(!partials || partials[name] === undefined) {
- throw({message: "unknown_partial '" + name + "'"});
- }
- if(typeof(context[name]) != "object") {
- return this.render(partials[name], context, partials, true);
- }
- return this.render(partials[name], context[name], partials, true);
- },
-
- render_i18n: function(html, context, partials) {
- if (html.indexOf(this.otag + "_i") == -1) {
- return html;
- }
- var that = this;
- var regex = new RegExp(this.otag + "\\_i" + this.ctag +
- "\\s*([\\s\\S]+?)" + this.otag + "\\/i" + this.ctag, "mg");
-
- // for each {{_i}}{{/i}} section do...
- return html.replace(regex, function(match, content) {
- var translationMode;
-
- if (that.pragmas && that.pragmas["TRANSLATION-HINT"] && that.pragmas["TRANSLATION-HINT"].mode) {
- translationMode = that.pragmas["TRANSLATION-HINT"].mode;
- } else if (context['_TRANSLATION-HINT_mode']) {
- translationMode = context['_TRANSLATION-HINT_mode'];
- }
-
- var params = content;
-
- if (translationMode) {
- params = {
- text: content,
- mode: translationMode
- };
- }
-
- return _(params);
- });
- },
-
- /*
- Renders inverted (^) and normal (#) sections
- */
- render_section: function(template, context, partials) {
- if(!this.includes("#", template) && !this.includes("^", template)) {
- // did not render anything, there were no sections
- return false;
- }
-
- var that = this;
-
- // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder
- var regex = new RegExp(
- "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1)
-
- this.otag + // {{
- "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3)
- this.ctag + // }}
-
- "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped
-
- this.otag + // {{
- "\\/\\s*\\3\\s*" + // /foo (backreference to voiding tag).
- this.ctag + // }}
-
- "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped.
-
- "g");
-
- // for each {{#foo}}{{/foo}} section do...
- return template.replace(regex, function(match, before, type, name, content, after) {
- // before contains only tags, no sections
- var renderedBefore = before ? that.render_tags(before, context, partials, true) : "",
-
- // after may contain both sections and tags, so use full rendering function
- renderedAfter = after ? that.render(after, context, partials, true) : "";
-
- var value = that.find(name, context);
- if(type == "^") { // inverted section
- if(!value || that.is_array(value) && value.length === 0) {
- // false or empty list, render it
- return renderedBefore + that.render(content, context, partials, true) + renderedAfter;
- } else {
- return renderedBefore + "" + renderedAfter;
- }
- } else if(type == "#") { // normal section
- if(that.is_array(value)) { // Enumerable, Let's loop!
- return renderedBefore + that.map(value, function(row) {
- return that.render(content, that.create_context(row), partials, true);
- }).join("") + renderedAfter;
- } else if(that.is_object(value)) { // Object, Use it as subcontext!
- return renderedBefore + that.render(content, that.create_context(value),
- partials, true) + renderedAfter;
- } else if(typeof value === "function") {
- // higher order section
- return renderedBefore + value.call(context, content, function(text) {
- return that.render(text, context, partials, true);
- }) + renderedAfter;
- } else if(value) { // boolean section
- return renderedBefore + that.render(content, context, partials, true) + renderedAfter;
- } else {
- return renderedBefore + "" + renderedAfter;
- }
- }
- });
- },
-
- /*
- Replace {{foo}} and friends with values from our view
- */
- render_tags: function(template, context, partials, in_recursion) {
- // tit for tat
- var that = this;
-
- var new_regex = function() {
- return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
- that.ctag + "+", "g");
- };
-
- var regex = new_regex();
- var tag_replace_callback = function(match, operator, name) {
- switch(operator) {
- case "!": // ignore comments
- return "";
- case "=": // set new delimiters, rebuild the replace regexp
- that.set_delimiters(name);
- regex = new_regex();
- return "";
- case ">": // render partial
- return that.render_partial(name, context, partials);
- case "{": // the triple mustache is unescaped
- return that.find(name, context);
- default: // escape the value
- return that.escape(that.find(name, context));
- }
- };
- var lines = template.split("\n");
- for(var i = 0; i < lines.length; i++) {
- lines[i] = lines[i].replace(regex, tag_replace_callback, this);
- if(!in_recursion) {
- this.send(lines[i]);
- }
- }
-
- if(in_recursion) {
- return lines.join("\n");
- }
- },
-
- set_delimiters: function(delimiters) {
- var dels = delimiters.split(" ");
- this.otag = this.escape_regex(dels[0]);
- this.ctag = this.escape_regex(dels[1]);
- },
-
- escape_regex: function(text) {
- // thank you Simon Willison
- if(!arguments.callee.sRE) {
- var specials = [
- '/', '.', '*', '+', '?', '|',
- '(', ')', '[', ']', '{', '}', '\\'
- ];
- arguments.callee.sRE = new RegExp(
- '(\\' + specials.join('|\\') + ')', 'g'
- );
- }
- return text.replace(arguments.callee.sRE, '\\$1');
- },
-
- /*
- find `name` in current `context`. That is find me a value
- from the view object
- */
- find: function(name, context) {
- name = this.trim(name);
-
- // Checks whether a value is thruthy or false or 0
- function is_kinda_truthy(bool) {
- return bool === false || bool === 0 || bool;
- }
-
- var value;
- if(is_kinda_truthy(context[name])) {
- value = context[name];
- } else if(is_kinda_truthy(this.context[name])) {
- value = this.context[name];
- }
-
- if(typeof value === "function") {
- return value.apply(context);
- }
- if(value !== undefined) {
- return value;
- }
- // silently ignore unkown variables
- return "";
- },
-
- // Utility methods
-
- /* includes tag */
- includes: function(needle, haystack) {
- return haystack.indexOf(this.otag + needle) != -1;
- },
-
- /*
- Does away with nasty characters
- */
- escape: function(s) {
- s = String(s === null ? "" : s);
- return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
- switch(s) {
- case "&": return "&amp;";
- case "\\": return "\\\\";
- case '"': return '&quot;';
- case "'": return '&#39;';
- case "<": return "&lt;";
- case ">": return "&gt;";
- default: return s;
- }
- });
- },
-
- // by @langalex, support for arrays of strings
- create_context: function(_context) {
- if(this.is_object(_context)) {
- return _context;
- } else {
- var iterator = ".";
- if(this.pragmas["IMPLICIT-ITERATOR"]) {
- iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
- }
- var ctx = {};
- ctx[iterator] = _context;
- return ctx;
- }
- },
-
- is_object: function(a) {
- return a && typeof a == "object";
- },
-
- is_array: function(a) {
- return Object.prototype.toString.call(a) === '[object Array]';
- },
-
- /*
- Gets rid of leading and trailing whitespace
- */
- trim: function(s) {
- return s.replace(/^\s*|\s*$/g, "");
- },
-
- /*
- Why, why, why? Because IE. Cry, cry cry.
- */
- map: function(array, fn) {
- if (typeof array.map == "function") {
- return array.map(fn);
- } else {
- var r = [];
- var l = array.length;
- for(var i = 0; i < l; i++) {
- r.push(fn(array[i]));
- }
- return r;
- }
- }
- };
-
- return({
- name: "mustache.js",
- version: "0.3.1-dev-twitter",
-
- /*
- Turns a template and view into HTML
- */
- to_html: function(template, view, partials, send_fun) {
- var renderer = new Renderer();
- if(send_fun) {
- renderer.send = send_fun;
- }
- renderer.render(template, view || {}, partials);
- if(!send_fun) {
- return renderer.buffer.join("\n");
- }
- }
- });
-}();
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1129087853/151aec2f-1534-4f61-9f3e-1e787cb51a8b_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1129087853/151aec2f-1534-4f61-9f3e-1e787cb51a8b_mini.png
deleted file mode 100755
index daa825d60..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1129087853/151aec2f-1534-4f61-9f3e-1e787cb51a8b_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1139176116/5c42a320-1e91-4d89-a034-0f140d2f23ba_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1139176116/5c42a320-1e91-4d89-a034-0f140d2f23ba_mini.png
deleted file mode 100755
index f336453d3..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1139176116/5c42a320-1e91-4d89-a034-0f140d2f23ba_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1277610502/Untitled-9_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1277610502/Untitled-9_mini.jpg
deleted file mode 100755
index 586f3a2ac..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/1277610502/Untitled-9_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/316019228/326994260_1117936370_0_mini.jpeg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/316019228/326994260_1117936370_0_mini.jpeg
deleted file mode 100755
index 0d324633e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/316019228/326994260_1117936370_0_mini.jpeg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/81990615/nightexterior-1_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/81990615/nightexterior-1_mini.jpg
deleted file mode 100755
index 808e14507..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/81990615/nightexterior-1_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/959692632/13659_1215732676789_1332990286_30703899_6344768_n_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/959692632/13659_1215732676789_1332990286_30703899_6344768_n_mini.jpg
deleted file mode 100755
index dc33e0af2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/profile_images/959692632/13659_1215732676789_1332990286_30703899_6344768_n_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/sticky/default_profile_images/default_profile_4_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/sticky/default_profile_images/default_profile_4_mini.png
deleted file mode 100755
index f38de2578..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a0.twimg.com/sticky/default_profile_images/default_profile_4_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/favicon.ico b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/favicon.ico
deleted file mode 100755
index 00450d4fe..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/icon_lock.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/icon_lock.gif
deleted file mode 100755
index 53e664140..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/icon_lock.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/reject_small.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/reject_small.gif
deleted file mode 100755
index d346a0da4..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/reject_small.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/spinner.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/spinner.gif
deleted file mode 100755
index 6e5bace6e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/spinner.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/sprite-icons.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/sprite-icons.png
deleted file mode 100755
index a93cede94..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/sprite-icons.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/toggle_down_dark.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/toggle_down_dark.png
deleted file mode 100755
index f3fd0f4b1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/images/toggle_down_dark.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/javascripts/dismissable.js@1302114648 b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/javascripts/dismissable.js@1302114648
deleted file mode 100755
index 605865ff9..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/javascripts/dismissable.js@1302114648
+++ /dev/null
@@ -1 +0,0 @@
-(function(A){A.fn.dismissable=function(B){var D=A(this);var C={authenticity_token:twttr.form_authenticity_token,_method:"put"};C["user["+B.userAttribute+"]"]="1";D.find("a.dismiss").click(function(){D.hide();A.ajax({type:"POST",url:B.userUrl,data:C});return false});return this}})(jQuery); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/stylesheets/following.css@1302114648.css b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/stylesheets/following.css@1302114648.css
deleted file mode 100755
index 49f2f3f50..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/a/1302214109/stylesheets/following.css@1302114648.css
+++ /dev/null
@@ -1 +0,0 @@
-body #content h2,body #content h2{font:18px 'Helvetica',sans-serif;font-weight:bold;color:#000;margin-left:10px;}.profile-user,body#profile div.section,body#profile_favorites div.section{padding:0 10px;}.profile-user h2.thumb{clear:both;float:none;padding:10px 0;line-height:1.25em;}.profile-user h2 img{float:left;}.profile-user h2 div{margin-left:65px;}#follow h2 img{margin-right:5px;}#follow h2 small{font:11px 'Lucida Grande',Arial,sans-serif;font-weight:normal;}.protected-profile-controls .profile-controls{height:23px;}#friend_requests h2.heading form{float:right;}body#friend_requests.ie7 h2.heading form{margin-top:-15px;padding-right:8px;}.denied-follow-request{float:right;padding-left:30px;background:transparent url(../images/reject_small.gif) no-repeat 0 center;margin:5px -100px 0 0;}.subpage #content ul.ctrlbar{padding:8px 10px;background-color:#f6f6f6;clear:both;float:none;}.wrapper{padding:15px;}#content div.section{padding:0;}#content div.section ul li{padding:0;}#content div.section ul.ctrlbar li{margin-right:4px;position:static;}.ctrlbar li{display:inline-block;margin-right:4px;position:relative;}.ctrlbar a{display:inline-block;vertical-align:middle;outline:none;padding:3px 4px;border:1px solid transparent;}.ctrlbar a i{display:block;overflow:hidden;width:13px;height:13px;background-image:url(../images/sprite-icons.png);background-repeat:no-repeat;}.ctrlbar a.expanded i{background-position:-1px -81px;}.follow-expanded .ctrlbar a.expanded,.follow-compact .ctrlbar a.compact{background-color:#fff;border-color:#ccc;}.ctrlbar a.compact i{background-position:-17px -81px;}#follow_grid table{margin-top:10px;width:100%;border-collapse:collapse;}#follow_grid tr{font:12px 'Lucida Grande',Arial,sans-serif;color:#333;border-bottom:1px solid #eee;}#follow_grid tr .is-blocked{position:static;}#follow_grid tr.even td{background-color:transparent;}#follow_grid tr:hover td{background-color:#f6f6f6;}#follow_grid th{font:11px 'Lucida Grande',Arial,sans-serif;color:#999;}#follow_grid th,#follow_grid td{padding:10px;vertical-align:top;}#follow_grid th{padding-bottom:6px;}#follow_grid th.actions-header,#follow_grid th.settings-header{text-align:right;}#follow_grid td.thumb{padding-right:0;}.user i{display:inline-block;width:13px;height:13px;background-image:url(../images/sprite-icons.png);background-repeat:no-repeat;overflow:hidden;outline:none;}#follow_grid .thumb{height:50px;width:50px;}#follow_grid .thumb img{width:50px;height:50px;}.user .user-detail{font:11px 'Lucida Grande',Arial,sans-serif;line-height:16px;width:225px;}#follow_grid td.user-detail{padding-right:0;}#follow_grid td.thumb{width:10%;}.protected .screenname{padding-right:12px;background:transparent url(../images/icon_lock.gif) no-repeat 100% 30%;}.verified-icon{vertical-align:top;padding:2px;}.user .user-detail address{position:relative;}.user .screenname{font:15px 'Helvetica';font-weight:bold;}.user .fullname,.user .location,.user .user-body{color:#666;}.user .user-body{display:block;overflow:hidden;width:265px;color:#666;}.user .user-detail strong{color:#333;}.user .user-body em{font-style:normal;}.user .currently em{white-space:nowrap;}.blocked-user,.blocked-user:hover,.blocked-user .screenname,.blocked-user .user-body,.blocked-user .user-body strong,.blocked-user .user-body:hover{background-color:#f2f2f2;color:#666;width:100%;}.user .is-following,.user .is-blocked,.user .is-pending{display:none;padding-left:.5em;}#container .following .is-following,#container .blocking .is-blocked,#container .pending .is-pending{display:inline-block;}.blocking .is-pending{display:none;}#follow_grid .is-following,#follow_grid .is-blocked,#follow_grid .is-pending{position:absolute;top:0;right:0;}.profile-user .is-following,.profile-user .is-blocked,.profile-user .is-pending{padding-left:0;}.user .is-following i,.user .is-blocked i,.user .is-pending i{height:9px;width:10px;margin-right:5px;}.profile-user .is-following i,.profile-user .is-blocked i,.profile-user .is-pending i{height:13px;width:15px;position:relative;top:1px;}.user .is-following i{background-position:-160px -16px;}.user .is-blocked i{background-position:-224px -16px;}.user .is-pending i{background-position:-192px -16px;}.profile-user .user .is-following i{background-position:-144px -16px;}.profile-user .user .is-blocked i{background-position:-208px -16px;}.profile-user .user .is-pending i{background-position:-176px -16px;}#follow_grid .user:hover .fullname,#follow_grid .user:hover .location,#follow_grid .user:hover .user-body{color:#333;}#follow_grid .user-actions-outer,#follow_grid.follow-compact .user-actions-outer{width:90px;padding-right:10px;}.current-user-following-page .user-actions-outer{width:40px;}#follow_grid .user-settings{width:80px;float:right;}#follow_grid .blocked-user:hover .user-body{color:#666;}.profile-user ul.user-settings{float:left;margin-left:10px;}#follow_grid .user-actions-outer,#follow_grid .user-settings-outer{text-align:right;}ul.user-settings>li{display:none;position:static;}.profile-user ul.user-settings>li{margin:0;}#follow_grid .following ul.user-settings>li,.profile-user .following ul.user-settings>li{display:inline-block;}ul.user-actions>li{display:inline-block;}ul.user-settings>li>a,ul.user-actions>li>a{display:inline-block;width:16px;height:16px;background-repeat:no-repeat;overflow:hidden;cursor:pointer;background-image:url(../images/sprite-icons.png);text-decoration:none;margin-right:3px;outline:none;position:relative;}ul.user-settings>li>a{margin-top:4px;}.profile-user ul.user-settings>li a{margin-right:0;}.user-settings li.sms-setting a.on{background-position:-64px -48px;}.is-blocked .learn-more{font-size:11px;margin-left:3px;}#follow_grid .user:hover .user-settings li.sms-setting a.on,.profile-user .user-settings li.sms-setting a.on{background-position:-48px -48px;}.user-settings li.sms-setting a.off{background-position:-80px -48px;}#follow_grid .user:hover .user-settings li.sms-setting a.off,.profile-user .user-settings li.sms-setting a.off{background-position:-160px -48px;}.user-settings li.replies-setting a.on{background-position:-16px -48px;}#follow_grid .user:hover .user-settings li.replies-setting a.on,.profile-user .user-settings li.replies-setting a.on{background-position:0 -48px;}.user-settings li.replies-setting a.off{background-position:-32px -48px;}#follow_grid .user:hover .user-settings li.replies-setting a.off,.profile-user .user-settings li.replies-setting a.off{background-position:-144px -48px;}.user-settings li.shares-setting a.on{background-position:-112px -48px;}.user:hover .user-settings li.shares-setting a.on,.profile-user .user-settings li.shares-setting a.on{background-position:-96px -48px;}.user-settings li.shares-setting a.off{background-position:-128px -48px;}.user:hover .user-settings li.shares-setting a.off,.profile-user .user-settings li.shares-setting a.off{background-position:-176px -48px;}.user .user-actions i{display:block;width:15px;}#follow_grid .user-actions .follow-action button{width:29px;}.profile-user .user-actions .follow-action button i{float:left;margin:0 5px 0 0;}.user-actions button{height:25px;}.current-user-following-page .user-actions .follow-action button{display:inline-block;}#follow_grid .pending .user-actions .follow-action button,.profile-user .pending .user-actions .follow-action button,#follow_grid .following .user-actions .follow-action button,.profile-user .following .user-actions .follow-action button,#follow_grid .blocking .user-actions .follow-action button,.profile-user .blocking .user-actions .follow-action button,#follow_grid .current-user-following-page .following .user-actions .follow-action button{display:none;}.user-actions .follow-action button i{display:block;background-position:-160px -32px;margin:0 4px;}#follow_grid .user:hover .user-actions .follow-action button i,.profile-user .user .user-actions .follow-action button i{background-position:-176px -32px;}.user-actions .action-menu{vertical-align:top;}.profile-controls .followed-by{margin-top:4px;text-align:left;font-size:11px;}.profile-controls .followed-by hr{color:#F6F6F6;background:#F6F6F6;border:0 solid #F6F6F6;border-top:1px solid #eee;border-bottom:1px solid #fff;height:0;margin:0 0 5px 0;display:block;}.profile-controls .followed-by label{color:#666;}.user-actions .action-menu button{width:36px;}.user-actions .action-menu button i{display:block;background-position:0 -64px;width:22px;margin:1px 7px;}#follow_grid .user:hover .user-actions .action-menu button i,.profile-user .user .user-actions .action-menu button i,.user-actions .action-menu button.clicked i{background-position:-32px -64px;}#follow_grid .user .user-actions .accept-action button,#follow_grid .user .user-actions .deny-action button{color:#aaa;margin-right:3px;}#follow_grid .user:hover .user-actions .accept-action button,#follow_grid .user:hover .user-actions .deny-action button{color:#333;}#friend_requests td.thumb{width:5px!important;padding-right:0;}#friend_requests td.user-detail{width:500px;}#friend_requests td.user-actions-outer{width:200px!important;}#friend_requests .user .user-body{width:400px;}body#friend_requests.ie7 #follow_grid table tr td{border-bottom:1px solid #eee!important;}body#friend_requests.ie7 td.user-actions-outer ul{width:190px;display:inline;}body#friend_requests.ie7 td.user-actions-outer ul li{float:left!important;}body#friend_requests.ie8 #follow_grid th.name-header{text-align:left!important;}body#friend_requests #follow_grid.empty{height:300px;}#follow_requests_all{color:#ccc;}.user-actions .menu button.clicked{background-image:none;}.user-actions .menu ul{display:none;position:absolute;width:200px;margin-top:-1px;padding:4px 0;text-align:left;border:1px solid #666;background-color:#fff;z-index:9999;}.user-actions .menu ul li a,.user-actions .menu ul li label,.user-actions .menu ul li input[type="checkbox"]{display:inline-block;font:11px 'Lucida Grande',Arial,sans-serif;color:#666;position:relative;padding:4px 5px;vertical-align:top;}.user-actions .menu ul li .loaddisableding-spinner{display:inline-block;position:relative;top:4px;left:1px;margin-left:4px;}.user-actions .action-menu ul li a{padding:4px 5px 4px 27px;}.user-actions .menu ul li a{display:block;color:#666;text-decoration:none;}.user-actions .menu ul li:hover{color:#fff;background-color:#666;}.user-actions .menu ul li:hover *{color:#fff;}.user-actions .menu ul li.divider{border-top:1px solid #ddd;}.user-actions .menu ul a i{position:absolute;left:7px;top:4px;width:15px;}.user-actions .mention i{background-position:-16px -32px;}.user-actions .mention:hover i{background-position:0 -32px;}.user-actions .direct-message i{background-position:-48px -32px;}.user-actions .direct-message:hover i{background-position:-32px -32px;}.user-actions .follow i{background-position:-176px -32px;}.user-actions .follow:hover i{background-position:-160px -32px;}.current-user-following-page .user-actions .follow{display:none;}.user-actions .remove i{background-position:-208px -32px;}.user-actions .remove:hover i{background-position:-192px -32px;}.user-actions .unfollow i{background-position:-112px -32px;}.user-actions .unfollow:hover i{background-position:-96px -32px;}.user-actions .block i{background-position:-144px -32px;}.user-actions .report-for-spam i{background-position:-272px -32px;}.user-actions .report-for-spam:hover i{background-position:-256px -32px;}.user-actions .block:hover i{background-position:-128px -32px;}.user-actions .unblock i{background-position:-144px -32px;}.user-actions .unblock:hover i{background-position:-128px -32px;}.user-actions .unfollow,.user-actions .unblock,.user-actions .direct-message,.user-actions .nudge,.pending .user-actions .follow,#follow_grid .following .user-actions .follow,.profile-user .following .user-actions .follow,.blocking .user-actions .block,.blocking .user-actions .report-for-spam,#friend_requests .follow-request .user-actions .mention,#friend_requests .follow-request .user-actions .direct-message{display:none;}#follow_grid .following .user-actions .unfollow,.profile-user .following .user-actions .unfollow,.direct-messageable .user-actions .direct-message,.blocking .user-actions .unblock{display:block;}.sidebar-actions.blocked .unblock-sidebar-action,.sidebar-actions.unblocked .block-sidebar-action,.sidebar-actions.unblocked .report-for-spam-sidebar-action{display:block;}.sidebar-actions.unblocked .unblock-sidebar-action,.sidebar-actions.blocked .block-sidebar-action,.sidebar-actions.blocked .report-for-spam-sidebar-action{display:none;}#follow_grid.follow-compact td{padding:4px 0 4px 10px;vertical-align:middle;}#follow_grid.follow-compact .thumb{height:24px;width:1%;padding-left:10px;}#follow_grid.follow-compact .thumb img{width:24px;height:24px;}#follow_grid.follow-compact .fullname{padding-left:.25em;}#follow_grid.follow-compact td.user-detail{line-height:16px;}#follow_grid.follow-compact .user-detail br,#follow_grid.follow-compact .location,#follow_grid.follow-compact .user-body{display:none;}#follow_grid td.user-actions,#follow_grid td.user-settings{padding-right:10px;}#pagination.pagination{padding:0 10px;}#similar-wrapper{padding:15px;}body.safari .user-actions .action-menu button{padding-top:5px;}body.safari .user-actions .action-menu button i{margin:0 -2px;}body.safari #follow_grid .user-actions .follow-action button i{margin:0 -2px;}body.safari .user-actions .menu ul li .loaddisableding-spinner{margin-right:-1px;}body.ie7 .profile-controls{zoom:1;}body.ie7 .ctrlbar li{float:left;}body.ie7 #content ul.ctrlbar{height:24px;background-color:#f6f6f6;}body.ie7 .user-detail{width:275px;}body.ie7 .user-actions{text-align:right;width:70px;}body.ie7 .profile-user .user-actions{width:100%;}body.ie7 .profile-user .following .user-actions{width:auto;}body.ie7 .profile-user .follow-action button.btn{width:75px;}body.ie7 .profile-user .is-following i{margin:2px 5px 2px 0;}body.ie7 .user-actions-outer{display:inline-block;}body.ie7 .profile-user .user-settings{margin-top:1px;}body.ie7 .profile-user .user-settings li{float:left;}body.ie7 .user-settings li a{margin-right:4px;}body.ie7 ul.user-actions>li.follow-action{float:left;}body.ie7 ul.user-actions>li.follow-action button{padding:3px 8px;}body.ie7 ul.user-actions>li.action-menu,body.firefox2 ul.user-actions>li.action-menu{float:right;}body.ie7 ul.user-actions>li>button{height:24px;}body.ie7 .user-actions .action-menu button{width:36px;margin-right:-2px;}body.ie7 .user-actions .action-menu ul{margin-top:22px;margin-left:-34px;}body.ie7 .user-actions button i,body.ie8 .user-actions button i{margin:0 -1px;}body.firefox2 .profile-user .profile-controls{height:2em;}body.firefox2 .profile-user .user-actions{width:100%;}body.firefox2 .profile-user .following .user-actions{width:auto;}body.firefox2 .following .is-following,body.firefox2 .blocking .is-blocked,body.firefox2 .pending .is-pending{display:block;}body.firefox2 #follow_grid .following ul.user-settings>li,body.firefox2 .profile-user .following ul.user-settings>li{display:block;float:left;}body.firefox2 #follow_grid .following ul.user-settings>li a,body.firefox2 .profile-user .following ul.user-settings>li a{display:block;margin-right:4px;}body.firefox2 .user .is-following i{display:block;float:left;margin:4px 5px 4px 0;}body.firefox2 .profile-user .user .is-following i{margin:5px 5px 5px 0;}body.firefox2 #follow_grid .is-following,body.firefox2 #follow_grid .is-blocked,body.firefox2 #follow_grid .is-pending{top:2px;}body.firefox2 #content ul.ctrlbar{height:24px;background-color:#f6f6f6;}body.firefox-windows .ctrlbar li{float:left;}body.firefox-windows .ctrlbar li a{display:block;}body.firefox2 .user-actions{text-align:right;width:70px;}body.firefox2 ul.user-actions>li.follow-action{float:left;}body.firefox2 ul.user-actions>li.action-menu{float:right;}body.firefox2 .user-actions .action-menu button,width:36px;margin-right:-2px;}body.opera .user-actions .follow-action button i{margin-left:-4px;}body.opera .user-actions .action-menu button i{margin-left:-3px;}body.opera .user-actions .action-menu ul{margin-top:10px;}body.chrome .user-actions .action-menu button{padding-top:5px;}body.chrome .user-actions .action-menu button i{margin:0 -2px;}body.chrome .user-actions .follow-action button i{margin:0!important;}body.ie8 .ctrlbar a:hover,body.safari .ctrlbar a:hover,body.firefox .ctrlbar a:hover,body.firefox_win .ctrlbar a:hover,body.firefox_2 .ctrlbar a:hover{background-color:#fff;border-color:#ccc;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/1239180764/GlassblowerX_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/1239180764/GlassblowerX_mini.jpg
deleted file mode 100755
index 4c33d429a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/1239180764/GlassblowerX_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/1248229613/redsugarskullnecklace4-pola_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/1248229613/redsugarskullnecklace4-pola_mini.jpg
deleted file mode 100755
index 6f135e4c8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/1248229613/redsugarskullnecklace4-pola_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/333032766/5600_106787006838_550741838_2009237_6385345_n_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/333032766/5600_106787006838_550741838_2009237_6385345_n_mini.jpg
deleted file mode 100755
index 8bad69637..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/333032766/5600_106787006838_550741838_2009237_6385345_n_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/754757071/rawr_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/754757071/rawr_mini.jpg
deleted file mode 100755
index eed8c3301..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/754757071/rawr_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/874705507/01_3_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/874705507/01_3_mini.jpg
deleted file mode 100755
index a03e86a7b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/874705507/01_3_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/959721336/16869_103046893051833_100000395672538_70559_3952672_n_1__mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/959721336/16869_103046893051833_100000395672538_70559_3952672_n_1__mini.jpg
deleted file mode 100755
index 9559bd342..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a1.twimg.com/profile_images/959721336/16869_103046893051833_100000395672538_70559_3952672_n_1__mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/ajax.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/ajax.gif
deleted file mode 100755
index 16e32a32c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/ajax.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arr-inline-form.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arr-inline-form.gif
deleted file mode 100755
index c75a49c5d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arr-inline-form.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arr2.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arr2.gif
deleted file mode 100755
index 577be1871..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arr2.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arrow_right_dark.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arrow_right_dark.png
deleted file mode 100755
index 4e892821b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/arrow_right_dark.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/bg-btn-blue.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/bg-btn-blue.png
deleted file mode 100755
index 058f726d9..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/bg-btn-blue.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/bg-btn-signup_gold.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/bg-btn-signup_gold.png
deleted file mode 100755
index ba1f78f4e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/bg-btn-signup_gold.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn-bg.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn-bg.gif
deleted file mode 100755
index f14912f0f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn-bg.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_green_arrow.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_green_arrow.gif
deleted file mode 100755
index 15de49eae..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_green_arrow.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_green_arrow_small.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_green_arrow_small.gif
deleted file mode 100755
index 2a0719256..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_green_arrow_small.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_red_small.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_red_small.gif
deleted file mode 100755
index 8d566b514..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/btn_red_small.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-blue.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-blue.gif
deleted file mode 100755
index f3fbf46f6..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-blue.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-chart.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-chart.gif
deleted file mode 100755
index 15dc0d957..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-chart.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-dark.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-dark.gif
deleted file mode 100755
index 4821ae5ad..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-dark.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-green.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-green.gif
deleted file mode 100755
index 24e2603a7..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-green.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-mint.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-mint.gif
deleted file mode 100755
index bea9ab7c5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-mint.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-pink.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-pink.gif
deleted file mode 100755
index abe2f4567..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-pink.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-red.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-red.gif
deleted file mode 100755
index dba831415..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-red.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-yellow.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-yellow.gif
deleted file mode 100755
index fec04bd96..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn-yellow.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn.gif
deleted file mode 100755
index 5d1e16452..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/buttons/bg-btn.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/checkmark.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/checkmark.gif
deleted file mode 100755
index a1e71e6ce..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/checkmark.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/close_small.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/close_small.png
deleted file mode 100755
index f266cef81..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/close_small.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/commercial/garuda-overlay.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/commercial/garuda-overlay.gif
deleted file mode 100755
index 22b502937..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/commercial/garuda-overlay.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/dialog_arrows_sprite.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/dialog_arrows_sprite.gif
deleted file mode 100755
index f3d54033f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/dialog_arrows_sprite.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divider.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divider.png
deleted file mode 100755
index 0392537bc..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divider.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divot.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divot.gif
deleted file mode 100755
index f562d712e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divot.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy-up.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy-up.png
deleted file mode 100755
index e4d2727db..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy-up.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy.gif
deleted file mode 100755
index 273b2d074..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy.png
deleted file mode 100755
index 49c4da5a1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/divvy.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/follow_check.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/follow_check.gif
deleted file mode 100755
index a2fb9e2d5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/follow_check.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_chrome_help_banner_back.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_chrome_help_banner_back.png
deleted file mode 100755
index 959a44154..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_chrome_help_banner_back.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_creation_hint_arrow.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_creation_hint_arrow.gif
deleted file mode 100755
index efb4839a0..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_creation_hint_arrow.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_firefox_help_banner_back.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_firefox_help_banner_back.png
deleted file mode 100755
index 9ffd9751d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_firefox_help_banner_back.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_ie_gtb_help_banner_back.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_ie_gtb_help_banner_back.png
deleted file mode 100755
index a2e56897e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/geo_ie_gtb_help_banner_back.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon-mobile.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon-mobile.gif
deleted file mode 100755
index b2dc6aca5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon-mobile.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_add.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_add.png
deleted file mode 100755
index 2ebf92cf2..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_add.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_direct_reply.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_direct_reply.gif
deleted file mode 100755
index 80b6c30d0..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_direct_reply.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_lock.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_lock.gif
deleted file mode 100755
index 53e664140..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_lock.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_remove.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_remove.png
deleted file mode 100755
index 3a4f1ddc9..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_remove.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_reply.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_reply.gif
deleted file mode 100755
index a4379a70b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_reply.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_throbber.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_throbber.gif
deleted file mode 100755
index fa124c5fb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_throbber.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_trash.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_trash.gif
deleted file mode 100755
index 916a332a3..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/icon_trash.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/inline-media.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/inline-media.png
deleted file mode 100755
index 8c4d15e29..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/inline-media.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/larry-shadowed-big.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/larry-shadowed-big.png
deleted file mode 100755
index bd1e56347..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/larry-shadowed-big.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/lock_icon_small.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/lock_icon_small.png
deleted file mode 100755
index 620828832..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/lock_icon_small.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/more.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/more.gif
deleted file mode 100755
index 8382f19b5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/more.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/nav_search_submit.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/nav_search_submit.png
deleted file mode 100755
index 29e1d0a13..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/nav_search_submit.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/check.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/check.png
deleted file mode 100755
index 1e0188d58..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/check.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_129px.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_129px.png
deleted file mode 100755
index b1d8591a8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_129px.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_146px.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_146px.png
deleted file mode 100755
index 5b99bda01..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_146px.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_170px.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_170px.png
deleted file mode 100755
index d990e2e23..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_170px.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_236px.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_236px.png
deleted file mode 100755
index 7b8b74d49..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/connect_236px.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/gradient-background.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/gradient-background.png
deleted file mode 100755
index 503ab9f10..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/gradient-background.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/rays-box.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/rays-box.jpg
deleted file mode 100755
index bb19d1f61..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/rays-box.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/t_170px.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/t_170px.png
deleted file mode 100755
index 2cce58117..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/oauth2/t_170px.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/petal_spinner.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/petal_spinner.gif
deleted file mode 100755
index 8a1547805..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/petal_spinner.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/retweet/retweet-x.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/retweet/retweet-x.png
deleted file mode 100755
index 7f1f31bd8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/retweet/retweet-x.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/round-btn-hover.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/round-btn-hover.gif
deleted file mode 100755
index d8d6030f1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/round-btn-hover.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/round-btn.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/round-btn.gif
deleted file mode 100755
index f65bb1504..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/round-btn.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/rss.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/rss.gif
deleted file mode 100755
index 0ee61c7cd..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/rss.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/spinner.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/spinner.gif
deleted file mode 100755
index 6e5bace6e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/spinner.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/sprite-icons.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/sprite-icons.png
deleted file mode 100755
index a93cede94..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/sprite-icons.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/sprite-icons.png@v3 b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/sprite-icons.png@v3
deleted file mode 100755
index a93cede94..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/sprite-icons.png@v3
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tables/tablesorter-indicators.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tables/tablesorter-indicators.png
deleted file mode 100755
index af3c40522..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tables/tablesorter-indicators.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/thumb-bird-bw.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/thumb-bird-bw.gif
deleted file mode 100755
index dbe336910..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/thumb-bird-bw.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-east.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-east.gif
deleted file mode 100755
index 697550bdb..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-east.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-north.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-north.gif
deleted file mode 100755
index c22e72b45..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-north.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-south.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-south.gif
deleted file mode 100755
index cd48fcd6e..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-south.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-west.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-west.gif
deleted file mode 100755
index bd51b5706..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/tipsy/tipsy-west.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_closed.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_closed.gif
deleted file mode 100755
index ce8fd78e3..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_closed.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_dark.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_dark.gif
deleted file mode 100755
index 4e0ed3707..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_dark.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_dark.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_dark.png
deleted file mode 100755
index f3fd0f4b1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_dark.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_light.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_light.gif
deleted file mode 100755
index c05d02d70..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_light.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_light.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_light.png
deleted file mode 100755
index d35416159..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_down_light.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_opened.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_opened.gif
deleted file mode 100755
index 3543c3bcf..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_opened.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_up_dark.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_up_dark.gif
deleted file mode 100755
index f1721e884..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_up_dark.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_up_dark.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_up_dark.png
deleted file mode 100755
index 951d903d8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toggle_up_dark.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toptweet-overlay.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toptweet-overlay.gif
deleted file mode 100755
index cd1a0f69c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/toptweet-overlay.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/translator/translator.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/translator/translator.png
deleted file mode 100755
index 4b3a45505..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/translator/translator.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/trendtip-pointer.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/trendtip-pointer.gif
deleted file mode 100755
index adf8e0578..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/trendtip-pointer.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/verified/verified.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/verified/verified.png
deleted file mode 100755
index 19c0ec066..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/verified/verified.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/verified/verified_small.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/verified/verified_small.png
deleted file mode 100755
index b0fdcd4df..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/verified/verified_small.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/warning-sign.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/warning-sign.png
deleted file mode 100755
index 0ef7aa4cf..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/images/warning-sign.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/javascripts/geov1.js@1302114648 b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/javascripts/geov1.js@1302114648
deleted file mode 100755
index 870fdd961..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/javascripts/geov1.js@1302114648
+++ /dev/null
@@ -1 +0,0 @@
-twttr.geo={LOG_VERSION:2,LOCATION_CACHE_INTERVAL:30000,BROWSER_GEO_BANNER_APPEAR_DELAY:500,BROWSER_GEO_BANNER_DISAPPEAR_INTERVAL:100,PLACE_SEARCH_AUTOCOMPLETE_DELAY:250,MAX_NEARBY_PLACES:12,MAX_PLACE_SEARCH_RESULTS:50,MAX_PLACE_AUTOCOMPLETE_RESULTS:8,PLACE_SEARCH_RESULTS_PER_PAGE:5,PLACE_CREATION_ACCURACY_THRESHOLD:500,ACCEPTABLE_LOCATION_ACCURACY:1000,ACCEPTABLE_LOCATION_TIMEOUT:5000,LOCATION_TIMEOUT:25000,LOCATION_MAXIMUM_AGE:60000,MAX_SIMILAR_PLACES:5,GENERIC_PLACE_TYPES:{city:null,neighborhood:null,admin:null,country:null},TARGET_POI_NAME_LENGTH:40,TARGET_PLACE_NAME_LENGTH:50,templates:{dropdownItem:{container:'<li id="place_{{id}}"><span class="place_item_icon">&nbsp;</span><span class="place_noicon">{{formatted_name}}</span></li>',poi:'<li id="place_{{id}}"><span class="place_item_icon">&nbsp;</span><span class="place_icon">&nbsp;</span> {{formatted_name}} <span class="place_details">{{details}}</span></li>'},searchResultItem:{container:'<li id="result_place_{{id}}"><span class="place_noicon"><a href="#">{{formatted_name}}</a></span></li>',poi:'<li id="result_place_{{id}}"><span class="place_icon">&nbsp;</span> <a href="#">{{formatted_name}}</a> <span class="place_details">{{details}}</span></li>'},autocompleteItem:{container:'<li><span class="place_noicon">{{formatted_name}}</span></li>',poi:'<li><span class="place_icon">&nbsp;</span> {{formatted_name}} <span class="place_details">{{details}}</span></li>'},nearbyActivityHeader:{container:'<span><a href="#">{{formatted_name}}</a></span>',poi:'<span><a href="#">{{full_name}} <span class="place_icon">&nbsp;</span></a></span>'},nearbyActivityItem:{container:'<li id="result_place_{{id}}"><a href="#"><span class="place_noicon">{{formatted_name}}</span></a><div class="geo_address">{{details}}</div></li>',poi:'<li id="result_place_{{id}}"><a href="#">{{formatted_name}}&nbsp;<span class="place_icon">&nbsp;</span></a><div class="geo_address">{{details}}</div></li>'}},options:{more_places:false,autocomplete:false,autocomplete_zero_delay:false,place_creation:false,place_creation_needs_high_accuracy:false,allow_set_location_manually:false,show_place_details_in_map:false}};twttr.geo.getBestContainer=function(A){if(!A){return{name:"",full_name:"",contained_within:[],place_type:"city",bounding_box:{type:"Polygon",coordinates:[[[-122.51368188,37.70813196],[-122.35845384,37.70813196],[-122.35845384,37.83245301],[-122.51368188,37.83245301]]]}}}var B={name:A.part_of_name||"",full_name:A.part_of_name||"",contained_within:[],place_type:"city"};if(A.contained_within){A.contained_within.every(function(C){B=C;return C.place_type!="city"})}return B};twttr.geo.getBestCity=function(A){return(A&&A.place_type=="city")?A:twttr.geo.getBestContainer(A)};twttr.geo.getLocationFromPlace=function(A){if(!A||!A.bounding_box||A.bounding_box.type!="Polygon"||!A.bounding_box.coordinates){return null}var B=A.bounding_box.coordinates[0];if(!B||B.length!=4){return null}return{accuracy:500*twttr.geo.greatCircleDistanceInKm(B[0][1],B[0][0],B[2][1],B[2][0]),latitude:(B[0][1]+B[2][1])*0.5,longitude:(B[0][0]+B[2][0])*0.5}};twttr.geo.getPlacePageLinkFromPlace=function(A){return"/search?"+$.param({q:"place:"+A.id,format:"html"})};twttr.geo.getPlacePageLinkAttrsFromPlace=function(A){var C=[A.attributes?A.attributes.street_address:null,A.contained_within&&A.contained_within.length>0?A.contained_within[0].full_name:null].filter(function(D){return D}).join(", ");var B=A.place_type=="poi"?C:A.name+", "+C;return{title:A.full_name,_query:"place:"+A.id,_place_details:C,_place_map_link:"httpdisabled://maps.google.com/maps?"+$.param({q:B})}};twttr.geo.getPlaceDetails=function(A){if(A.attributes&&A.attributes.street_address){return A.attributes.street_address}switch(A.place_type){case"city":return _("a city");case"neighborhood":return _("a neighborhood");case"country":return _("a country");case"admin":return _("a state or province");default:return _("a place")}return twttr.geo.getBestContainer(A).name};twttr.geo.formatPlaceName=function(A,B){if(A.length<=B){return A}A=A.replace(/ [(].*[)]/g,"");if(A.length<=B){return A}var C="...";return A.substr(0,B-C.length)+C};twttr.geo.renderPlace=function(B,A){if(A.place_type in twttr.geo.GENERIC_PLACE_TYPES){B=B.container;A.formatted_name=twttr.geo.formatPlaceName(A.full_name,twttr.geo.TARGET_PLACE_NAME_LENGTH)}else{B=B.poi;A.formatted_name=twttr.geo.formatPlaceName(A.name,twttr.geo.TARGET_POI_NAME_LENGTH)}A.details=twttr.geo.getPlaceDetails(A);return $(Mustache.to_html(B,A))};twttr.geo.geoScribe=function(A,B){scribe($.extend({event_name:A,ui_version:1,log_version:twttr.geo.LOG_VERSION},B),"geo_checkins")};twttr.geo.Exceptions={GeoSupportException:function(){this.msg=_("This browser does not support GeoLocation")}};twttr.geo.Errors={PermissionDeniedError:function(){this.allowRetry=false;this.fatal=true;this.msg=_("Please grant your web browser permission to tell Twitter where you are.")},LocationDetectionError:function(){this.allowRetry=true;this.fatal=false;this.msg=_("We were unable to detect your location.")}};twttr.geo.greatCircleDistanceInKm=function(H,F,G,E){var C=Math.PI/180;var A=Math.sin((G-H)*C*0.5);var B=Math.sin((E-F)*C*0.5);var D=A*A+Math.cos(H*C)*Math.cos(G*C)*B*B;return 12742*Math.atan2(Math.sqrt(D),Math.sqrt(1-D))};twttr.klass("twttr.geo.Map",function(B){if(!twttr.geo.mapsUI.mapsAvailable()){return }var A={mapTypeId:google.maps.MapTypeId.ROADMAP,disableDefaultUI:true,scrollwheel:false,navigationControl:true,navigationControlOptions:{position:google.maps.ControlPosition.TOP_LEFT,style:google.maps.NavigationControlStyle.SMALL}};this.map=new google.maps.Map(B,A);this.bounds=null}).method("createMapOverlay",function(){function A(B){this.setMap(B)}A.prototype=new google.maps.OverlayView();A.prototype.onAdd=function(){};A.prototype.onRemove=function(){};A.prototype.draw=function(){};this.mapOverlay=new A(this.map)}).method("extendBounds",function(A){if(!this.bounds){this.bounds=new google.maps.LatLngBounds()}this.bounds.extend(A)}).method("addPoint",function(A,C){var E=this;var F=new google.maps.LatLng(A[1],A[0]);E.extendBounds(F);var D=new google.maps.MarkerImage("httpdisabled://s.twimg.com/a/1302214109/images/pin.png",new google.maps.Size(43,32),null,new google.maps.Point(14,33));E.marker=new google.maps.Marker({flat:true,icon:D,map:E.map,position:F,clickable:false,zIndex:2});if(C){var B=new google.maps.MarkerImage(C,new google.maps.Size(24,24),null,new google.maps.Point(13,32));E.avatar=new google.maps.Marker({flat:true,icon:B,map:E.map,position:F,zIndex:3})}}).method("addPoi",function(B,D){var F=this;var A=typeof (D)=="function";var G=new google.maps.LatLng(B[1],B[0]);F.extendBounds(G);var E=new google.maps.MarkerImage("httpdisabled://s.twimg.com/a/1302214109/images/poi-pin.png",new google.maps.Size(43,32),null,new google.maps.Point(14,33));var C=new google.maps.Marker({flat:true,icon:E,map:F.map,position:G,draggable:A,clickable:A,zIndex:2});if(A){google.maps.event.addListener(C,"dragend",function(H){D(H.latLng.lat(),H.latLng.lng())})}}).method("addFocusablePoint",function(A,F){var D=this;var G=new google.maps.LatLng(A[1],A[0]);D.extendBounds(G);var E=new google.maps.MarkerImage("httpdisabled://s.twimg.com/a/1302214109/images/place-minor10x.png",new google.maps.Size(10,10),new google.maps.Point(10,0),new google.maps.Point(5,5));var C=new google.maps.MarkerImage("httpdisabled://s.twimg.com/a/1302214109/images/place-minor10x.png",new google.maps.Size(10,10),null,new google.maps.Point(5,5));var B=new google.maps.Marker({flat:true,icon:C,map:D.map,position:G,clickable:F!==undefined,zIndex:2});if(F){if(D.mapOverlay===undefined){D.createMapOverlay()}google.maps.event.addListener(B,"mouseover",function(H){F(true,D.mapOverlay.getProjection().fromLatLngToContainerPixel(G))});google.maps.event.addListener(B,"mouseout",function(H){F(false,D.mapOverlay.getProjection().fromLatLngToContainerPixel(G))})}return function(H){if(H){B.setIcon(E);B.setZIndex(3)}else{B.setIcon(C);B.setZIndex(2)}}}).method("addAccuracyRing",function(B,A,F){var E=new google.maps.LatLng(B[1],B[0]);var D=new google.maps.Circle({map:F?this.map:null,center:E,radius:A,clickable:false,fillColor:"#0040FF",fillOpacity:0.08,strokeColor:"#2929D4",strokeOpacity:0.7,strokeWeight:0.5,zIndex:1});var C=D.getBounds();if(A>200){this.extendBounds(C.getNorthEast());this.extendBounds(C.getSouthWest())}}).method("addPlacePolygon",function(B){if(B[0][0] instanceof Array){B=B[0]}var D=[];for(var C=0;C<B.length;C++){var A=new google.maps.LatLng(B[C][1],B[C][0]);D.push(A);this.extendBounds(A)}var E=new google.maps.Polygon({path:D,strokeColor:"#FF0000",strokeOpacity:0.5,strokeWeight:0.5,fillColor:"#FF0000",fillOpacity:0.2});E.setMap(this.map)}).method("isEmpty",function(){return !this.bounds}).method("adjustBounds",function(B){var A=this.bounds.getSouthWest();var D=this.bounds.getNorthEast();if(D.equals(A)){this.map.setZoom(B||13);this.map.setCenter(D)}else{var F=this.bounds.getCenter();var C=0.7;function E(H,G){return H*C+G*(1-C)}this.map.fitBounds(new google.maps.LatLngBounds(new google.maps.LatLng(E(A.lat(),F.lat()),E(A.lng(),F.lng())),new google.maps.LatLng(E(D.lat(),F.lat()),E(D.lng(),F.lng()))))}}).method("resize",function(){google.maps.event.trigger(this.map,"resize")});twttr.geo.mapsUI={templates:{mapProgress:'<div id="geo_map_progress" class="hoverer"><div class="hovercard-divot"></div><div class="hoverer-inner"><div id="geo_map_spinner">&nbsp;</div></div></div>',mapWithPlace:'<div id="geo_modal" class="hoverer"><div class="hovercard-divot"></div><div class="hoverer-inner geo_map_with_place"><div id="map_canvas"></div><div class="geo_map_place_details"><div class="geo_map_place_name"></div><div class="geo_map_place_address"></div><div class="geo_map_place_container"></div><div class="geo_map_place_phone"></div><div class="geo_map_place_tweets"><a href="javascript:undefined">{{_i}}Tweets at this place &rarr;{{/i}}</a></div></div><a href="#" class="map_close">&times;</a></div></div>',mapWithoutPlace:'<div id="geo_modal" class="hoverer"><div class="hovercard-divot"></div><div class="hoverer-inner"><div id="map_canvas"></div><a href="#" class="map_close">&times;</a></div></div>'},googleApiAvailable:function(){return typeof google!="undefined"},loaddisabledMaps:function(C){if(this.googleApiAvailable()&&google.loaddisabled!==undefined){var B=window.location.hostname.match(/^(.+\.)?twitter\.com$/);var A=google.loaddisabled("maps","3",{callback:C,other_params:B?"client=free-twitter&sensor=false":"sensor=false"})}else{C()}},mapsAvailable:function(){return this.googleApiAvailable()&&google.maps!==undefined},initialize:function(){var A=this;if(A.googleApiAvailable()){A.liveClickHandler=function(C){C.preventDefault();var B=$(this).closest("span.entry-meta");voidMapModal(B.meta(),B.find("a.geocoded_google_link"))};$(".geo-pin, a.geocoded_google_link").live("click",A.liveClickHandler)}},closeMapModal:function(){$(".geo-pin.selected").removeClass("selected");$("#geo_modal").remove();$("#geo_map_progress").remove();this.geoMap=null}voidMapModal:function(G,B){var D=this;D.closeMapModal();var C=$(B);C.addClass("selected");C.after(Mustache.to_html(D.templates.mapProgress));D.showHover($("#geo_map_progress"),C,150);var F=G.place_id;var E=F&&twttr.geo.options.show_place_details_in_map?D.templates.mapWithPlace:D.templates.mapWithoutPlace;C.after(Mustache.to_html(E));$("html").one("click",function(H){D.closeMapModal()});$(".map_close").click(function(H){H.preventDefault();D.closeMapModal()});var A=$("#map_canvas").get(0);twttr.geo.mapsUI.loaddisabledMaps(function(){D.geoMap=new twttr.geo.Map(A);var H=D.geoMap;var I=false;var J=function(){if(!I&&G.latlng){D.geoMap.addPoint(G.latlng.slice().reverse(),G.avatar_url)}if(D.geoMap.isEmpty()){D.closeMapModal();return }D.geoMap.adjustBounds();$("#geo_map_progress").remove();D.showHover($("#geo_modal"),C,0)};if(F){twttr.api.getPlaceDetails({place_id:G.place_id,success:function(L,N){if(H!=D.geoMap){return }var M=L.geometry.coordinates;if(L.geometry.type=="Polygon"){D.geoMap.addPlacePolygon(M)}else{if(L.geometry.type=="MultiPolygon"){M.forEach(function(O){D.geoMap.addPlacePolygon(O)})}else{if(L.geometry.type=="Point"){D.geoMap.addPoint(M,G.avatar_url);I=true}}}$(".geo_map_place_name").text(L.name);$(".geo_map_place_address").text((L.attributes&&L.attributes.street_address)||"");var K=twttr.geo.getBestContainer(L);$(".geo_map_place_container").text(K.full_name||"");$(".geo_map_place_phone").text((L.attributes&&L.attributes.phone)||"");$(".geo_map_place_tweets a").attr("href",twttr.geo.getPlacePageLinkFromPlace(L));if(window.location.pathname=="/"){$(".geo_map_place_tweets a").attr(twttr.geo.getPlacePageLinkAttrsFromPlace(L)).isSearchLink().click(function(){D.closeMapModal()})}J()}})}else{J()}})},showHover:function(A,B,C){A.visible(false);twttr.SimplePositioner.setPosition(A,B,{itemHeight:180,offsets:{above:{top:-10,left:-40},below:{top:10,left:-40}},direction:"prefer below",hasContainer:true});A.click(function(D){D.stopPropagation()});setTimeout(function(){A.visible(true)},C)}};$(function(){twttr.geo.mapsUI.initialize()});twttr.klass("twttr.geo.PlacesDropdown",function(B,D){var C=this;C.placer=B;C.opts=D;var A="<a id='place_link' href='#'><span id='place_name'></span> â–¾</a><ul class='round places_list'/>";$("#place_content").html(A).bind("tweet",function(){var E=C.placer.getState();C.placer.determinePlaces(function(){C.rebuildPlacesDropdown()},function(){$(".geo_disable_webclient:first").click()});if($("#place_id").val()!=""){twttr.geo.geoScribe("geotweet",E)}});C.$placesList=$("#place_content ul.places_list");C.rebuildPlacesDropdown();$("#place_link").click(function(E){E.preventDefault();if($("#place_content ul.places_list:visible").length>0){C.closeMenu()}else{voidMenu();E.stopPropagation()}})}).method("rebuildPlacesDropdown",function(){var A=this;A.$placesList.empty();A.appendPoiPlaces(A.placer.places);A.appendNonPoiPlaces(A.placer.places);A.appendMorePlaces();$(".geo_more_places").click(function(B){B.preventDefault();new twttr.geo.PlaceSearchDialog(A.placer,A.opts,function(){A.rebuildPlacesDropdown();A.showSelectedPlace()});twttr.geo.geoScribe("click_search_places")});A.showSelectedPlace()}).method("appendPoiPlaces",function(A){var B=false;A.forEach(function(C){if(C.place_type=="poi"){this.$placesList.append(this.createPlaceItem(C));B=true}},this);return B}).method("appendNonPoiPlaces",function(A){A.forEach(function(B){if(B.place_type!="poi"){this.$placesList.append(this.createPlaceItem(B))}},this)}).method("createPlaceItem",function(A){var C=this;var B=twttr.geo.renderPlace(twttr.geo.templates.dropdownItem,A);B.click(function(D){D.preventDefault();C.placer.selectPlace(A);C.rebuildPlacesDropdown();C.closeMenu();twttr.geo.geoScribe("click_place_item",C.placer.getState())});return B}).method("appendMorePlaces",function(){if(this.opts.more_places){this.$placesList.append('<li class="geo_more_places"><span class="place_item_icon more_places">&nbsp;</span>'+_("Search places...")+"</li>")}}).method("showSelectedPlace",function(){var A=this.placer.selectedPlace;var B;if(A.place_type!="poi"){B=_("in {{full_name}}")}else{B='<span class="place_icon">&nbsp;</span>'+_("at {{full_name}}")}$("#place_id").val(A.id);$("#place_name").html(Mustache.to_html(B,A));this.$placesList.children("li.selected").removeClass("selected");$("#place_"+A.id).addClass("selected")}).method(voidMenu",function(){var B=this;var A=$("#place_link");var C=$("#place_link").position();B.$placesList.css({left:C.left,top:C.top+A.outerHeight()}).show();$("html").one("click",function(){B.closeMenu()});twttr.geo.geoScribe(void_places_dropdown",B.placer.getState())}).method("closeMenu",function(){this.$placesList.hide()});twttr.klass("twttr.geo.PlaceSearchDialog",function(E,B,H){var F=this;F.opts=B;F.onPlaceAccepted=H;F.place=E.selectedPlace;F.placer=E;F.city=twttr.geo.getBestCity(F.place);F.originalCity=F.city;F.placeHeading="{{_i}}Where are you?{{/i}}";F.placeString=(F.place&&F.place.place_type!="city")?F.place.name:"";F.originalPlaceString=F.placeString;F.placeHtml='<form id="place_search_form"><table class="geo_place_search_table"><tr><td class="geo_place_search_col1 geo_place_search_city">{{_i}}City{{/i}}</td><td class="geo_place_search_city">{{city}}&#32;&nbsp;<a href="#" id="change_city">{{_i}}Change{{/i}}</a></td></tr><tr><td class="geo_place_search_col1 geo_place_search_place">{{_i}}Place Name{{/i}}</td><td class="geo_place_search_place"><input id="place_search_query" type="text" autocomplete="off" class="round-left help-focusable" title="{{_i}}Type the name of a place{{/i}}"/><span class="place_search_submit round-right" title="{{_i}}Search{{/i}}">&nbsp;</span><ul class="round places_list place_search_dropdown"></ul></td></tr><tr><td></td><td class="geo_place_search_hint">{{_i}}Optional{{/i}}</td></tr><tr><td></td><td><div id="place_search_results"></div><button type="button" class="btn" id="place_search_done">{{_i}}Done{{/i}}</button><button type="button" class="btn hidden" id="place_search_cancel">{{_i}}Cancel{{/i}}</button></td></tr></table></form>';F.cityHeading="{{_i}}Change City{{/i}}</a>";F.cityHtml='<form id="place_search_form"><table class="geo_place_search_table"><tr><td class="geo_place_search_col1 geo_place_search_place">{{_i}}City{{/i}}</td><td class="geo_place_search_place"><input id="place_search_query" type="text" autocomplete="off" class="round-left help-focusable" title="{{_i}}Enter a city, state{{/i}}"/><span class="place_search_submit round-right" title="{{_i}}Search{{/i}}">&nbsp;</span><ul class="round places_list place_search_dropdown"></ul></td></tr><tr><td></td><td><div id="place_search_results"></div></td></tr></table></form>';F.noCityHeading="{{_i}}Where are you?{{/i}}</a>";$(".place_search_dialog").remove();F.dialog=new twttr.dialog({content:$("<div/>").appendTo("body"),heading:$('<div><span id="geo_search_places_title"></span></div>'),footer:null,cssClass:"place_search_dialog",closeButton:true,renderInline:true,modal:true,fixed:false});var D=E.opts.geoParams;F.searchParams={max_results:twttr.geo.MAX_PLACE_SEARCH_RESULTS,granularity:D.granularity};if(E.detectedPlace&&F.city.id==twttr.geo.getBestCity(E.detectedPlace).id&&D.lat!==undefined&&D.lon!==undefined&&D.accuracy!==undefined){twttr.merge(F.searchParams,{lat:D.lat,lon:D.lon,accuracy:D.accuracy})}else{F.setSearchParamsFromCity()}F.setCityMode(false);var G=$("#place_search_results");G.append("<ul/>");for(var C=0,A=G.find("ul");C<twttr.geo.MAX_PLACE_SEARCH_RESULTS;C++){A.append("<li>&nbsp;</li>")}F.void();G.empty();$("#place_search_query").focus().select()}).method("setHeadingAndContent",function(A,B){$("#geo_search_places_title").html(Mustache.to_html(A));$(".place_search_dialog .modal-content").html(Mustache.to_html(B,{city:this.city.full_name}))}).method("scribeSearch",function(B,C,A){var D=this;twttr.geo.geoScribe(B,$.extend({query:$("#place_search_query").helpVal(),mode:C?"city":"place",container_id:D.city.id,place_creation_allowed:D.shouldAllowPlaceCreation(C)},D.searchParams,A))}).method("setCityMode",function(B){var C=this;if(C.city.full_name==""){C.setHeadingAndContent(C.noCityHeading,C.cityHtml);B=true}else{if(B){C.setHeadingAndContent(C.cityHeading,C.cityHtml)}else{C.setHeadingAndContent(C.placeHeading,C.placeHtml)}}var A=$("#place_search_query");if(B){A.val(C.city.full_name)}else{A.val(C.placeString)}A.helpText().selectOnClick();if(twttr.geo.options.autocomplete){C.placeAutocomplete=new twttr.autocomplete({$input:A,$dropdown:$(".place_search_dropdown"),getInputVal:function(){return A.helpVal()},fetchMatches:function(E,G,F){twttr.api.search({data:twttr.merge({},C.searchParams,{query:E,autocomplete:"true",max_results:twttr.geo.MAX_PLACE_AUTOCOMPLETE_RESULTS,granularity:B?"city":C.searchParams.granularity}),success:function(H,I){G(H.result.places)},error:function(){F()}})},renderMatch:function(F,E,G){return twttr.geo.renderPlace(twttr.geo.templates.autocompleteItem,F).click(function(I){var H=[];G.forEach(function(J){H.push(J.id)});C.placeAccepted(F,B);C.scribeSearch("place_search_dialog_select_autocomplete",B,{selected_id:F.id,selected_index:E,place_ids:H})})},delay:twttr.geo.options.autocomplete_zero_delay?0:twttr.geo.PLACE_SEARCH_AUTOCOMPLETE_DELAY})}var D=$("#place_search_form");D.submit(function(E){E.preventDefault();var F=A.helpVal();if(C.placeAutocomplete){C.placeAutocomplete.hide()}if(!F){C.placeAccepted(C.city,B);return }if(B&&F==C.city.full_name){C.setCityMode(false);return }C.setWaitCursor(true);$("#place_search_done").hide();$("#place_search_cancel").show();$("#place_search_results").html(Mustache.to_html('<div class="geo_search_message">{{_i}}Searching for "{{query}}"...{{/i}}</div>',{query:F})).show();twttr.api.search({data:twttr.merge({},C.searchParams,{query:F,granularity:B?"city":C.searchParams.granularity}),success:function(G){C.setWaitCursor(false);C.searchResultPlaces=G.result.places;twttr.geo.mapsUI.loaddisabledMaps(function(){C.displayResults(0,B)})},error:function(G,I,H){C.setWaitCursor(false);C.displaySearchError(G,B)}})});$(".place_search_submit").click(function(){C.searchTrigger="click_icon";D.submit()});A.keydown(function(E){if(E.keyCode==13){C.searchTrigger="enter_key";E.preventDefault();D.submit()}});$("#place_search_done").click(function(){C.searchTrigger="click_done";var E=A.helpVal();if(C.place&&C.place.name==E&&C.city==C.originalCity){C.placeAccepted(C.place,B);C.scribeSearch("place_search_dialog_done_no_changes",B)}else{D.submit()}});$("#place_search_cancel").click(function(){C.dialog.close();C.scribeSearch("place_search_dialog_close",B,{triggered_by:"click_cancel"})});$("#change_city").click(function(E){E.preventDefault();C.placeString=A.helpVal();C.setCityMode(true);C.scribeSearch("place_search_dialog_change_city")});A.focus().select()}).method("setWaitCursor",function(A){$(".place_search_submit").toggleClass("loaddisableding",A)}).method("shouldAllowPlaceCreation",function(A){return !A&&this.opts.place_creation&&twttr.geo.mapsUI.mapsAvailable()&&(!this.opts.place_creation_needs_high_accuracy||this.searchParams.accuracy!==undefined&&this.searchParams.accuracy<=twttr.geo.PLACE_CREATION_ACCURACY_THRESHOLD)&&this.city.country_code=="US"}).method("displayResults",function(I,G){var E=this;var B=I*twttr.geo.PLACE_SEARCH_RESULTS_PER_PAGE;var F=B+twttr.geo.PLACE_SEARCH_RESULTS_PER_PAGE;var A=E.searchResultPlaces.slice(B,F);var J=$("#place_search_results").empty();var H=$("#place_search_query").helpVal();if(A.length==0){J.html(Mustache.to_html('<div class="geo_search_message">{{_i}}We couldn\'t find "{{query}}."{{/i}}</div>',{query:H}))}var C=[];var D=$("<ul/>").appendTo(J);A.forEach(function(K,L){C.push(K.id);var M=twttr.geo.renderPlace(twttr.geo.templates.searchResultItem,K);M.find("a").click(function(N){N.preventDefault();E.scribeSearch("place_search_dialog_select_result",G,{place_ids:C,selected_id:K.id,selected_index:L});E.placeAccepted(K,G)}).attr("title",twttr.geo.getPlaceDetails(K));D.append(M)});if(E.searchResultPlaces.length>twttr.geo.PLACE_SEARCH_RESULTS_PER_PAGE){J.append(Mustache.to_html('<div class="geo_next_prev"><a href="#" id="geo_prev_result">&laquo;&nbsp;{{_i}}Prev{{/i}}</a><a href="#" id="geo_next_result">{{_i}}Next{{/i}}&nbsp;&raquo;</a></div>'));E.setNextPrev($("#geo_prev_result"),I>0,I-1,G);E.setNextPrev($("#geo_next_result"),F<E.searchResultPlaces.length,I+1,G)}if(E.shouldAllowPlaceCreation(G)){J.append(Mustache.to_html("<div class='geo_add_place'>{{#found}}{{_i}}Not what you're looking for?{{/i}}&#32;{{/found}}<a href='#'>{{_i}}Add this place!{{/i}}</a></div>",{found:A.length>0}));$(".geo_add_place a").click(function(K){K.preventDefault();E.dialog.close();new twttr.geo.PlaceCreationDialog(E.city,H,E.searchParams,function(L){E.placeAccepted(L,false)},E.opts.queryParams.accuracyring!==undefined);E.scribeSearch("place_search_dialog_add",G,{place_ids:C})})}E.scribeSearch("place_search_dialog_show_results",G,{place_ids:C,triggered_by:E.searchTrigger})}).method("setNextPrev",function(A,D,C,B){var E=this;A.click(function(F){F.preventDefault();if(D){E.displayResults(C,B)}});if(!D){A.addClass("link-disabled")}}).method("placeAccepted",function(A,B){var C=this;if(B){if(!A.id){C.dialog.close()}else{if(C.city.id!=A.id){C.city=A;if(C.placeString!=C.originalPlaceString){C.placeString=""}C.setSearchParamsFromCity()}}C.setCityMode(false)}else{C.dialog.close();if(C.originalCity!=C.city){C.placer.selectPlace(C.city)}C.placer.selectPlace(A);C.onPlaceAccepted()}}).method("setSearchParamsFromCity",function(){var A=this;if(A.city&&A.city.id){delete A.searchParams.lat;delete A.searchParams.lon;delete A.searchParams.accuracy;A.searchParams.contained_within=A.city.id}}).method("displaySearchError",function(B,A){$("#place_search_results").text(_("Sorry, search is temporarily unavailable, please try again later."));this.scribeSearch("place_search_dialog_error",A)});twttr.klass("twttr.geo.PlaceCreationDialog",function(C,F,D,E,B){var G=this;G.container=C;if(D.contained_within!==undefined){var A=twttr.geo.getLocationFromPlace(C);if(A){G.lat=A.latitude;G.lon=A.longitude;G.accuracy=A.accuracy}}else{G.lat=D.lat;G.lon=D.lon;G.accuracy=D.accuracy}G.originalGeoParams=D;G.placeName=F;G.onPlaceCreated=E;G.showAccuracyRing=B;G.draggedPin=false;G.streetAddress="";G.createHtml='<div class="geo_map"><div class="geo_map_canvas"></div><div class="geo_map_hint"><span></span><div class="round">{{_i}}Click and move the pin to edit this location.{{/i}}</div></div></div><div class="geo_place_create"><table cellspacing="0" cellpadding="0"><tr><td class="geo_place_creation_row1 geo_place_search_col1">{{_i}}Name{{/i}}</td><td class="geo_place_creation_row1"><input id="geo_place_name" class="geo_form_input round help-focusable" type="text"title="{{_i}}Type the name of a place{{/i}}"/></td></tr><tr><td class="geo_place_search_col1 geo_place_creation_row2">{{_i}}Address{{/i}}</td><td class="geo_place_creation_row2"><input id="geo_place_address" class="geo_form_input round help-focusable" type="text"title="{{_i}}Optional{{/i}}"/></td></tr><tr><td></td><td><div class="geo_place_creation_hint">{{_i}}"795 Folsom St" or "19th and Urban"{{/i}}</div><div class="geo_place_city">{{_i}}In {{city_name}}{{/i}}</div><div><button type="button" class="btn" id="geo_create_place">{{_i}}Add this Place{{/i}}</button><span id="geo_creating_place">&nbsp;</span></div><div class="error" id="geo_creation_error"></div></td></tr></table></div>';G.similarHtml='<div class="geo_map"><div class="geo_map_canvas" /><div class="geo_map_place_bubble"><span/><div class="round"><div class="geo_place_title" /><div class="geo_place_details" /></div></div></div><div class="geo_place_create"><div>{{_i}}This place may already exist. Did you mean:{{/i}}</div><ul/><div><button type="button" class="btn" id="geo_create_place">{{_i}}No, Just Add this Place{{/i}}</button><a href="#" class="geo_go_back">{{_i}}Go Back{{/i}}</a><span id="geo_creating_place">&nbsp;</span></div><div class="error" id="geo_creation_error"></div></div>';$(".place_creation_dialog").remove();G.dialog=new twttr.dialog({content:$("<div/>").appendTo("body"),heading:$(Mustache.to_html("<div>{{_i}}Add this place.{{/i}}</div>")),footer:null,cssClass:"place_creation_dialog",closeButton:true,renderInline:true,modal:true,fixed:false});G.showCreatePlace()}).method("showCreatePlace",function(){var B=this;$(".place_creation_dialog .modal-content").html(Mustache.to_html(B.createHtml,{city_name:B.container.full_name}));B.inProgress=false;$("#geo_place_name").val(B.placeName).helpText().change(function(C){B.updateState()}).keydown(function(C){setTimeout(function(){B.updateState()},0)});$("#geo_create_place").click(function(){B.placeName=$("#geo_place_name").helpVal();B.streetAddress=$("#geo_place_address").helpVal();B.callSimilarPlaces()});B.void();B.updateMapHeight();B.geoMap=new twttr.geo.Map($(".geo_map_canvas").get(0));B.geoMap.addPoi([B.lon,B.lat],function(C,D){B.lat=C;B.lon=D;B.draggedPin=true});B.geoMap.addAccuracyRing([B.lon,B.lat],B.accuracy,B.showAccuracyRing);B.geoMap.adjustBounds(15);B.updateState();$("#geo_place_address").val(B.streetAddress).helpText().focus();var A=true;setTimeout(function(){if(A){$(".geo_map_hint").fadeTo(700,0.8)}},700);$(".geo_map").mousedown(function(C){A=false;$(".geo_map_hint").fadeOut(200)})}).method("showSimilarPlaces",function(){var B=this;$(".place_creation_dialog .modal-content").html(Mustache.to_html(B.similarHtml));B.inProgress=false;$("#geo_create_place").click(function(){B.callCreatePlace()});$("a.geo_go_back").click(function(D){D.preventDefault();B.showCreatePlace()});var C=$(".geo_place_create ul");B.similarPlaces.forEach(function(D){$placeItem=twttr.geo.renderPlace(twttr.geo.templates.searchResultItem,D);$placeItem.find("a").click(function(E){E.preventDefault();B.dialog.close();B.onPlaceCreated(D)}).attr("title",twttr.geo.getPlaceDetails(D));C.append($placeItem)});B.updateMapHeight();B.geoMap=new twttr.geo.Map($(".geo_map_canvas").get(0));B.geoMap.addPoi([B.lon,B.lat]);$geoMapPlaceBubble=$(".geo_map_place_bubble");var A=$(".geo_map_canvas").position();B.similarPlaces.slice().reverse().forEach(function(E){var D=E.bounding_box.coordinates[0][0];var F=B.geoMap.addFocusablePoint(D,function(H,G){if(H){$geoMapPlaceBubble.find(".geo_place_title").text(E.name);$geoMapPlaceBubble.find(".geo_place_details").text(twttr.geo.getPlaceDetails((E)));$geoMapPlaceBubble.show().css({left:A.left+G.x-$geoMapPlaceBubble.width()/2,top:A.top+G.y,opacity:0.8})}else{$geoMapPlaceBubble.hide()}});$("#result_place_"+E.id).hover(function(){F(true)},function(){F(false)})});B.geoMap.adjustBounds(15);B.updateState()}).method("getPlaceCreationParams",function(){var B=this;var A={lat:B.lat,lon:B.lon,name:B.placeName,contained_within:B.container.id,accuracy:B.draggedPin?0:B.originalGeoParams.accuracy};if(B.token){A.token=B.token}if(B.streetAddress){A["attribute:street_address"]=B.streetAddress}return A}).method("callSimilarPlaces",function(){var A=this;if(!A.inProgress){A.inProgress=true;A.updateState();twttr.api.similarPlaces({data:A.getPlaceCreationParams(),success:function(B){A.token=B.result.token;A.inProgress=false;A.similarPlaces=B.result.places.slice(0,twttr.geo.MAX_SIMILAR_PLACES);if(A.similarPlaces.length>0&&twttr.geo.options&&twttr.geo.options.show_similar_places){A.showSimilarPlaces()}else{A.callCreatePlace()}},error:function(){A.onCreationError();A.scribeCreatePlace("similar_places_error")}})}}).method("callCreatePlace",function(){var A=this;if(!A.inProgress){A.inProgress=true;A.updateState();twttr.api.createPlace({data:A.getPlaceCreationParams(),success:function(B){A.inProgress=false;A.updateState();A.dialog.close();A.onPlaceCreated(B);A.scribeCreatePlace("success")},error:function(){A.onCreationError();A.scribeCreatePlace("create_place_error")}})}}).method("scribeCreatePlace",function(A){var B=this;twttr.geo.geoScribe("create_place",$.extend({status:A,original_lat:B.originalGeoParams.lat,original_lon:B.originalGeoParams.lon,original_accuracy:B.originalGeoParams.accuracy,dragged_pin:B.draggedPin},B.getPlaceCreationParams()))}).method("onCreationError",function(){this.inProgress=false;$("#geo_creation_error").text(_("We couldn't add this place. Please try again."));this.updateState();this.updateMapHeight();this.geoMap.resize()}).method("updateState",function(){$("#geo_creating_place").toggleClass("geo_spinner",this.inProgress)}).method("updateMapHeight",function(){var D=$(".geo_map_canvas");var A=Math.max(210,$(".geo_place_create").outerHeight());D.height(A);var B=$(".geo_map_hint");var C=D.position();B.css({left:C.left+(D.width()-B.width())/2-1,top:C.top+A/2})});twttr.klass("twttr.geo.Locator",function(B){var A=this;A.position=null;A.locator=null;A.locatorType="none";if(B&&B.lat!==undefined&&B.lon!==undefined){A.locatorType="manual";A.locator={watchPosition:function(C){C({coords:{latitude:B.lat,longitude:B.lon,accuracy:parseInt(B.accuracy)||200}});return 0},clearWatch:function(){}}}else{if(navigator&&navigator.geolocation){A.locatorType="html5";A.locator=navigator.geolocation;if(navigator.userAgent.indexOf("Firefox")!=-1){A.browserGeoPermissionsHelpBannerTemplate=A.templates.firefoxGeoPermissionsHelpBanner}else{if(navigator.userAgent.indexOf("Chrome")!=-1){A.browserGeoPermissionsHelpBannerTemplate=A.templates.chromeGeoPermissionsHelpBanner}else{if(navigator.userAgent.indexOf("MSIE")!=-1&&navigator.userAgent.indexOf("GTB")!=-1){A.browserGeoPermissionsHelpBannerTemplate=A.templates.ieGoogleToolbarGeoPermissionsHelpBanner}}}}else{if(typeof google!="undefined"&&typeof google.gears!="undefined"){A.locatorType="gears";A.locator=google.gears.factory.create("beta.geolocation")}}}}).augmentProto({templates:{firefoxGeoPermissionsHelpBanner:'<div id="geo_browser_help_banner" class="geo_firefox"><div>{{_i}}Before Twitter can get your location...{{/i}}</div><div><img src="httpdisabled://s.twimg.com/a/1302214109/images/geo_browser_help_banner_1.png" />{{_i}}Check "Remember for this site"{{/i}}</div><div><img src="httpdisabled://s.twimg.com/a/1302214109/images/geo_browser_help_banner_2.png" />{{_i}}Click "Share Location"{{/i}}</div></div>',chromeGeoPermissionsHelpBanner:'<div id="geo_browser_help_banner" class="geo_chrome"><div>{{_i}}Click "Allow" to let Twitter get your location.{{/i}}</div></div>',ieGoogleToolbarGeoPermissionsHelpBanner:'<div id="geo_browser_help_banner" class="geo_ie_gtb"><div>{{_i}}Before Twitter can get your location...{{/i}}</div><div><img src="httpdisabled://s.twimg.com/a/1302214109/images/geo_browser_help_banner_1.png" />{{_i}}Check "Remember for this site"{{/i}}</div><div><img src="httpdisabled://s.twimg.com/a/1302214109/images/geo_browser_help_banner_2.png" />{{_i}}Click "Share my location"{{/i}}</div></div>'}}).method("isLocatable",function(){return !!(this.locator)}).method("getLocation",function(A){var C=this;if(!C.isLocatable()){throw new twttr.geo.Exceptions.GeoSupportException()}var B=$.extend({onSuccess:function(D){},onFailure:function(D){},options:{timeout:twttr.geo.LOCATION_TIMEOUT,enableHighAcuracy:true,maximumAge:twttr.geo.LOCATION_MAXIMUM_AGE}},A);if(!C.getBrowserGeoPermissionsHelpBannerSeen()){C.detectBrowserGeoPermissionsBanner()}C.position=null;C.waitForAcceptableId=setTimeout(function(){C.waitForAcceptableId=null;if(C.watchId!=null){C.watchPositionAcceptable(B.onSuccess)}},twttr.geo.ACCEPTABLE_LOCATION_TIMEOUT);C.watchId=null;C.watchId=C.locator.watchPosition(function(D){setTimeout(function(){if(C.watchId!=null){C.watchPositionSuccess(D,B.onSuccess)}},0)},function(D){setTimeout(function(){if(C.watchId!=null){C.watchPositionError(D,B.onFailure)}},0)},B.options)}).method("watchPositionSuccess",function(A,C){var B=this;B.setBrowserGeoPermissionsHelpBannerSeen();B.position={latitude:A.coords.latitude,longitude:A.coords.longitude,accuracy:A.coords.accuracy};if(B.waitForAcceptableId==null||(B.position.accuracy!=undefined&&B.position.accuracy<twttr.geo.ACCEPTABLE_LOCATION_ACCURACY)){B.watchPositionAcceptable(C)}}).method("watchPositionError",function(B,C){var D=this;D.setBrowserGeoPermissionsHelpBannerSeen();var A;if(B.code==B.PERMISSION_DENIED){A=new twttr.geo.Errors.PermissionDeniedError()}else{A=new twttr.geo.Errors.LocationDetectionError()}if(A.fatal){var E=new ShortNotification();E.setMessage(A.msg);E.show()}D.watchPositionCleanup();C(A)}).method("watchPositionAcceptable",function(B){var A=this;if(A.position){A.watchPositionCleanup();B(A.position)}}).method("watchPositionCleanup",function(){var A=this;clearTimeout(A.waitForAcceptableId);A.locator.clearWatch(A.watchId);A.watchId=null}).method("getWindowHeight",function(){return $(window).height()}).method("getBrowserGeoPermissionsHelpBannerSeen",function(){return $.cookie("geo_browser_help_banner")}).method("setBrowserGeoPermissionsHelpBannerSeen",function(){var A=this;if(A.showBrowserGeoPermissionsHelpBanner){A.clearDetectBrowserGeoPermissionsBanner();if(!A.getBrowserGeoPermissionsHelpBannerSeen()){$.cookie("geo_browser_help_banner","1",{expires:3650})}}}).method("showBrowserGeoPermissionsHelpBanner",function(){$("body").append(Mustache.to_html(this.browserGeoPermissionsHelpBannerTemplate))}).method("detectBrowserGeoPermissionsBanner",function(){var B=this;if(B.browserGeoPermissionsHelpBannerTemplate){var A=B.getWindowHeight();this.browserGeoPermissionsHelpTimer=setTimeout(function(){if(B.getWindowHeight()<A){B.showBrowserGeoPermissionsHelpBanner();B.browserGeoPermissionsHelpInterval=setInterval(function(){if(B.getWindowHeight()==A){B.clearDetectBrowserGeoPermissionsBanner()}},twttr.geo.BROWSER_GEO_BANNER_DISAPPEAR_INTERVAL)}},twttr.geo.BROWSER_GEO_BANNER_APPEAR_DELAY)}}).method("clearDetectBrowserGeoPermissionsBanner",function(){clearTimeout(this.browserGeoPermissionsHelpTimer);clearInterval(this.browserGeoPermissionsHelpInterval);$("#geo_browser_help_banner").remove()});twttr.klass("twttr.geo.Placer",function(A){var C=this;C.opts=A;C.places=[];C.detectedParams={};var B=C.opts.geoParams;if(B.lat!==undefined&&B.lon!==undefined){C.detectedParams.lat=parseFloat(B.lat).toFixed(4);C.detectedParams.lon=parseFloat(B.lon).toFixed(4)}if(B.ip!==undefined){C.detectedParams.ip=B.ip}}).augmentProto({PLACE_OVERRIDES_COOKIE:"place_overrides",RECENT_PLACE_COOKIE:"recent_place",MAX_PLACE_OVERRIDES:8,STICKY_RADIUS_IN_KM:0.1}).method("search",function(E,C,B){var A=this;try{twttr.api.search({data:A.opts.geoParams,success:function(F){A.places=F.result.places;A.determinePlaces(E,C)},error:function(F){if(F.status==503){B()}else{C()}}})}catch(D){C()}}).method("determinePlaces",function(C,B){var A=this;if(A.places.every(function(D){if(D.place_type!="poi"){A.detectedPlace=D;return false}return true})){B();return }if(A.getOverrides().every(function(D){if(A.isOverrideCloseToDetected(D)){A.selectPlaceById(D.id,C,B);return false}return true})){A.selectPlace(A.detectedPlace);C()}}).method("selectPlaceById",function(E,D,B){var A=this;if(A.places.every(function(F){if(F.id==E){A.selectPlace(F);D();return false}return true})){try{twttr.api.getPlaceDetails({place_id:E,success:function(F){A.selectPlace(F);D()},error:function(){B()}})}catch(C){B()}}}).method("setOverrides",function(A){if(A!=this.getOverrides()){if(A.length>0){$.cookie(this.PLACE_OVERRIDES_COOKIE,A.map(function(B){return $.param(B)}).join(","),{expires:3650})}else{$.cookie(this.PLACE_OVERRIDES_COOKIE,null)}}}).method("getOverrides",function(){return($.cookie(this.PLACE_OVERRIDES_COOKIE)||"").split(",").filter(function(A){return A!=""}).map(function(A){return twttr.unparam(A)})}).method("selectPlace",function(A){var B=this;if(B.places.every(function(C){if(A.id==C.id){B.selectedPlace=C;return false}return true})){B.places.unshift(A);B.selectedPlace=A}if(B.selectedPlace.place_type!="poi"){B.setOverride();B.setRecentPlaceId(B.selectedPlace.id)}}).method("setOverride",function(){var A=this;var B=A.getOverrides().filter(function(C){return !A.isOverrideCloseToDetected(C)});if(A.detectedPlace&&A.selectedPlace.id!=A.detectedPlace.id){B.unshift(twttr.merge({id:A.selectedPlace.id},A.detectedParams))}A.setOverrides(B.slice(0,A.MAX_PLACE_OVERRIDES))}).method("getRecentPlaceId",function(){return $.cookie(this.RECENT_PLACE_COOKIE)}).method("setRecentPlaceId",function(A){$.cookie(this.RECENT_PLACE_COOKIE,A,{expires:3650})}).method("isOverrideCloseToDetected",function(A){var B=this.detectedParams;if(!B){return false}if(A.lat!==undefined&&A.lon!==undefined&&B.lat!==undefined&&B.lon!==undefined&&twttr.geo.greatCircleDistanceInKm(A.lat,A.lon,B.lat,B.lon)<this.STICKY_RADIUS_IN_KM){return true}return B.ip&&B.ip==A.ip}).method("getState",function(){var A=this;var B={geo_params:A.opts.geoParams,place_ids:[]};var C=[];A.places.forEach(function(D,E){B.place_ids.push(D.id);if(A.selectedPlace&&A.selectedPlace.id==D.id){B.selected_place_index=E}});if(A.selectedPlace){B.selected_place_id=A.selectedPlace.id}if(A.detectedPlace){B.detected_place_id=A.detectedPlace.id}return B});twttr.klass("twttr.geo.NearbyPlacer",function(A){var B=this;B.opts=A;B.places=[]}).method("search",function(D,B){var A=this;try{twttr.api.search({data:twttr.merge({require_activity:true},A.opts.geoParams),success:function(E){A.places=E.result.places;A.determinePlaces(D,B)},error:function(E){B()}})}catch(C){B()}}).method("determinePlaces",function(C,B){var A=this;if(!A.detectedPlace){A.places.every(function(D){if(D.place_type!="poi"){A.detectedPlace=D;return false}return true})}if(!A.selectedPlace){A.selectPlace(A.detectedPlace)}if(A.selectedPlace){A.places.every(function(D,E){if(D.id==A.selectedPlace.id){A.places.splice(E,1);return false}return true});A.fudgePlaceRanking(A.places);C()}else{B()}}).method("fudgePlaceRanking",function(C){var A=C.length;var B=0;for(var D=0;D<A;D++){if(C[D].place_type!="poi"){C.splice(B,0,C.splice(D,1)[0]);B+=1;if(B==2){break}}}}).method("selectPlace",function(B){var C=this;C.selectedPlace=B;if(B!=C.detectedPlace){var A=twttr.geo.getLocationFromPlace(B);C.opts.geoParams.lat=A.latitude;C.opts.geoParams.lon=A.longitude;C.opts.geoParams.accuracy=A.accuracy;delete C.opts.geoParams.contained_by;delete C.opts.geoParams.ip}});twttr.klass("twttr.geo.NearbyActivity",function(A){var B=this;B.$nearbyActivity=$("#side_geo_nearby_activity .sidebar-menu");B.placer=new twttr.geo.NearbyPlacer({geoParams:{granularity:"poi",max_results:30}});if(A){twttr.merge(B.placer.opts.geoParams,A.opts.geoParams,{granularity:"poi",max_results:30});B.placer.detectedPlace=A.detectedPlace;B.placer.selectPlace(A.selectedPlace);B.search()}else{if(twttr.geo.IP){B.placer.opts.geoParams.ip=twttr.geo.IP;B.search()}else{B.showError()}}}).augmentProto({templates:{choose:'<p class="geo_nearby_activity"><small>{{_i}}Find interesting places nearby and see what people are saying there! To get started, tell us where you\'d like to explore:{{/i}}</small></p><p class="geo_nearby_activity"><a href="#" class="geo_nearby_activity_change">{{_i}}Search places...{{/i}}</a></p>',finding:'<p class="geo_nearby_activity geo_find_in_progress"><small>{{_i}}Finding places nearby...{{/i}}</small></p>',places:'<div class="geo_nearby_activity"><small><span class="geo_nearby_activity_header"></span>&#32;<a href="#" class="geo_nearby_activity_change geo_minorlink">{{_i}}Change{{/i}}</a></small><ul/></div>',error:'<p class="geo_nearby_activity"><small>{{_i}}Location service is currently unavailable.{{/i}}&#32;<a href="#" class="geo_nearby_activity_retry">{{_i}}Try again{{/i}}</a></small></p>',nextPrev:'<p class="geo_nearby_activity"><a href="#" class="geo_prev">{{_i}}Prev{{/i}}</a><span class="geo_prev_next_separator">&nbsp;|&nbsp;</span><a href="#" class="geo_next">{{_i}}Next{{/i}}</a></p>',noPlaces:'<p class="geo_nearby_activity"><small>{{_i}}No active places nearby.{{/i}}</small></p>'}}).method("show",function(B,A){var C=this;C.$nearbyActivity.html(Mustache.to_html(B));C.$nearbyActivity.find(".geo_nearby_activity_change").click(function(D){D.preventDefault();new twttr.geo.PlaceSearchDialog(C.placer,{},function(){C.search()})});C.$nearbyActivity.find(".geo_nearby_activity_retry").click(function(D){D.preventDefault();C.search()});$("#na_menu span").hide().filter(A?".with-place":".without-place").show()}).method("search",function(){var A=this;A.show(A.templates.finding);A.placer.search(function(){A.showPlaces(0)},function(){A.showError()})}).method("showError",function(){var A=this;A.show(A.placer.selectedPlace?A.templates.error:A.templates.choose)}).method("showPlaces",function(C){var F=this;F.show(F.templates.places,true);F.$nearbyActivity.find(".geo_nearby_activity_header").append(F.renderPlace(twttr.geo.templates.nearbyActivityHeader,F.placer.selectedPlace));var E=F.placer.places.length;if(E==0){F.$nearbyActivity.append(Mustache.to_html(F.templates.noPlaces));return }var B=C*twttr.geo.PLACE_SEARCH_RESULTS_PER_PAGE;var A=B+twttr.geo.PLACE_SEARCH_RESULTS_PER_PAGE;var D=F.placer.places.slice(B,A);D.forEach(function(G){F.$nearbyActivity.find("ul").append(F.renderPlace(twttr.geo.templates.nearbyActivityItem,G))});if(E>twttr.geo.PLACE_SEARCH_RESULTS_PER_PAGE){F.$nearbyActivity.append(Mustache.to_html(F.templates.nextPrev));F.setNextPrev(F.$nearbyActivity.find(".geo_prev"),C>0,C-1);F.setNextPrev(F.$nearbyActivity.find(".geo_next"),A<E,C+1)}}).method("renderPlace",function(B,A){var C=this;var D=twttr.geo.renderPlace(B,A);D.find("a").attr(twttr.geo.getPlacePageLinkAttrsFromPlace(A)).isSearchLink().click(function(){C.placer.selectPlace(A);C.search()});return D}).method("setNextPrev",function(A,C,B){var D=this;A.click(function(E){E.preventDefault();if(C){D.showPlaces(B)}});if(!C){A.addClass("link-disabled")}});twttr.klass("twttr.geo.UpdateUi",function(B){var A=this;A.opts=twttr.merge({geo_enabled:false,has_dismissed_geo_promo:false,current_user_path:null,granularity:"neighborhood",queryParams:twttr.unparam(window.location.search.substr(1))},twttr.geo.options,B);if(A.opts.queryParams.ip){twttr.geo.IP=A.opts.queryParams.ip}A.locator=new twttr.geo.Locator(A.opts.queryParams);$(".geo_enable_webclient").live("click",function(C){C.preventDefault();A.enableGeoForWebClient()});$(".geo_disable_webclient").live("click",function(C){C.preventDefault();A.disableGeoForWebClient()});if(A.opts.geo_enabled){if($.cookie("geo_webclient")){A.detectLocation(false)}else{A.disableGeoForWebClient();A.initNearbyActivity()}}else{if(!$.cookie("geo_promo_hidden")&&!$("#latest_status.first-tweet").length){A.setGeoStatus('<span class="geo_new">'+_("New!")+"</span> "+_("Add a location to your tweets.")+' <a id="show_geo_dialog" href="#">'+_("Turn it on")+'</a> - <a id="hide_geo_promo" href="#">'+_("No thanks")+"</a>");$("#hide_geo_promo").click(function(C){C.preventDefault();if(!$(this).hasClass("link-disabled")){A.hidePromoDialog();$.cookie("geo_promo_hidden","1",{expires:3650});$("#geo_status").slideUp();twttr.geo.geoScribe("promo_bar_no_thanks")}});$("#show_geo_dialog").click(function(C){C.preventDefault();C.stopPropagation();if(!$(this).hasClass("link-disabled")){A.showPromoDialog();twttr.geo.geoScribe("void")}});if(!A.opts.has_dismissed_geo_promo){A.showPromoDialog();twttr.geo.geoScribe("promo_bar_dialog_pop")}twttr.geo.geoScribe("promo_bar_shown")}A.initNearbyActivity()}}).augmentProto({templates:{disable_geo:' <a href="#" class="geo_disable_webclient"><span>&nbsp;</span></a>'}}).method("initNearbyActivity",function(A){if(twttr.geo.options.nearby_activity&&!this.nearbyActivity){this.nearbyActivity=new twttr.geo.NearbyActivity(A)}}).method("setGeoStatus",function(A){$("#geo_status").html(A)}).method("scribeLocationDetection",function(A,B){twttr.geo.geoScribe("location_detection_complete",$.extend({status:A,locator_type:this.locator.locatorType},B))}).method("lookupPlacesAndShowDropdown",function(B,D){var C=this;var A=new twttr.geo.Placer({geoParams:B});A.search(function(){C.scribeLocationDetection("place_lookup_succeeded",A.getState());C.setGeoStatus('<span id="place_content"></span>'+C.templates.disable_geo);new twttr.geo.PlacesDropdown(A,C.opts);C.initNearbyActivity(A)},function(){C.cannotDetectLocation(D);C.scribeLocationDetection("place_lookup_failed",A.getState())},function(){C.setGeoStatus(_("Location service is currently unavailable.")+' <a href="#" class="geo_enable_webclient">'+_("Try again")+"</a>"+C.templates.disable_geo);C.initNearbyActivity()})}).method("detectLocationByIp",function(B){var A=this;if(twttr.geo.IP){$("#lat").val();$("#lon").val();A.lookupPlacesAndShowDropdown({ip:twttr.geo.IP,accuracy:16000,granularity:A.opts.granularity,max_results:twttr.geo.MAX_NEARBY_PLACES},B)}else{A.scribeLocationDetection("place_lookup_no_ip");A.cannotDetectLocation(B)}}).method("cannotDetectLocation",function(B){var A=this;if(A.opts.allow_set_location_manually){if(B){A.setLocationManually()}else{A.setGeoStatus(_("We couldn't find you!")+' <a href="#" class="geo_add_manual">'+_("Add Location")+"</a>"+A.templates.disable_geo);$(".geo_add_manual").click(function(C){C.preventDefault();A.setLocationManually()})}}else{A.setGeoStatus(_("Unable to associate your coordinates with a place.")+' <a href="#" class="geo_enable_webclient">'+_("Try again")+"</a>"+A.templates.disable_geo)}A.initNearbyActivity()}).method("setLocationManually",function(){var D=this;var C=new twttr.geo.Placer({geoParams:{granularity:D.opts.granularity}});var A=function(){D.setGeoStatusAddYourLocation();new twttr.geo.PlaceSearchDialog(C,D.opts,function(){D.setGeoStatus('<span id="place_content"></span>'+D.templates.disable_geo);new twttr.geo.PlacesDropdown(C,D.opts)});twttr.geo.geoScribe("set_location_manually")};var B=C.getRecentPlaceId();if(B){D.setGeoStatus('<span class="crosshairs">&nbsp;</span><span class="geo_progress">'+_("Getting recent location...")+"</span>"+D.templates.disable_geo);C.selectPlaceById(B,function(){A()},function(){A()})}else{A()}}).method("detectLocation",function(B){$("#lat").val("");$("#lon").val("");$("#place_id").val("");this.setGeoStatus('<span class="crosshairs">&nbsp;</span><span class="geo_progress">'+_("Getting your location...")+"</span>"+this.templates.disable_geo);var A=this;if(!A.locator.isLocatable()||A.opts.queryParams.nodetect!==undefined){A.detectLocationByIp(B)}else{A.locator.getLocation({onSuccess:function(C){$("#lat").val(C.latitude);$("#lon").val(C.longitude);A.lookupPlacesAndShowDropdown({lat:C.latitude,lon:C.longitude,accuracy:C.accuracy,granularity:A.opts.granularity,max_results:twttr.geo.MAX_NEARBY_PLACES},false)},onFailure:function(C){if(!C.fatal){A.detectLocationByIp(B)}else{A.disableGeoForWebClient();A.scribeLocationDetection("denied_by_user")}}})}}).method("showPromoDialog",function(){var B=this;var C=$("#show_geo_dialog");var A=$('<div class="hoverer" id="geo-promo-hoverer"> <div class="hoverer-inner"> <div class="tiny-map"><img src="httpdisabled://s.twimg.com/a/1302214109/images/tiny-map.gif"></div> <h3>'+_("Add a location to your tweets")+'</h3> <div id="geo_dialog_descr">'+_('Ever had something you wanted to share ("fireworks!", "party!", "ice cream truck!", or "quicksand...") that would be better with a location?')+" "+_("By turning on this feature, you can include location information like neighborhood, town, or exact point when you tweet.")+"<br><br>"+_("When you tweet with a location, Twitter stores that location.")+" "+_("You can switch location on/off before each tweet and always have the option to delete your location history.")+' <a id="geo_learn_more" href="httpdisabled://twitter.zendesk.com/forums/26810/entries/78525" target="_blank">'+_("Learn more")+'</a> </div> <div> <button id="geo_turn_location_on" class="btn">'+_("Turn location on")+'</button> <a href="#" id="geo_not_now" class="geo_dialog_close">'+_("Not now")+'</a> </div> </div> <div class="hovercard-divot"></div> </div>').insertAfter(C);twttr.SimplePositioner.setPosition(A,C,{direction:"below",offsets:{below:{top:10,left:-50}},hasContainer:true});$("#show_geo_dialog,#hide_geo_promo").addClass("link-disabled");$("#geo_turn_location_on").click(function(){B.turnLocationOn();twttr.geo.geoScribe("promo_dialog_turn_location_on")});$(".geo_dialog_close").click(function(D){D.preventDefault();B.hidePromoDialog();twttr.geo.geoScribe("promo_dialog_not_now")});$("#geo-promo-hoverer").click(function(D){D.stopPropagation()});$("html").one("click",function(){if($("#geo-promo-hoverer:visible").length>0){B.hidePromoDialog();twttr.geo.geoScribe("promo_dialog_click_outside")}});A.css("visibility","visible")}).method("hidePromoDialog",function(){if(!this.opts.has_dismissed_geo_promo){this.setUserFlag("has_dismissed_geo_promo");this.opts.has_dismissed_geo_promo=true}$("#geo-promo-hoverer").remove();$("#show_geo_dialog,#hide_geo_promo").removeClass("link-disabled")}).method("turnLocationOn",function(){this.setUserFlag("geo_enabled");this.opts.geo_enabled=true;this.hidePromoDialog();this.enableGeoForWebClient()}).method("setUserFlag",function(A){data={authenticity_token:twttr.form_authenticity_token,_method:"put"};data["user["+A+"]"]="1";$.ajax({type:"POST",url:this.opts.current_user_path,data:data})}).method("enableGeoForWebClient",function(){if(!$.cookie("geo_webclient")){$.cookie("geo_webclient","1",{expires:3650})}this.detectLocation(true)}).method("setGeoStatusAddYourLocation",function(){this.setGeoStatus('<span class="crosshairs">&nbsp;</span><a href="#" class="geo_enable_webclient">'+_("Add your location")+"</a>")}).method("disableGeoForWebClient",function(){$("#lat").val("");$("#lon").val("");$("#place_id").val("");if($.cookie("geo_webclient")){$.cookie("geo_webclient",null)}this.setGeoStatusAddYourLocation()});
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/javascripts/twitter.js@1302215522 b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/javascripts/twitter.js@1302215522
deleted file mode 100755
index 2bce4f72a..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/javascripts/twitter.js@1302215522
+++ /dev/null
@@ -1,2435 +0,0 @@
-/*
- * Copyright (c) 2007 Josh Bush (digitalbush.com)
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
-
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
- * Version: Beta 1
- * Release: 2007-06-01
- */
-(function($) {
- var map=new Array();
- $.Watermark = {
- ShowAll:function(){
- for (var i=0;i<map.length;i++){
- if(map[i].obj.val()==""){
- map[i].obj.val(map[i].text);
- map[i].obj.css("color",map[i].WatermarkColor);
- }else{
- map[i].obj.css("color",map[i].DefaultColor);
- }
- }
- },
- HideAll:function(){
- for (var i=0;i<map.length;i++){
- if(map[i].obj.val()==map[i].text)
- map[i].obj.val("");
- }
- }
- }
-
- $.fn.Watermark = function(text,color) {
- if(!color)
- color="#aaa";
- return this.each(
- function(){
- var input=$(this);
- var defaultColor=input.css("color");
- map[map.length]={text:text,obj:input,DefaultColor:defaultColor,WatermarkColor:color};
- function clearMessage(){
- if(input.val()==text)
- input.val("");
- input.css("color",defaultColor);
- }
-
- function insertMessage(){
- if(input.val().length==0 || input.val()==text){
- input.val(text);
- input.css("color",color);
- }else
- input.css("color",defaultColor);
- }
-
- input.focus(clearMessage);
- input.blur(insertMessage);
- input.change(insertMessage);
-
- insertMessage();
- }
- );
- };
-})(jQuery);
-/*
- * Cookie plugin
- *
- * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
- * Dual licensed under the MIT and GPL licenses:
- * http://voidsource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- *
- */
-jQuery.cookie = function(name, value, options) {
- if (typeof value != 'undefined') { // name and value given, set cookie
- options = options || {};
- if (value === null) {
- value = '';
- options.expires = -1;
- }
- var expires = '';
- if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
- var date;
- if (typeof options.expires == 'number') {
- date = new Date();
- date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
- } else {
- date = options.expires;
- }
- expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
- }
- // CAUTION: Needed to parenthesize options.path and options.domain
- // in the following expressions, otherwise they evaluate to undefined
- // in the packed version for some reason...
- var path = options.path ? '; path=' + (options.path) : '';
- var domain = options.domain ? '; domain=' + (options.domain) : '';
- var secure = options.secure ? '; secure' : '';
- document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
- } else { // only name given, get cookie
- var cookieValue = null;
- if (document.cookie && document.cookie != '') {
- var cookies = document.cookie.split(';');
- for (var i = 0; i < cookies.length; i++) {
- var cookie = jQuery.trim(cookies[i]);
- // Does this cookie string begin with the name we want?
- if (cookie.substring(0, name.length + 1) == (name + '=')) {
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
- break;
- }
- }
- }
- return cookieValue;
- }
-};
-/*
- * jQuery Color Animations
- * Copyright 2007 John Resig
- * Released under the MIT and GPL licenses.
- */
-
-(function(jQuery){
-
- // We override the animation for all of these color styles
- jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor', 'borderColor'], function(i,attr){
- jQuery.fx.step[attr] = function(fx){
- if ( fx.state == 0 ) {
- fx.start = getColor( fx.elem, attr );
- fx.end = getRGB( fx.end );
- }
-
- fx.elem.style[attr] = "rgb(" + [
- Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
- Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
- Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
- ].join(",") + ")";
- }
- });
-
- // Color Conversion functions from highlightFade
- // By Blair Mitchelmore
- // http://jquery.offput.ca/highlightFade/
-
- // Parse strings looking for color tuples [255,255,255]
- function getRGB(color) {
- var result;
-
- // Check if we're already dealing with an array of colors
- if ( color && color.constructor == Array && color.length == 3 )
- return color;
-
- // Look for rgb(num,num,num)
- if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
- return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];
-
- // Look for rgb(num%,num%,num%)
- if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
- return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];
-
- // Look for #a0b1c2
- if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
- return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];
-
- // Look for #fff
- if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
- return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];
-
- // Otherwise, we're most likely dealing with a named color
- return colors[jQuery.trim(color).toLowerCase()];
- }
-
- function getColor(elem, attr) {
- var color;
-
- do {
- color = jQuery.curCSS(elem, attr);
-
- // Keep going until we find an element that has color, or we hit the body
- if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
- break;
-
- attr = "backgroundColor";
- } while ( elem = elem.parentNode );
-
- return getRGB(color);
- };
-
- // Some named colors to work with
- // From Interface by Stefan Petre
- // http://interface.eyecon.ro/
-
- var colors = {
- aqua:[0,255,255],
- azure:[240,255,255],
- beige:[245,245,220],
- black:[0,0,0],
- blue:[0,0,255],
- brown:[165,42,42],
- cyan:[0,255,255],
- darkblue:[0,0,139],
- darkcyan:[0,139,139],
- darkgrey:[169,169,169],
- darkgreen:[0,100,0],
- darkkhaki:[189,183,107],
- darkmagenta:[139,0,139],
- darkolivegreen:[85,107,47],
- darkorange:[255,140,0],
- darkorchid:[153,50,204],
- darkred:[139,0,0],
- darksalmon:[233,150,122],
- darkviolet:[148,0,211],
- fuchsia:[255,0,255],
- gold:[255,215,0],
- green:[0,128,0],
- indigo:[75,0,130],
- khaki:[240,230,140],
- lightblue:[173,216,230],
- lightcyan:[224,255,255],
- lightgreen:[144,238,144],
- lightgrey:[211,211,211],
- lightpink:[255,182,193],
- lightyellow:[255,255,224],
- lime:[0,255,0],
- magenta:[255,0,255],
- maroon:[128,0,0],
- navy:[0,0,128],
- olive:[128,128,0],
- orange:[255,165,0],
- pink:[255,192,203],
- purple:[128,0,128],
- violet:[128,0,128],
- red:[255,0,0],
- silver:[192,192,192],
- white:[255,255,255],
- yellow:[255,255,0]
- };
-
-})(jQuery);
-/* Copyright (c) 2008 Brandon Aaron (http://brandonaaron.net)
- * Dual licensed under the MIT (http://voidsource.org/licenses/mit-license.php)
- * and GPL (http://voidsource.org/licenses/gpl-license.php) licenses.
- *
- * Version: 1.0.3
- * Requires jQuery 1.1.3+
- * Docs: http://docs.jquery.com/Plugins/livequery
- */
-
-(function($) {
-
-$.extend($.fn, {
- livequery: function(type, fn, fn2) {
- var self = this, q;
-
- // Handle different call patterns
- if ($.isFunction(type))
- fn2 = fn, fn = type, type = undefined;
-
- // See if Live Query already exists
- $.each( $.livequery.queries, function(i, query) {
- if ( self.selector == query.selector && self.context == query.context &&
- type == query.type && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) )
- // Found the query, exit the each loop
- return (q = query) && false;
- });
-
- // Create new Live Query if it wasn't found
- q = q || new $.livequery(this.selector, this.context, type, fn, fn2);
-
- // Make sure it is running
- q.stopped = false;
-
- // Run it immediately for the first time
- q.run();
-
- // Contnue the chain
- return this;
- },
-
- expire: function(type, fn, fn2) {
- var self = this;
-
- // Handle different call patterns
- if ($.isFunction(type))
- fn2 = fn, fn = type, type = undefined;
-
- // Find the Live Query based on arguments and stop it
- $.each( $.livequery.queries, function(i, query) {
- if ( self.selector == query.selector && self.context == query.context &&
- (!type || type == query.type) && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) && !this.stopped )
- $.livequery.stop(query.id);
- });
-
- // Continue the chain
- return this;
- }
-});
-
-$.livequery = function(selector, context, type, fn, fn2) {
- this.selector = selector;
- this.context = context || document;
- this.type = type;
- this.fn = fn;
- this.fn2 = fn2;
- this.elements = [];
- this.stopped = false;
-
- // The id is the index of the Live Query in $.livequery.queries
- this.id = $.livequery.queries.push(this)-1;
-
- // Mark the functions for matching later on
- fn.$lqguid = fn.$lqguid || $.livequery.guid++;
- if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++;
-
- // Return the Live Query
- return this;
-};
-
-$.livequery.prototype = {
- stop: function() {
- var query = this;
-
- if ( this.type )
- // Unbind all bound events
- this.elements.unbind(this.type, this.fn);
- else if (this.fn2)
- // Call the second function for all matched elements
- this.elements.each(function(i, el) {
- query.fn2.apply(el);
- });
-
- // Clear out matched elements
- this.elements = [];
-
- // Stop the Live Query from running until restarted
- this.stopped = true;
- },
-
- run: function() {
- // Short-circuit if stopped
- if ( this.stopped ) return;
- var query = this;
-
- var oEls = this.elements,
- els = $(this.selector, this.context),
- nEls = els.not(oEls);
-
- // Set elements to the latest set of matched elements
- this.elements = els;
-
- if (this.type) {
- // Bind events to newly matched elements
- nEls.bind(this.type, this.fn);
-
- // Unbind events to elements no longer matched
- if (oEls.length > 0)
- $.each(oEls, function(i, el) {
- if ( $.inArray(el, els) < 0 )
- $.event.remove(el, query.type, query.fn);
- });
- }
- else {
- // Call the first function for newly matched elements
- nEls.each(function() {
- query.fn.apply(this);
- });
-
- // Call the second function for elements no longer matched
- if ( this.fn2 && oEls.length > 0 )
- $.each(oEls, function(i, el) {
- if ( $.inArray(el, els) < 0 )
- query.fn2.apply(el);
- });
- }
- }
-};
-
-$.extend($.livequery, {
- guid: 0,
- queries: [],
- queue: [],
- running: false,
- timeout: null,
-
- checkQueue: function() {
- if ( $.livequery.running && $.livequery.queue.length ) {
- var length = $.livequery.queue.length;
- // Run each Live Query currently in the queue
- while ( length-- )
- $.livequery.queries[ $.livequery.queue.shift() ].run();
- }
- },
-
- pause: function() {
- // Don't run anymore Live Queries until restarted
- $.livequery.running = false;
- },
-
- play: function() {
- // Restart Live Queries
- $.livequery.running = true;
- // Request a run of the Live Queries
- $.livequery.run();
- },
-
- registerPlugin: function() {
- $.each( arguments, function(i,n) {
- // Short-circuit if the method doesn't exist
- if (!$.fn[n]) return;
-
- // Save a reference to the original method
- var old = $.fn[n];
-
- // Create a new method
- $.fn[n] = function() {
- // Call the original method
- var r = old.apply(this, arguments);
-
- // Request a run of the Live Queries
- $.livequery.run();
-
- // Return the original methods result
- return r;
- }
- });
- },
-
- run: function(id) {
- if (id != undefined) {
- // Put the particular Live Query in the queue if it doesn't already exist
- if ( $.inArray(id, $.livequery.queue) < 0 )
- $.livequery.queue.push( id );
- }
- else
- // Put each Live Query in the queue if it doesn't already exist
- $.each( $.livequery.queries, function(id) {
- if ( $.inArray(id, $.livequery.queue) < 0 )
- $.livequery.queue.push( id );
- });
-
- // Clear timeout if it already exists
- if ($.livequery.timeout) clearTimeout($.livequery.timeout);
- // Create a timeout to check the queue and actually run the Live Queries
- $.livequery.timeout = setTimeout($.livequery.checkQueue, 20);
- },
-
- stop: function(id) {
- if (id != undefined)
- // Stop are particular Live Query
- $.livequery.queries[ id ].stop();
- else
- // Stop all Live Queries
- $.each( $.livequery.queries, function(id) {
- $.livequery.queries[ id ].stop();
- });
- }
-});
-
-// Register core DOM manipulation methods
-$.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove');
-
-// Run Live Queries when the Document is ready
-$(function() { $.livequery.play(); });
-
-
-// Save a reference to the original init method
-var init = $.prototype.init;
-
-// Create a new init method that exposes two new properties: selector and context
-$.prototype.init = function(a,c) {
- // Call the original init and save the result
- var r = init.apply(this, arguments);
-
- // Copy over properties if they exist already
- if (a && a.selector)
- r.context = a.context, r.selector = a.selector;
-
- // Set properties
- if ( typeof a == 'string' )
- r.context = c || document, r.selector = a;
-
- // Return the result
- return r;
-};
-
-// Give the init function the jQuery prototype for later instantiation (needed after Rev 4091)
-$.prototype.init.prototype = $.prototype;
-
-})(jQuery);/*
- * Metadata - jQuery plugin for parsing metadata from elements
- *
- * Copyright (c) 2006 John Resig, Yehuda Katz, J�örn Zaefferer, Paul McLanahan
- *
- * Dual licensed under the MIT and GPL licenses:
- * http://voidsource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- *
- * Revision: $Id: jquery.metadata.js 3640 2007-10-11 18:34:38Z pmclanahan $
- *
- */
-
-/**
- * Sets the type of metadata to use. Metadata is encoded in JSON, and each property
- * in the JSON will become a property of the element itself.
- *
- * There are four supported types of metadata storage:
- *
- * attr: Inside an attribute. The name parameter indicates *which* attribute.
- *
- * class: Inside the class attribute, wrapped in curly braces: { }
- *
- * elem: Inside a child element (e.g. a script tag). The
- * name parameter indicates *which* element.
- * html5: Values are stored in data-* attributes.
- *
- * The metadata for an element is loaddisableded the first time the element is accessed via jQuery.
- *
- * As a result, you can define the metadata type, use $(expr) to loaddisabled the metadata into the elements
- * matched by expr, then redefine the metadata type and run another $(expr) for other elements.
- *
- * @name $.metadata.setType
- *
- * @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
- * @before $.metadata.setType("class")
- * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
- * @desc Reads metadata from the class attribute
- *
- * @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
- * @before $.metadata.setType("attr", "data")
- * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
- * @desc Reads metadata from a "data" attribute
- *
- * @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
- * @before $.metadata.setType("elem", "script")
- * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
- * @desc Reads metadata from a nested script element
- *
- * @example <p id="one" class="some_class" data-item_id="1" data-item_label="Label">This is a p</p>
- * @before $.metadata.setType("html5")
- * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
- * @desc Reads metadata from a series of data-* attributes
- *
- * @param String type The encoding type
- * @param String name The name of the attribute to be used to get metadata (optional)
- * @cat Plugins/Metadata
- * @descr Sets the type of encoding to be used when loaddisableding metadata for the first time
- * @type undefined
- * @see metadata()
- */
-
-(function($) {
-
-$.extend({
- metadata : {
- defaults : {
- type: 'class',
- name: 'metadata',
- cre: /({.*})/,
- single: 'metadata'
- },
- setType: function( type, name ){
- this.defaults.type = type;
- this.defaults.name = name;
- },
- get: function( elem, opts ){
- var settings = $.extend({},this.defaults,opts);
- // check for empty string in single property
- if ( !settings.single.length ) settings.single = 'metadata';
-
- var data = $.data(elem, settings.single);
- // returned cached data if it already exists
- if ( data ) return data;
-
- data = "{}";
-
- var getData = function(data) {
- if(typeof data != "string") return data;
-
- if( data.indexOf('{') < 0 ) {
- data = eval("(" + data + ")");
- }
- }
-
- var getObject = function(data) {
- if(typeof data != "string") return data;
-
- data = eval("(" + data + ")");
- return data;
- }
-
- if ( settings.type == "html5" ) {
- var object = {};
- $( elem.attributes ).each(function() {
- var name = this.nodeName;
- if(name.match(/^data-/)) name = name.replace(/^data-/, '');
- else return true;
- object[name] = getObject(this.nodeValue);
- });
- } else {
- if ( settings.type == "class" ) {
- var m = settings.cre.exec( elem.className );
- if ( m )
- data = m[1];
- } else if ( settings.type == "elem" ) {
- if( !elem.getElementsByTagName ) return;
- var e = elem.getElementsByTagName(settings.name);
- if ( e.length )
- data = $.trim(e[0].innerHTML);
- } else if ( elem.getAttribute != undefined ) {
- var attr = elem.getAttribute( settings.name );
- if ( attr )
- data = attr;
- }
- object = getObject(data.indexOf("{") < 0 ? "{" + data + "}" : data);
- }
-
- $.data( elem, settings.single, object );
- return object;
- }
- }
-});
-
-/**
- * Returns the metadata object for the first member of the jQuery object.
- *
- * @name metadata
- * @descr Returns element's metadata object
- * @param Object opts An object contianing settings to override the defaults
- * @type jQuery
- * @cat Plugins/Metadata
- */
-$.fn.metadata = function( opts ){
- return $.metadata.get( this[0], opts );
-};
-
-})(jQuery);//Licensed under The MIT License
-//Copyright (c) 2008 Jason Frame (jason@onehackoranother.com)
-
-
-(function($) {
- $.fn.tipsy = function(opts) {
-
- opts = $.extend({fade: false, gravity: 'n'}, opts || {});
- // ...Added by andy@twitter.com 20090717
- if(!opts['offsetTop']) { opts['offsetTop'] = 0; }
- if(!opts['offsetLeft']) { opts['offsetLeft'] = 0; }
- if(!opts['header']) { opts['header'] = ''; }
- if(!opts['footer']) { opts['footer'] = ''; }
- if(!opts['hideTimeout']) { opts['hideTimeout'] = 100; }
- if(!opts['showTimeout']) { opts['hideTimeout'] = 0; }
- if(!opts['additionalCSSClass']) { opts['additionalCSSClass'] = ''; }
- var showTimeoutKey = false;
- // ...Added by andy@twitter.com 20090717
- var tip = null, cancelHide = false;
- this.hover(function() {
-
- // ...Added by andy@twitter.com 20090717
- var linkText = $(this).text();
- var header = opts['header'].replace('%{link}', linkText);
- var footer = opts['footer'].replace('%{link}', linkText);
- // ...Added by andy@twitter.com 20090717
-
- $.data(this, 'cancel.tipsy', true);
-
- var tip = $.data(this, 'active.tipsy');
- if (!tip) {
- $('.tipsy').hide();
- tip = $('<div class="tipsy '+ opts['additionalCSSClass'] +'"><div class="tipsy-inner">' + header + $(this).attr('title') + footer + '</div></div>');
- tip.css({position: 'absolute', zIndex: 100000});
- $(this).attr('title', '');
- $.data(this, 'active.tipsy', tip);
- // Added by rael@twitter.com 20090628...
- } else if ($(this).attr('title') != '') {
- tip.find('.tipsy-inner').html($(this).attr('title'));
- $(this).attr('title', '');
- // ...Added by rael@twitter.com 20090628
- }
-
- var pos = $.extend({}, $(this).offset(), {width: this.offsetWidth, height: this.offsetHeight});
- // ...Added by andy@twitter.com 20090717
- pos.top = pos.top + opts['offsetTop'];
- pos.left = pos.left + opts['offsetLeft'];
-
- // void tips if timeout to fade
- $('.tipsy').hide();
- // ...Added by andy@twitter.com 20090717
- tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).appendTo(document.body);
- var actualWidth = tip[0].offsetWidth, actualHeight = tip[0].offsetHeight;
-
- switch (opts.gravity.charAt(0)) {
- case 'n':
- tip.css({top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}).addClass('tipsy-north');
- break;
- case 'l':
- //left north align
- tip.css({top: pos.top + pos.height, left: pos.left + pos.width / 2 - 18}).addClass('tipsy-north');
- break;
- case 's':
- tip.css({top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}).addClass('tipsy-south');
- break;
- case 'e':
- tip.css({top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}).addClass('tipsy-east');
- break;
- case 'w':
- tip.css({top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}).addClass('tipsy-west');
- break;
- }
- // ...Added by andy@twitter.com 20090717
- function show() {
- if (opts.fade) {
- tip.css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: 1});
- } else {
- tip.css({visibility: 'visible'});
- }
- }
- if(opts['showTimeout']) {
- showTimeoutKey = setTimeout(show, opts['showTimeout']);
- } else {
- show();
- }
- }, function() {
- clearTimeout(showTimeoutKey);
- // ...Added by andy@twitter.com 20090717
- $.data(this, 'cancel.tipsy', false);
- var self = this;
- setTimeout(function() {
- if ($.data(this, 'cancel.tipsy')) return;
- var tip = $.data(self, 'active.tipsy');
- if (opts.fade) {
- tip.stop().fadeOut(function() { $(this).remove(); });
- } else {
- tip.remove();
- }
- }, opts['hideTimeout']);
- });
-
- };
-})(jQuery);
-/*
- * jQuery Form Plugin
- * version: 2.36 (07-NOV-2009)
- * @requires jQuery v1.2.6 or later
- *
- * Examples and documentation at: http://malsup.com/jquery/form/
- * Dual licensed under the MIT and GPL licenses:
- * http://voidsource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- */
-;(function($) {
-
-/*
- Usage Note:
- -----------
- Do not use both ajaxSubmit and ajaxForm on the same form. These
- functions are intended to be exclusive. Use ajaxSubmit if you want
- to bind your own submit handler to the form. For example,
-
- $(document).ready(function() {
- $('#myForm').bind('submit', function() {
- $(this).ajaxSubmit({
- target: '#output'
- });
- return false; // <-- important!
- });
- });
-
- Use ajaxForm when you want the plugin to manage all the event binding
- for you. For example,
-
- $(document).ready(function() {
- $('#myForm').ajaxForm({
- target: '#output'
- });
- });
-
- When using ajaxForm, the ajaxSubmit function will be invoked for you
- at the appropriate time.
-*/
-
-/**
- * ajaxSubmit() provides a mechanism for immediately submitting
- * an HTML form using AJAX.
- */
-$.fn.ajaxSubmit = function(options) {
- // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
- if (!this.length) {
- log('ajaxSubmit: skipping submit process - no element selected');
- return this;
- }
-
- if (typeof options == 'function')
- options = { success: options };
-
- var url = $.trim(this.attr('action'));
- if (url) {
- // clean url (don't include hash vaue)
- url = (url.match(/^([^#]+)/)||[])[1];
- }
- url = url || window.location.href || '';
-
- options = $.extend({
- url: url,
- type: this.attr('method') || 'GET',
- iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
- }, options || {});
-
- // hook for manipulating the form data before it is extracted;
- // convenient for use with rich editors like tinyMCE or FCKEditor
- var veto = {};
- this.trigger('form-pre-serialize', [this, options, veto]);
- if (veto.veto) {
- log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
- return this;
- }
-
- // provide opportunity to alter form data before it is serialized
- if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
- log('ajaxSubmit: submit aborted via beforeSerialize callback');
- return this;
- }
-
- var a = this.formToArray(options.semantic);
- if (options.data) {
- options.extraData = options.data;
- for (var n in options.data) {
- if(options.data[n] instanceof Array) {
- for (var k in options.data[n])
- a.push( { name: n, value: options.data[n][k] } );
- }
- else
- a.push( { name: n, value: options.data[n] } );
- }
- }
-
- // give pre-submit callback an opportunity to abort the submit
- if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
- log('ajaxSubmit: submit aborted via beforeSubmit callback');
- return this;
- }
-
- // fire vetoable 'validate' event
- this.trigger('form-submit-validate', [a, this, options, veto]);
- if (veto.veto) {
- log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
- return this;
- }
-
- var q = $.param(a);
-
- if (options.type.toUpperCase() == 'GET') {
- options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
- options.data = null; // data is null for 'get'
- }
- else
- options.data = q; // data is the query string for 'post'
-
- var $form = this, callbacks = [];
- if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
- if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
-
- // perform a loaddisabled on the target only if dataType is not provided
- if (!options.dataType && options.target) {
- var oldSuccess = options.success || function(){};
- callbacks.push(function(data) {
- $(options.target).html(data).each(oldSuccess, arguments);
- });
- }
- else if (options.success)
- callbacks.push(options.success);
-
- options.success = function(data, status) {
- for (var i=0, max=callbacks.length; i < max; i++)
- callbacks[i].apply(options, [data, status, $form]);
- };
-
- // are there files to uploaddisabled?
- var files = $('input:file', this).fieldValue();
- var found = false;
- for (var j=0; j < files.length; j++)
- if (files[j])
- found = true;
-
- var multipart = false;
-// var mp = 'multipart/form-data';
-// multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
-
- // options.iframe allows user to force iframe mode
- // 06-NOV-09: now defaulting to iframe mode if file input is detected
- if ((files.length && options.iframe !== false) || options.iframe || found || multipart) {
- // hack to fix Safari hang (thanks to Tim Molendijk for this)
- // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
- if (options.closeKeepAlive)
- $.get(options.closeKeepAlive, fileUploaddisabled);
- else
- fileUploaddisabled();
- }
- else
- $.ajax(options);
-
- // fire 'notify' event
- this.trigger('form-submit-notify', [this, options]);
- return this;
-
-
- // private function for handling file uploaddisableds (hat tip to YAHOO!)
- function fileUploaddisabled() {
- var form = $form[0];
-
- if ($(':input[name=submit]', form).length) {
- alert('Error: Form elements must not be named "submit".');
- return;
- }
-
- var opts = $.extend({}, $.ajaxSettings, options);
- var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
-
- var id = 'jqFormIO' + (new Date().getTime());
- var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ opts.iframeSrc +'" />');
- var io = $io[0];
-
- $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
-
- var xhr = { // mock object
- aborted: 0,
- responseText: null,
- responseXML: null,
- status: 0,
- statusText: 'n/a',
- getAllResponseHeaders: function() {},
- getResponseHeader: function() {},
- setRequestHeader: function() {},
- abort: function() {
- this.aborted = 1;
- $io.attr('src', opts.iframeSrc); // abort op in progress
- }
- };
-
- var g = opts.global;
- // trigger ajax global events so that activity/block indicators work like normal
- if (g && ! $.active++) $.event.trigger("ajaxStart");
- if (g) $.event.trigger("ajaxSend", [xhr, opts]);
-
- if (s.beforeSend && s.beforeSend(xhr, s) === false) {
- s.global && $.active--;
- return;
- }
- if (xhr.aborted)
- return;
-
- var cbInvoked = 0;
- var timedOut = 0;
-
- // add submitting element to data if we know it
- var sub = form.clk;
- if (sub) {
- var n = sub.name;
- if (n && !sub.disabled) {
- options.extraData = options.extraData || {};
- options.extraData[n] = sub.value;
- if (sub.type == "image") {
- options.extraData[name+'.x'] = form.clk_x;
- options.extraData[name+'.y'] = form.clk_y;
- }
- }
- }
-
- // take a breath so that pending repaints get some cpu time before the uploaddisabled starts
- setTimeout(function() {
- // make sure form attrs are set
- var t = $form.attr('target'), a = $form.attr('action');
-
- // update form attrs in IE friendly way
- form.setAttribute('target',id);
- if (form.getAttribute('method') != 'POST')
- form.setAttribute('method', 'POST');
- if (form.getAttribute('action') != opts.url)
- form.setAttribute('action', opts.url);
-
- // ie borks in some cases when setting encoding
- if (! options.skipEncodingOverride) {
- $form.attr({
- encoding: 'multipart/form-data',
- enctype: 'multipart/form-data'
- });
- }
-
- // support timout
- if (opts.timeout)
- setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
-
- // add "extra" data to form if provided in options
- var extraInputs = [];
- try {
- if (options.extraData)
- for (var n in options.extraData)
- extraInputs.push(
- $('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
- .appendTo(form)[0]);
-
- // add iframe to doc and submit the form
- $io.appendTo('body');
- io.attachEvent ? io.attachEvent('onloaddisabled', cb) : io.addEventListener('loaddisabled', cb, false);
- form.submit();
- }
- finally {
- // reset attrs and remove "extra" input elements
- form.setAttribute('action',a);
- t ? form.setAttribute('target', t) : $form.removeAttr('target');
- $(extraInputs).remove();
- }
- }, 10);
-
- var domCheckCount = 50;
-
- function cb() {
- if (cbInvoked++) return;
-
- io.detachEvent ? io.detachEvent('onloaddisabled', cb) : io.removeEventListener('loaddisabled', cb, false);
-
- var ok = true;
- try {
- if (timedOut) throw 'timeout';
- // extract the server response from the iframe
- var data, doc;
-
- doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
-
- var isXml = opts.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
- log('isXml='+isXml);
- if (!isXml && (doc.body == null || doc.body.innerHTML == '')) {
- if (--domCheckCount) {
- // in some browsers (Opera) the iframe DOM is not always traversable when
- // the onloaddisabled callback fires, so we loop a bit to accommodate
- cbInvoked = 0;
- setTimeout(cb, 100);
- return;
- }
- log('Could not access iframe DOM after 50 tries.');
- return;
- }
-
- xhr.responseText = doc.body ? doc.body.innerHTML : null;
- xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
- xhr.getResponseHeader = function(header){
- var headers = {'content-type': opts.dataType};
- return headers[header];
- };
-
- if (opts.dataType == 'json' || opts.dataType == 'script') {
- // see if user embedded response in textarea
- var ta = doc.getElementsByTagName('textarea')[0];
- if (ta)
- xhr.responseText = ta.value;
- else {
- // account for browsers injecting pre around json response
- var pre = doc.getElementsByTagName('pre')[0];
- if (pre)
- xhr.responseText = pre.innerHTML;
- }
- }
- else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
- xhr.responseXML = toXml(xhr.responseText);
- }
- data = $.httpData(xhr, opts.dataType);
- }
- catch(e){
- ok = false;
- $.handleError(opts, xhr, 'error', e);
- }
-
- // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
- if (ok) {
- opts.success(data, 'success');
- if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
- }
- if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
- if (g && ! --$.active) $.event.trigger("ajaxStop");
- if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
-
- // clean up
- setTimeout(function() {
- $io.remove();
- xhr.responseXML = null;
- }, 100);
- };
-
- function toXml(s, doc) {
- if (window.ActiveXObject) {
- doc = new ActiveXObject('Microsoft.XMLDOM');
- doc.async = 'false';
- doc.loaddisabledXML(s);
- }
- else
- doc = (new DOMParser()).parseFromString(s, 'text/xml');
- return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
- };
- };
-};
-
-/**
- * ajaxForm() provides a mechanism for fully automating form submission.
- *
- * The advantages of using this method instead of ajaxSubmit() are:
- *
- * 1: This method will include coordinates for <input type="image" /> elements (if the element
- * is used to submit the form).
- * 2. This method will include the submit element's name/value data (for the element that was
- * used to submit the form).
- * 3. This method binds the submit() method to the form for you.
- *
- * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
- * passes the options argument along after properly binding events for submit elements and
- * the form itself.
- */
-$.fn.ajaxForm = function(options) {
- return this.ajaxFormUnbind().bind('submit.form-plugin', function() {
- $(this).ajaxSubmit(options);
- return false;
- }).bind('click.form-plugin', function(e) {
- var target = e.target;
- var $el = $(target);
- if (!($el.is(":submit,input:image"))) {
- // is this a child element of the submit el? (ex: a span within a button)
- var t = $el.closest(':submit');
- if (t.length == 0)
- return;
- target = t[0];
- }
- var form = this;
- form.clk = target;
- if (target.type == 'image') {
- if (e.offsetX != undefined) {
- form.clk_x = e.offsetX;
- form.clk_y = e.offsetY;
- } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
- var offset = $el.offset();
- form.clk_x = e.pageX - offset.left;
- form.clk_y = e.pageY - offset.top;
- } else {
- form.clk_x = e.pageX - target.offsetLeft;
- form.clk_y = e.pageY - target.offsetTop;
- }
- }
- // clear form vars
- setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
- });
-};
-
-// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
-$.fn.ajaxFormUnbind = function() {
- return this.unbind('submit.form-plugin click.form-plugin');
-};
-
-/**
- * formToArray() gathers form element data into an array of objects that can
- * be passed to any of the following ajax functions: $.get, $.post, or loaddisabled.
- * Each object in the array has both a 'name' and 'value' property. An example of
- * an array for a simple login form might be:
- *
- * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
- *
- * It is this array that is passed to pre-submit callback functions provided to the
- * ajaxSubmit() and ajaxForm() methods.
- */
-$.fn.formToArray = function(semantic) {
- var a = [];
- if (this.length == 0) return a;
-
- var form = this[0];
- var els = semantic ? form.getElementsByTagName('*') : form.elements;
- if (!els) return a;
- for(var i=0, max=els.length; i < max; i++) {
- var el = els[i];
- var n = el.name;
- if (!n) continue;
-
- if (semantic && form.clk && el.type == "image") {
- // handle image inputs on the fly when semantic == true
- if(!el.disabled && form.clk == el) {
- a.push({name: n, value: $(el).val()});
- a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
- }
- continue;
- }
-
- var v = $.fieldValue(el, true);
- if (v && v.constructor == Array) {
- for(var j=0, jmax=v.length; j < jmax; j++)
- a.push({name: n, value: v[j]});
- }
- else if (v !== null && typeof v != 'undefined')
- a.push({name: n, value: v});
- }
-
- if (!semantic && form.clk) {
- // input type=='image' are not found in elements array! handle it here
- var $input = $(form.clk), input = $input[0], n = input.name;
- if (n && !input.disabled && input.type == 'image') {
- a.push({name: n, value: $input.val()});
- a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
- }
- }
- return a;
-};
-
-/**
- * Serializes form data into a 'submittable' string. This method will return a string
- * in the format: name1=value1&amp;name2=value2
- */
-$.fn.formSerialize = function(semantic) {
- //hand off to jQuery.param for proper encoding
- return $.param(this.formToArray(semantic));
-};
-
-/**
- * Serializes all field elements in the jQuery object into a query string.
- * This method will return a string in the format: name1=value1&amp;name2=value2
- */
-$.fn.fieldSerialize = function(successful) {
- var a = [];
- this.each(function() {
- var n = this.name;
- if (!n) return;
- var v = $.fieldValue(this, successful);
- if (v && v.constructor == Array) {
- for (var i=0,max=v.length; i < max; i++)
- a.push({name: n, value: v[i]});
- }
- else if (v !== null && typeof v != 'undefined')
- a.push({name: this.name, value: v});
- });
- //hand off to jQuery.param for proper encoding
- return $.param(a);
-};
-
-/**
- * Returns the value(s) of the element in the matched set. For example, consider the following form:
- *
- * <form><fieldset>
- * <input name="A" type="text" />
- * <input name="A" type="text" />
- * <input name="B" type="checkbox" value="B1" />
- * <input name="B" type="checkbox" value="B2"/>
- * <input name="C" type="radio" value="C1" />
- * <input name="C" type="radio" value="C2" />
- * </fieldset></form>
- *
- * var v = $(':text').fieldValue();
- * // if no values are entered into the text inputs
- * v == ['','']
- * // if values entered into the text inputs are 'foo' and 'bar'
- * v == ['foo','bar']
- *
- * var v = $(':checkbox').fieldValue();
- * // if neither checkbox is checked
- * v === undefined
- * // if both checkboxes are checked
- * v == ['B1', 'B2']
- *
- * var v = $(':radio').fieldValue();
- * // if neither radio is checked
- * v === undefined
- * // if first radio is checked
- * v == ['C1']
- *
- * The successful argument controls whether or not the field element must be 'successful'
- * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
- * The default value of the successful argument is true. If this value is false the value(s)
- * for each element is returned.
- *
- * Note: This method *always* returns an array. If no valid value can be determined the
- * array will be empty, otherwise it will contain one or more values.
- */
-$.fn.fieldValue = function(successful) {
- for (var val=[], i=0, max=this.length; i < max; i++) {
- var el = this[i];
- var v = $.fieldValue(el, successful);
- if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
- continue;
- v.constructor == Array ? $.merge(val, v) : val.push(v);
- }
- return val;
-};
-
-/**
- * Returns the value of the field element.
- */
-$.fieldValue = function(el, successful) {
- var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
- if (typeof successful == 'undefined') successful = true;
-
- if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
- (t == 'checkbox' || t == 'radio') && !el.checked ||
- (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
- tag == 'select' && el.selectedIndex == -1))
- return null;
-
- if (tag == 'select') {
- var index = el.selectedIndex;
- if (index < 0) return null;
- var a = [], ops = el.options;
- var one = (t == 'select-one');
- var max = (one ? index+1 : ops.length);
- for(var i=(one ? index : 0); i < max; i++) {
- var op = ops[i];
- if (op.selected) {
- var v = op.value;
- if (!v) // extra pain for IE...
- v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
- if (one) return v;
- a.push(v);
- }
- }
- return a;
- }
- return el.value;
-};
-
-/**
- * Clears the form data. Takes the following actions on the form's input fields:
- * - input text fields will have their 'value' property set to the empty string
- * - select elements will have their 'selectedIndex' property set to -1
- * - checkbox and radio inputs will have their 'checked' property set to false
- * - inputs of type submit, button, reset, and hidden will *not* be effected
- * - button elements will *not* be effected
- */
-$.fn.clearForm = function() {
- return this.each(function() {
- $('input,select,textarea', this).clearFields();
- });
-};
-
-/**
- * Clears the selected form elements.
- */
-$.fn.clearFields = $.fn.clearInputs = function() {
- return this.each(function() {
- var t = this.type, tag = this.tagName.toLowerCase();
- if (t == 'text' || t == 'password' || tag == 'textarea')
- this.value = '';
- else if (t == 'checkbox' || t == 'radio')
- this.checked = false;
- else if (tag == 'select')
- this.selectedIndex = -1;
- });
-};
-
-/**
- * Resets the form data. Causes all form elements to be reset to their original value.
- */
-$.fn.resetForm = function() {
- return this.each(function() {
- // guard against an input with the name of 'reset'
- // note that IE reports the reset function as an 'object'
- if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
- this.reset();
- });
-};
-
-/**
- * Enables or disables any matching elements.
- */
-$.fn.enable = function(b) {
- if (b == undefined) b = true;
- return this.each(function() {
- this.disabled = !b;
- });
-};
-
-/**
- * Checks/unchecks any matching checkboxes or radio buttons and
- * selects/deselects and matching option elements.
- */
-$.fn.selected = function(select) {
- if (select == undefined) select = true;
- return this.each(function() {
- var t = this.type;
- if (t == 'checkbox' || t == 'radio')
- this.checked = select;
- else if (this.tagName.toLowerCase() == 'option') {
- var $sel = $(this).parent('select');
- if (select && $sel[0] && $sel[0].type == 'select-one') {
- // deselect all other options
- $sel.find('option').selected(false);
- }
- this.selected = select;
- }
- });
-};
-
-// helper fn for console logging
-// set $.fn.ajaxSubmit.debug to true to enable debug logging
-function log() {
- if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
- window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
-};
-
-})(jQuery);
-if(!Array.forEach){Array.prototype.forEach=function(D,E){var C=E||window;for(var B=0,A=this.length;B<A;++B){D.call(C,this[B],B,this)}};Array.prototype.map=function(E,F){var D=F||window;var A=[];for(var C=0,B=this.length;C<B;++C){A.push(E.call(D,this[C],C,this))}return A};Array.prototype.filter=function(E,F){var D=F||window;var A=[];for(var C=0,B=this.length;C<B;++C){if(!E.call(D,this[C],C,this)){continue}A.push(this[C])}return A};Array.prototype.every=function(D,E){var C=E||window;for(var B=0,A=this.length;B<A;++B){if(!D.call(C,this[B],B,this)){return false}}return true};Array.prototype.indexOf=function(B,C){var C=C||0;for(var A=0;A<this.length;++A){if(this[A]===B){return A}}return -1}}Array.prototype.contains=function(A){if(Array.contains){return this.contains(A)}return this.indexOf(A)>-1};Array.prototype.insert=function(A){if(!this.contains(A)){this.push(A)}};if(!Array.remove){Array.remove=function(D,C,B){var A=D.slice((B||C)+1||D.length);D.length=C<0?D.length+C:C;return D.push.apply(D,A)}}Function.prototype.method=function(A,B){this.prototype[A]=B;return this};Function.prototype.methods=function(B){for(var A in B){this.method(A,B[A])}return this};Function.prototype.augmentProto=function(A){for(key in A){this.prototype[key]=A[key]}return this};Function.prototype.pBind=function(B){var A=this;return function(){return A.apply(B,arguments)}};Function.prototype.widget=function(){this.prototype.bind=function(B,A){this.$root.bind(B,A);return this};this.prototype.trigger=function(A,B){this.$root.trigger(A,B)};this.prototype.find=function(A){return this.$root.find(A)};return this};String.prototype.toCamel=function(){return this.replace(/[-_\s]\D/gi,function(A){return A.charAt(A.length-1).toUpperCase()})};String.prototype.escapeHTML=function(){return this.replace(/&/g,"&amp;").replace(/>/g,"&gt;").replace(/</g,"&lt;").replace(/"/g,"&quot;")};String.prototype.unescapeHTML=function(){return this.replace(/&amp;/g,"&").replace(/&gt;/g,">").replace(/&lt;/g,"<").replace(/&quot;/g,'"')};String.prototype.stripTags=function(){return this.replace(/<\/?[^>]+>/gi,"").replace(/<|>/g,"")};String.prototype.trim=function(){return this.replace(/^\s\s*/,"").replace(/\s\s*$/,"")};window.twttr=window.twttr||{};twttr.actionsTillReady=new Array("canTweet","sidebarTab","inPageLink");twttr.augmentObject=function(B,C){for(var A in C){B[A]=C[A]}return B};twttr.augmentObject(twttr,{namespaceOf:function(A){return twttr.is.object(A)?A:window},merge:function(){var D=arguments;var E=D[0];var H=arguments[arguments.length-1];var C=false;if(twttr.is.nil(E)||!twttr.is.def(E)){if(D.length<2){return{}}[].shift.call(D);return this.merge.apply(this,D)}if(twttr.is.bool(H)){C=H;[].pop.call(D)}for(var G=1,B=D.length;G<B;G++){var A=D[G];for(var F in A){if(C&&A[F]&&typeof A[F]==="object"){if(!E[F]){E[F]=(A[F] instanceof Array)?[]:{}}else{if(typeof E[F]!=="object"){E[F]=A[F]}}this.merge(E[F],A[F],true)}else{E[F]=A[F]}}}return E},extend:function(B,C){var A=function(){};A.prototype=C.prototype;B.prototype=new A();B.prototype.constructor=B;B.uber=C.prototype;if(C.prototype.constructor==Object.prototype.constructor){C.prototype.constructor=C}},klass:function(A,B){return twttr.magic(A,B)},augmentAndExtend:function(B,C,D){var A=twttr.namespaceOf(B);A[C]=function(){A[C].uber.constructor.apply(this,arguments)};twttr.extend(A[C],D);return A[C]},auxo:function(C,D,B){var A=twttr.is.object(B)?B:twttr;return twttr.augmentAndExtend(A,C,D)},augmentString:function(C,A){var B=window;C.split(".").forEach(function(F,E,D){B=B[F]=B[F]||(twttr.is.def(D[E+1])?{}:A)});return B},magic:function(B,A){if(twttr.is.string(B)){return twttr.augmentString(B,A)}else{return twttr.augmentObject(B,A)}},inspect:function(B){console.clear();var C=$(B);var H=C.data("events");var A=0;var G=0;var E=[];var D=[];for(key in H){E.push(key);A++;D.push("\n*******************\n");D.push("Events for "+key+"\n\n");for(fn in H[key]){var F=H[key][fn];G++;D.push(F.toString()+"\n")}}console.log("************* Summary *************");console.log("for target",C);console.log(A+" types of events",E);console.log(G,"Total Event Listeners");console.log("Event listeners assigned to target");console.log(D.join(" "))},is:{bool:function(A){return typeof A==="boolean"},nil:function(A){return A===null},def:function(A){return !(typeof A==="undefined")},number:function(A){return typeof A==="number"&&isFinite(A)},fn:function(A){return typeof A==="function"},array:function(A){return A?this.number(A.length)&&this.fn(A.splice):false},string:function(A){return typeof A==="string"},blank:function(A){return A===""},falsy:function(A){return A===false||A===null||A===undefined},object:function(A){return(A&&(typeof A==="object"||this.fn(A)))||false}},widget:function(A){A.prototype.bind=function(C,B){this.$element.bind(C,B)}}});if(!window.console){var names=["log","debug","info","warn","error","assert","dir","dirxml","group","groupEnd","time","timeEnd","count","trace","profile","profileEnd"];window.console={};for(var i=0;i<names.length;++i){window.console[names[i]]=function(){}}}function setupTranslationCallback(){if(!twttr.i18n_missing_interval){twttr.i18n_missing_interval=window.setInterval(function(){if(twttr.i18n_missing&&twttr.i18n_missing.length>0){$.ajax({type:"POST",data:$.param({authenticity_token:twttr.form_authenticity_token,location:window.location.href,"strings[]":twttr.i18n_missing}),url:"/translate/untranslated_javascript"});twttr.i18n_missing=new Array()}},10000)}}function recordUntranslatedString(A){if(!twttr.i18n_missing){twttr.i18n_missing=new Array()}if(!twttr.i18n_missing_reported){twttr.i18n_missing_reported={}}if(!twttr.i18n_missing_reported[A]){twttr.i18n_missing.push(encodeURIComponent(A));twttr.i18n_missing_reported[A]=true}}function _(C,A){if(twttr.i18n){var B=twttr.i18n[C];if(B){C=B}else{recordUntranslatedString(C)}}return replaceParams(C,A)}function replaceParams(B,A){if(A){for(var C in A){B=B.replace(new RegExp("\\%\\{"+C+"\\}","gi"),A[C])}}return B}var h=function(){var A=$("<div/>");return function(B){return B?A.text(B).html().replace(/\"/gi,"&quot;"):B}}();function unh(A){return A?A.replace(/&(amp;)+/g,"&").replace(/&[a-z]+;/gi,function(B){if(unh.HTML_ESCAPE_TOKENS[B]){return unh.HTML_ESCAPE_TOKENS[B]}return B}):A}window.unh.HTML_ESCAPE_TOKENS={"&lt;":"<","&gt;":">","&quot;":'"'};function addSlashes(A){return A.replace(/\'/g,"\\'").replace(/\"/g,'\\"')}var reverseString=function(A){return A?A.split("").reverse().join(""):A};var numberWithDelimiter=function(B,A){s=B.toString();if(s.indexOf(".")!=-1){return s}A=A?A:",";return s.replace(/(.)(?=(.{3})+$)/g,"$1"+A)};var timeAgo=function(C){if(!C){return false}var H=new Date();var G=new Date(C);if(document.all){G=new Date(Date.parse(C.replace(/( \+)/," UTC$1")))}var D=H-G;var B=1000,F=B*60,A=F*60;if(isNaN(D)||D<0){return false}var E=-1;$.each([5,10,20],function(){if(D<this*B){E=this;return false}});if(E!=-1){return _("less than %{time} seconds ago",{time:E})}if(D<B*40){return _("half a minute ago")}if(D<F){return _("less than a minute ago")}if(D<B*90){return _("1 minute ago")}if(D<F*45){return _("%{time} minutes ago",{time:Math.round(D/F)})}if(D<F*90){return _("about 1 hour ago")}if(D<A*24){return _("about %{time} hours ago",{time:Math.round(D/A)})}return G.toLocaleString().replace(/ GMT[+-][0-9]+:?[0-9]+/,"")};var updateTimeAgo=function(){$(".timestamp").each(function(){var B=$(this);var A=timeAgo(B.meta().time);if(B.meta().prefix!=null){A=B.meta().prefix+" "+A}if(A&&B.find("*").length==0){B.html(A)}});$(".timestamp-title").each(function(){var B=$(this);var A=timeAgo(B.meta().time);if(A){B.attr("title",A)}})};var DEBUG=false;$.extend({log:function(A){if(window.console){console.log(A)}},debug:function(A){if(DEBUG){console.log(A)}},inspect:function(B){var A="{\n";for(var C in B){A+="\t"+C+": "+B[C]+"\n"}A+="}";console.log(A);return A},getStackTrace:function(){var I=[];var C=false;try{D.dont.exist+=0}catch(F){if(F.stack){var J=F.stack.split("\n");for(var D=0,E=J.length;D<E;D++){I.push(J[D])}I.shift();C=true}else{if(window.opera&&F.message){var J=F.message.split("\n");for(var D=0,E=J.length;D<E;D++){if(J[D].match(/^\s*[A-Za-z0-9\-_\$]+\(/)){var H=J[D];if(J[D+1]){H+=" at "+J[D+1];D++}I.push(H)}}I.shift();C=true}}}if(!C){var B=arguments.callee.caller;while(B){var G=B.toString();var A=G.substring(G.indexOf("function")+8,G.indexOf(""))||"anonymous";I.push(A);B=B.caller}}return I}});(function(){if(document.all){if(/MSIE (\d+\.\d+);/.test(navigator.userAgent)){var A=new Number(RegExp.$1);if(A>=8){$.browser.msie8=true}else{if(A>=7){$.browser.msie7=true}else{$.browser.msie6=true}}}}})();var _tmp={};twttr.augmentObject(twttr,{templates:{},timeouts:{},wait:function(){var A={};twttr.clearWait=function(B){if(twttr.is.def(A[B])){clearTimeout(B);delete A[B]}};return function(E,C){var B="TIMER_"+(new Date()).getTime();var D=setTimeout(function(){if(!twttr.is.def(A[B])){return }E()},C);A[B]=D;return B}}(),processJson:function(json){if(typeof (json)=="object"){var evals=[];$.each(json,function(selector,content){var c=selector.charAt(0);if(c=="$"){evals.push(content)}else{if(c=="!"){var notification=window[selector.substring(1)+"Notification"];if(notification){(new notification()).setMessage(content).show()}}else{var $contentPadded=$("<div></div>").html(content);var $content=$(selector,$contentPadded);if($content.length==1){$(selector).replaceWith($content)}else{$(selector).html(content)}$(selector).show()}}});$.each(evals,function(index,js){if(js){eval(js)}})}},googleAnalytics:function(A){if(window.pageTracker){window.pageTracker._trackEvent("Ajax","refresh",A,null)}},trackPageView:function(C,B,D){if(window.pageTracker){var A;if(C){A=C.toString();if(B){A="/search/tweets/"+encodeURIComponent(h(page.query))}if(D){A=A+D}window.pageTracker._trackPageview(A)}else{window.pageTracker._trackPageview()}}},fadeAndReplace:function(A,B){$(A).fadeOut("medium",function(){$(A).html(B)});$(A).fadeIn("medium")},error:function(A){alert(A?A:_("Whoops! Something went wrong. Please refresh the page and try again!"))},loaddisableding:function(){$("#loaddisableder").fadeIn(200)},loaddisableded:function(){$("#loaddisableder").fadeOut(200)},updateLocation:function(A,E){if(!E){E=document}if(A){var D=A.replace(/^https?:\/\/.+?\//,"").replace(/#/gi,"%23").replace(/\s/gi,"+");var C=D.replace(/[^\w\d_-].*$/,"");var B=(C.length>0)?$(E).find("#"+C):[];if(B.length>0){B.get(0).id=C+"_tmp_for_update_location"}E.location.hash=D;if(B.length>0){B.get(0).id=C}}},NON_CHAR_KEY_CODES:[8,9,16,17,18,19,20,27,33,34,35,36,37,38,39,40,45,46,91,92,93],isNonCharKeyCode:function(A){return $.inArray(A.keyCode,twttr.NON_CHAR_KEY_CODES)!=-1||((A.ctrlKey||A.metaKey)&&$.inArray(A.keyCode,[67,88])!=-1)}});$.extend($.expr[":"],{onthepage:"($(elem).is(':visible') && $(elem).parents(':hidden').length == 0)"});jQuery.fn.move=function(A){var B=$(this).html();$(this).remove();$(A).html(B)};jQuery.fn.meta=function(){var B={type:"attr",name:"data"};var C=$(this);if(C.length==1){return C.metadata(B)}else{var A=[];C.each(function(){A.push($(this).metadata(B))});return A}};jQuery.fn.visible=function(A){$(this).each(function(){$(this).css("visibility",A?"visible":"hidden")})};jQuery.fn.isLoading=function(){$(this).addClass("loaddisableding")};$.fn.isLoaded=function(){$(this).removeClass("loaddisableding")};$.fn.replace_text=function(C,B){var A=$(this).html();if(A){$(this).html(A.replace(C,B))}};var pluralize=function(C,B,A){return C==1?B:A};var setDocumentTitle=function(A){document.title=unh(A.stripTags())||""};var addCountToDocumentTitle=function(A){document.title=(A?"("+numberWithDelimiter(A)+") ":"")+document.title.replace(/\([^)]*[0-9]\)\s+/gi,"")};var getSessionUserScreenName=function(){var A;if(page.user_screenname){A=page.user_screenname}else{if($('meta[name="session-user-screen_name"]:first').get(0)){A=$('meta[name="session-user-screen_name"]:first').get(0).content}else{A=$('meta[name="session-user-screen_name"]').get(0).content}}return A};var sessionUserIsPageUser=function(){try{return $('meta[name="session-user-screen_name"]:first').get(0).content==$('meta[name="page-user-screen_name"]:first').get(0).content}catch(A){return false}};$.fn.focusEnd=function(){return this.each(function(){var A=this;if(A.style.display!="none"){if($.browser.msie){A.focus();var B=A.createTextRange();B.collapse(false);B.select()}else{A.setSelectionRange(A.value.length,A.value.length);A.focus()}}})};$.fn.focusFirstTextField=function(){return this.find("input[type=text]:visible:enabled:first").focus().length>0},$.fn.focusFirstTextArea=function(){return this.find("textarea:visible:enabled:first").focus().length>0};$.fn.focusFirstTexttarget=function(){return this.focusFirstTextField()||this.focusFirstTextArea()};$.fn.maxLength=function(A){return this.each(function(){$(this).keydown(function(B){return this.value.length<=A||twttr.isNonCharKeyCode(B)})})};$.fn.replaceClass=function(B,A){return this.each(function(){var C=$(this);if(C.hasClass(B)){C.removeClass(B).addClass(A)}else{if(C.hasClass(A)){C.removeClass(A).addClass(B)}}})};$.fn.isSelectAll=function(A){return this.each(function(){var B=$(this);if(typeof (A)=="string"){var D=$(A).find("input[type=checkbox]")}else{var D=A}function C(){var E=true;D.each(function(){if(!this.checked){E=false;return false}});B.get(0).checked=E}B.click(function(){var E=B.get(0).checked;D.each(function(){this.checked=E});$(this).trigger("select-all-changed",E)});D.click(function(){C();$(this).trigger("checkbox-changed",this.checked)})})};function bodytarget(){return $("body")}twttr.klass("twttr.Observer",function(){this.fns=[]}).method("listen",function(A){this.fns.push(A)}).method("unlisten",function(A){this.fns=this.fns.filter(function(B){if(B!==A){return B}})}).method("trigger",function(C,B){var A=B||window;this.fns.forEach(function(D){D.call(A,C)})});twttr.klass("twttr.User",function(A){this.screen_name=A}).method("update",function(B,A){twttr.tweeters[this.screen_name][B]=A;return this}).method("updateAll",function(B){for(var A in B){twttr.tweeters[this.screen_name][A]=B[A]}return this}).method("data",function(B){var A=twttr.tweeters[this.screen_name];return B?A[B]:A});twttr.augmentObject(twttr.User,{UserFetchTimeout:5000,UserFetchUrl:"/users/show",_bail:false,_requesting:false,bail:function(){this._bail=true},isRequesting:function(){return this._requesting},getCurrentUser:function(A){return this.findById(page.sessionUserId,A)},find:function(F,C,G){var B,A;var D=this;if(twttr.is.fn(C)){B=window;A=C}else{B=C;A=G}var E=twttr.is.def(F.screen_name)?F.screen_name.toLowerCase():null;if(E&&twttr.tweeters[E]){A.call(B,new twttr.User(E),true);return true}else{$.ajax({url:this.UserFetchUrl,type:"GET",data:F,dataType:"json",timeout:this.UserFetchTimeout,beforeSend:function(){D._requesting=true},success:function(K){D._requesting=false;var H=K.user;if(H){var I={};var J=H.screen_name.toLowerCase();I[J]=H;twttr.User.merge(I,true);if(D._bail){D._bail=false;return false}A.call(B,new twttr.User(J),false)}else{if(D._bail){D._bail=false;return false}A.call(B,null,false)}},error:function(H){D._requesting=false;if(D._bail){D._bail=false;return false}A.call(B,null,false)}});return false}},findByScreenName:function(B,A,C){return this.find({screen_name:B,hovercard:true},A,C)},findById:function(D,A,C){var B=twttr._birdtags[D];if(twttr.is.def(B)){this.findByScreenName(B,A,C)}else{this.find({user_id:D,hovercard:true},A,C)}},merge:function(){twttr.tweeters={};twttr._birdtags={};return function(D,A){var D=D||{};if(A){twttr.merge(twttr.tweeters,D,true)}else{var C=twttr.merge(D,twttr.tweeters,true);twttr.merge(twttr.tweeters,C,true)}for(var B in twttr.tweeters){twttr._birdtags[twttr.tweeters[B].user_id]=B}}}()});twttr.loaddisabledTemplate=function(A,B){if(twttr.templates[A]){return twttr.templates[A]}B=B||function(){};$.get("/mustaches/"+A+".html",null,function(D){var C={templates:{}};C.templates[A]=D;twttr.merge(twttr,C,true);B(twttr.templates)},"html")};twttr.loaddisabledTemplates=function(A,B){B=B||function(){};A.forEach(function(D,C){twttr.loaddisabledTemplate(D,function(E){var F=A.every(function(G){return twttr.is.def(E[G])});if(F){B(twttr.templates)}})})};twttr.SimplePositioner={setPosition:function(H,I,J){var D={inline:false,direction:null,offsets:{inline:{top:0,left:0},below:{top:0,left:0},above:{top:0,left:0}},hasContainer:false};var A=twttr.merge({},D,J,true);var F=F instanceof jQuery?H:$(H);var C=I instanceof jQuery?I:$(I);var E=A.hasContainer?C.position():C.offset();if(!A.inline){var G=this;function B(K){G.clearPosition();switch(K){case"above":G._positionAbove(F,C,E,A.offsets.above,A.hasContainer);break;case"below":G._positionBelow(F,C,E,A.offsets.below);break;case"prefer below":B("below");if((F.offset().top-$(document).scrollTop())+(A.itemHeight||F.height())>$(window).height()){B("prefer above")}break;default:B("above");if((F.offset().top-$(document).scrollTop())<0){B("below")}break}}B(A.direction)}else{this._positionInline(F,C,E,A.offsets.inline);F.css("left",E.left+A.offsets.inline.left)}},clearPosition:function(){$("body").removeClass("loaddisableding-hoverer-above")},_positionAbove:function(E,F,C,A,B){E.addClass("position_above").removeClass("position_below").removeClass("position_inline");var G=Math.round(C.top+A.top);var H;if(B){H=F.parents().filter(function(){return $(this).css("position")=="relative"}).outerHeight()}else{var D=$("body");D.addClass("loaddisableding-hoverer-above");var I=parseInt(D.css("padding-top"));G+=I>0?12:0;H=D.outerHeight()}E.css({bottom:H-G,left:this._getLeftPosition(E,F,C)+A.left})},_positionBelow:function(A,C,D,E){var B=Math.round(D.top+C.height()+E.top);A.addClass("position_below").removeClass("position_above").removeClass("position_inline");A.css({top:B,left:this._getLeftPosition(A,C,D)+E.left})},_positionInline:function(A,B,D,C){A.css("top",D.top+C.top).addClass("position_inline").removeClass("position_below").removeClass("position_above")},_getLeftPosition:function(A,B,C){return Math.round(C.left+(B.width()/2))}};twttr.unparam=function(F){var E={};var C=F.split("&");for(var B=0,A=C.length;B<A;B++){var D=C[B].split("=",2);E[decodeURIComponent(D[0])]=(D.length==2?decodeURIComponent(D[1].replace(/\+/g," ")):null)}return E};twttr.klass("twttr.Validator",function(A,C,B){this.$field=$(A);this.value=this.$field.val();if(twttr.is.string(this.value)){this.value=jQuery.trim(this.value)}this.fieldName="";if(twttr.is.object(C)){B=C}else{this.fieldName=C}this.valid=B.valid;this.invalid=B.invalid});twttr.Validator.augmentProto({is:function(){var A=null;var B=this;$.each(arguments,function(D,C){if(!C._decorated){C=C()}if(!C(B.value)){A=C;return false}});if(A){this.invalid(this.$field,this.fieldName,A.errorMessage)}else{this.valid(this.$field,this.fieldName)}}});twttr.validate=function(B,A){function C(D,F,E){return new twttr.Validator(D,F,E)}twttr.augmentObject(C,B);return A(C)};$.fn.helpText=function(){this.each(function(){var B=$(this);var A=B.hasClass("help-focusable");if(A){B.mouseup(function(C){if(!B.helpVal()==""){B.select();C.preventDefault()}})}B.focus(function(C){B.setHelpState(false,A)}).blur(function(){if(document.selection){document.selection.empty()}else{getSelection().removeAllRanges()}B.setHelpState(true)});B.setHelpState(true)});return this};$.fn.helpVal=function(){var A=$.trim(this.val());return A==this.attr("title")?"":A};$.fn.setHelpState=function(A,B){this.each(function(){var D=$(this);var C="help-text";if(A){if(!D.helpVal()){D.val(D.attr("title"));D.addClass(C);if(this.hasFocus&&D.hasClass("help-focusable")){D.select()}}else{D.removeClass(C)}}else{D.removeClass(C);if(!D.helpVal()){if(B){D.select()}else{D.val("")}}}})};$.fn.selectOnClick=function(){this.each(function(){var B=$(this);var A=true;B.click(function(){if(A){A=false;this.select()}}).blur(function(){A=true})});return this};twttr.klass("twttr.autocomplete",function(A){var B=this;B.opts=twttr.merge({getInputVal:function(){return B.opts.$input.val()},hoverClass:"hover",delay:350},A);B.cache={};B._clearFakeFocus();B.opts.$input.keydown(function(C){switch(C.keyCode){case 38:B.arrowUp();break;case 40:B.arrowDown();break;case 13:if(!B.hasFakeFocus){return }B.$fakeFocus.click();break;case 27:if(B.opts.$dropdown.is(":visible")){B.hide()}else{return }break;case 9:if(B.opts.$dropdown.is(":visible")){B.hide()}return ;default:B._onInputChange();return }B.keyDownEvent=true;C.stopPropagation();C.preventDefault()}).keypress(function(C){if(C.charCode==0&&(C.keyCode==38||C.keyCode==40)){if(!B.keyDownEvent){if(C.keyCode==38){B.arrowUp()}else{B.arrowDown()}}B.keyDownEvent=false;C.preventDefault()}}).change(function(){B._onInputChange()}).blur(function(){if(!B.hovering){B.hide()}})}).method("arrowDown",function(){if(this.hasFakeFocus){this._setFakeFocus(this.$fakeFocus.next())}else{this._show()}}).method("arrowUp",function(){this._setFakeFocus(this.$fakeFocus.prev())}).method("hide",function(){this._clearFakeFocus();this.opts.$dropdown.hide();this.displayedInputVal=this.opts.getInputVal()}).method("_show",function(){this.displayedInputVal="";this._display();this._setFakeFocus(this.opts.$dropdown.children(":first"))}).method("_clearFakeFocus",function(){this.$fakeFocus=$([]);this.hasFakeFocus=false;this.opts.$dropdown.children().removeClass(this.opts.HoverClass)}).method("_setFakeFocus",function(A){if(A.length>0){this.hasFakeFocus=true;this.$fakeFocus=A;this.$fakeFocus.addClass(this.opts.hoverClass).siblings().removeClass(this.opts.hoverClass)}}).method("_onInputChange",function(){var A=this;setTimeout(function(){A._display()},0)}).method("_display",function(){var B=this;var A=B.opts.getInputVal();if(B.displayedInputVal!=A){B._clearFakeFocus();var D=B.opts.$dropdown.hide().empty();B.displayedInputVal="";var C=B.cache[A];if(C){C.forEach(function(G,F){D.append(B.opts.renderMatch(G,F,C))});D.children().hover(function(){if(B.hasFakeFocus){B._setFakeFocus($(this))}else{$(this).addClass(B.opts.hoverClass)}B.hovering=true},function(){if(!B.hasFakeFocus){$(this).removeClass(B.opts.hoverClass)}B.hovering=false});var E=B.opts.$input.position();D.css({left:E.left,top:E.top+B.opts.$input.outerHeight()-1}).show();B.displayedInputVal=A}else{if(A&&C===undefined){B._fetch(A)}}}}).method("_fetch",function(A){var B=this;clearTimeout(B.timerId);B.timerId=setTimeout(function(){B.cache[A]=false;B.opts.fetchMatches(A,function(C){if(C&&C.length>0){B.cache[A]=C;B._display()}},function(){B.cache[A]=undefined})},B.opts.delay)});/*!
- * twitter-text-js 1.3.1
- *
- * Copyright 2010 Twitter, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-if (!window.twttr) {
- window.twttr = {};
-}
-
-(function() {
- twttr.txt = {};
- twttr.txt.regexen = {};
-
- var HTML_ENTITIES = {
- '&': '&amp;',
- '>': '&gt;',
- '<': '&lt;',
- '"': '&quot;',
- "'": '&#32;'
- };
-
- // HTML escaping
- twttr.txt.htmlEscape = function(text) {
- return text && text.replace(/[&"'><]/g, function(character) {
- return HTML_ENTITIES[character];
- });
- };
-
- // Builds a RegExp
- function regexSupplant(regex, flags) {
- flags = flags || "";
- if (typeof regex !== "string") {
- if (regex.global && flags.indexOf("g") < 0) {
- flags += "g";
- }
- if (regex.ignoreCase && flags.indexOf("i") < 0) {
- flags += "i";
- }
- if (regex.multiline && flags.indexOf("m") < 0) {
- flags += "m";
- }
-
- regex = regex.source;
- }
-
- return new RegExp(regex.replace(/#\{(\w+)\}/g, function(match, name) {
- var newRegex = twttr.txt.regexen[name] || "";
- if (typeof newRegex !== "string") {
- newRegex = newRegex.source;
- }
- return newRegex;
- }), flags);
- }
-
- // simple string interpolation
- function stringSupplant(str, values) {
- return str.replace(/#\{(\w+)\}/g, function(match, name) {
- return values[name] || "";
- });
- }
-
- // Space is more than %20, U+3000 for example is the full-width space used with Kanji. Provide a short-hand
- // to access both the list of characters and a pattern suitible for use with String#split
- // Taken from: ActiveSupport::Multibyte::Handlers::UTF8Handler::UNICODE_WHITESPACE
- var fromCode = String.fromCharCode;
- var UNICODE_SPACES = [
- fromCode(0x0020), // White_Space # Zs SPACE
- fromCode(0x0085), // White_Space # Cc <control-0085>
- fromCode(0x00A0), // White_Space # Zs NO-BREAK SPACE
- fromCode(0x1680), // White_Space # Zs OGHAM SPACE MARK
- fromCode(0x180E), // White_Space # Zs MONGOLIAN VOWEL SEPARATOR
- fromCode(0x2028), // White_Space # Zl LINE SEPARATOR
- fromCode(0x2029), // White_Space # Zp PARAGRAPH SEPARATOR
- fromCode(0x202F), // White_Space # Zs NARROW NO-BREAK SPACE
- fromCode(0x205F), // White_Space # Zs MEDIUM MATHEMATICAL SPACE
- fromCode(0x3000) // White_Space # Zs IDEOGRAPHIC SPACE
- ];
-
- for (var i = 0x009; i <= 0x000D; i++) { // White_Space # Cc [5] <control-0009>..<control-000D>
- UNICODE_SPACES.push(String.fromCharCode(i));
- }
-
- for (var i = 0x2000; i <= 0x200A; i++) { // White_Space # Zs [11] EN QUAD..HAIR SPACE
- UNICODE_SPACES.push(String.fromCharCode(i));
- }
-
- twttr.txt.regexen.spaces = regexSupplant("[" + UNICODE_SPACES.join("") + "]");
- twttr.txt.regexen.punct = /\!'#%&'\(\)*\+,\\\-\.\/:;<=>\?@\[\]\^_{|}~/;
- twttr.txt.regexen.atSigns = /[@ï¼ ]/;
- twttr.txt.regexen.extractMentions = regexSupplant(/(^|[^a-zA-Z0-9_])(#{atSigns})([a-zA-Z0-9_]{1,20})(?=(.|$))/g);
- twttr.txt.regexen.extractReply = regexSupplant(/^(?:#{spaces})*#{atSigns}([a-zA-Z0-9_]{1,20})/);
- twttr.txt.regexen.listName = /[a-zA-Z][a-zA-Z0-9_\-\u0080-\u00ff]{0,24}/;
-
- // Latin accented characters (subtracted 0xD7 from the range, it's a confusable multiplication sign. Looks like "x")
- twttr.txt.regexen.latinAccentChars = regexSupplant("ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ\\303\\277");
- twttr.txt.regexen.latenAccents = regexSupplant(/[#{latinAccentChars}]+/);
-
- twttr.txt.regexen.endScreenNameMatch = regexSupplant(/^(?:#{atSigns}|[#{latinAccentChars}]|:\/\/)/);
-
- // Characters considered valid in a hashtag but not at the beginning, where only a-z and 0-9 are valid.
- twttr.txt.regexen.hashtagCharacters = regexSupplant(/[a-z0-9_#{latinAccentChars}]/i);
- twttr.txt.regexen.autoLinkHashtags = regexSupplant(/(^|[^0-9A-Z&\/\?]+)(#|#)([0-9A-Z_]*[A-Z_]+#{hashtagCharacters}*)/gi);
- twttr.txt.regexen.autoLinkUsernamesOrLists = /(^|[^a-zA-Z0-9_]|RT:?)([@ï¼ ]+)([a-zA-Z0-9_]{1,20})(\/[a-zA-Z][a-zA-Z0-9_\-]{0,24})?/g;
- twttr.txt.regexen.autoLinkEmoticon = /(8\-\#|8\-E|\+\-\(|\`\@|\`O|\&lt;\|:~\(|\}:o\{|:\-\[|\&gt;o\&lt;|X\-\/|\[:-\]\-I\-|\/\/\/\/Ö\\\\\\\\|\(\|:\|\/\)|∑:\*\)|\( \| \))/g;
-
- // URL related hash regex collection
- twttr.txt.regexen.validPrecedingChars = regexSupplant(/(?:[^-\/"':!=A-Za-z0-9_@ï¼ ]|^|\:)/);
- twttr.txt.regexen.validDomain = regexSupplant(/(?:[^#{punct}\s][\.-](?=[^#{punct}\s])|[^#{punct}\s]){1,}\.[a-z]{2,}(?::[0-9]+)?/i);
-
- twttr.txt.regexen.validGeneralUrlPathChars = /[a-z0-9!\*';:=\+\$\/%#\[\]\-_,~]/i;
- // Allow URL paths to contain balanced parens
- // 1. Used in Wikipedia URLs like /Primer_(film)
- // 2. Used in IIS sessions like /S(dfd346)/
- twttr.txt.regexen.wikipediaDisambiguation = regexSupplant(/(?:\(#{validGeneralUrlPathChars}+\))/i);
- // Allow @ in a url, but only in the middle. Catch things like http://example.com/@user
- twttr.txt.regexen.validUrlPathChars = regexSupplant(/(?:#{wikipediaDisambiguation}|@#{validGeneralUrlPathChars}+\/|[\.,]?#{validGeneralUrlPathChars})/i);
-
- // Valid end-of-path chracters (so /foo. does not gobble the period).
- // 1. Allow =&# for empty URL parameters and other URL-join artifacts
- twttr.txt.regexen.validUrlPathEndingChars = regexSupplant(/(?:[a-z0-9=_#\/]|#{wikipediaDisambiguation})/i);
- twttr.txt.regexen.validUrlQueryChars = /[a-z0-9!\*'\(\);:&=\+\$\/%#\[\]\-_\.,~]/i;
- twttr.txt.regexen.validUrlQueryEndingChars = /[a-z0-9_&=#\/]/i;
- twttr.txt.regexen.validUrl = regexSupplant(
- '(' + // $1 total match
- '(#{validPrecedingChars})' + // $2 Preceeding chracter
- '(' + // $3 URL
- '(https?:\\/\\/)' + // $4 Protocol
- '(#{validDomain})' + // $5 Domain(s) and optional post number
- '(\\/' + // $6 URL Path
- '(?:' +
- '#{validUrlPathChars}+#{validUrlPathEndingChars}|' +
- '#{validUrlPathChars}+#{validUrlPathEndingChars}?|' +
- '#{validUrlPathEndingChars}' +
- ')?' +
- ')?' +
- '(\\?#{validUrlQueryChars}*#{validUrlQueryEndingChars})?' + // $7 Query String
- ')' +
- ')'
- , "gi");
-
- // Default CSS class for auto-linked URLs
- var DEFAULT_URL_CLASS = "tweet-url";
- // Default CSS class for auto-linked lists (along with the url class)
- var DEFAULT_LIST_CLASS = "list-slug";
- // Default CSS class for auto-linked usernames (along with the url class)
- var DEFAULT_USERNAME_CLASS = "username";
- // Default CSS class for auto-linked hashtags (along with the url class)
- var DEFAULT_HASHTAG_CLASS = "hashtag";
- // HTML attribute for robot nofollow behavior (default)
- var HTML_ATTR_NO_FOLLOW = " rel=\"nofollow\"";
-
- // Simple object cloning function for simple objects
- function clone(o) {
- var r = {};
- for (var k in o) {
- if (o.hasOwnProperty(k)) {
- r[k] = o[k];
- }
- }
-
- return r;
- }
-
- twttr.txt.autoLink = function(text, options) {
- options = clone(options || {});
- return twttr.txt.autoLinkUsernamesOrLists(
- twttr.txt.autoLinkUrlsCustom(
- twttr.txt.autoLinkHashtags(text, options),
- options),
- options);
- };
-
-
- twttr.txt.autoLinkUsernamesOrLists = function(text, options) {
- options = clone(options || {});
-
- options.urlClass = options.urlClass || DEFAULT_URL_CLASS;
- options.listClass = options.listClass || DEFAULT_LIST_CLASS;
- options.usernameClass = options.usernameClass || DEFAULT_USERNAME_CLASS;
- options.usernameUrlBase = options.usernameUrlBase || "httpdisabled://twitter.com/";
- options.listUrlBase = options.listUrlBase || "httpdisabled://twitter.com/";
- if (!options.suppressNoFollow) {
- var extraHtml = HTML_ATTR_NO_FOLLOW;
- }
-
- var newText = "",
- splitText = twttr.txt.splitTags(text);
-
- for (var index = 0; index < splitText.length; index++) {
- var chunk = splitText[index];
-
- if (index !== 0) {
- newText += ((index % 2 === 0) ? ">" : "<");
- }
-
- if (index % 4 !== 0) {
- newText += chunk;
- } else {
- newText += chunk.replace(twttr.txt.regexen.autoLinkUsernamesOrLists, function(match, before, at, user, slashListname, offset, chunk) {
- var after = chunk.slice(offset + match.length);
-
- var d = {
- before: before,
- at: at,
- user: twttr.txt.htmlEscape(user),
- slashListname: twttr.txt.htmlEscape(slashListname),
- extraHtml: extraHtml,
- chunk: twttr.txt.htmlEscape(chunk)
- };
- for (var k in options) {
- if (options.hasOwnProperty(k)) {
- d[k] = options[k];
- }
- }
-
- if (slashListname && !options.suppressLists) {
- // the link is a list
- var list = d.chunk = stringSupplant("#{user}#{slashListname}", d);
- d.list = twttr.txt.htmlEscape(list.toLowerCase());
- return stringSupplant("#{before}#{at}<a class=\"#{urlClass} #{listClass}\" href=\"#{listUrlBase}#{list}\"#{extraHtml}>#{chunk}</a>", d);
- } else {
- if (after && after.match(twttr.txt.regexen.endScreenNameMatch)) {
- // Followed by something that means we don't autolink
- return match;
- } else {
- // this is a screen name
- d.chunk = twttr.txt.htmlEscape(user);
- d.dataScreenName = !options.suppressDataScreenName ? stringSupplant("data-screen-name=\"#{chunk}\" ", d) : "";
- return stringSupplant("#{before}#{at}<a class=\"#{urlClass} #{usernameClass}\" #{dataScreenName}href=\"#{usernameUrlBase}#{chunk}\"#{extraHtml}>#{chunk}</a>", d);
- }
- }
- });
- }
- }
-
- return newText;
- };
-
- twttr.txt.autoLinkHashtags = function(text, options) {
- options = clone(options || {});
- options.urlClass = options.urlClass || DEFAULT_URL_CLASS;
- options.hashtagClass = options.hashtagClass || DEFAULT_HASHTAG_CLASS;
- options.hashtagUrlBase = options.hashtagUrlBase || "httpdisabled://twitter.com/search?q=%23";
- if (!options.suppressNoFollow) {
- var extraHtml = HTML_ATTR_NO_FOLLOW;
- }
-
- return text.replace(twttr.txt.regexen.autoLinkHashtags, function(match, before, hash, text) {
- var d = {
- before: before,
- hash: twttr.txt.htmlEscape(hash),
- text: twttr.txt.htmlEscape(text),
- extraHtml: extraHtml
- };
-
- for (var k in options) {
- if (options.hasOwnProperty(k)) {
- d[k] = options[k];
- }
- }
-
- return stringSupplant("#{before}<a href=\"#{hashtagUrlBase}#{text}\" title=\"##{text}\" class=\"#{urlClass} #{hashtagClass}\"#{extraHtml}>#{hash}#{text}</a>", d);
- });
- };
-
-
- twttr.txt.autoLinkUrlsCustom = function(text, options) {
- options = clone(options || {});
- if (!options.suppressNoFollow) {
- options.rel = "nofollow";
- }
- if (options.urlClass) {
- options["class"] = options.urlClass;
- delete options.urlClass;
- }
-
- delete options.suppressNoFollow;
- delete options.suppressDataScreenName;
-
- return text.replace(twttr.txt.regexen.validUrl, function(match, all, before, url, protocol, domain, path, queryString) {
- var tldComponents;
-
- if (protocol) {
- var htmlAttrs = "";
- for (var k in options) {
- htmlAttrs += stringSupplant(" #{k}=\"#{v}\" ", {k: k, v: options[k].toString().replace(/"/, "&quot;").replace(/</, "&lt;").replace(/>/, "&gt;")});
- }
- options.htmlAttrs || "";
-
- var d = {
- before: before,
- htmlAttrs: htmlAttrs,
- url: twttr.txt.htmlEscape(url)
- };
-
- return stringSupplant("#{before}<a href=\"#{url}\"#{htmlAttrs}>#{url}</a>", d);
- } else {
- return all;
- }
- });
- };
-
- twttr.txt.extractMentions = function(text) {
- var screenNamesOnly = [],
- screenNamesWithIndices = twttr.txt.extractMentionsWithIndices(text);
-
- for (var i = 0; i < screenNamesWithIndices.length; i++) {
- var screenName = screenNamesWithIndices[i].screenName;
- screenNamesOnly.push(screenName);
- }
-
- return screenNamesOnly;
- };
-
- twttr.txt.extractMentionsWithIndices = function(text) {
- if (!text) {
- return [];
- }
-
- var possibleScreenNames = [],
- position = 0;
-
- text.replace(twttr.txt.regexen.extractMentions, function(match, before, atSign, screenName, after) {
- if (!after.match(twttr.txt.regexen.endScreenNameMatch)) {
- var startPosition = text.indexOf(atSign + screenName, position);
- position = startPosition + screenName.length + 1;
- possibleScreenNames.push({
- screenName: screenName,
- indices: [startPosition, position]
- });
- }
- });
-
- return possibleScreenNames;
- };
-
- twttr.txt.extractReplies = function(text) {
- if (!text) {
- return null;
- }
-
- var possibleScreenName = text.match(twttr.txt.regexen.extractReply);
- if (!possibleScreenName) {
- return null;
- }
-
- return possibleScreenName[1];
- };
-
- twttr.txt.extractUrls = function(text) {
- var urlsOnly = [],
- urlsWithIndices = twttr.txt.extractUrlsWithIndices(text);
-
- for (var i = 0; i < urlsWithIndices.length; i++) {
- urlsOnly.push(urlsWithIndices[i].url);
- }
-
- return urlsOnly;
- };
-
- twttr.txt.extractUrlsWithIndices = function(text) {
- if (!text) {
- return [];
- }
-
- var urls = [],
- position = 0;
-
- text.replace(twttr.txt.regexen.validUrl, function(match, all, before, url, protocol, domain, path, query) {
- var tldComponents;
-
- if (protocol) {
- var startPosition = text.indexOf(url, position),
- position = startPosition + url.length;
-
- urls.push({
- url: url,
- indices: [startPosition, position]
- });
- }
- });
-
- return urls;
- };
-
- twttr.txt.extractHashtags = function(text) {
- var hashtagsOnly = [],
- hashtagsWithIndices = twttr.txt.extractHashtagsWithIndices(text);
-
- for (var i = 0; i < hashtagsWithIndices.length; i++) {
- hashtagsOnly.push(hashtagsWithIndices[i].hashtag);
- }
-
- return hashtagsOnly;
- };
-
- twttr.txt.extractHashtagsWithIndices = function(text) {
- if (!text) {
- return [];
- }
-
- var tags = [],
- position = 0;
-
- text.replace(twttr.txt.regexen.autoLinkHashtags, function(match, before, hash, hashText) {
- var startPosition = text.indexOf(hash + hashText, position);
- position = startPosition + hashText.length + 1;
- tags.push({
- hashtag: hashText,
- indices: [startPosition, position]
- });
- });
-
- return tags;
- };
-
- // this essentially does text.split(/<|>/)
- // except that won't work in IE, where empty strings are ommitted
- // so "<>".split(/<|>/) => [] in IE, but is ["", "", ""] in all others
- // but "<<".split("<") => ["", "", ""]
- twttr.txt.splitTags = function(text) {
- var firstSplits = text.split("<"),
- secondSplits,
- allSplits = [],
- split;
-
- for (var i = 0; i < firstSplits.length; i += 1) {
- split = firstSplits[i];
- if (!split) {
- allSplits.push("");
- } else {
- secondSplits = split.split(">");
- for (var j = 0; j < secondSplits.length; j += 1) {
- allSplits.push(secondSplits[j]);
- }
- }
- }
-
- return allSplits;
- };
-
- twttr.txt.hitHighlight = function(text, hits, options) {
- var defaultHighlightTag = "em";
-
- hits = hits || [];
- options = options || {};
-
- if (hits.length === 0) {
- return text;
- }
-
- var tagName = options.tag || defaultHighlightTag,
- tags = ["<" + tagName + ">", "</" + tagName + ">"],
- chunks = twttr.txt.splitTags(text),
- split,
- i,
- j,
- result = "",
- chunkIndex = 0,
- chunk = chunks[0],
- prevChunksLen = 0,
- chunkCursor = 0,
- startInChunk = false,
- chunkChars = chunk,
- flatHits = [],
- index,
- hit,
- tag,
- placed,
- hitSpot;
-
- for (i = 0; i < hits.length; i += 1) {
- for (j = 0; j < hits[i].length; j += 1) {
- flatHits.push(hits[i][j]);
- }
- }
-
- for (index = 0; index < flatHits.length; index += 1) {
- hit = flatHits[index];
- tag = tags[index % 2];
- placed = false;
-
- while (chunk != null && hit >= prevChunksLen + chunk.length) {
- result += chunkChars.slice(chunkCursor);
- if (startInChunk && hit === prevChunksLen + chunkChars.length) {
- result += tag;
- placed = true;
- }
-
- if (chunks[chunkIndex + 1]) {
- result += "<" + chunks[chunkIndex + 1] + ">";
- }
-
- prevChunksLen += chunkChars.length;
- chunkCursor = 0;
- chunkIndex += 2;
- chunk = chunks[chunkIndex];
- chunkChars = chunk;
- startInChunk = false;
- }
-
- if (!placed && chunk != null) {
- hitSpot = hit - prevChunksLen;
- result += chunkChars.slice(chunkCursor, hitSpot) + tag;
- chunkCursor = hitSpot;
- if (index % 2 === 0) {
- startInChunk = true;
- } else {
- startInChunk = false;
- }
- } else if(!placed) {
- placed = true;
- result += tag;
- }
- }
-
- if (chunk != null) {
- if (chunkCursor < chunkChars.length) {
- result += chunkChars.slice(chunkCursor);
- }
- for (index = chunkIndex + 1; index < chunks.length; index += 1) {
- result += (index % 2 === 0 ? chunks[index] : "<" + chunks[index] + ">");
- }
- }
-
- return result;
- };
-
-
-}());var updateCount=function(A,F,D){try{var E=$(A);var C=parseInt(E.html().replace(/[^0-9]/g,""))+F;return setCount(A,C,D)}catch(B){return false}};var setCount=function(A,C,D){try{var E=$(A);if(D){E.fadeOut(D,function(){E.html(numberWithDelimiter(C)).fadeIn(D)})}else{E.html(numberWithDelimiter(C))}return C}catch(B){return false}};var updateFollowingCount=function(A){return updateCount("#following_count",A)};var updateFollowersCount=function(A){return updateCount("#follower_count",A)};twttr.statusUpdateError={decider:function(req){var message;try{message=eval("("+req.responseText+")").error}catch(err){}if(!message){if(req&&req.status==403){message=_("You are not authorized to perform this operation.")}else{message=_("Something is technically wrong. Please try again in a moment.")}}if(message){new ShortNotification().setMessage(message).show();$("#tweeting_button, #update-submit").removeClass("btn-disabled").removeAttr("disabled");$(".char-counter").removeClass("loaddisableding")}},revoked:function(){twttr.reloaddisabled()}};twttr.isReplyOnlyTweet=function(A){var B=/^\@([a-zA-Z0-9_]{1,20})\s*$/;if(A.match(B)){return true}return false};$.fn.isAlertBox=function(){return this.each(function(){var A=$(this);A.find("a").click(function(){var B=$(this).attr("href");$.ajax({type:"POST",dataType:"text",data:{authenticity_token:twttr.form_authenticity_token},url:"/account/clear_user_alert",success:function(){A.slideUp("fast");window.location=B}});return false})})};$.fn.isUpdateForm=function(){return this.each(function(){var O=$(this);var H=O.find("textarea").isCharCounter();var A=O.find("#tweeting_button, #update-submit");var B=O.find("label.doing");var J=O.find(".char-counter");var F=/^\s*@(\w+)\W+/;var D=/^\s*[dD][mM]?\s+(?:(\w+)\W+)?/;var I=O.find(".places-nearby");var E;var N=false;function M(){var P=H.val();if(twttr.isReplyOnlyTweet(P)){location.href=RegExp.$1;return false}if(P.length>140){alert(_("That tweet is over 140 characters!"));return false}else{if(P.replace(/s\*/g,"")==""){return false}else{A.addClass("btn-disabled").attr("disabled",true);return true}}}A.bind("click",function(Q){var P=$(this);Q.preventDefault();if(!P.hasClass("btn-disabled")){P.closest("form").submit()}});function K(P){if(twttr.is.def(P.users)){twttr.User.merge(P.users,true)}A.removeClass("btn-disabled").removeAttr("disabled");var Q=P.text;if(P.messageForFlash){(new ShortNotification()).setMessage(P.messageForFlash).show()}else{if(P.errorForFlash){(new InfoNotification()).setMessage(P.errorForFlash).show()}else{if($("body").attr("id")!="home"){(new ShortNotification()).setMessage(_("Your status has been updated!")).show()}else{if(P.status_li){$("#timeline tr.hentry:first").removeClass("latest-status");$.Timeline.prepend(P.status_li)}}setCount("#update_count",P.status_count,250);if(P.latest_status){updateTimeAgo();$("#latest_status").html(P.latest_status).isCurrentStatus(true)}$("#place_content").trigger("tweet")}}H.val("").focusEnd();$("#in_reply_to_status_id").val("");$("#in_reply_to").val("");C("");H.trigger("change");J.removeClass("loaddisableding");if(document.all){J.text("140")}else{J.css("color","#ccc")}}function C(Q){var P;if(P=Q.match(D)){B.html(P[1]?_("Direct message %{person}:",{person:P[1]}):_("Direct message:"));A.val(_("send"))}else{if(P=Q.match(F)){B.html(_("Reply to %{screen_name}:",{screen_name:P[1]}));A.val(_("reply"))}else{B.html(_("What’s happening?"));A.val(_("update"))}}}H.bind("keyup blur focus",function(){C($(this).val())});O.submit(function(){if(M()){twttr.googleAnalytics("/status/update/refresh");var T=H.val();E={authenticity_token:twttr.form_authenticity_token,status:T,twttr:true};var Q=window.location.href;if($("body").attr("id")=="home"&&((Q.indexOf("page=")==-1)||Q.match(/page=1(?!\d)/))){E.return_rendered_status=true}var P=$("#in_reply_to_status_id").val();var S;if(P&&(S=T.match(F))){if(S[1]==$("#in_reply_to").val()){E.in_reply_to_status_id=P;twttr.countAdsReplies&&twttr.countAdsReplies(P)}}var R=$("#source").val();if(R){E.source=R}E.lat=$("#lat").val();E.lon=$("#lon").val();E.place_id=$("#place_id").val();E.display_coordinates=$("#display_coordinates").val();G(E)}return false});function G(P){$.ajax({type:"POST",dataType:"json",url:"/status/update",data:P,beforeSend:function(){J.addClass("loaddisableding");if(document.all){J.html("&nbsp;&nbsp;&nbsp;&nbsp;")}else{J.css("color","transparent")}},success:K,error:function(Q){twttr.statusUpdateError.decider(Q)}})}try{H.focusEnd()}catch(L){}})};$.fn.isLocationTrends=function(){return this.each(function(){var H=$(this);var F=$("#location_menu");var A=$("#change_location");var K=$("#trends .trends-links");var D=new twttr.AttachedDialog({handle:$("#tt_menu span"),content:$("#local_trends"),width:"545px",gravity:"east",weight:"top",modal:false});$(document).click(function(M){var L=$(M.target);if(voided&&!L.parents(".modal, .trends-links li").length){D.close()}});D.find("#location_done").click(function(){D.close();A.removeClass("active")});var J=false;if($("#local_trends_notice").length){setTimeout(function(){(J=new twttr.AttachedDialog({handle:$("#tt_menu span"),content:$("#local_trends_notice").parent(),width:"186px",gravity:"east",weight:"top"voidonloaddisabled:true,closeButton:true,modal:false})).bind("close",function(){return false})void();J.find("#location_notice_set").click(function(){J.close();void();return false})},500)}function G(O){D.find("a.active-parent").removeClass("active-parent");var L=$(O).attr("parents");if(L){var M=L.split(" ");for(var N=0;N<M.length;N++){$("."+M[N]).addClass("active-parent")}}}function E(){return F.find("em")}function C(L){if(!L){return false}$.ajax({type:"POST",url:"/users/update_trend_location_id",data:{authenticity_token:twttr.form_authenticity_token,trend_location_id:L},success:function(){K.append($("<em></em>").append(L))}});return false}A.click(function(){D.toggle();if(J){J.close()}A.toggleClass("active");return false});D.find("a").click(function(){var L=$(this);var M=L.attr("id").replace("trend_loc_","");D.find(".active").removeClass("active");D.find("#trend_loc_"+M).parent().addClass("active");G(L);if(M){$.ajax({type:"GET",dataType:"json",url:"/users/location_trends",data:{twttr:true,trend_location_id:M},beforeSend:function(){$("#trends_loaddisableding").show()},success:function(N){K.hide();K.fadeIn();$("#trends_loaddisableding").hide();if(N){var O=[];K.html("");$.each(N.trends,function(){var P=this;var S=P.name;var R=$('<a class="search_link" href="/search?q='+encodeURIComponent(P.query)+'"name="'+S+'">'+S+"</a>");R.isSearchLink();if(P.promoted){twttr.formatPromotedTrend(R,P.promoted)}var Q=P.description;var T=$("<li></li>");if(Q){T.append(R).append($("<em></em>").append(Q))}else{T.append(R)}K.append(T)});F.html(N.location["name"]);loaddisabledTrendDescriptions();C(N.location["id"])}else{}},error:function(N){$.debug("error: "+N.responseText)},complete:function(){$("#trends_loaddisableding").hide()}})}return false});var B=E();if(B){var I=$("#trend_loc_"+B);I.parent().addClass("active");G(I)}})};$.fn.isDirectMessageForm=function(){return this.each(function(){var L=$(this);var D=L.find("textarea").isCharCounter();var B=/^\s*[dD][mM]?\s+([A-Za-z0-9]{1,20})[^A-Za-z0-9]/;var F=L.find("select");var A=L.find("#dm-submit");var E=L.find(".char-counter");var G="";A.attr("disabled","disabled").addClass("btn-disabled");try{D.focusEnd()}catch(I){}function C(N){if(F.val()){return }if((matches=N.match(B))&&matches[1]&&(G!=matches[1])){var M=true;F.find("option").each(function(){if(this.innerHTML.toLowerCase()==matches[1].toLowerCase()){F.val(this.value);M=false;return false}});if(M){F.append(_('<option value="%{screen_name}">%{screen_name}</option>',{screen_name:matches[1]}));F.val(matches[1])}G=matches[1]}}A.click(function(M){var P=D.val();var N=P.match(B);var O=F.find("option[value="+F.val()+"]");if(N&&N[1]&&N[1].toLowerCase()==O.text().toLowerCase()){D.val(P.replace(B,""))}return true});F.change(function(M){D.trigger("update",M)});D.bind("keyup blur focus",function(M){C($(this).val());D.trigger("update",M)});function H(M){(new ShortNotification()).setMessage(M.messageForFlash).show();if($("body").attr("id")=="sent"){$.Timeline.prepend(M.direct_message_li)}D.val("");F.val("");G="";D.trigger("change");E.removeClass("loaddisableding");if(document.all){E.text("140")}else{E.css("color","#ccc")}}if(F.length>0){function J(){if(F.length&&(F.find("option").length==0)){$.ajax({type:"GET",dataType:"json",url:"/direct_messages/recipients_list",data:{twttr:true},success:function(N){if(N){var M=[];$.each(N,function(){var O=this;if((O.length>1)&&O[0]&&O[1]){M.push('<option value="'+O[0]+'">'+O[1]+"</option>")}});F.html('<option value="" selected="selected"></option>'+M.join(""))}},error:function(M){$.debug("error: "+M.responseText)}})}}var K=$("body").attr("id");if(K=="direct_messages"||K=="inbox"||K=="sent"){J()}L.bind("loaddisabledrecipients",null,function(M){J()});L.submit(function(){twttr.googleAnalytics("/direct_messages/create/refresh");var N=D.val();var M={authenticity_token:twttr.form_authenticity_token,text:N,"user[id]":F.val(),twttr:true};$.ajax({type:"POST",dataType:"json",url:"/direct_messages/create",data:M,beforeSend:function(){E.addClass("loaddisableding");if(document.all){E.text("")}else{E.css("color","transparent")}},success:H,error:function(O){twttr.statusUpdateError.decider(O)}});return false})}})};$.fn.isTimelineTabLink=function(){return this.each(function(){var A=$(this);A.click(function(B){document.body.id=A.meta().dispatch_action}).bind("loaddisableding",null,function(B){A.parent("li").addClass("loaddisableding")}).bind("loaddisableded",null,function(B){A.parent("li").removeClass("loaddisableding")}).bind("aborted",null,function(B){A.parent("li").removeClass("loaddisableding")})})};$.fn.isEmbeddedMediaExpander=function(){return this.livequery(function(){var A=$(this);var B=A.parent().find(".embedded_media");A.click(function(){B.slideToggle("normal",function(){if(A.hasClass("embedded_media_icon_active")){A.removeClass("embedded_media_icon_active")}else{A.addClass("embedded_media_icon_active")}})})})};twttr.TEXT_AREA_CHANGE_EVENTS="blur focus change "+($.browser.mozilla?"paste input":"keyup");$.fn.isCharCounter=function(){return this.each(function(){var A=true;var F=$(this);var I=F.closest("form");var E=I.find(".char-counter");var H=I.find("#tweeting_button, #update-submit, #dm-submit");var D=I.find("select");function C(){H.addClass("btn-disabled").attr("disabled","disabled");A=true}function G(){if(A){H.removeClass("btn-disabled").removeAttr("disabled");A=false}}function B(){var K=F.val();var J=K.length;E.html(""+(140-J));if(J<=0){E.css("color","#cccccc");C()}else{if(J<=140&&(D.length==0||D.val())){G()}else{C()}if(J>130){E.css("color","#d40d12")}else{if(J>120){E.css("color","#5c0002")}else{E.css("color","#cccccc")}}}}F.bind(twttr.TEXT_AREA_CHANGE_EVENTS,function(J){B()});D.change(function(J){B()});F.focus()})};$("body.profiles #user_description").each(function(){var H=$(this);var D=H.closest("td").find(".char-counter");var C=parseInt(D.text(),10);var E=!!$(".about-yourself").attr("data-decider-shorten-urls");var B={original:[C,D.css("color")],warning:[20,"#5c0002"],error:[10,"#d40d12"]};function G(){return 19}function F(){var I;if(E){var K=H.val();var J=twttr.txt.extractUrls(K);I=K.length;I-=J.join("").length;I=I+(J.length*G())}else{I=H.val().length}return C-I}function A(){var I=F();D.html(I);if(I<=B.error[0]){D.css("color",B.error[1])}else{if(I<=B.warning[0]){D.css("color",B.warning[1])}else{D.css("color",B.original[1])}}}A();H.bind(twttr.TEXT_AREA_CHANGE_EVENTS,A);H.closest("form").submit(function(I){if(F()<0){(new ShortNotification()).setMessage(_("Bio is too long")).show();I.preventDefault();return false}})});$.fn.isCurrentStatus=function(A){return this.each(function(){var C=$(this);var J=$("#latest_status");var E=C.find("#latest_text");var G=E.find(".status-text");var I=E.find(".retweet-source-user");var H=$(this).parent("#update_notifications");var B=J.find("strong");$("#latest_text_full, #latest_text").click(function(){$("#latest_text_full, #latest_text").toggle()});E.css("color","transparent");var F=$("#latest_text_full .status-text").text();if(I.length>0){G.append(F.escapeHTML())}else{G.html("<strong>"+_("Latest: ")+"</strong>").append(F.escapeHTML())}E.css("color","");if(A){var D=J.find("span, strong");D.each(function(){$(this).data("old_color",$(this).css("color")).animate({color:"#333"},500)});clearTimeout(twttr.timeouts.latest_status_timeout);twttr.timeouts.latest_status_timeout=setTimeout(function(){D.each(function(){$(this).animate({color:$(this).data("old_color")},1500,function(){$(this).css("color","")})})},1500)}})};function initializeTimeline(){$.Statuses.initialize($("#timeline"))}function getListItemFromChild(A){return A.parents(".hentry:first")}function getStatusIdFromListItem(B){var A=/status_(.*)/i.exec(B.attr("id"));return(A)?A[1]:null}function getScreenNameFromListItem(B){var A=/u-([A-Za-z0-9_]+)/i.exec(B.attr("class"));return(A)?A[1]:null}function getShareIdFromListItem(B){var A=/(.)* s-([\d]+)(.)*/i.exec(B.attr("class"));return(A)?A[2]:getStatusIdFromListItem(B)}function timelineRefresh(E,A){var C=$("#results_update");if(C.length==0){return }if(!E||(("home,search,replies,inbox".indexOf(E)==-1)&&!E.match(/^\/?list/))){return }if(!A){A=($("#results_update").attr("href").replace(/^\//,"")||window.location.hash.replace(/^#/,"")||E).replace(/^([^\/])/,"/$1")}A=A.replace(/\/?list\//,"/");var B,D=$("#new_results_notification").meta();if(E==="search"){B=D.search}else{B=D.timeline}$("#new_results_notification").data("count",0);if(page.timelineRefresher){if(page.timelineRefresher.dispatchAction==E){return }else{page.timelineRefresher.stop()}}page.newResults=null;page.timelineRefresher=new Occasionally(B.delay*1000,B.max_delay*1000,function(){var F=false;if($("ol#timeline").length){$.ajax({method:"GET",dataType:"json",url:A,data:{since_id:getMaxStatusIdFromTimeline(),refresh:true},success:function(G){processTimelineRefresh(G,E)},error:function(){if(page.timelineRefresher){page.timelineRefresher.stop();page.timelineRefresher=null}}})}},function(){return page.newResults},B.decay);page.timelineRefresher.dispatchAction=E;page.timelineRefresher.start()}function getMaxStatusIdFromTimeline(){var A=0;$("ol#timeline > li").each(function(){var B=parseInt(this.id.replace(/^[A-Z_]+/gi,""));if(A<B){A=B}});return A}function processTimelineRefresh(J,D){if(twttr.is.def(J.users)){twttr.User.merge(J.users)}var G=$("#new_results_notification").meta().timeline;var K=$("<div>"+J["#timeline"]+"</div>");var A=$("#content ol#timeline");K.find("#timeline > li").each(function(){if(A.find("li#"+this.id).length){$(this).remove()}});var F=K.find("ol > li");var C=F.length;var E=($("#new_results_notification").data("count")||0)+C;if(C){A.prepend(F.addClass("buffered"));K.remove();A.find("li.buffered:gt("+(G.max_refresh_size-1)+")").remove();var B={results_count:numberWithDelimiter(E),username:getSessionUserScreenName()};var H=$("#results_update").is(":visible")?"":' style="display:none;"';var I='<a id="results_update" class="minor-notification" href="/'+D+'" accesskey="n"'+H+">";if(D=="inbox"){I+=((E==1)?_("1 new message."):_("%{results_count} new messages.",B))}else{if(D=="replies"){I+=((E==1)?_("1 new mention of @%{username}.",B):_("%{results_count} new mentions of @%{username}.",B))}else{if(D=="search"){I+=((E==1)?_("1 new tweet since you started searching."):_("%{results_count} new tweets since you started searching.",B))}else{I+=((E==1)?_("1 new tweet."):_("%{results_count} new tweets.",B))}}}I+="</a>";$("#results_update").replaceWith(I);$("#results_update").click(function(){$("#content ol#timeline > li.buffered").addClass("unbuffered").removeClass("buffered");$("#content ol#timeline > li.last-on-refresh").removeClass("last-on-refresh");$("#content ol#timeline > li.unbuffered:last").addClass("last-on-refresh");updateTimeAgo();$("#content ol#timeline > li.unbuffered").removeClass("unbuffered");$("#results_update").hide();addCountToDocumentTitle();$.Timeline.triggerPageHeightChangedEvent();$.Timeline.triggerTimelineChanged();$("#new_results_notification").data("count",0);return false});$("#new_results_notification").data("count",E);$("#results_update:hidden").slideDown("normal",function(){$.Timeline.triggerPageHeightChangedEvent();var L=$(this);if(twttr.is.def(twttr.HOVERCARD)){twttr.HOVERCARD.reposition(L.get(0).offsetHeight+parseInt(L.css("margin-top")))}});addCountToDocumentTitle(E);if(G.interrupt&&page.timelineRefresher){page.timelineRefresher.stop()}}else{K.remove()}page.newResults=(C>0)}$(document).ready(function(){$().Page();twttr.setDefaultBucket();initializeTimeline();$("#pagination #more").isMoreButton();$("body").bind("ajaxSuccess",twttr.setupRetweetTips);twttr.setupRetweetTips();$("span.byline a").tipsy({gravity:"n"});$("#content #trend_description img").tipsy({gravity:"s"});$("a.promoted-trend").promotedTrendsTipsy()});$.fn.promotedTrendsTipsy=function(){return this.each(function(){var E=$(this);var A=E.find("span");var D=E.attr("data");var B=JSON.parse(D);var C=_("Promoted by %{name}",{name:B.promoted_content["user"]["name"]});A.attr("title",C);A.tipsy({gravity:"n",html:true,additionalCSSClass:"garuda-tipsy-container",showTimeout:300})})};twttr.augmentObject(twttr,{RETWEETING_BACKGROUND_COLOR:"#ffffe5",_bucket:null,setDefaultBucket:function(){this._bucket=parseInt(page.sessionUserId)%2},getBucket:function(){return this._bucket},setBucket:function(A){this._bucket=A},applyTipsy:function(A,C,B){if(!A.data("tipsy_applied")){A.data("tipsy_applied",true);A.attr("title",A.attr("title")+C);A.tipsy(B)}},isRetweetTimeline:function(){return !!(location.hash&&location.hash.match(/retweet/))},setupRetweetTips:function(){$("span.status-body span.shared-content a.screen-name, div.shared-by-avatar-tiles a.profile-pic img.photo").each(function(){var A=$(this);if(A.data("tipsy_applied")||!twttr.isRetweetTimeline()){return }var B="left-align";var C="";if($("body#home").length>0&&!A.hasClass("you")){var C=_('<div class="retweet_tip_tip">Tip: To hide/show retweets from this user, click on their username and look for the retweet setting <div class="retweet-icon"></div></div>');B+=" retweet-tooltip"}twttr.applyTipsy(A,C,{gravity:"l",hideTimeout:10000,additionalCSSClass:B})});$("span.big-retweet-icon").each(function(){if($("body#profile").length==0){twttr.applyTipsy($(this),"",{gravity:"s",hideTimeout:10000})}else{$(this).attr("title","")}})},getStatusBodyParent:function(A){return A.parents(".status-body").parent()},setRetweetingStyles:function(B,E,D){var A=getListItemFromChild(B);var C=twttr.getStatusBodyParent(B);C.append("<span class='retweeting loaddisableding'>"+E+"</span>");A.addClass("no-hover");if($("body.status").length==0){A.css("background-color",twttr.RETWEETING_BACKGROUND_COLOR)}},unsetRetweetingStyles:function(B){var A=getListItemFromChild(B);var C=twttr.getStatusBodyParent(B);A.removeClass("no-hover");C.find(".retweeting.loaddisableding").remove()},animateStatusReplacement:function(B,D){var C=getListItemFromChild(B);var F=$(D.status_li);F.hide();C.after(F);if(C.hasClass("latest-status")){F.addClass("latest-status")}var A=F.height();var E=C.height();F.remove().show().height(E);if($("body.status").length==0){F.css("background-color",twttr.RETWEETING_BACKGROUND_COLOR)}C.replaceWith(F);if(A!=E){F.animate({height:A},500,function(){F.css("height",null);twttr.animateStatusColorChange(F)})}else{twttr.animateStatusColorChange(F)}if(D.latest_status){$("#latest_status").html(D.latest_status).isCurrentStatus(true)}},animateStatusColorChange:function(A){A.animate({backgroundColor:"#FFF"},1500,function(){A.css("background-color",null)})}});$.fn.Page=function(){var A=$('meta[name="session-user-screen_name"]:first').get(0);var D=$('meta[name="page-user-screen_name"]:first').get(0);var B=$('meta[name="session-userid"]:first').get(0);var C=A&&D&&A.content==D.content;if(typeof (page)=="undefined"){page={}}page=$.extend(page,{timeline:null,sessionUserScreenName:(A?A.content:null),sessionUserId:(B?B.content:null),pageUserScreenName:(D?D.content:null),loggedIn:$('meta[name="session-loggedin"][content="y"]').length>0,hideUnfavorited:C,isTimelineChange:false,currentTimelineChange:{},$oldTimelineLink:""})};$.Statuses={initialize:function(A){if(page.loggedIn){var B=$(A).find(".hentry");$.each($.Statuses.actions,function(){var C=this;C.apply(B)})}},actions:{isTweet:function(){this.livequery(function(){var A=$("body#show.status").length>0;var B=$("body#profile").length>0;if(!A&&!B){var C=$(this).find("a.hashtag");C.isSearchLink(SEARCH_CALLBACKS.hashtagLink)}})},isHoverable:function(){if($("body.ie,body.ie6").get(0)){this.livequery(function(){var A=$(this);A.hover(function(){A.addClass("hover")},function(){A.removeClass("hover")})})}},isFavoriteable:function(){$(".fav-action").live("click",function(){var D=$(this);if(D.hasClass("blocked")){return false}var B=D.parents(".hentry:first");var E=B.attr("id").replace(/status_/,"");var C=D.hasClass("fav")?"destroy":"create";twttr.googleAnalytics("/favorites/"+C+"/refresh/"+E);function A(){var F=D.hasClass("fav");D.removeClass(F?"fav":"non-fav").addClass(F?"non-fav":"fav").attr("title",(F?_("favorite this tweet"):_("un-favorite this tweet")))}$.ajax({type:"POST",dataType:"json",url:"/favorites/"+C+"/"+E,data:{authenticity_token:twttr.form_authenticity_token},beforeSend:function(){A();D.addClass("blocked")},complete:function(){D.removeClass("blocked")}});return false},this)},isReplyable:function(){$(".reply").live("click",function(){var E=$(this);var C=E.parents(".hentry:first");var G=C.attr("id").replace(/status_/,"");var A=C.attr("class").match(/u-([A-Za-z0-9_]+)/);var B=A[1];if(!B){alert(_("Whoops! Something went wrong. Please refresh the page and try again!"));return }if(C.hasClass("direct_message")){var F=$("#text");twttr.googleAnalytics("/direct_messages/reply/"+B+"/"+G);var D=$("#direct_message_user_id");if(!D.find("option[text='"+B+"']").attr("selected",true).length){D.append('<option value="'+B+'" selected="selected">'+B+"</option>")}F.trigger("update");$("#text").focusEnd()}else{if(C.hasClass("status")||C.hasClass("share")){var F=$("#status");twttr.googleAnalytics("/reply/"+B+"/"+G);if(F.size()){F.val("@"+B+" "+F.val().replace(RegExp("@"+B+" ?","i"),"")).trigger("update");$("#status").focusEnd();$("#in_reply_to_status_id").val(G);$("#in_reply_to").val(B);window.scroll(0,0)}else{window.location=E.find("a").attr("href");return false}}}window.scroll(0,0);return false},this)},isRetweetable:function(){$(".retweet-link").live("click",function(A){new RetweetInlineForm().show({targetNode:$(this)});A.preventDefault()},this)},isDeleteable:function(){$(".del").live("click",function(D){var C=$(this);var A=C.parents(".hentry:first");var F=A.attr("id").replace(/[^\d]*/,"");var E=A.hasClass("latest-status");var B;if(A.hasClass("direct_message")){B="/direct_messages/destroy"}else{B="/status/destroy"}if(confirm(_("Sure you want to delete this tweet? There is NO undo!"))){twttr.googleAnalytics(B+"/refresh/"+F);$.ajax({type:"POST",url:B+"/"+F,data:{authenticity_token:twttr.form_authenticity_token,latest_status:E},dataType:(B=="/status/destroy"?"json":null),beforeSend:function(){A.fadeOut(500);updateCount("#update_count",-1,250)},success:function(G){A.remove();if(B=="/status/destroy"){if(E){twttr.processJson(G);updateLatest()}}setCount("#update_count",G.status_count)},error:function(G){A.fadeIn(0);var H=_("Whoops! Something went wrong. Please try again!");if(G&&G.status==403&&G.responseText!=""){H=G.responseText}(new InfoNotification()).setMessage(H).show()}})}D.preventDefault()},this)},isUndoable:function(){$(".undo").live("click",function(){var C=$(this);var B=C.parents(".hentry:first");var A=B.attr("id").replace(/status_/,"");$.ajax({type:"POST",url:"/statuses/"+A+"/retweet",data:{_method:"delete",authenticity_token:twttr.form_authenticity_token,controller_name:page.controller_name,action_name:page.action_name,user_screenname:page.pageUserScreenName},dataType:"json",beforeSend:function(){C.attr("title","").removeClass("undo");twttr.setRetweetingStyles(C,_("Undoing..."))},success:function(D){if(D.status_li){twttr.animateStatusReplacement(C,D)}else{B.fadeOut(500,function(){var E=$("ol#timeline .hentry:visible:first");if(!E.hasClass("share")){E.addClass("latest-status")}})}(new InfoNotification()).setMessage(_("Your followers will no longer see the tweet as retweeted by you.")).show()},complete:function(){twttr.unsetRetweetingStyles(B)}});return false},this)},isMappable:function(){$(".geo_pin").live("click",function(){var B=jQuery(this);var A=B.next();var C=B.position();A.css({left:C.left-25,bottom:C.top+20});A.show();A.find(".map_close").click(function(){A.hide();return false})},this)}}};$.Timeline={prepend:function(A){$("#timeline").prepend(A);$.Timeline.triggerTimelineChanged()},append:function(A){$("#timeline").append(A);$.Timeline.triggerTimelineChanged()},registerTimelineEvent:function(A){$("body").bind("timeline-changed",A)},unregisterTimelineEvent:function(A){$("body").unbind("timeline-changed",A)},triggerTimelineChanged:function(){$("body").trigger("timeline-changed")},registerPageHeightChangedEvent:function(A){$("body").bind("page-height-changed",A)},unregisterPageHeightChangedEvent:function(A){$("body").unbind("page-height-changed",A)},triggerPageHeightChangedEvent:function(){$("body").trigger("page-height-changed")}};function basicMoreButtonHandler(A){return function(){var C=$(this);C.blur();if(C.hasClass("loaddisableding")){return false}var B=C.attr("href");var D=$("#more").text();$.ajax(jQuery.extend({type:"GET",url:B,dataType:"json"},A));return false}}$.fn.isMoreButton=function(){return this.live("click",basicMoreButtonHandler({beforeSend:function(){$("#timeline li:last-child").addClass("last-on-page");$("#more").addClass("loaddisableding").html("")},success:function(A){updateTimeAgo();if(twttr.is.def(A.users)){twttr.User.merge(A.users)}$("#timeline").append($(A["#timeline"]).find(".hentry"));$("#pagination").html(A["#pagination"]);page.retainTimeline=true;if(window.onPageChange){onPageChange()}page.retainTimeline=null;$.Timeline.triggerTimelineChanged()},error:function(){$("#timeline li:last-child").removeClass("last-on-page");$("#more").removeClass("loaddisableding").text(_("more"));(new ShortNotification()).setMessage(_("Whoops! Something went wrong. Please try again!")).show()}}))};$(function(){var request=function(data,success){return function(){var self=this;var $this=$(this);var notification=(new ProgressNotification()).setProgressMessage($this.attr("progress")).setCompletedMessage($this.attr("completed"));$.ajax({type:$this.attr("method"),dataType:"json",url:$this.attr("href")||$this.attr("action"),data:data.apply(self),success:function(){notification.done();if(success){success.apply(self)}},beforeSend:function(){twttr.loaddisableding();notification.show()},complete:twttr.loaddisableded});return false}};$("form.restful").livequery("submit",request(function(){return $(this).serializeArray()},function(){$(this).trigger("submitted")}));$("a.restful").livequery("click",request(function(){return eval("("+$(this).attr("data")+")")}))});function updateLatest(){var A=$("#latest_status");if(A.length){A.isCurrentStatus(true)}$("#timeline li:first").addClass("latest-status")}function setTitleAndHeading(H){var Q=$("#timeline_heading h1");var P=$("#timeline_heading h2");var H=H||$("body").attr("id");var C=h(page.query);var F=h(page.prettyQuery);var J=getSessionUserScreenName();var B=$('meta[name="page-user-screen_name"]:first').get(0)||$('meta[name="page-user-screen_name"]').get(0);if(B){var M=B.content}if(!twttr.titles_and_headings){var N={user:J,name:page.user_fullname,pageUser:M};twttr.titles_and_headings={home:{title:_("Home"),heading:_("Home")},replies:{title:("@"+J),heading:_("Tweets mentioning @%{user}",N)},favorites:{title:_("Your Favorites"),heading:_("Your Favorites")},inbox:{title:_("Direct Messages"),heading:_("Direct messages sent only to you")},direct_messages:{title:_("Direct Messages"),heading:_("Direct messages sent only to you")},sent:{title:_("Sent Direct Messages"),heading:_("Direct messages you've sent")},retweets_by_others:{title:_("Retweets",N),heading:"&nbsp;"},profile_favorites:{title:_("%{pageUser}'s Favorites",N),heading:_("%{pageUser}'s Favorites",N)},profile:{title:_("%{name} (%{pageUser}) on Twitter",N),heading:null}}}var I,E='<li class="name-search-link"><a href="#">'+_("Search for users &raquo;")+"</a></li>";if(page.searchError!=undefined){I={title:page.searchError,heading:("<ul>"+E+"</ul>"+page.searchError)}}else{if(H=="search"){I={title:_("Search - %{query}",{query:F})};var G=$("#side #saved_searches ul.sidebar-menu li.active");var O;if(G.length){var K=G.attr("id").replace("ss_","");O='<a href="/saved_searches/destroy/'+K+'" title="'+F+'" _query="'+C+'" class="delete-search-link">'+_("Remove this saved search")+"</a>"}else{O='<a href="/saved_searches/create" class="save-search-link" title="'+F+'" _query="'+C+'" _place_details="'+h(page.placeDetails)+'" _place_map_link="'+h(page.placeMapLink)+'">'+_("Save this search")+"</a>"}var D=($("li.status").length>0);if(D){E='<ul class="has-saved-search"><li>'+O+"</li>"+E+"</ul>"}else{E="<ul>"+E+"</ul>"}if(D){I.heading=E+_("Real-time results for <b>%{query}</b>",{query:F})}else{I.heading=E+_("No real-time results for <b>%{query}</b>",{query:F})}}else{I=twttr.titles_and_headings[H]}}if(I){var L=(H=="profile")?"":"Twitter / ";setDocumentTitle(L+I.title);P.remove();if(I.heading){Q.html(I.heading);Q.parent("div").show()}else{Q.parent("div").hide()}var A=$("#geo_place_details");if(page.placeDetails){A.text(page.placeDetails);$('<span class="geo_map_link_separator">|</span><a target="_blank" href="'+h(page.placeMapLink)+'">map</a>').appendTo(A);A.show()}else{A.hide()}if(H=="search"){Q.find(".save-search-link").isSaveSearchLink().end().find(".delete-search-link").isRemoveSearchLink()}$("#heading .name-search-link a").attr("href","/search/users?q="+encodeURIComponent(page.query))}}function loaddisabledTrendDescriptions(){if(!page.trendDescriptions){page.trendDescriptions={}}$("#trends a").each(function(){var B=$(this);var D=B.parent().find("em");if(D.length){var C=B.text();var E=D.text().replace(new RegExp(C.replace(/([^\w])/gi,"\\$1"),"gi"),"<strong>"+C+"</strong>");var F=B.attr("title").length?B.attr("title"):B.attr("name");page.trendDescriptions[F]=[C,E]}});var A=page.trendDescriptions[page.query];if(A){$("#trend_info").hide();$("#trend_description span").text(_("%{trend} is a popular topic on Twitter right now.",{trend:A[0]}));$("#trend").text(_("%{trend}",{trend:A[0]}));$("#trend_description p").html(A[1]);$("#trend_description").show()}else{$("#trend_description").hide();$("#trend_info").show()}(A&&A[1].length>0)?$(".trenddesc").show():$(".trenddesc").hide()}$.fn.isSaveSearchLink=function(){return this.each(function(){var A=$(this);var B=$("#saved_searches");var C=B.find("ul.sidebar-menu");A.click(function(){if(C.find("li").length>=10){(new InfoNotification()).setMessage(_("You can only save ten searches. To remove a saved search, select the search and click <strong>remove this saved search</strong>.")).show();return false}var D=A.attr("title");var F=A.attr("_query")||D;var E=$('<li><a href="/search?q='+encodeURIComponent(F)+'" class="search-link" title="'+h(D)+'" _query="'+h(F)+'" _place_details="'+h(A.attr("_place_details"))+'" _place_map_link="'+h(A.attr("_place_map_link"))+'"><span>'+h(D)+"</span></a></li>");E.find("a").isSearchLink(SEARCH_CALLBACKS.savedSearchLink);E.fadeOut(1,function(){C.append(E);E.fadeIn(100)});if(B.hasClass("collapsed")){B.trigger("expand")}B.fadeIn();$("#side ul.sidebar-menu li").removeClass("active");$("#side #custom_search").removeClass("active");E.addClass("active");$.ajax({type:"POST",dataType:"json",url:"/saved_searches/create",data:{q:F,authenticity_token:twttr.form_authenticity_token,twttr:true},beforeSend:function(){A.replaceWith('<span class="loaddisableding">'+_("Save this search")+"</span>")},success:function(G){E.attr("id","ss_"+G.id);setTitleAndHeading("search")},error:function(G){(new InfoNotification()).setMessage(G.responseText).show();E.remove()}});return false})})};$.fn.isRemoveSearchLink=function(){return this.each(function(){var A=$(this);var C=A.attr("_query");var B=A.attr("href");A.click(function(){var D=$("#side #saved_searches li a[_query='"+C+"']").parent("li");D.fadeOut(100,function(){D.remove();var E=$("#saved_searches ul.sidebar-menu a");if(E.length==0){$("#saved_searches").hide()}setTitleAndHeading("search");$("#side #custom_search").addClass("active")});$.ajax({type:"POST",url:B,data:{authenticity_token:twttr.form_authenticity_token,twttr:true},beforeSend:function(){A.replaceWith('<span class="loaddisableding">'+_("Remove this saved search")+"</span>")},error:function(){(new InfoNotification()).setMessage(_("Whoops! Something went wrong. Please refresh the page and try again!")).show()}});return false})})};function showSearchHelpText(){if($("#timeline li").length==0){var A=[_("Try a more general search."),_("Try using different words.")];var B='<div class="no-results">'+_("Suggestions:")+"<ol>";for(var C=0;C<A.length;C++){B+="<li>"+A[C]+"</li>"}B+="</ol></div>";setTimeout(function(){$("#timeline_heading").after(B)},1)}else{if($("#pagination a.more").length==0){$("#pagination").empty().html('<p class="no-more-tweets">'+_("Older tweets are temporarily unavailable.")+"</p>")}}}function onPageChange(A){var C=$("body").attr("id");if(C!="search"){$("#sidebar_search_q").val("").blur()}else{twttr.updateLocation("search?q="+encodeURIComponent(page.query))}setTitleAndHeading(C);loaddisabledTrendDescriptions();if(C=="search"&&page.searchError==undefined){showSearchHelpText()}page.searchError=undefined;if(!A){if(!page.retainTimeline){$("#results_update").hide()}$(".no-results").remove();$("#new_results_count").html("0")}if(!$("body").hasClass("front")){$(".in-page-link").isInPageLink();$(".in-page-list-link").isListInPageLink();try{$(".in-page-list-label").isListInPageLabel();$(".in-page-label").isInPageLabel()}catch(B){}}if(C=="list"||C=="list_show"){C=(window.location.hash||window.location.pathname).replace(/^#/,"").replace(/^([^\/])/,"/$1");if(C.indexOf("/list")!=0){C="/list"+C}}twttr.trackPageView(C,(page.query&&page.query.length>0?page.query:null),A?null:"/ajax")}function initializePage(A){if(("home".indexOf(A)==-1)&&($("body#list_show").length==0)){twttr.updateLocation(A)}initializeSidebar();$("#side form#sidebar_search").isSearchForm();$("#side .collapsible").isCollapsibleMenu();onPageChange(true);timelineRefresh(A);$(".saved-search-links li a").isSearchLink(SEARCH_CALLBACKS.savedSearchLink);$(".trends-links li a").isSearchLink(SEARCH_CALLBACKS.trendLink);$("#dm_tabs a, #retweet_tabs a").isTimelineTabLink();$("div.bulletin").isBulletin();$("ul.sidebar-menu a").isSidebarTab();highlightSearchTerms()}function highlightSearchTerms(){function C(F,K){var J=document.createElement("div");var E=F.childNodes;for(var G=0,H=E.length;G<H;++G){C(E[G],K)}if(F.nodeType==3){if(!F.nodeValue.match(K)){return }var L=F.nodeValue.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(K,"<em>$1</em>");J.innerHTML=L;var D=F.parentNode;var I=J.lastChild;D.replaceChild(I,F);while(J.firstChild){D.insertBefore(J.firstChild,I)}}}var A={};function B(D){if(A[D]){return A[D]}A[D]=new RegExp("("+D+")","gi");return A[D]}$("#timeline > li .entry-content").livequery(function(){if(location.hash.match(/search\?q=(.+)/)){var E=decodeURIComponent(RegExp.$1);var D=B(E);C(this,D)}})}function initializeSidebar(){if($("#side ul.sidebar-menu li.active").length==0){var B=$("body").attr("id");var A=null;if(B=="search"){B=page.query;if(B){var C=$.grep($("#side ul.sidebar-menu li a"),function(D){return $(D).attr("_query")==page.query})[0];if(C){A=$(C).parent("li")}else{$("#side #custom_search").addClass("active")}}}else{if(B){if(B=="sent"||B=="inbox"){B="direct_messages"}A=$("#side ul.sidebar-menu li#"+B+"_tab")}}if(A&&A.length){$(A.get(0)).addClass("active")}}}$.fn.isCollapsibleMenu=function(){function A(){var B=[];$("#side .collapsible").each(function(){var C=$(this);var E=C.find("h2.sidebar-title").attr("id");if(E){E=E.replace("_menu","")}else{return true}var D=C.hasClass("collapsed")?"C":"O";B.push(E+D)});$.cookie("menus",B.join("_"))}return this.each(function(){var D=$(this);var B=D.find("h2.sidebar-title");function F(G){$.ajax({type:"GET",url:G,dataType:"html",beforeSend:function(){D.addClass("loaddisableding")},success:function(H){D.find(".sidebar-menu").remove();B.after(H);C()},complete:function(){D.removeClass("loaddisableding")}})}function C(){var G=D.find(".sidebar-menu");D.find("#friends_view_all").fadeIn();G.slideDown(100,function(){D.removeClass("collapsed");A()})}function E(){var G=D.find(".sidebar-menu");D.find("a.xref").fadeOut(100);D.find("div#friends_view_all").fadeOut(100);G.slideUp(100,function(){D.addClass("collapsed");A()})}D.bind("expand",function(){C()});D.bind("collapse",function(){E()});B.click(function(H){if(H.target.nodeName.toLowerCase()=="a"){return true}var G=D.find("a.fetch-contents");if(D.hasClass("collapsed")){D.find("a.xref").fadeIn(100);if(G.length){F(G.attr("href"));G.remove()}else{C()}}else{E()}})})};$.fn.isSidebarTab=function(){var A=this.each(function(){var B=$(this);B.bind("click",function(){B.trigger("active")}).bind("active",null,function(C){if(B.parents("#side").length>0){$(window).scrollTop(0);$("#side ul.sidebar-menu li, #trends_list li").removeClass("active");$("#side #custom_search").removeClass("active");B.parent("li").addClass("active")}}).bind("loaddisableding",null,function(C){B.parent("li").addClass("loaddisableding")}).bind("loaddisableded",null,function(C){B.parent("li").removeClass("loaddisableding")}).bind("aborted",null,function(C){B.parent("li").removeClass("loaddisableding")})});return A};$.fn.isInPageLink=function(B){var A=this.each(function(){var C=$(this);var D=C.meta();var E=D.dispatch_action;C.click(function(H){var F=H.srcElement||H.originalTarget||H.target;if(F.tagName.toLowerCase()=="em"){H.stopImmediatePropagation();return true}if($.browser.msie){this.hideFocus=true}var G=C.attr("href");if(E!="search"){page.query=""}if(page.isTimelineChange){page.currentTimelineChange.abort();page.$oldTimelineLink.trigger("aborted")}page.currentTimelineChange=$.ajax({type:"GET",url:G,dataType:"json",beforeSend:function(){page.isTimelineChange=true;C.trigger("loaddisableding");page.$oldTimelineLink=C},success:function(I){if(twttr.is.def(I.users)){twttr.User.merge(I.users)}twttr.processJson(I);twttr.updateLocation(E=="list"?"/list"+G:G);if(E){page.action_name=E;$("body").attr("id",E);if(E=="direct_messages"||E=="inbox"||E=="sent"){$("#direct_message_form").trigger("loaddisabledrecipients")}if(I.searchError!=undefined){page.searchError=I.searchError}}if(page.timelineRefresher){page.timelineRefresher.stop();page.timelineRefresher=null}addCountToDocumentTitle();timelineRefresh(E,G);$.Timeline.triggerPageHeightChangedEvent();$.Timeline.triggerTimelineChanged()},complete:function(I){onPageChange();$("body").addClass("replyable");C.trigger("loaddisableded");page.isTimelineChange=false;if(B){B(C)}}});return false})});return A};function reloaddisabledTimeline(B){var A=(window.location.hash||B).toString().replace(/^#?([^\/])/,"/$1").replace(/^\/?list/,"");page.currentTimelineChange=$.ajax({type:"GET",url:A,dataType:"json",beforeSend:function(){page.isTimelineChange=true},success:function(C){page.searchError=C.searchError;if(twttr.is.def(C.users)){twttr.User.merge(C.users)}twttr.processJson(C);if(page.timelineRefresher){page.timelineRefresher.stop();page.timelineRefresher=null}addCountToDocumentTitle();timelineRefresh(B,A)},error:function(){(new InfoNotification()).setMessage(_("Whoops! Something went wrong. Please refresh the page and try again!")).show()},complete:function(){$("#sidebar_search_q").val("").blur();onPageChange();$("body").addClass("replyable");initializeTimeline();$("#timeline").removeClass("loaddisableding");page.isTimelineChange=false;if(B.match(/\/?list\//)){var C=$(".lists-links a[href="+h(A)+"]");$("#side ul.sidebar-menu li, #trends_list li").removeClass("active");$("#side #custom_search").removeClass("active");if(C.length){C.parent("li").addClass("active");setTimelineForListInPageLink(C)}}}})}$.fn.isBulletin=function(){return this.each(function(){var A=$(this);var B=A.find("a.close, a.hide");B.click(function(){A.fadeOut();return false})})};$.fn.isBrowserUpgradeBulletin=function(A){return this.each(function(){var B=$(this);B.find("a.close, a.hide").click(function(){$.cookie(A+"_upgrade","y")})})};$.fn.isDeviceFailBulletin=function(){return this.each(function(){var A=$(this);var B=A.find("a.hide-fail-notice, a.close, a.hide");var C=B.attr("id").replace("hide_device_","");B.click(function(){$.ajax({type:"POST",dataType:"text",url:"/devices/update/"+C,data:{authenticity_token:twttr.form_authenticity_token,"device[fail_alert]":"0",twttr:true},success:function(D){if(D.match(/success/)){A.fadeOut(200)}else{twttr.error()}},beforeSend:null,complete:null});return false})})};$.fn.isDeviceBouncingBulletin=function(){return this.each(function(){var A=$(this);var B=A.find("a.hide-fail-notice, a.close, a.hide");B.click(function(){A.fadeOut(200);return false})})};$.fn.isBouncingEmailBulletin=function(){return this.each(function(){var A=$(this);A.find("a.close, a.hide").click(function(){$.ajax({type:"POST",dataType:"text",url:"/bouncers/reset",data:{authenticity_token:twttr.form_authenticity_token,twttr:true},beforeSend:null,complete:function(){(new InfoNotification()).setMessage(_("Your email notifications should resume shortly.")).show()}});return false})})};$.fn.isNotificationSetting=function(){return this.each(function(){var B=$(this);var A=B.attr("id").replace("notify_on_","").replace("notify_off_","");B.click(function(){var C=B.attr("value");$.ajax({type:"POST",dataType:"text",url:"/friendships/device_"+C+"/"+A,data:{authenticity_token:twttr.form_authenticity_token,twttr:true},success:function(D){if(D.match(/success/)){$(".follow-control").trigger("refresh",["notify_"+(C=="follow"?"on":"off")])}else{twttr.error()}}})})})};$.fn.isNudgable=function(){return this.each(function(){var A=$(this);A.click(function(){var B=A.parents("form");B.find("input[name=authenticity_token]").val(twttr.form_authenticity_token);B.submit();return false})})};$.fn.isSlugField=function(B,A){return this.bind("keyup",function(){var C=slug($(this).val());if(B){B.val(C)}if(A){A.text(C)}})};var slug=function(A){return A.toLowerCase().replace(/[^a-z0-9]/g,"-").replace(/-+/g,"-").replace(/^[_-]+|[_-]+$/g,"")};$.fn.isDeleteButton=function(A){if(!confirm(A)){return false}};$.fn.disable=function(){$(this).attr("disabled","disabled").addClass("disabled")};$.fn.enable=function(){$(this).removeAttr("disabled").removeClass("disabled")};$.fn.textAreaSizeLimiter=function(C){var D=$(this);var A=C.maxLength;var B=C.infoMessageSelector;var E=D.parents("form").find("input[type=submit]");D.keyup(function(){var F=D.val().length;if(F>A){E.attr("disabled","DISABLED").removeClass("btn").addClass("dbtn");$(B).show()}else{E.removeAttr("disabled").removeClass("dbtn").addClass("btn");$(B).hide()}})};$.fn.isPasswordStrengthField=function(A,B){return this.each(function(){if(!A){return }if(!B){B={}}var H=$(this);var J=$(A);J.append('<span class="pstrength-text"></span>');var F=J.find(".pstrength-text");function E(K){J.children().each(function(){var L=$(this);if(L.hasClass("pstrength-text")){if(K){L.show()}else{L.hide()}}else{if(K){L.hide()}else{L.show()}}})}function I(L){var P=0;var N=B.minlength?B.minlength:6;if(L.length<N){return{score:L.length,message:_("Too short"),className:"password-invalid"}}if(B.username){var Q=(typeof (B.username)=="function")?B.username():B.username;if(Q&&(L.toLowerCase()==Q.toLowerCase())){return{score:0,message:_("Too obvious"),className:"password-invalid"}}}if(L.match(/\s/)){return{score:0,message:_("Cannot contain spaces"),className:"password-invalid"}}if($.inArray(L.toLowerCase(),twttr.BANNED_PASSWORDS)!=-1){return{score:0,message:_("Too obvious"),className:"password-invalid"}}if(B.requireStrong){size=10;var K="# ` ~ ! @ $ % ^ & * ( ) - _ = + [ ] { } | ; : ' \" , . < > / ?".split(" ");K=$.map(K,function(R){return"\\"+R}).join("");var M=["\\d","[a-z]","[A-Z]","["+K+"]"];var O=$.map(M,function(R){return"(?=.*"+R+")"}).join("");if(!L.match(new RegExp("("+O+"){10,}"))){return{score:0,message:_("Too Weak"),className:"password-invalid"}}}P+=L.length*4;P+=(D(1,L).length-L.length)*1;P+=(D(2,L).length-L.length)*1;P+=(D(3,L).length-L.length)*1;P+=(D(4,L).length-L.length)*1;if(L.match(/(.*[0-9].*[0-9].*[0-9])/)){P+=5}if(L.match(/(.*[!@#$%^&*?_~].*[!@#$%^&*?_~])/)){P+=5}if(L.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/)){P+=10}if(L.match(/([a-zA-Z])/)&&L.match(/([0-9])/)){P+=15}if(L.match(/([!@#$%^&*?_~])/)&&L.match(/([0-9])/)){P+=15}if(L.match(/([!@#$%^&*?_~])/)&&L.match(/([a-zA-Z])/)){P+=15}if(L.match(/^\w+$/)||L.match(/^\d+$/)){P-=10}if(P<0){P=0}if(P>100){P=100}if(P<34){return{score:P,message:_("Weak"),className:"password-weak"}}if(P<50){return{score:P,message:_("Good"),className:"password-good"}}if(P<75){return{score:P,message:_("Strong"),className:"password-strong"}}return{score:P,message:_("Very Strong"),className:"password-verystrong"}}function D(L,O){var K="";for(var N=0;N<O.length;N++){var P=true;for(var M=0;M<L&&(M+N+L)<O.length;M++){P=P&&(O.charAt(M+N)==O.charAt(M+N+L))}if(M<L){P=false}if(P){N+=L-1;P=false}else{K+=O.charAt(N)}}return K}function C(K){if(K&&J.hasClass(K)){return false}J.removeClass("password-weak").removeClass("password-good").removeClass("password-strong").removeClass("password-verystrong").removeClass("password-invalid");return true}function G(){var L=H.val();if(L.length==0){C();E(false)}else{if(L.length){E(true)}}if(L.length>0){var K=I(L);F.html(K.message);if(C(K.className)){J.addClass(K.className)}}}H.bind("show-password-meter",function(){J.show()});H.bind("hide-password-meter",function(){J.hide()});H.keyup(function(){G()});H.blur(function(){if(this.value.length==0){C();H.trigger("hide-password-meter")}});if(H.val()){G();J.show()}})};$.fn.isOAuthApplication=function(){return this.each(function(){var C=$(this);var B=C.attr("id").replace("oauth_application_","");var A=C.find(".revoke-access");A.click(function(){$.ajax({type:"POST",dataType:"json",url:"/oauth/revoke",data:{authenticity_token:twttr.form_authenticity_token,token:B,twttr:true},success:function(D){if(D.revoked){C.addClass("revoked")}else{C.removeClass("revoked")}A.text(D.label)}});return false})})};$.fn.screenName=function(){return $(this).find(".screen-name").text()||page.sessionUserScreenName};$.fn.userId=function(){var A;if(A=$(this).attr("id")){return A.replace("user_","")}else{return page.sessionUserId}};twttr.klass("twttr.MinimumDelayCallback",function(A){this.waitUntil=twttr.getTimeMillis()+A}).method("delay",function(C){var A=twttr.getTimeMillis();var B=this.waitUntil-A;if(B>0){setTimeout(function(){this.delay(C)}.pBind(this),B)}else{C.apply()}});twttr.augmentObject(twttr,{getTimeMillis:function(){return new Date().getTime()}});twttr.augmentObject(twttr,{formatPromotedTrend:function(B,C){B.addClass("promoted-trend");B.attr("data",C);var D=JSON.parse(C);var A=$("<span/>");if(D.promoted_content.advertiser_name){A.append(_("Promoted by %{name}",{name:D.promoted_content.advertiser_name}))}else{A.append(_("Promoted"))}B.append(A).promotedTrendsTipsy();return B}});jQuery.fn.pulsate=function(F,C){var D=$(this);var E=1;var A=function(){E=E+0.5;var G=E>F?function(){}:B;D.fadeIn(C,G)};var B=function(){E=E+0.5;D.fadeOut(C,A)};B()};$("html").keypress(function(C){var B=C.charCode?C.charCode:C.keyCode?C.keyCode:0;var A=$(C.target);if(A&&A.hasClass("a-btn")&&B==32){A.click();C.preventDefault()}});$("#status_update_form").isUpdateForm();twttr.reloaddisabled=function(){window.location.reloaddisabled()};twttr.ajaxSetup=function(){$.ajaxSetup({data:{twttr:true,authenticity_token:twttr.form_authenticity_token}})};if(!window.SEARCH_CALLBACKS){window.SEARCH_CALLBACKS={summize:"processSummize",loaddisabled:"pageLoadSearch",searchLink:"processSearchLink",trendLink:"processTrendLink",savedSearchLink:"processSavedSearchLink",searchForm:"processSearchForm",hashtagLink:"processHashtagLink",inResultsLink:"processInResultsLink",more:"processSearchMore",refresh:"processSearchRefresh"}}twttr.addRetweetSearchTipsy=function(){$("a.meta-retweets").tipsy({gravity:"n",html:true,additionalCSSClass:"garuda-tipsy-container",showTimeout:300});$("a.meta-retweets").click(function(A){A.preventDefault();return false})};twttr.decoratePromotedTweets=function(){$("#timeline li.garuda-tweet").bind("hovercard",function(B,A){var C=twttr.createAdHoverTrackingParameters($(B.target),A);twttr.asyncAdsClickCount(C)});$(".garuda-tweet").each(function(){var A=$(this);if(!A.is(":first-child")){A.siblings(":not(.garuda-tweet):first").before(A)}})};twttr.prepareSearchResults=function(){twttr.addRetweetSearchTipsy();twttr.decoratePromotedTweets()};$(twttr.prepareSearchResults);$.Timeline.registerTimelineEvent(twttr.prepareSearchResults);twttr.searchTwitter=function(B,A){A.trigger("loaddisableding");var C=$('<a href="search?q='+encodeURIComponent(B)+'" data="{&quot;dispatch_action&quot;:&quot;search&quot;}" />');C.bind("loaddisableded",null,function(E){A.trigger("loaddisableded")});var D=function(){C.isInPageLink().click()};$("#user_search_results").slideUp();$("#heading").removeClass("hide-name-search");if(!A.hasClass("promoted-trend")){twttr.oneboxUserSearch(B,D)}else{D()}};twttr.oneboxUserSearch=function(C,D){var B=$("#user_search_results"),A=3;C=B.length&&C.split(/\s/).length<3?C.replace(/(^|\b)(from\:|to\:|near\:|source\:)/g,""):"";if(C.split(/\:/).length>1){C=""}if(C){$.ajax({type:"POST",url:"/search/namesearch",dataType:"json",data:{q:C,limit:A},success:function(F){var E=Math.min(F.length,A);if(E){var I="",J=[];for(var H=0;H<E;++H){var L=["user"],K=F[H];J.push(K.id);K.escaped_name=K.name?K.name.escapeHTML():K.screen_name;K.profile_url="/"+K.screen_name+"?from_source=onebox";L.push("u-"+K.screen_name);if(!H){L.push("first")}if(H==E-1){L.push("last")}if(K.verified){L.push("verified")}else{if(K["protected"]){L.push("protected")}}I+='<li class="'+L.join(" ")+'" data-position="'+H+'" data-result-user-id="'+K.id+'">';I+=replaceParams('<a class="profilepic" href="%{profile_url}"><img class="fn" src="%{profile_image_url}" alt="%{escaped_name}" /></a><div class="bio"><p class="username"><span><a href="%{profile_url}">%{screen_name}</a></span></p><p class="fullname">%{name}</p></div>',K);I+="</li>"}B.find("ul").attr("class","clearfix size"+E).html(I);B.find("p.seeall a").attr("href","/search/users?q="+encodeURIComponent(C));B.find("h2 strong").html(C.escapeHTML());B.slideDown();$("#heading").addClass("hide-name-search");scribe({event_name:"onebox_search_results",query:C,user_results:J,user_results_count:E},"onebox_user_search",{filter:"onebox_user_search"});var G=function(M){scribe($.extend({event_name:"onebox_click_result"},M),"onebox_user_search",{filter:"onebox_user_search"})};B.find("li a").click(G).bind("hovercard",function(M,N){var P=$(this).parents("li:first"),O={query:C,position:P.attr("data-position"),result_user_id:P.attr("data-result-user-id")};switch(N){case"hovercard-profile-pic":case"hovercard-screen-name":G.call(this,O);break;case"hovercard-follow":scribe($.extend({event_name:"onebox_follow",follow_context:"hovercard"},O),"onebox_user_search",{filter:"onebox_user_search"});break;case"hovercard-show":case"hovercard-loaddisableding":setTimeout(function(){$("div.hovercard-inner:first a.tweet-url").each(function(){var Q=$(this);Q.attr("href",Q.attr("href")+"?from_source=onebox")});$("div.hovercard-inner:first a.loaddisabled-more").click()},5);default:if(N!="hovercard-loaddisableding"){scribe($.extend({event_name:"onebox_hovercard_action",hovercard_action:N},O),"onebox_user_search",{filter:"onebox_user_search"})}}})}}})}if(D){D()}};$.fn.isSearchForm=function(){return this.each(function(){var B=$(this);var A=$(B.find('input[type="text"]')[0]);var C=B.find("#sidebar_search_submit");A.Watermark(_("Search")).focus(function(){A.select();return true});C.click(function(){B.submit()});B.submit(function(E){E.preventDefault();var D=A.val();page.query=D;page.prettyQuery=D;page.placeDetails="";if(D!=""){C.addClass("loaddisableding");twttr.searchTwitter(D,B)}$("#side ul.sidebar-menu li").removeClass("active");$("#side #custom_search").addClass("active");return false});B.bind("loaddisableded",null,function(D){C.removeClass("loaddisableding")})})};$.fn.isSearchLink=function(A){return this.each(function(){var B=$(this);B.click(function(C){C.preventDefault();page.prettyQuery=B.attr("name")||B.attr("title");page.query=B.attr("_query")||page.prettyQuery;page.placeDetails=B.attr("_place_details");page.placeMapLink=B.attr("_place_map_link");twttr.searchTwitter(page.query,B);if(B.parents("#side").length>0){$("#side ul.sidebar-menu li").removeClass("active");B.parent("li").addClass("active")}$("#trends_list li.active a").removeClass("active")})})};var LIST_PUBLIC_MODE="public";var LIST_PRIVATE_MODE="private";var LIST_MAX_NAME_LENGTH=25;var LIST_MAX_DESCRIPTION_LENGTH=100;var numeric_mode=function(A){switch(A){case"public":return 0;case"private":return 1;default:return 0}};var updateListFollowersCount=function(A){return updateCount("#subscribers_tab .stat-count",A)};var updateListFollowingCount=function(A){return updateCount("#members_tab .stat-count",A)};var fadeUserOnListUnfollow=function(A){A.fadeOut("medium",function(){A.remove()})};var onListMembersPage=function(A){return $("body").hasClass("lists_members")&&$('.list-header h2 a[href="'+A.uri+'"]').length==1};var linkToList=function(A,B){A.dispatch_action="list";return'<li><a class="list_'+A.id+'" href="'+A.uri+'" data="'+h(JSON.stringify(A))+'">'+(B?"<em />":"")+"<span>"+listDisplayName(A)+"</span></a></li>"};var listDisplayName=function(A){return(page.sessionUserScreenName&&page.sessionUserScreenName==A.user?h(A.slug):"<b>@</b>"+h(A.user)+"/<wbr/>"+h(A.slug))+lockIconForList(A)};var lockIconForList=function(A){return(A.mode==LIST_PRIVATE_MODE)?'<span class="lock-icon" title="Private List"></span>':""};var findListIndexBySlug=function(A,B){return jQuery.map(A,function(D,C){if(D.slug==B){return C}else{return null}})};$.fn.isUserListMenu=function(){var A=$("#list_menu");return this.one("click",function(){var D=$(this);var E=D.parents(".user");var C={};$.map(E.meta().lists,function(F){C[F.slug]=true});$("body").click();D.addClass("clicked").after(A.html());var B=D.siblings("ul");if(B.find("li:not(.new-list)").size()>=twttr.ListPerUserLimit){B.find(".new-list").remove()}B.find("li").each(function(){var F=$(this);if(F.hasClass("new-list")){F.isNewListLink()}else{F.isUserListItem(C[F.find('input[type="checkbox"]').meta().slug])}});$("html").one("click",function(){D.removeClass("clicked").blur().siblings("ul").remove().end().isUserListMenu();return false});return false})};$.fn.isUserListItem=function(D){var A=function(I,H,F,G){I.show();H.hide();var E=(G=="POST");H.attr("checked",E);F.unbind("click.checkbox");F.bind("click.while-processing",function(){return false})};var C=function(H,G,F,E){H.hide();G.show();F.unbind("click.while-processing");F.bind("click.checkbox",function(I){B.call(this,F,G,H,E);return false})};var B=function(M,F,I,L){var H=L?"DELETE":"POST";var G=M.parents(".user");var K=G.attr("id").replace("user_","");var J={authenticity_token:twttr.form_authenticity_token,twttr:true};var E=M.find('input[type="checkbox"]').meta().uri+"/members";if(H=="POST"){J["member[id]"]=K}else{E+="/"+K}$.ajax({type:H,dataType:"json",url:E,data:J,beforeSend:function(){A(I,F,M,H)},complete:function(){C(I,F,M,L)},success:function(N){L=(H=="POST");F.attr("checked",L);if(H=="POST"){addListToUser(G,N);if(onListMembersPage(N)){updateListFollowingCount(1)}}else{removeListFromUser(G,N);if(onListMembersPage(N)){fadeUserOnListUnfollow(G);updateListFollowingCount(-1)}}},error:function(){F.attr("checked",L)}})};return this.each(function(){var E=$(this);var F=E.find('input[type="checkbox"]');var H=E.find(".loaddisableding-spinner");var G=false;if(D){G=F.attr("checked",true)}E.bind("click.checkbox",function(I){B.call(this,E,F,H,G);return false})})};$.fn.isNewListLink=function(){return this.click(function(){var A=$(this).parents(".user");if(A.length==0){A=null}$(this).parent(".ul").remove()voidListDialog(true,{userObject:A});return false})};$.fn.isEditListLink=function(){return this.click(function()voidListDialog(false,$(this).meta());return false})};voidListDialog=function(D,F){if(!F){F={}}var G=$("#list_dialog");var B=$(G.html());var A=new twttr.dialog({closeButton:true,content:B,heading:$($("#list_dialog_header").html()),modal:true,width:"405px"});A.bind("close",function(){A.$root.remove()});var E="";A.$root.addClass("list-dialog");if(D){A.$root.addClass("create-list-dialog")}else{E=F.description;A.$root.addClass("update-list-dialog").find('input[type="submit"]').val(_("Update list")).end().find(".list-name").val(F.name).end().find(".list-slug-title-and-slug").show().end().find(".list-description").val(E).end().find(".list-link span").text(F.slug).end().find('input[name="list[mode]"][value="'+numeric_mode(F.mode)+'"]').attr("checked",true);var C=A.find(".private-warning");A.find('input[name="list[mode]"]').change(function(){if(this.value==numeric_mode(LIST_PRIVATE_MODE)&&this.checked){C.show()}else{C.hide()}})}$(".list-description",A.$root).maxLength(LIST_MAX_DESCRIPTION_LENGTH-2);A.find(".list-name").focus();A.$root.isListDialog(D,F,A);void()};$.fn.isListDialog=function(C,A,B){return this.each(function(){var G=$(this);var F=A.userObject;var D=G.find("form");D.find(".list-name").one("keyup",function(){console.log("keyup");$(this).siblings(".list-slug-title-and-slug").show()}).isSlugField(D.find(".list-slug-field"),D.find(".list-link span"));if(F){D.find(".list-member-id").val(F.userId())}var E=$(this).find('input[type="submit"]');D.submit(function(I){var H=D.serialize();if(!C){H+="&"+$('<input type="hidden" name="_method" value="PUT" />').serialize()}$.ajax({type:"POST",dataType:"json",url:C?D.attr("action"):A.uri,data:H,beforeSend:function(){E.attr("disabled","disabled")},success:function(J){B.close();B.$root.remove();if(C){addListToMenu(J);if(F){addListToUser(F,J)}addListToLists(J);(new ShortNotification()).setMessage(_("Yay! Your list was created.")).show()}else{window.location=J.uri}},error:function(J){(new InfoNotification()).setMessage(J.responseText).show()},complete:function(){E.removeAttr("disabled","disabled")}});I.preventDefault()})})};$.fn.isDestroyListLink=function(){return this.click(function(D){var C=$(this);var A=C.next("form");var B=A.attr("action");if(confirm(_("Are sure you want to delete this list? There is NO undo!"))){$.ajax({url:B,type:"POST",dataType:"json",data:{_method:"delete",authenticity_token:twttr.form_authenticity_token,twttr:true},beforeSend:function(){C.disable()},success:function(){document.location="/"},error:function(){C.enable()}})}return false})};$.fn.isSubscribeListLink=function(){return this.click(function(B){var A=$(this);$.ajax({url:A.attr("href"),type:"POST",dataType:"json",data:{authenticity_token:twttr.form_authenticity_token,twttr:true},beforeSend:function(){A.disable()},complete:function(){A.enable()},success:function(){A.parents(".list").addClass("subscriber");updateListFollowersCount(1)},error:function(){A.parents(".list").removeClass("subscriber")}});return false})};$.fn.isUnsubscribeListLink=function(){return this.click(function(B){var A=$(this);$.ajax({url:A.attr("href"),type:"POST",dataType:"json",data:{_method:"delete",authenticity_token:twttr.form_authenticity_token,twttr:true},success:function(){A.parents(".list").removeClass("subscriber");var C=$("#lists_subscribers #follow_grid #user_"+page.sessionUserId);fadeUserOnListUnfollow(C);updateListFollowersCount(-1)},error:function(){A.parents(".list").addClass("subscriber")}});B.preventDefault()})};$.fn.isListInPageLink=function(){return this.each(function(){var A=$(this);A.isInPageLink(setTimelineForListInPageLink)})};var setTimelineForListInPageLink=function(A){$("#timeline_heading").show();var E=$("#timeline_heading h1");var D=$("#timeline_heading h2");var C=A.meta();var B=h(C.uri);var F=listDisplayName(C);D.remove();E.html(F);E.after('<h2 class="list-subheading"><p class="list-numbers"><a href="'+B+'/members">'+_("Following:")+" <span>"+h(C.member_count)+"</span></a>"+(C.mode==LIST_PRIVATE_MODE?"":'<a href="'+B+'/subscribers">'+_("Followers:")+" <span>"+h(C.subscriber_count)+"</span></a>")+'</p><p class="list-link"><a href="'+B+'">'+_("View list page")+"<span> ›</span></a></p></h2>");if(C.member_count==0){$("#timeline_heading h2").append($(C.user==page.sessionUserScreenName?"#list_no_members_owner":"#list_no_members").html())}setDocumentTitle("Twitter / "+C.full_name)};var addListToUser=function(B,A){return B.each(function(){if(findListIndexBySlug(B.meta().lists,A.slug).length==0){B.meta().lists.push(A);if(B.find(".list-tags").length>0){B.find(".list-tags-outer:hidden").show();B.find(".list-tags").append(linkToList(A))}}})};var removeListFromUser=function(B,A){$.each(findListIndexBySlug(B.meta().lists,A.slug),function(){Array.remove(B.meta().lists,this);B.find(".list-tags .list_"+A.id).each(function(){$(this).parent("li").remove()});if(B.meta().lists.length==0){B.find(".list-tags-outer:visible").hide()}})};var addListToMenu=function(B){var A=$("#list_menu");A.find(".new-list").before('<li><img class="loaddisableding-spinner" src="httpdisabled://s.twimg.com/a/1302214109/images/spinner.gif" style="display: none;" alt="waiting" title="waiting" height="14" width="14"/><input type="checkbox" id="list_'+B.id+'" data="'+h(JSON.stringify(B))+'" /> <label for="list_'+B.id+'">'+h(B.name)+lockIconForList(B)+"</label></li>")};var isInPageLists=function(){return $("#side_lists.in-page-lists").length==1};var addListToLists=function(C){var B=isInPageLists();var A=$("ul.lists-links").siblings(".no-lists").remove().end().append(linkToList(C,B)).find(".list_"+C.id);if(B){A.addClass("in-page-list-link").isListInPageLink().isSidebarTab().click()}};var bindAdminListActions=function(){$("#admin_list a.destroy-list").isDestroyListLink();$("#admin_list a.edit-list").isEditListLink()};var isMoreButton=function(){$("#lists_pagination #more").live("click",basicMoreButtonHandler({beforeSend:function(){$("#more").addClass("loaddisableding").html("")},success:function(A){$("#lists_table tbody").append($(A["#lists"]));$("#lists_pagination").html(A["#pagination"])},error:function(){$("#more").removeClass("loaddisableding").text(_("more"));(new ShortNotification()).setMessage(_("Whoops! Something went wrong. Please try again!")).show()}}))};$.fn.equals=function(A){return this.length==1&&A.length==1&&this.get(0)==A.get(0)};$.fn.hasParent=function(A){return jQuery.inArray(A[0],this.parents())>-1};function InlineForm(A){this.initialize(A)}jQuery.extend(InlineForm.prototype,{defaultOptions:{title:"",submitBtnValue:"",showCancel:true,closeOnOutsideClick:true,formClass:"",timelineChangedEvents:false,pageHeightChangedEvents:false},overrideDefaultOptions:{},initialize:function(A){this.options=jQuery.extend({},this.defaultOptions);jQuery.extend(this.options,this.overrideDefaultOptions);jQuery.extend(this.options,A);this.$form=$('<div class="inline-form '+this.options.formClass+'"></div>');this.$buttonParent=$('<div class="inline-form-buttons"></div>');this.$button=$('<button type="button" class="btn">'+this.options.submitBtnValue+"</button>");if(this.options.showCancel){this.$cancel=$('<span class="cancel">&nbsp;</span>')}this.$form_inner=$('<div class="inline-form-inner"></div>');this.$input=$('<textarea class="inline-form-input"></textarea>');this.$inputsPrompt=$('<div class="inline-inputs-prompt"></div>');this.$title=$('<div class="title">'+this.options.title+"</div>");this.$body=$('<div class="body">'+(this.options.body||"")+"</div>");this.initEvents()},initEvents:function(){this.buttonEvent=this.submitForm.pBind(this);this.closeEvent=this.close.pBind(this);this.outsideClickEvent=this.destroyFromEvent.pBind(this);this.timelineEvent=this.timelineEvent.pBind(this);if(this.options.timelineChangedEvents){$.Timeline.registerTimelineEvent(this.timelineEvent)}if(this.options.pageHeightChangedEvents){this.pageHeightChangedEvent=this.pageHeightChangedEvent.pBind(this);$.Timeline.registerPageHeightChangedEvent(this.pageHeightChangedEvent)}},addEvents:function(){this.$button.click(this.buttonEvent);if(this.options.showCancel){this.$cancel.click(this.closeEvent)}if(this.options.closeOnOutsideClick){$(window).click(this.outsideClickEvent)}},removeEvents:function(){this.$button.unbind("click",this.buttonEvent);if(this.options.showCancel){this.$cancel.unbind("click",this.closeEvent)}if(this.options.closeOnOutsideClick){$(window).unbind("click",this.outsideClickEvent)}if(this.options.timelineChangedEvents){$.Timeline.unregisterTimelineEvent(this.timelineEvent)}$.Timeline.unregisterPageHeightChangedEvent(this.pageHeightChangedEvent)},onSendError:function(A){if(this.sendNotification){this.sendNotification.cancel()}(new InfoNotification()).setMessage(_("Whoops! Something went wrong. Please refresh the page and try again!")).show();this.close()},onSendSuccess:function(A){},formAction:function(){},timelineEvent:function(){},pageHeightChangedEvent:function(){this.positionForm()},postData:function(){},beforePost:function(){},onComplete:function(){},submitForm:function(){this.$button.disable();var A={authenticity_token:twttr.form_authenticity_token};jQuery.extend(A,this.postData());if(this.progressNotificationText){this.sendNotification=(new ProgressNotification()).setProgressMessage(this.progressNotificationText).setCompletedMessage(_("Ok, done.")).show()}this.beforePost();$.ajax({type:"POST",dataType:"json",dataFilter:function(B){if(!jQuery.trim(B)){return null}return B},url:this.formAction(),data:A,error:function(B){this.onSendError(B)}.pBind(this),success:function(B){this.onSendSuccess(B);this.close();if(this.sendNotification){this.sendNotification.done()}}.pBind(this),beforeSend:twttr.loaddisableding,complete:function(){twttr.loaddisableded();this.onComplete()}.pBind(this)})},arrange:function(){var A=$('<div class="inline-form-inputs"></div>');if(this.options.showCancel){this.$buttonParent.append(this.$cancel)}this.$buttonParent.append(this.$button);this.$form_inner.append(A.append(this.$title).append(this.$body).append(this.$inputsPrompt).append(this.$input)).append(this.$buttonParent);this.$form.append(this.$form_inner);this.$form.hide();this.baseElement().append(this.$form)},baseElement:function(){return this.$parentNode||$(document.body)},show:function(A){this.addEvents();this.$targetNode=A.targetNode;this.$parentNode=A.parentNode;this.positionForm();this.arrange();this.$form.fadeIn(100);this.currentlyShown=true;this.afterShow()},afterShow:function(){},positionForm:function(){if(this.$targetNode&&this.$targetNode.width()>0){var C=this.position();var B=C[0];var A=C[1];this.$form.css("top",B).css("left",A)}else{this.close()}},close:function(){this.removeEvents();this.$form.remove();this.currentlyShown=false;this.afterClose()},afterClose:function(){},destroyFromEvent:function(B){var A=$(B.target);if(A.equals(this.$targetNode)||jQuery.inArray(this.$targetNode.get(0),A.parents())!=-1||A.equals(this.$form)||A.hasParent(this.$form)){return }this.close()},position:function(){var A=this.$targetNode.offset();return[A.top,A.left]}});RetweetInlineForm=function(){var A=_("Yes");var B=_("Retweet to your followers?");this.initialize({title:B,submitBtnValue:A})};RetweetInlineForm.prototype=new InlineForm();jQuery.extend(RetweetInlineForm.prototype,{overrideDefaultOptions:{formClass:"retweet-dlg",pageHeightChangedEvents:true},formAction:function(){var B=getListItemFromChild(this.$targetNode);var A=getStatusIdFromListItem(B);return"/statuses/"+A+"/retweet"},postData:function(){return{controller_name:page.controller_name,action_name:page.action_name}},beforePost:function(){this.close();twttr.setRetweetingStyles(this.$targetNode,_("Updating..."))},onSendSuccess:function(A){twttr.animateStatusReplacement(this.$targetNode,A);twttr.countAds(this.$targetNode)},onComplete:function(){twttr.unsetRetweetingStyles(this.$targetNode)},afterShow:function(){getListItemFromChild(this.$targetNode).addClass("perma-hover");this.$targetNode.find("a").blur()},afterClose:function(){getListItemFromChild(this.$targetNode).removeClass("perma-hover")},position:function(){var A=this.$targetNode.offset();return[parseInt(A.top)+20,parseInt(A.left)-220]}});$(document).ready(function(){try{var A="share-text-active";$(".status").each(function(){var E=$(this);var C=E.find(".retweet-link");var D=E.find(".share-text");C.hover(function(){D.addClass(A)},function(){D.removeClass(A)})})}catch(B){}});(function(){jQuery.inherits=function(A,C){function B(){}B.prototype=C.prototype;A.prototype=new B();A.prototype.constructor=A}})();(function(){jQuery.fn.equals=function(A){return this.get(0)==A.get(0)}})();(function(){jQuery.fn.hasParent=function(A){var B=false;this.parents().map(function(){if($(this).equals(A)){B=true}});return B}})();function Notification(B){this.$bar=jQuery('<div class="notification-bar"></div>');this.$barContainer=jQuery('<div class="notification-bar-container"></div>');this.$barContents=jQuery('<div class="notification-bar-contents"></div>');this.$barBackground=jQuery('<div class="notification-bar-bkg"></div>');this.$message=jQuery('<div class="message"></div>');this.$bar.hide();this.$barBackground.hide();var A=this;this.$bar.click(function(C){A.removeAfterEvent(C)});this.className=B}Notification.SLIDE_SPEED_IN_MS=300;Notification.prototype.remove=function(){var A=this;this.slideUp(function(){A.$bar.remove();A.$barBackground.remove();window.clearTimeout(A.timeout)})};Notification.prototype.removeAfterEvent=function(B){var A=$(B.target);if(A.get(0).nodeName.toLowerCase()=="a"&&A.hasParent(this.$message)){return }this.remove()};Notification.prototype.setMessage=function(A){this.msg=A;return this};Notification.prototype.show=function(){this.$message.addClass(this.className).html(this.msg);this.$barContainer.append(this.$barBackground).append(this.$bar.append(this.$barContents.append(this.$message)));jQuery("#notifications").append(this.$barContainer);this.$barBackground.height(this.$bar.height());this.showBar();if(this.onShow){this.onShow()}return this};Notification.prototype.removeInMilliseconds=function(){var A=this;this.timeout=window.setTimeout(function(){A.remove()},A.timeoutInMilliseconds)};Notification.prototype.showBar=function(){this.$bar.show();this.$barBackground.show()};Notification.prototype.onShow=function(){this.removeInMilliseconds()};Notification.prototype.slideUp=function(A){this.$bar.slideUp(Notification.SLIDE_SPEED_IN_MS);this.$barBackground.slideUp(Notification.SLIDE_SPEED_IN_MS,A)};function ShortNotification(){Notification.call(this,"message-info");this.timeoutInMilliseconds=3000}jQuery.inherits(ShortNotification,Notification);ShortNotification.prototype.showBar=function(){this.$bar.slideDown(Notification.SLIDE_SPEED_IN_MS);this.$barBackground.slideDown(Notification.SLIDE_SPEED_IN_MS)};function InfoNotification(){Notification.call(this,"message-info");this.timeoutInMilliseconds=6000}jQuery.inherits(InfoNotification,Notification);InfoNotification.prototype.showBar=function(){this.$bar.slideDown(Notification.SLIDE_SPEED_IN_MS);this.$barBackground.slideDown(Notification.SLIDE_SPEED_IN_MS)};function ProgressNotification(){Notification.call(this,"message-progress");this.timeoutInMilliseconds=1000}jQuery.inherits(ProgressNotification,Notification);ProgressNotification.prototype.setProgressMessage=function(A){return this.setMessage(A)};ProgressNotification.prototype.setCompletedMessage=function(A){this.completedMsg=A;return this};ProgressNotification.prototype.onShow=function(){};ProgressNotification.prototype.cancel=function(){this.timeoutInMilliseconds=0;this.removeInMilliseconds()};ProgressNotification.prototype.done=function(){this.$message.addClass("message-progress-done").removeClass(this.className).html(this.completedMsg);this.removeInMilliseconds()};function ErrorNotification(){Notification.call(this,"message-error");this.timeoutInMilliseconds=8000}jQuery.inherits(ErrorNotification,Notification);function Occasionally(A,D,C,B,E){this.interval=A;this.maxDecayTime=D;this.job=C;this.decayCallback=B;this.timesRun=0;this.decayRate=1;this.decayMultiplier=E||1.25;this.maxRequests=360}Occasionally.prototype.start=function(){this.stop();this.run()};Occasionally.prototype.stop=function(){if(this.worker){window.clearTimeout(this.worker)}};Occasionally.prototype.run=function(){var A=this;this.decayRate=this.decayCallback()?Math.max(1,this.decayRate/this.decayMultiplier):this.decayRate*this.decayMultiplier;var B=this.interval*this.decayRate;B=(B>=this.maxDecayTime)?this.maxDecayTime:B;this.worker=window.setTimeout(function(){A.execute()},Math.floor(B))};Occasionally.prototype.execute=function(){this.job();if(++this.timesRun<this.maxRequests){this.run()}};twttr.countClick=function(){var A=twttr.createTrackingParameters(this);twttr.asyncClickCount(A)};twttr.countAds=function(A){if(A.parents(".garuda-tweet").get(0)){var B=twttr.createAdLinkTrackingParameters(A);twttr.asyncAdsClickCount(B)}};twttr.countPromotedTrends=function(B,A){var C=twttr.createPromoteTrendTrackingParameters(B,A);twttr.asyncPromotedTrendEventLog(C)};twttr.asyncClickCount=function(A){(new Image()).src="/abacus?"+$.param(A)};twttr.asyncAdsClickCount=function(A){(new Image()).src="/abacus/garuda_click?"+$.param(A)};twttr.asyncPromotedTrendEventLog=function(A){(new Image()).src="/abacus/promoted_trend_event?"+$.param(A)};twttr.createAdHoverTrackingParameters=function(A,B){var C=twttr.createAdTrackingParameters(A);return $.extend({},C,{linkType:B})};twttr.createAdLinkTrackingParameters=function(B){var A=twttr.identifyLinkType(B,["retweet-link","reply","entry-meta","fav","non-fav"]);var C=twttr.createAdTrackingParameters(B);return $.extend({},C,{linkType:A})};twttr.identifyLinkType=function(A,E){var C=["web","profile-pic","screen-name","hashtag","username"];if(typeof (E)!="undefined"){C=C.concat(E)}for(var B=0;B<C.length;B++){var D=C[B];if(A.hasClass(D)){if(D=="fav"){return"non-fav"}else{if(D=="non-fav"){return"fav"}else{return D}}}}};twttr.countAdsReplies=function(A){var B=$("#content li.garuda-tweet");if(B.length>0){if(twttr.tweetIdForStatus(B)==A){twttr.countAds(B.find(".reply"))}}};twttr.tweetIdForStatus=function(A){return A.find(".meta a").attr("href").match(/\/(\d+)$/)[1]};twttr.createAdTrackingParameters=function(G){var N=G.closest(".status");var K=twttr.tweetIdForStatus(N);var M=$('meta[name="session-userid"]');var F=M.attr("content")||-1;var E=$('meta[name="client-ip"]');var D=E.attr("content")||-1;var C=JSON.parse(N.attr("data"));var B=C.advertiser_id;var J=C.campaign_id;var I=C.ad_id;var A=C.impression_id;var H=page.query;var L=twttr.form_authenticity_token||$('input[name="authenticity_token"]').attr("value");return{url:G.attr("href"),tweetId:K,userId:F,userIP:D,advertiserId:B,campaignId:J,adId:I,impressionId:A,query:H,authenticity_token:L}};twttr.createTrackingParameters=function(F){var B=$(F);var A=twttr.identifyLinkType(B);var E=B.closest(".status").find(".meta").children("a").get(0).href.split("/");var G=E[E.length-1];var H=$('meta[name="session-userid"]');var D=H.attr("content")||-1;var C=twttr.form_authenticity_token||$('input[name="authenticity_token"]').attr("value");return{url:F.href,linkType:A,tweetId:G,userId:D,authenticity_token:C}};twttr.createPromoteTrendTrackingParameters=function(C,D){var A=$(C);var B=twttr.form_authenticity_token;return{event_name:D,url:A.attr("href"),promoted_trend_id:JSON.parse(A.attr("data")).promoted_content.id,authenticity_token:B}};twttr.registerTracker=function(C,A,B){C.live(A,B)};twttr.setupTracking=function(){twttr.registerTracker($("#content li.status").find("a.tweet-url"),"mousedown",function(){if($(this).parents("li.garuda-tweet").length==0){twttr.countClick.pBind(this)()}});var A=$("#content li.garuda-tweet").find("a.tweet-url, .entry-meta, .fav-action.non-fav, .fav-action.fav, .meta");twttr.registerTracker(A,"mousedown",function(){twttr.countAds($(this))});var B=$("a.promoted-trend");twttr.registerTracker(B,"click",function(){twttr.countPromotedTrends($(this),"c")})};twttr.logPromotedTrendImpression=function(){var A=$("a.promoted-trend");if(A.length>0){twttr.countPromotedTrends(A,"i")}};$(document).ready(function(){twttr.setupTracking();twttr.logPromotedTrendImpression()});/*
- http://www.JSON.org/json2.js
- 2009-09-21
-
- Public Domain.
-
- NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
-
- See http://www.JSON.org/js.html
-
- This file creates a global JSON object containing two methods: stringify
- and parse.
-
- JSON.stringify(value, replacer, space)
- value any JavaScript value, usually an object or array.
-
- replacer an optional parameter that determines how object
- values are stringified for objects. It can be a
- function or an array of strings.
-
- space an optional parameter that specifies the indentation
- of nested structures. If it is omitted, the text will
- be packed without extra whitespace. If it is a number,
- it will specify the number of spaces to indent at each
- level. If it is a string (such as '\t' or '&nbsp;'),
- it contains the characters used to indent at each level.
-
- This method produces a JSON text from a JavaScript value.
-
- When an object value is found, if the object contains a toJSON
- method, its toJSON method will be called and the result will be
- stringified. A toJSON method does not serialize: it returns the
- value represented by the name/value pair that should be serialized,
- or undefined if nothing should be serialized. The toJSON method
- will be passed the key associated with the value, and this will be
- bound to the value
-
- For example, this would serialize Dates as ISO strings.
-
- Date.prototype.toJSON = function (key) {
- function f(n) {
- // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
-
- return this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z';
- };
-
- You can provide an optional replacer method. It will be passed the
- key and value of each member, with this bound to the containing
- object. The value that is returned from your method will be
- serialized. If your method returns undefined, then the member will
- be excluded from the serialization.
-
- If the replacer parameter is an array of strings, then it will be
- used to select the members to be serialized. It filters the results
- such that only members with keys listed in the replacer array are
- stringified.
-
- Values that do not have JSON representations, such as undefined or
- functions, will not be serialized. Such values in objects will be
- dropped; in arrays they will be replaced with null. You can use
- a replacer function to replace those with JSON values.
- JSON.stringify(undefined) returns undefined.
-
- The optional space parameter produces a stringification of the
- value that is filled with line breaks and indentation to make it
- easier to read.
-
- If the space parameter is a non-empty string, then that string will
- be used for indentation. If the space parameter is a number, then
- the indentation will be that many spaces.
-
- Example:
-
- text = JSON.stringify(['e', {pluribus: 'unum'}]);
- // text is '["e",{"pluribus":"unum"}]'
-
-
- text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
- // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
-
- text = JSON.stringify([new Date()], function (key, value) {
- return this[key] instanceof Date ?
- 'Date(' + this[key] + ')' : value;
- });
- // text is '["Date(---current time---)"]'
-
-
- JSON.parse(text, reviver)
- This method parses a JSON text to produce an object or array.
- It can throw a SyntaxError exception.
-
- The optional reviver parameter is a function that can filter and
- transform the results. It receives each of the keys and values,
- and its return value is used instead of the original value.
- If it returns what it received, then the structure is not modified.
- If it returns undefined then the member is deleted.
-
- Example:
-
- // Parse the text. Values that look like ISO date strings will
- // be converted to Date objects.
-
- myData = JSON.parse(text, function (key, value) {
- var a;
- if (typeof value === 'string') {
- a =
-/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
- if (a) {
- return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
- +a[5], +a[6]));
- }
- }
- return value;
- });
-
- myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
- var d;
- if (typeof value === 'string' &&
- value.slice(0, 5) === 'Date(' &&
- value.slice(-1) === ')') {
- d = new Date(value.slice(5, -1));
- if (d) {
- return d;
- }
- }
- return value;
- });
-
-
- This is a reference implementation. You are free to copy, modify, or
- redistribute.
-
- This code should be minified before deployment.
- See http://javascript.crockford.com/jsmin.html
-
- USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
- NOT CONTROL.
-*/
-
-/*jslint evil: true */
-
-/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
- call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
- getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
- lastIndex, length, parse, prototype, push, replace, slice, stringify,
- test, toJSON, toString, valueOf
-*/
-
-
-// Create a JSON object only if one does not already exist. We create the
-// methods in a closure to avoid creating global variables.
-
-if (!this.JSON) {
- this.JSON = {};
-}
-
-(function () {
-
- function f(n) {
- // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
-
- if (typeof Date.prototype.toJSON !== 'function') {
-
- Date.prototype.toJSON = function (key) {
-
- return isFinite(this.valueOf()) ?
- this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z' : null;
- };
-
- String.prototype.toJSON =
- Number.prototype.toJSON =
- Boolean.prototype.toJSON = function (key) {
- return this.valueOf();
- };
- }
-
- var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- gap,
- indent,
- meta = { // table of character substitutions
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- },
- rep;
-
-
- function quote(string) {
-
-// If the string contains no control characters, no quote characters, and no
-// backslash characters, then we can safely slap some quotes around it.
-// Otherwise we must also replace the offending characters with safe escape
-// sequences.
-
- escapable.lastIndex = 0;
- return escapable.test(string) ?
- '"' + string.replace(escapable, function (a) {
- var c = meta[a];
- return typeof c === 'string' ? c :
- '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- }) + '"' :
- '"' + string + '"';
- }
-
-
- function str(key, holder) {
-
-// Produce a string from holder[key].
-
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length,
- mind = gap,
- partial,
- value = holder[key];
-
-// If the value has a toJSON method, call it to obtain a replacement value.
-
- if (value && typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
-
-// If we were called with a replacer function, then call the replacer to
-// obtain a replacement value.
-
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
-
-// What happens next depends on the value's type.
-
- switch (typeof value) {
- case 'string':
- return quote(value);
-
- case 'number':
-
-// JSON numbers must be finite. Encode non-finite numbers as null.
-
- return isFinite(value) ? String(value) : 'null';
-
- case 'boolean':
- case 'null':
-
-// If the value is a boolean or null, convert it to a string. Note:
-// typeof null does not produce 'null'. The case is included here in
-// the remote chance that this gets fixed someday.
-
- return String(value);
-
-// If the type is 'object', we might be dealing with an object or an array or
-// null.
-
- case 'object':
-
-// Due to a specification blunder in ECMAScript, typeof null is 'object',
-// so watch out for that case.
-
- if (!value) {
- return 'null';
- }
-
-// Make an array to hold the partial results of stringifying this object value.
-
- gap += indent;
- partial = [];
-
-// Is the value an array?
-
- if (Object.prototype.toString.apply(value) === '[object Array]') {
-
-// The value is an array. Stringify every element. Use null as a placeholder
-// for non-JSON values.
-
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = str(i, value) || 'null';
- }
-
-// Join all of the elements together, separated with commas, and wrap them in
-// brackets.
-
- v = partial.length === 0 ? '[]' :
- gap ? '[\n' + gap +
- partial.join(',\n' + gap) + '\n' +
- mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
-
-// If the replacer is an array, use it to select the members to be stringified.
-
- if (rep && typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- k = rep[i];
- if (typeof k === 'string') {
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- } else {
-
-// Otherwise, iterate through all of the keys in the object.
-
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- }
-
-// Join all of the member texts together, separated with commas,
-// and wrap them in braces.
-
- v = partial.length === 0 ? '{}' :
- gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
- mind + '}' : '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
- }
-
-// If the JSON object does not yet have a stringify method, give it one.
-
- if (typeof JSON.stringify !== 'function') {
- JSON.stringify = function (value, replacer, space) {
-
-// The stringify method takes a value and an optional replacer, and an optional
-// space parameter, and returns a JSON text. The replacer can be a function
-// that can replace values, or an array of strings that will select the keys.
-// A default replacer method can be provided. Use of the space parameter can
-// produce text that is more easily readable.
-
- var i;
- gap = '';
- indent = '';
-
-// If the space parameter is a number, make an indent string containing that
-// many spaces.
-
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
-
-// If the space parameter is a string, it will be used as the indent string.
-
- } else if (typeof space === 'string') {
- indent = space;
- }
-
-// If there is a replacer, it must be a function or an array.
-// Otherwise, throw an error.
-
- rep = replacer;
- if (replacer && typeof replacer !== 'function' &&
- (typeof replacer !== 'object' ||
- typeof replacer.length !== 'number')) {
- throw new Error('JSON.stringify');
- }
-
-// Make a fake root object containing our value under the key of ''.
-// Return the result of stringifying the value.
-
- return str('', {'': value});
- };
- }
-
-
-// If the JSON object does not yet have a parse method, give it one.
-
- if (typeof JSON.parse !== 'function') {
- JSON.parse = function (text, reviver) {
-
-// The parse method takes a text and an optional reviver function, and returns
-// a JavaScript value if the text is a valid JSON text.
-
- var j;
-
- function walk(holder, key) {
-
-// The walk method is used to recursively walk the resulting structure so
-// that modifications can be made.
-
- var k, v, value = holder[key];
- if (value && typeof value === 'object') {
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = walk(value, k);
- if (v !== undefined) {
- value[k] = v;
- } else {
- delete value[k];
- }
- }
- }
- }
- return reviver.call(holder, key, value);
- }
-
-
-// Parsing happens in four stages. In the first stage, we replace certain
-// Unicode characters with escape sequences. JavaScript handles many characters
-// incorrectly, either silently deleting them, or treating them as line endings.
-
- cx.lastIndex = 0;
- if (cx.test(text)) {
- text = text.replace(cx, function (a) {
- return '\\u' +
- ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- });
- }
-
-// In the second stage, we run the text against regular expressions that look
-// for non-JSON patterns. We are especially concerned with '()' and 'new'
-// because they can cause invocation, and '=' because it can cause mutation.
-// But just to be safe, we want to reject all unexpected forms.
-
-// We split the second stage into 4 regexp operations in order to work around
-// crippling inefficiencies in IE's and Safari's regexp engines. First we
-// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
-// replace all simple value tokens with ']' characters. Third, we delete all
-//void brackets that follow a colon or comma or that begin the text. Finally,
-// we look to see that the remaining characters are only whitespace or ']' or
-// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
-
- if (/^[\],:{}\s]*$/.
-test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
-replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
-replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
-
-// In the third stage we use the eval function to compile the text into a
-// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
-// in JavaScript: it can begin a block or an object literal. We wrap the text
-// in parens to eliminate the ambiguity.
-
- j = eval('(' + text + ')');
-
-// In the optional fourth stage, we recursively walk the new structure, passing
-// each name/value pair to a reviver function for possible transformation.
-
- return typeof reviver === 'function' ?
- walk({'': j}, '') : j;
- }
-
-// If the text is not JSON parseable, then a SyntaxError is thrown.
-
- throw new SyntaxError('JSON.parse');
- };
- }
-}());
-var scrobject={scribeHost:window.location.hostname,toScribeParams:function(A){var B=[];for(var C in A){B[B.length]=encodeURIComponent(C)+"="+encodeURIComponent(A[C])}return B.join("&")},scribeUrl:function(C,B){var A="/scribe?";if(B.host){A=window.location.protocol+"//"+B.host+A}else{if(!/[\/\.]twitter\.com/.test(scrobject.scribeHost)&&!/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/.test(scrobject.scribeHost)&&scrobject.scribeHost!="localhost"){A=window.location.protocol+"//twitter.com"+A}}return A+scrobject.toScribeParams(C)}};function scribe(A,D,C,B){C=C||{};if(window.DARKMODE_SCRIBE){return this}if(!D){console.warn("You must specify a category in order to use scribe");return this}if(typeof (A)=="function"){A=A.call(this,B)}if(A==null){console.warn("You must provide logged data in order to use scribe");return this}if(!A.event_name){console.warn('You must include an "event_name" field in your logged data in order to use scribe');return this}var E={log:JSON.stringify(A),ts:(new Date()).getTime()};if(C.filter){E.filter=C.filter}if(D){E.category=D}(new Image()).src=scrobject.scribeUrl(E,C);return this}function scribeAB(A){scribe(A,"www_ab_testing")}function watchABEvent(C,B,D,A){if(C){var E=$(C);if(!D&&E.attr("abdata")){D=JSON.parse(E.attr("abdata"))}args={experimentData:D,handler:A};$(C).bind(B,args,function(F){scribeAB(F.data.experimentData);continuePropogation=true;if(F.data.handler){continuePropogation=F.data.handler();if(!continuePropogation){F.stopPropagation()}}return(continuePropogation)})}}function watchReloaddisabledingABLink(B){var A=$(B);if(A&&A.attr("abdata")){var C=JSON.parse(A.attr("abdata"));watchABEvent(A,"click",C,function(){setTimeout('document.location = "'+A.attr("href")+'"',100);return(false)})}}if(!window.console){window.console={warn:function(A){}}}if(window.jQuery){(function(A){A.extend(A.fn,{scribe:function(B,D,C){C=C||{};A(this).bind(C.clientEvent||"mousedown",function(E){window.scribe.call(this,B,D,C,E)});return this}})})(jQuery);(function(B){var A=B("a.ab-reloaddisableding");if(typeof A.livequery=="function"){A.livequery(function(){watchReloaddisabledingABLink(B(this))})}})(jQuery)};twttr.position={adjacent:function(I,H,A){var F,G;A=(A||{});F=G=H.offset();G.gravity=A.gravity;G.weight=A.weight;var D={height:H.outerHeight(),width:H.outerWidth()};var B={height:I.outerHeight(),width:I.outerWidth()};var C={height:$(window).height(),width:$(window).width()};var E={height:$("body").height(),width:$("body").width()};if(!G.gravity){G.gravity="vertical"}if("vertical,north,south".indexOf(G.gravity)!=-1){if("right,left,center".indexOf(G.weight)==-1){G.weight=(F.left>C.width/2)?"right":"left"}if(G.gravity=="vertical"){G.gravity=((F.top+B.height)>($(window).scrollTop()+C.height))?"south":"north"}if(A.position=="relative"){F={left:0,top:0};G.left=0}if(G.weight=="right"){G.left=F.left-B.width+D.width}else{if(G.weight=="center"){G.left=F.left-((B.width-D.width)/2)}}G.top=(G.gravity=="north")?(F.top+D.height):(F.top-B.height)}if("horizontal,east,west".indexOf(G.gravity)!=-1){if("top,bottom,center".indexOf(G.weight)==-1){if((F.top-(B.height/2))<0){G.weight="top"}else{if((F.top+(B.height/2))>Math.max(C.height,E.height)){G.weight="bottom"}else{G.weight="center"}}}if(G.gravity=="horizontal"){G.gravity=((F.left+(D.width/2))>C.width/2)?"east":"west"}if(A.position=="relative"){F={left:0,top:0};G.top=0}if(G.weight=="center"){G.top=F.top+(D.height/2)-(B.height/2)}else{if(G.weight=="bottom"){G.top=F.top-B.height+D.height}}G.left=(G.gravity=="west")?(F.left+D.width):(F.left-B.width)}return G},center:function(A){var C=$(window);var B={top:parseInt((C.height()-A.outerHeight())/2),left:parseInt((C.width()-A.outerWidth())/2)};if($("body.ie6").length){B.top+=C.scrollTop();B.left+=C.scrollLeft()}return B}};twttr.klass("twttr.dialog",function(A){this.opts=A;this.$heading=A.heading?$(A.heading):false;this.$footer=A.footer?$(A.footer):false;this.$content=$(A.content);this.createShell();this.bindEvents()}).widget().method("getHeaderHTML",function(){if(this.$heading&&this.$heading.length){return"<h2><span>"+this.$heading.html()+"</span>"+(this.opts.closeButton?'<a href="#" class="modal-close">&times;</a>':"")+"</h2>"}else{return(this.opts.closeButton?'<span class="no-heading"><a href="#" class="modal-close right">&times;</a></span>':"")}}).method("getShellHTML",function(){var A=(this.opts.modal===false);return['<div class="twttr-dialog'+(this.opts.cssClass?" "+this.opts.cssClass:"")+'" style="display: none;">','<div class="hanging"'+(this.opts.zIndex?' style="z-index: '+this.opts.zIndex+' !important;"':"")+">",'<div class="modal">','<div class="modal-inner">',this.getHeaderHTML(),'<div class="modal-content"> </div>',"</div>","</div>","</div>",(A?"":'<div class="modal-overlay"></div>'),"</div>"].join("")}).method("createShell",function(){var C=this;this.$root=$(this.getShellHTML());if(this.opts.width){this.find(".hanging").css({width:this.opts.width})}var D=this.$content.parent().length?this.$content.parent():$(document.body);this.$content.move(this.find(".modal-content"));if(this.$footer.length){this.find(".modal-content").after('<div class="footer"></div>');this.$footer.move(this.find(".footer"))}if(this.opts.renderInline){D.append(this.$root)}else{$(document.body).append(this.$root)}if(this.opts.fixed===false){this.find(".hanging").css({position:"absolute"})}var B=this.$root.find(".modal-submit");if(B.length>0){if(C.opts.noajax){B.bind("click",function(E){B.closest("form").submit()});return }var A=C.opts.ajax.complete;B.bind("click",function(F){F.preventDefault();B.attr("disabled",true);B.addClass("dbtn").removeClass("btn");var E=$(this).closest("form");$.ajax($.extend((C.opts.ajax||{}),{type:E.attr("method"),url:E.attr("action"),data:E.serialize(),complete:function(G){B.attr("disabled",false);B.addClass("btn").removeClass("dbtn");if(A){A(G)}}}))})}}).method("bindEvents",function(){var A=this;this.find(".modal-close").click(function(B){B.preventDefault();A.close()});if(this.find(".modal-close").length){$(document).keydown(function(B){if(B.which==27){B.preventDefault();A.close()}})}if(this.opts.popup){$(document).click(function(B){if(voided&&!$(B.target).parents(".modal").length){A.close()}})}}).method("windowHeight",function(){return $(window).height()}).method("scrollTop",function(){return $(window).scrollTop()}).method(void",function(){this.$root.fadeIn("fast");var A=this.find(".hanging");var B=this.center(A);if(this.opts.top){B.top=this.opts.top}if(this.opts.left){B.left=this.opts.left}if(this.opts.maxTop){B.top=Math.min(B.top,this.opts.maxTop)}if(this.opts.maxLeft){B.left=Math.min(B.left,this.opts.maxLeft)}A.css({top:B.top,left:B.left});this.$root.trigger(void");voided=true;if(this.windowHeight()<A.outerHeight()){A.css("position","absolute");A.css("top",this.scrollTop()+"px")}else{if(this.opts.fixed===false){A.css("top",B.top+this.scrollTop())}}this.$root.find("input[type=text]:first").focus()}).method("close",function(){this.$root.fadeOut("fast");voided=false;this.$root.trigger("close")}).method("toggle",function(){voided?this.close():void()});twttr.augmentObject(twttr.dialog.prototype,twttr.position);twttr.auxo("AttachedDialog",twttr.dialog).method(void",function(){this.$root.addClass("attached");this.$root.fadeIn("fast");voided=true;if(!this.positioned){var A=this.find(".hanging");var D=this.adjacent(this.find(".hanging"),$(this.opts.handle),this.opts);if(this.opts.offsetX){D.left+=this.opts.offsetX}if(this.opts.offsetY){D.top+=this.opts.offsetY}twttr.augmentObject(this.opts,D);var B=this.opts.gravity;if(B&&("horizontal,vertical".indexOf(B)==-1)){if("north,south".indexOf(B)==-1){var C=parseInt(this.find(".hanging").height());this.find(".modal-inner").prepend('<div class="'+B+'" style="height:'+C+'px;"></div>');D.left+=this.nudge(B);D.top+=this.nudge(this.opts.weight)}else{this.find(".modal")[(B=="north"?"before":"after")]('<div class="'+B+'"></div>');D.top+=this.nudge(B);D.left+=this.nudge(this.opts.weight)}}this.find(".hanging").css({top:D.top,left:D.left});if(this.opts.weight&&this.opts.weight!="auto"){this.find(".hanging").addClass("weight-"+this.opts.weight)}if(this.opts.modal){this.find(".modal-overlay").height(Math.max($(window).height(),$("body").height())+25)}this.positioned=true}}).method("nudge",function(A){return(twttr.AttachedDialog.offsets[A]||0)});twttr.AttachedDialog.offsets={top:-15,bottom:30,east:-10,west:10,south:-10,north:4};$.extend($.fn,{hoverTip:function(A,E){E=(E||{});var F=false;var B=$(this);var G=$(A);var D=document.all&&($.browser.version<8);var C=false;if(D){$("body").append(G);G.hover(function(H){clearTimeout(C)},function(H){G.fadeOut("fast")})}else{E.position="relative";B.prepend(G)}B.hover(function(H){F=setTimeout(function(){clearTimeout(F);pos=twttr.position.adjacent(G,B,E);var I=pos.top;G.css({left:pos.left,top:I}).fadeIn("fast")},400)},function(I){var H=$(I.target);clearTimeout(F);if(!H.is(B)){C=setTimeout(function(){G.fadeOut("fast")},(D?200:0))}})}});(function(A){A.fn.extend({isSigninMenu:function(){return this.each(function(){var D=A(this),B=A(".signin"),C=D.find(".textbox input"),E=true;B.bind("click focus",function(G){G.preventDefault();if(!E){return }E=false;setTimeout(function(){E=true},500);var F=A(this);F.toggleClass("void");D.toggleClass("offscreen");if(F.hasClass("void")){A(document).trigger("signinMenu.show");setTimeout(function(){A("#username").focus()},50)}else{A(document).trigger("signinMenu.hide");C.val("");setTimeout(function(){A("#home_search_q, #searchform_q").focus()},0)}});C.bind("focus keydown",function(F){if((F.type=="keydown"&&F.keyCode==27)||(F.type=="focus"&&!B.hasClass("void"))){B.trigger("click")}});D.mouseup(function(){return false});A(document).mouseup(function(F){if(A(F.target).parent("a.signin").length==0&&B.hasClass("void")){B.trigger("click")}})})}})})(jQuery);
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/phoenix/img/sprite-icons.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/phoenix/img/sprite-icons.png
deleted file mode 100755
index a93cede94..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/phoenix/img/sprite-icons.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/stylesheets/geo.css@1302114648.css b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/stylesheets/geo.css@1302114648.css
deleted file mode 100755
index 803efe531..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/stylesheets/geo.css@1302114648.css
+++ /dev/null
@@ -1 +0,0 @@
-.geo_new{color:#C00;}.geo_progress{color:#999;}.crosshairs{display:inline-block;background:url(../images/sprite-icons.png) -64px -80px no-repeat;height:11px;width:11px;margin:0 4px 0 0;vertical-align:middle;}a.geo_disable_webclient span{display:inline-block;background:url(../images/sprite-icons.png) no-repeat -112px -80px;height:7px;width:7px;margin:0 3px;vertical-align:middle;}a:hover.geo_disable_webclient span{background-position:-128px -80px;}.near{color:#8c8c8c;font-size:14px;}a.places-nearby{position:absolute;left:385px;top:148px;}.geo_notifications{display:none;}#place_link:focus{outline:none;}#place_link span.place_icon{display:inline-block;background:url(../images/sprite-icons.png) no-repeat -240px -64px;height:11px;width:7px;vertical-align:middle;margin-right:4px;}#geo_browser_help_banner{color:#FFF;font:12px Verdana;position:fixed;right:0;text-align:left;top:0;z-index:10000;}#geo_browser_help_banner.geo_firefox{background:#333 url(../images/geo_firefox_help_banner_back.png) no-repeat right;-moz-border-radius-bottomleft:4px;height:108px;}#geo_browser_help_banner.geo_chrome{background:#333 url(../images/geo_chrome_help_banner_back.png) no-repeat right;-webkit-border-radius-bottomleft:4px;height:65px;}#geo_browser_help_banner.geo_ie_gtb{background:#333 url(../images/geo_ie_gtb_help_banner_back.png) no-repeat right;height:108px;}#geo_browser_help_banner.geo_firefox>div{margin:8px 183px -3px 10px;}#geo_browser_help_banner.geo_chrome>div{margin:25px 120px 20px 20px;}#geo_browser_help_banner.geo_ie_gtb>div{margin:8px 200px -3px 10px;}#geo_browser_help_banner img{margin-right:6px;position:relative;top:8px;}ul.places_list{background-color:#FFF;border:1px solid #AAA;padding:4px 0 4px 0;text-align:left;}#place_content ul.places_list li,ul.places_list li{color:#333;padding:3px 8px 3px 4px;cursor:pointer;}.geo_more_places{border-top:1px solid #ccc;padding-top:5px;margin-top:4px;}#place_content ul.places_list li:hover,#place_content ul.places_list a:hover{color:white;background-color:#666;outline:none;}li .place_item_icon{background:transparent;display:inline-block;height:9px;margin:0 4px 2px 0;vertical-align:middle;width:10px;}li.selected .place_item_icon{background:url(../images/sprite-icons.png) no-repeat -160px -16px;}li .refresh{background:url(../images/sprite-icons.png) no-repeat -96px -80px;width:7px;margin:0 5px 2px 2px;}ul.places_list li:hover .refresh{background:url(../images/sprite-icons.png) no-repeat -80px -80px;}li .clear{display:inline-block;background:url(../images/sprite-icons.png) no-repeat -128px -80px;height:7px;width:7px;margin:0 5px 0 2px;vertical-align:middle;}ul.places_list li:hover .clear{background:url(../images/sprite-icons.png) no-repeat -112px -80px;}li .place_icon{display:inline-block;background:url(../images/sprite-icons.png) no-repeat -224px -64px;height:11px;width:7px;margin-right:4px;vertical-align:middle;}li .more_places{background:transparent;}li .place_details{color:#999;}#geo-promo-hoverer{width:420px;font-size:11px;text-align:left;visibility:hidden;}#geo-promo-hoverer .hoverer-inner{padding:15px;}#geo-promo-hoverer .hovercard-divot{left:40px;top:-11px;}#geo_modal.position_above .hovercard-divot{bottom:-11px;}#geo_modal.position_below .hovercard-divot{top:-11px;}#geo-promo-hoverer .tiny-map{float:right;padding:0 0 0 20px;}#geo_dialog_descr{margin:10px 0 10px 0;font-size:13px;}#geo_not_now{position:relative;top:5px;margin-left:8px;}#geo_turn_location_on{font-weight:bold;}a.geo_disable_webclient{color:#999;font-family:tahoma,sans-serif;font-size:12px;font-weight:bold;line-height:12px;text-shadow:1px 1px 1px #FFF;}a:hover.geo_disable_webclient{text-decoration:none;}.geo-pin{background:transparent url(../images/sprite-icons.png) no-repeat scroll -224px -64px;display:inline-block;height:11px;line-height:1.1em;width:7px;}.geo_map_with_place{width:490px;}#map_canvas{width:270px;height:170px;float:left;margin:1px;}.map_close{color:#999;text-decoration:none;-moz-border-radius:2px;background-color:#ddd;display:block;font-size:15px;margin:-2px;padding:0 4px 2px;position:absolute;right:0;top:0;text-decoration:none;}.map_close:hover{text-decoration:none;}.geo_map_place_details{width:195px;margin:10px;float:left;color:#333;}.geo_map_place_name{font-weight:bold;font-size:13px;margin-bottom:4px;}.geo_map_place_tweets{margin-top:5px;}.geo_map_place_tweets a{color:#2276bb;}#geo_map_progress.position_above .hovercard-divot{bottom:-11px;}#geo_map_progress.position_below .hovercard-divot{top:-11px;}#geo_map_progress .hoverer-inner{width:55px;}#geo_map_fail{display:none;}#geo_map_spinner{background:url(../images/spinner.gif) no-repeat;margin:10px 20px;}.place_search_dialog .hanging{width:450px;}.geo_place_search_table{font-family:'Lucida Grande',sans-serif;font-size:13px;}.geo_place_search_col1{font-weight:bold;text-align:right;padding-right:7px;padding-left:0;}.geo_place_search_city{padding-bottom:14px;padding-left:7px;}#geo_city{margin:0 0 16px 8px;}#geo_poi_hint{font-family:'Lucida Grande',sans-serif;font-size:11px;color:#999;padding:4px 0 8px 7px;}#place_search_results{padding:5px 0 0 7px;display:none;width:310px;}#place_search_done,#place_search_cancel{margin-top:20px;margin-bottom:5px;}#place_search_form input{border:1px solid #aaa!important;font-size:1em;outline:none;padding:5px;width:282px;vertical-align:middle;}#place_search_form #city_search_query{width:336px;}#place_search_form input:focus{outline:none;border-color:rgba(82,168,236,.75)!important;box-shadow:0 0 8px rgba(82,168,236,.5);-moz-box-shadow:0 0 8px rgba(82,168,236,.5);-webkit-box-shadow:0 0 8px rgba(82,168,236,.5);}.place_search_submit{-moz-border-radius-bottomright:3px;-moz-border-radius-topright:3px;border-style:solid;border-width:1px;margin-left:-1px;cursor:pointer;padding:.4em .9em;border-color:#999!important;padding-bottom:5px!important;padding-top:5px!important;vertical-align:middle;background:url(../images/nav_search_submit.png) repeat scroll -2px 0 transparent!important;}.place_search_submit:hover{background:url(../images/nav_search_submit.png) -2px -25px!important;}.place_search_submit:active{background:url(../images/nav_search_submit.png) -2px -50px!important;}.place_search_submit.loaddisableding,.place_search_submit.loaddisableding:hover,.place_search_submit.loaddisableding:active{background:#eee url(../images/spinner.gif) no-repeat 5px 5px!important;}#place_search_results li{margin:10px 0 0 0;list-style-type:none;white-space:nowrap;overflow:hidden;}#place_search_results .place_noicon,ul.place_search_dropdown.places_list .place_noicon{display:inline-block;margin-left:15px;}.wait{cursor:wait;}ul.place_search_dropdown.places_list li{padding-left:8px;white-space:nowrap;}.places_list li.hover{color:white;background-color:#666;outline:none;}ul.places_list{display:none;position:absolute;background-color:#FFF;border:1px solid #AAA;padding:4px 0 4px 0;text-align:left;z-index:9999;}#place_search_go_back{margin-top:12px;}#place_search_go_back,#change_city{font-weight:normal;color:#4d94be;}.geo_place_search_hint{padding:4px 0 0 7px;font-size:11px;color:#999;}div.geo_add_place{margin-top:20px;}div.geo_add_place a{font-weight:bold;}.geo_search_message{margin-top:12px;}.geo_next_prev{margin-top:12px;}#geo_prev_result{margin-right:20px;}.place_creation_dialog .hanging{width:650px;}.place_creation_dialog .modal-inner h2{margin:0!important;}.place_creation_dialog .modal-content{padding:0;}.place_creation_dialog .geo_map_canvas{width:312px;}.geo_place_search_table{font-family:'Lucida Grande',sans-serif;font-size:13px;width:100%;}.geo_place_creation_hint{padding:8px 0 0 7px;font-size:11px;color:#999;}.geo_form_input{border:1px solid #aaa!important;font-size:1em;outline:none;padding:5px;width:210px;vertical-align:middle;}.geo_form_input:focus{outline:none;border-color:rgba(82,168,236,.75)!important;box-shadow:0 0 8px rgba(82,168,236,.5);-moz-box-shadow:0 0 8px rgba(82,168,236,.5);-webkit-box-shadow:0 0 8px rgba(82,168,236,.5);}.geo_place_creation_row2{padding-top:15px;}.geo_place_city{margin:12px 0 15px;}#geo_creation_error{margin-top:8px;font-size:11px;}.geo_spinner{display:inline-block;background:url(../images/spinner.gif);height:14px;width:14px;margin-left:15px;line-height:1.9em;vertical-align:middle;}.geo_map{float:right;}.geo_place_create{padding:25px;width:280px;}.geo_place_create ul{margin:18px 0 20px 0;}.geo_place_create li{margin:10px 0;white-space:nowrap;overflow:hidden;}.geo_map_hint{opacity:0;width:160px;position:absolute;z-index:20;text-align:center;}.geo_map_hint span{display:inline-block;vertical-align:bottom;background-image:url(../images/geo_creation_hint_arrow.gif);background-repeat:no-repeat;width:21px;height:11px;}.geo_map_hint div{background-color:#424242;color:white;text-align:left;padding:10px;font-size:11px;font-weight:bold;}.geo_map_place_bubble{opacity:0;display:none;position:absolute;z-index:20;text-align:center;margin-top:10px;white-space:nowrap;}.geo_map_place_bubble span{display:inline-block;vertical-align:bottom;background-image:url(../images/geo_creation_hint_arrow.gif);background-repeat:no-repeat;width:21px;height:11px;}.geo_map_place_bubble>div{background-color:#424242;color:white;text-align:left;padding:10px;font-size:11px;font-weight:bold;}.geo_go_back{line-height:1.9em;margin:0 10px;}.geo_place_details{color:#aaa;}.geo_map_link_separator{margin:0 5px 0 10px;color:#aaa;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/stylesheets/twitter.css@1302114648.css b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/stylesheets/twitter.css@1302114648.css
deleted file mode 100755
index 52eb695df..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/a/1302214109/stylesheets/twitter.css@1302114648.css
+++ /dev/null
@@ -1 +0,0 @@
-.transparent{opacity:.0;}.ie .transparent{filter:alpha(opacity=0);}.error{color:#801b1b;}.notice{color:#801b1b;}.top{vertical-align:top!important;}.bottom{vertical-align:bottom!important;}.middle{vertical-align:middle!important;}.first{margin-top:0;padding-top:0;}.last{margin-bottom:0;padding-bottom:0;}.right{float:right;}.left{float:left;}.clearfix{zoom:1;}.clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden;}.help-text{color:#aaa;}.disabled{color:#bbb;}.link-disabled{color:#bbb;}.link-disabled:hover{text-decoration:none;cursor:default;}.inline{display:inline;}.clear{clear:both;}.loaddisableding{background-position:50% 50%;background-repeat:no-repeat;}.hidden{display:none;}.invisible{visibility:hidden;}.offscreen{position:absolute;left:-9999px;overflow:hidden;}.empty-set{padding:30px!important;}.numeric{font-family:'Helvetica Neue','Helvetica','Arial',sans-serif;}.no-border{border:0!important;}.round{-moz-border-radius:5px;-webkit-border-radius:5px;}.round-top-right{-moz-border-radius-topright:5px;-webkit-border-top-right-radius:5px;}.round-right{-moz-border-radius-topright:5px;-moz-border-radius-bottomright:5px;-webkit-border-top-right-radius:5px;-webkit-border-bottom-right-radius:5px;}.round-bottom-right{-moz-border-radius-bottomright:5px;-webkit-border-bottom-right-radius:5px;}.round-bottom{-moz-border-radius-topright:0;-moz-border-radius-topleft:0;-moz-border-radius-bottomright:5px;-moz-border-radius-bottomleft:5px;-webkit-border-top-right-radius:0;-webkit-border-top-left-radius:0;-webkit-border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;}.round-bottom-left{-moz-border-radius-bottomleft:5px;-webkit-border-bottom-left-radius:5px;}.round-left{-moz-border-radius-topleft:5px;-moz-border-radius-bottomleft:5px;-webkit-border-top-left-radius:5px;-webkit-border-bottom-left-radius:5px;}.round-top-left{-moz-border-radius-topleft:5px;-webkit-border-top-left-radius:5px;}.round-top{-moz-border-radius-topright:5px;-moz-border-radius-topleft:5px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-webkit-border-top-right-radius:5px;-webkit-border-top-left-radius:5px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;}#footer{text-align:center;padding:8px 0;margin-top:.7em;line-height:1;background:#fff;white-space:nowrap;}#footer li{display:inline;padding:0 4px;}#footer li.first:before{content:'';padding-right:0;}#footer.wide{width:100%;}body.ko #footer{font-size:11px;}#country_return_prompt{width:150px;padding:8px;margin-top:.7em;line-height:1;background:#fff;white-space:nowrap;}.tipsy{opacity:.8;filter:alpha(opacity=80);background-repeat:no-repeat;padding:5px;}.tipsy-inner{padding:8px 8px;max-width:200px;font:11px 'Lucida Grande',sans-serif;font-weight:bold;-moz-border-radius:4px;-khtml-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:#000;color:white;text-align:left;}.tipsy-north{background-image:url(../images/tipsy/tipsy-north.gif);background-position:top center;}.tipsy-south{background-image:url(../images/tipsy/tipsy-south.gif);background-position:bottom center;}.tipsy-east{background-image:url(../images/tipsy/tipsy-east.gif);background-position:right center;}.tipsy-west{background-image:url(../images/tipsy/tipsy-west.gif);background-position:left center;}*{margin:0;padding:0;}fieldset,img{border-width:0;border-color:transparent;}a{text-decoration:none;color:#2276BB;}a:hover{text-decoration:underline;}ul{list-style:none;}ul.dot li:before{content:"\00B7 \0020";}hr{display:none;}div.hr{height:1px;background:#eee;width:100%;overflow:hidden;margin:.5em 0;line-height:1;font-size:16px;}#delete #content .reallyimportant{-moz-border-radius:5px;-webkit-border-radius:5px;background:#ffffe3;font-size:120%;padding:1em;}#remember_delete_message{-webkit-box-shadow:0 1px 2px rgba(0,0,0,1);-moz-box-shadow:0 1px 2px rgba(0,0,0,1);margin:5px 0 15px 15px;padding:10px;width:80%;}input[type=text],input[type=password],select,textarea{border:1px solid #aaa;transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,-moz-box-shadow linear .2s;-webkit-transition:border linear .2s,-webkit-box-shadow linear .2s;}input[type=text]:focus,input[type=password]:focus,textarea:focus{outline:none;border-color:rgba(82,168,236,.75)!important;box-shadow:0 0 8px rgba(82,168,236,.5);-moz-box-shadow:0 0 8px rgba(82,168,236,.5);-webkit-box-shadow:0 0 8px rgba(82,168,236,.5);}input.with-box:focus,input[class*=search]:focus,input[id*=search]:focus{border-color:inherit!important;box-shadow:none;-moz-box-shadow:none;-webkit-box-shadow:none;}body.email-address-nag .email-address-nag-banner{display:block;}.no-display{display:none;}.email-address-nag .content-bubble-arrow{display:none;}.email-address-nag-banner,.employee-nag-banner{margin-top:23px;display:none;background-color:#ffd;color:#333;padding:13px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px;-webkit-border-top-left-radius:5px;-webkit-border-top-right-radius:5px;border-bottom:1px solid #c0deed;}.employee-nag-banner{display:block;}body.email-address-nag .employee-nag-banner{margin-top:0;-moz-border-radius-topleft:0;-moz-border-radius-topright:0;-webkit-border-top-left-radius:0;-webkit-border-top-right-radius:0;}.email-address-nag-banner .resending-email{margin-left:10px;}.email-address-nag .until-you-confirm-message,.email-notice .resend-message,.employee-nag-banner .employee-nag-message{line-height:20px;}body.email-address-nag #content,body.email-address-nag #side_base{-moz-border-radius-topleft:0;-moz-border-radius-topright:0;-webkit-border-top-left-radius:0;-webkit-border-top-right-radius:0;}body{text-align:center;font:.75em 'Lucida Grande',sans-serif;color:#333;}#container{width:763px;margin:1em auto;text-align:left;position:relative;z-index:1;}#content h1,#content h2,#content h3,#content h4,#content h5{margin:3px 0 4px;}.columns{margin-bottom:15px;width:100%;}td.column{padding:0;vertical-align:top;}.center-text{text-align:center;}#loaddisableder{position:absolute;top:.7em;right:-25px;padding:0;background-color:#FFF;border:1px solid #CCC;font-size:10px;line-height:0;z-index:999;}.ie7 #loaddisableder{top:22px;}#header{text-align:right;}#header.no-nav{text-align:left;}#logo{float:left;}.no-nav #logo img{position:relative;margin-bottom:-0.5em;}#logo img{margin-top:-2px;}#front #logo img{position:relative;z-index:99;}body.ie7 #logo img{margin:.6em 0 0 0!important;}body.ie6 #logo{filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true',src='/images/twitter_logo_header.png',sizingMethod='crop');display:block;width:155px;height:36px;cursor:pointer;}body.ie6 #logo img{visibility:hidden;position:static;}.top-navigation{background-color:#fff;white-space:nowrap;display:inline-block;padding:0 .7em;}.ie7 .top-navigation{margin-top:1em;display:inline;}.ie7 .top-navigation>li{vertical-align:middle;}.ie7 .top-navigation>.nav-search-container{padding:2px 0 2px 4px!important;zoom:1;}.top-navigation *{display:inline;}.top-navigation>li{position:relative;}.top-navigation>li>a{padding:.5em .15em;border:1px solid transparent;font-size:1.05em;display:inline-block;}.firefox2 .top-navigation{max-width:45em;margin-left:auto;padding-bottom:1px;}.top-navigation>li>a:focus{outline:none;}.ie6 .top-navigation{display:inline;padding:1em;}.admin-link{font-size:10px;position:absolute;right:-25px;top:.9em;}body#show .admin-link{top:5px;}#content{background-color:#FFF;width:564px;margin-top:0;word-wrap:break-word;-moz-border-radius-topleft:5px;-webkit-border-top-left-radius:5px;-moz-border-radius-bottomleft:5px;-webkit-border-bottom-left-radius:5px;}#content.wide{width:100%;-moz-border-radius:5px;-webkit-border-radius:5px;}.content-bubble-arrow{zoom:1;margin-top:6px;height:11px;background-repeat:no-repeat;background-position:22px 0;background-image:url(../images/arr2.gif);overflow:hidden;}#content.minheight{height:200px;}td.column{padding:0;vertical-align:top;}.wrapper{padding:5px 10px 15px;}#content div.section{position:relative;padding:6px 10px;}#content div.section>div{margin:1em 0;}#content div.section p{margin-bottom:1em;}#content div.section,div.section>div{clear:both;float:none;}#content div.section ul li{margin:0;padding:0 0 1em 0;}#content div.steps,#content div.section div.steps{margin-top:3em;}.subpage #side{margin-top:0;}#side_base{width:199px;line-height:1.2;background-color:#DDEEF6;border-left:1px solid #C0DEED;-moz-border-radius-topright:5px;-moz-border-radius-bottomright:5px;-webkit-border-bottom-right-radius:5px;-webkit-border-top-right-radius:5px;}#side_ad_base{height:185px;text-align:center;padding-top:5px;}#side_ad_base div{margin:auto;}#side{padding-top:.5em;width:198px;margin-bottom:10px;}#side .segment{margin:1em 10px;}#side .segment>*{padding-bottom:1em;}#side .segment p{line-height:1.6em!important;}#side .segment ul li{margin:0;padding:0 0 1em 0;}#side .promotion{background-color:#EDFEFF;font-size:11px;margin:1em auto;padding:6px 10px;text-align:left;width:152px;}#side .promotion a{outline:none;color:#333;}#side .promotion a:hover{text-decoration:none;}#side .promotion a.definition:hover strong{outline:none;text-decoration:underline;}#side .promotion .definition strong{display:block;color:#2276BB;}#side span.sponsored{color:#777;display:block;font-size:.9em;padding-bottom:.2em;padding-top:.2em;}#side .notice{margin:.5em auto 1em;padding:10px;background-color:#fff;text-align:center;}#side div.section{padding:13px;}#side div#profile.section{padding-bottom:16px;}#side div.last{border-top:1px solid #C0DEED;}#side h1{color:#333;font-size:1.1em;padding:0 0 2px;margin-bottom:.5em;}#side div.section-header h3{font:16px/18px Helvetica Neue,Helvetica,Arial,sans-serif;border-bottom:1px solid #C0DEED;color:#333;}#side .section-links{float:right;font-size:.9em;text-align:right;}#side div.msg strong{display:block;font-size:1.4em;}#side div.msg h3{font-size:1.25em;}#side ul{margin:0;}#side .faq-index ul{list-style-type:square;margin-left:15px;}#side .faq-index li{margin:10px 0;}#side p{padding:.5em 0;}#side ul{margin:0;}#side div#profile.section{margin-bottom:0;padding-bottom:0;padding-top:.3em;}#side div#profile.profile-side{margin-bottom:1em!important;}#side .profile-side .about{margin-bottom:.6em;}#side div.user_icon a,#side div.user_icon a:hover{text-decoration:none;color:#333;}#side div.user_icon a:hover{color:#0084b5;}#side .user_icon{padding:0 0 .8em;}#side .included-in{margin-top:10px;font-size:11px;}#side .included-in label{color:#666;}.side_thumb{height:31px;width:31px;}.verified-profile,.translator-profile{height:2.8em;}.verified-profile a{background:transparent url(../images/verified/verified.png) no-repeat scroll left center;color:#333;display:block;font-family:Georgia,serif;font-size:1.1em;padding:5px 0 5px 28px;}.translator-profile a{background:transparent url(../images/translator/translator.png) no-repeat scroll left center;color:#333;display:block;font-family:Georgia,serif;font-size:1.1em;padding:5px 0 5px 28px;}.translator-profile a span{font-size:.7em;padding-left:.5em;font-variant:small-caps;}.verified-profile a:hover,.translator-profile a:hover{text-decoration:none;color:#0084b5;}#side .user_icon img{padding-right:.8em;vertical-align:middle;}#me_name{font-size:1.35em;vertical-align:middle;}#side p.promotion{margin-bottom:1em;}.in-page-link{outline:none;}a.help-icon,span.help-icon,ul.sidebar-menu li .help-icon{background:transparent url(../images/sprite-icons.png) no-repeat -160px 0!important;display:inline-block;width:16px;height:16px;padding:0;text-indent:-999em;-moz-opacity:.75;opacity:.75;}a.help-icon:hover,span.help-icon:hover{-moz-opacity:1;opacity:1;}ul.sidebar-menu li .help-icon{display:none;position:absolute;top:6px;right:15px;}ul.sidebar-menu li a:hover .help-icon,ul.sidebar-menu li.active .help-icon{display:block;}ul.sidebar-menu li.loaddisableding .help-icon{display:none!important;}.promoted-trend{position:relative;}.promoted-trend span,ul.sidebar-menu li a.promoted-trend span{background:#ffebbe url(../images/commercial/garuda-overlay.gif) repeat-x 0 -32px;background:#fff -webkit-gradient(linear,0 0,0 100%,from(rgba(255,237,87,.5)),to(rgba(255,171,0,.5)));background:#fff -moz-linear-gradient(top,rgba(255,237,87,.5),rgba(255,171,0,.5));display:inline!important;width:auto;margin:0 0 0 5px;padding:2px 4px;color:#444;font:normal 11px/12px "Helvetica Neue",Helvetica,Arial,sans-serif;text-shadow:0 1px 1px rgba(255,255,255,.5)!important;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;box-shadow:0 1px 0 rgba(255,255,255,.5);-moz-box-shadow:0 1px 0 rgba(255,255,255,.5);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.5);}.promoted-trend:hover span,ul.sidebar-menu li a.promoted-trend:hover span,ul.sidebar-menu li.active a.promoted-trend span{background:#ffebbe url(../images/commercial/garuda-overlay.gif) repeat-x 0 -32px;background:#fff -webkit-gradient(linear,0 0,0 100%,from(rgba(255,237,87,.75)),to(rgba(255,171,0,.75)));background:#fff -moz-linear-gradient(top,rgba(255,237,87,.75),rgba(255,171,0,.75));}#side #trends,#side #saved_searches{width:198px;overflow:hidden;}#side #trends em{display:none;}ul.sidebar-menu li .side-tab-ajax{vertical-align:top;float:right;display:none;margin-right:1em;}ul.sidebar-menu span.stat_count{margin-top:0;font:bold 12px Helvetica Neue,Helvetica,Arial,sans-serif;float:right;margin-right:14px;-moz-border-radius:3px;-webkit-border-radius:3px;background-color:transparent;padding:0 .1em;}span.link-title{float:left;}.ie6 ul.sidebar-menu li{zoom:1;overflow:hidden;}.ie6 ul.sidebar-menu li a{margin-top:-2px;}ul.sidebar-menu li{padding-top:1px;}ul.sidebar-menu li a{cursor:pointer!important;display:block;clear:both;padding:.5em 0 .5em 14px;outline:none;background-image:none;margin-right:-1px;}.safari ul.sidebar-menu li a{padding:.5em 0 .5em 14px;}.ie8 ul.sidebar-menu li a{margin-right:0;}ul.sidebar-menu li a span{display:inline-block;overflow:hidden;width:150px;}ul#primary_nav.sidebar-menu li a span{display:inline-block;width:auto;}ul.sidebar-menu li a span.stat_count{display:block;}ul.sidebar-menu li.loaddisableding a{background:#EDFEFF url(../images/spinner.gif) no-repeat 171px .5em;}ul.sidebar-menu li.loaddisableding a span.stat_count{display:none!important;}ul.sidebar-menu li a:hover{background-color:#EDFEFF;text-decoration:none;}ul.sidebar-menu li.active a{font-weight:bold;color:#333;background-color:#EDFEFF;}#side ul.sidebar-actions{margin:.2em 14px 1em;}#side p{padding:.5em 0;}#side p.no-lists{padding:.5em 14px;}#side span.xref{display:block;padding:4px 14px;}#side p.sidebar-menu-actions{padding:.5em 14px;clear:both;display:block;}#side span.new-list,#side span.view-all{padding:0;margin:0 3px 0 0;font-size:11px;line-height:11px;}#side span.view-all{display:inline;margin:0;}#side span.pipe{border-left:1px solid #C0DEED;padding-left:4px;padding-right:4px;}#side #following span.xref{display:block;margin-top:-5px;padding:0 14px 5px 14px;}#side .geo_nearby_activity{padding:.5em 14px;}#side div.geo_nearby_activity{padding-top:0;}#side div.geo_nearby_activity li{margin-top:8px;}#side p.geo_find_in_progress{color:#999;}#side p.geo_nearby_activity a{padding:0;margin:0 3px 0 0;font-size:11px;line-height:11px;}#side .geo_address{color:#999;font-size:10px;}.geo_minorlink{color:#81B2D9;}.geo_prev_next_separator{color:#aaa;}#side .place_icon{background:url(../images/sprite-icons.png) no-repeat -240px -64px;display:inline-block;height:11px;width:7px;margin-right:4px;vertical-align:middle;}#na_menu .with-place{display:none;}#custom_search{padding:.4em 0;margin:1px 0 3px;}#side div#custom_search.active{background-color:#EDFEFF;}#sidebar_search input{border-color:#b4b4b4 #ccc #ccc #b4b4b4!important;border-style:solid none solid solid!important;border-width:1px 0 1px 1px!important;font-size:1em;padding:.4em;width:136px!important;margin:.25em 0 .25em 12px;outline:none;-moz-box-shadow:none;-webkit-box-shadow:none;}.ie7 #sidebar_search input{position:relative;width:145px!important;}.ie7 #sidebar_search .submit{position:relative;top:0;left:-10px;width:8px;margin-left:0;margin-right:0;}#sidebar_search_submit{background:url(../images/nav_search_submit.png) -2px 0!important;}#sidebar_search_submit:hover{background:url(../images/nav_search_submit.png) -2px -25px!important;}#sidebar_search_submit:active{background:url(../images/nav_search_submit.png) -2px -50px!important;}#sidebar_search_submit.loaddisableding,#sidebar_search_submit.loaddisableding:hover,#sidebar_search_submit.loaddisableding:active{background:#eee url(../images/spinner.gif) no-repeat 5px 5px!important;}#sidebar_search input,#sidebar_search_submit{padding-top:5px!important;padding-bottom:5px!important;border-color:#999!important;vertical-align:middle;}#sidebar_search .submit{-moz-border-radius-bottomright:3px;-moz-border-radius-topright:3px;-webkit-border-radius-bottom-right:3px;-webkit-border-radius-top-right:3px;background-color:#EEE;background-position:center top;border-style:solid;border-width:1px;cursor:pointer;padding:.4em .9em;}#saved_searches ul{margin-bottom:3px;}h2.sidebar-title{padding:.2em 14px .2em 14px;font-size:1.05em;font-weight:normal;}.ie h2.sidebar-title span{filter:alpha(opacity=70);}h2.sidebar-subtitle{padding:.2em 14px .2em 14px;font-size:1.3em;font-weight:normal;}#side .collapsible h2.sidebar-title{background:transparent url(../images/toggle_up_dark.png) no-repeat right center;width:157px;}#side .collapsible.collapsed h2.sidebar-title{background:transparent url(../images/toggle_down_dark.png) no-repeat right center;}#side div.collapsible.loaddisableding h2.sidebar-title{background:transparent url(../images/spinner.gif) no-repeat center right!important;}#side .collapsible a.fetch-contents{display:none;}#side .collapsible h2.sidebar-title:hover{cursor:pointer;}#side .collapsed .xref,#side .collapsed .sidebar-menu{display:none;}#side #following #following_list,#side #following #following-in-common-list{padding:5px 10px 5px 14px;}#side #following #friends_view_all,#side #following #follows_in_common_view_all{font-size:.9em;padding:0 14px;}#side p.sidebar-location{padding:3px 0 8px 0;border-bottom:1px dotted #C0DEED;width:170px;margin:0 14px 0 14px;}#side #change_location{font-size:11px;cursor:pointer;font-weight:normal;}#side button.active{background-image:none;text-shadow:none;border:1px solid #ccc;}#side #trends_loaddisableding{position:absolute;right:0;margin-right:14px;}#side #location_menu img{vertical-align:middle;}#local_trend_locations .trends_arrow{position:absolute;right:-9px;margin-top:4px;z-index:999;}#local_trend_locations p{clear:both;display:block;padding:10px 2px 2px 2px;height:26px;clear:both;}#local_trend_locations p button{float:right;margin-top:1px;}#local_trend_locations p span.info{font-size:9px;padding-left:2px;float:left;color:#999;}#local_trend_locations label{clear:both;display:block;padding-bottom:1px;}#side #local_trend_locations hr{height:0;border:0;border-top:1px solid #eee;width:100%;background:#eee;clear:both;margin:0;padding:0;display:block;}#local_trend_locations ul{clear:both;display:block;font-size:11px;margin:3px 0 10px -8px;}#local_trend_locations ul li{float:left;width:130px;}#local_trend_locations .last{border-right:0;}#local_trend_locations li a{display:block;color:#0084B4;text-shadow:0 1px #fff;text-decoration:none;padding:2px 8px 3px 8px;-moz-border-radius:12px;-webkit-border-radius:12px;background:#FFF;border-bottom:0;outline:none;overflow:hidden;line-height:15px;height:14px;margin-bottom:1px;}#local_trend_locations li a.active-parent{background:#f4f4f4;}#local_trend_locations li a:hover{background:#eee;text-shadow:0 1px #fff;}#local_trend_locations .active{cursor:default;}#local_trend_locations li span{display:block;color:#999;padding:3px 8px;margin:2px 0 2px 0;}#local_trend_locations li.active a,#side #local_trend_locations li.active a:hover{text-shadow:0 -1px #555;background:#777 url(../images/follow_check.gif) no-repeat 93% 5px;color:#fff;}#local_trends_notice .modal-inner{padding:8px 12px 12px 12px;}#local_trends_notice .trends_arrow{position:absolute;right:-9px;z-index:999;margin-top:4px;}#local_trends_notice strong.new{text-transform:uppercase;color:#C00;font:bold 10px Helvetica Neue,Helvetica,Arial,sans-serif;}#local_trends_notice h3{font:bold 18px Helvetica Neue,Helvetica,Arial,sans-serif;}#local_trends_notice p{font-size:11px;line-height:14px;padding-bottom:12px;color:#777;}#side a.indented-link{margin:.5em 14px 1em;display:block;}#home #rssfeed,#search #rssfeed,#profile #rssfeed,#profile_favorites #rssfeed,#favorites #rssfeed,#home #rssfeed .timeline-rss,#search #rssfeed .search-rss,#profile #rssfeed .profile-rss,#favorites #rssfeed .favorites-rss,#profile_favorites #rssfeed .favorites-rss{display:block;}#rssfeed,#rssfeed .timeline-rss,#rssfeed .search-rss,#rssfeed .favorites-rss,#rssfeed .profile-rss{display:none;}.rss{background-image:url(../images/rss.gif);margin:.5em 14px 1em;}#side hr{display:block;border:0;height:1px;margin:.5em 14px;opacity:.7;background:#C0DEED;color:#C0DEED;}.ie7 #side hr{width:170px;margin:0 14px;}.ie#side hr{filter:alpha(opacity=70);}.notify{text-align:center;line-height:1;padding:5px 0;background-repeat:no-repeat;background-position:left center;margin-bottom:8px;}.notify div{background-color:#edffe5;font-size:.9em;margin:0 12px;padding:10px 5px;-moz-border-radius:5px;-webkit-border-radius:5px;}#side .actions{border:1px solid #87bc44;margin:10px -3px;}#side .actions small{font-size:.9em;}#side .actions a{padding-left:7px;}#user_restricted h2{padding:10px;font-size:16pt;}#user_restricted img{margin:10px 10px 30px 10px;}#user_restricted p{padding:10px 0 0 10px;font-size:10pt;color:#555;}.side_thumb{height:31px;width:31px;}#side .user_icon{height:31px;display:block;clear:both;}#side .user_icon>*{vertical-align:middle;padding:0;}#side .user_icon img{padding-right:.8em;}#side .user_icon a{cursor:pointer;}#side #me_name{font:bold 1.2em/1.2em Helvetica Neue,Helvetica,sans-serif;position:absolute;margin-top:0;}#side #me_tweets{position:absolute;font-size:11px;margin-top:17px;font-family:Helvetica,Arial,sans-serif;}#side #me_tweets strong{font-size:10px;font-weight:normal;font-family:Helvetica,Arial,sans-serif;}#side .user_icon a:hover #me_tweets{text-decoration:underline;}#side .stats{clear:both;float:none;position:relative;margin:0;padding:0;}#side .stats td{padding:0;vertical-align:top;}#side .stats td+td{padding:0 5px;}#profile #side .stats td+td{padding:0 8px;}#side .stats td+td+td{padding:0!important;}#side .stats a span.stats_count{color:#333;}#side .smaller span.stats_count{font-size:1.1em!important;}#profile #side .smaller span.stats_count{font-size:1.3em!important;}#side .stats a:hover span.stats_count{color:#2276BB;}#side .stats .stats_count{display:block;}#side .stats td .numeric{font:bold 13px Helvetica Neue,Helvetica,Arial,sans-serif;text-decoration:none;}#side .stats td .label{text-transform:lowercase;font-size:.9em;}#side .stats a:hover{text-decoration:none;}#side .stats a:hover .label{text-decoration:underline;}#side .about li{padding-bottom:3px;}#side .about .label{font-weight:bold;}#side .about li#bio{word-wrap:break-word;overflow:hidden;width:170px;}ul#tabMenu li{border-top:1px solid #bddcad;}ul#tabMenu a,#side .section h1{display:block;padding:13px;text-decoration:none;color:#4c4c4c;font-weight:bold;font-size:110%;}#side .section h1{padding:0 0 .25em 0;}body#home ul#tabMenu a#home_tab,body#profile ul#tabMenu a#updates_tab,body#replies ul#tabMenu a#replies_tab,body.direct_messages ul#tabMenu a#direct_messages_tab,body.inbox ul#tabMenu a#inbox_tab,body#favourings ul#tabMenu a#favorites_tab,body#public_timeline ul#tabMenu a#public_timeline_tab{background-color:#fff;margin-left:-1px;padding-left:14px;}#following_list,#following-in-common-list{padding:0 0 0 3px;overflow:hidden;}#following_list span,#following-in-common-list span{float:left;padding:0 3px 2px 1px;}#following_list img,#following-in-common-list img{padding:0;}#device_control label{margin-right:5px;}#device_msg{margin-top:-5px;margin-bottom:0;}.rss{padding:.5em 0 .5em 20px;background-position:0 .5em;background-repeat:no-repeat;}#side p.complete{font-size:.9em;margin-top:1em;}.loaddisableding-spinner{display:none;position:relative;top:4px;left:1px;margin-left:4px;}.loaddisableding .loaddisableding-spinner{display:inline-block;}.loaddisableding-checkbox{margin:3px 1px 1px 4px;}.loaddisableding input.loaddisableding-checkbox{display:none;}fieldset.common-form{width:100%;margin:10px 0;}fieldset.common-form p{margin:0 0 5px 0;}fieldset.common-form th,fieldset.common-form td{padding:10px 5px;vertical-align:top;}fieldset.common-form th{text-align:left;width:10em;padding-top:10px;font-weight:normal;}fieldset.common-form small{color:#777;font-size:11px;}fieldset.common-form input[type="text"],fieldset.common-form input[type="password"],fieldset.common-form textarea,fieldset.common-form select,fieldset.common-form checkbox{border:1px solid #aaa;padding:4px 2px;}fieldset.common-form input[type="text"],fieldset.common-form input[type="password"],fieldset.common-form textarea{border-radius:3px;-moz-border-radius:3px;-o-border-radius:3px;-webkit-border-radius:3px;}fieldset.common-form input[type="text"],fieldset.common-form input[type="password"]{width:12em;}fieldset.common-form input[type="text"].medium,fieldset.common-form textarea.medium{width:50%;}fieldset.common-form input[type="text"].medium{-moz-border-radius:3px;-webkit-border-radius:3px;font-size:12px;}fieldset.common-form input[type="text"].wider,fieldset.common-form textarea.wider{width:75%;}fieldset.common-form input[type="text"].widest,fieldset.common-form textarea.widest{width:100%;}fieldset.common-form td[colspan="2"]{text-align:right;}fieldset.common-form label{white-space:nowrap;font-weight:normal;line-height:24px;}fieldset.common-form ul li{padding:5px 0;}fieldset.common-form ul li label{display:block;font-weight:bold;}fieldset.common-form ul li label sup{color:#888;}fieldset.common-form ul.options li{padding:0;margin:0;}fieldset.common-form ul.options li label{font-weight:normal;}fieldset.common-form table.input-form th{line-height:24px;vertical-align:top;}p.pseudo-input{background:#f3f3f3;width:210px;height:18px;margin:0!important;padding:3px 4px;border:1px solid #ddd;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;font:13px/18px Helvetica Neue,Helvetica,Arial,sans-serif!important;color:#777;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.04);}fieldset.common-form .instruction,fieldset.common-form .example,fieldset.common-form .required{font-size:x-small;color:#666;font-weight:normal;}fieldset.common-form .instruction,fieldset.common-form .example{margin-top:.5em;}fieldset.common-form .example{font-style:oblique;}fieldset.common-form .suggestion{color:#C00;font-weight:bold;font-size:10px;}fieldset.vertical-form{margin-top:1em;margin-bottom:1em;}fieldset.vertical-form label,fieldset.vertical-form input{display:block;}fieldset.vertical-form input{margin-top:1em;margin-bottom:1em;}fieldset.vertical-form input[type="text"]{width:165px;}div.direct-message-box fieldset.standard-form{width:548px;padding:10px 90px;}#direct_message_user_id{min-width:100px;}.buttons{padding-top:12px;text-align:center;}.buttons input,.buttons button{margin:0 3px;}.buttons a button{margin:0;}input.submit,button,input[type=submit],input[type=button],input[type="file"]>input[type="button"]{color:#000;-moz-border-radius:5px;-webkit-border-radius:5px;background-color:#e6e6e6;border:1px solid #ccc;font-size:x-small;padding:4px 8px;vertical-align:top;cursor:pointer;}input.submit:hover,button:hover,input[type=submit]:hover,input[type="file"]>input[type="button"]:hover{background-color:#d5d5d5;}input.flow-button,input.flow-button:hover{height:41px;padding:0 10px 2px 0;border:0;font-size:20px;background-color:transparent;}input.green-arrow,input.green-arrow:hover{background-image:url(../images/btn_green_arrow.gif)!important;width:234px!important;background-color:transparent;}input.green-arrow-small,input.green-arrow-small:hover{background-image:url(../images/btn_green_arrow_small.gif)!important;width:138px!important;}input.red-small,input.red-small:hover{background-image:url(../images/btn_red_small.gif)!important;width:114px!important;text-align:center;padding:0 0 2px 0;}.hentry .actions>div.follow-actions{visibility:visible;text-align:left;}.follow-actions .following{background-position:0 50%;background-repeat:no-repeat;}.follow-actions p{padding-left:14px;}.follow-actions .pending{color:#666;}.follow-actions input.submit{width:8em;}.home_page_control input.profilesubmit{background-color:#74CA00;font-size:2em;color:#fff;font-weight:bold;margin:20px 0 10px 0;padding:10px;border:1px solid #0f0;width:175px;cursor:hand;}.home_page_control input.profilesubmit:hover{background-color:#8CF500;}.link-menu>a{padding:.5em .75em .5em .5em;background:transparent url(../images/divot.gif) no-repeat 100% 50%;}.link-menu>ul,.link-menu>span,.link-menu>div{position:absolute;left:0;z-index:999;}body#direct_messages #dm_update_box,body#inbox #dm_update_box,body#sent #dm_update_box{display:block;}body#direct_messages #status_update_box,body#inbox #status_update_box,body#sent #status_update_box{display:none;}.status-btn{float:right;padding:5px 12px 0 5px;}.status-btn input.round-btn{background-image:url(../images/round-btn.gif);width:115px;height:32px;border:0;color:#666;font-size:14px;margin-left:3px;}.status-btn input.round-btn:hover{background-image:url(../images/round-btn-hover.gif);color:#444;}.status-btn input.disabled,.status-btn input.disabled:hover{background-image:url(../images/round-btn.gif);color:#aaa;cursor:default;}#tweeting_controls{float:right;padding:5px 12px 0 5px;_padding:5px 0 0 5px;}.bar{line-height:1.9em;position:relative;padding:0 10px;}.bar h3{font-size:1.4em;}.bar h3 label{font-family:'Helvetica Neue','Helvetica','Arial',sans-serif;font-weight:normal;color:#333;padding-right:130px;font-size:20px;line-height:1.1;width:50%;margin-bottom:10px;}.bar span{color:#ccc;font-size:2em;display:block;position:absolute;top:0;*top:5px;background:transparent;right:10px;}.bar span strong.loaddisableding{background:transparent url(../images/spinner.gif) no-repeat center center!important;color:transparent;}.ie7 .bar span strong.loaddisableding{background-position:left center!important;}.ie7 #status-field-char-counter{line-height:1em;position:relative;top:-3px;}.status-update-form .info{padding:1px 0 0 10px;}.status-update-form textarea{height:2.5em;width:515px;padding:5px;font:1.15em/1.1 'Lucida Grande',sans-serif;overflow:auto;resize:none;}#update_notifications{color:#666;float:left;font-size:11px!important;line-height:16px;overflow:visible;min-height:30px;margin:3px 8px 0 0;padding:2px 4px 2px 0;text-align:left;width:365px;word-wrap:break-word;}.ie7 #update_notifications,.ie6 #update_notifications{width:395px;}.ie #share_location{margin-right:5px;}.ie6 #update_notifications{display:inline;height:30px;}#latest_meta{color:#999;}#latest_status .retweet-source-user{font-weight:bold;}#latest_text{cursor:pointer;}#latest_text_full{display:none;}.firefox2 #update_notifications{float:none;}#dm_update_box{display:none;}#content .tabMenu{text-align:left;margin:25px 0 5px 0;}#content .tabMenu li{display:inline;margin:0;padding:0;}#content .tabMenu li a{margin-right:1px;display:inline;padding:6px 15px 5px 15px;background-color:#F0F0F0;text-decoration:none;color:#2276BB;-moz-border-radius:3px 3px 0 0;-webkit-border-top-left-radius:3px;-webkit-border-top-right-radius:3px;}body #content .tabMenu li a{font-size:13px!important;text-transform:capitalize;}#content .tabMenu li a:hover{background-color:#E6E6E6;}#content .tabMenu li.active a{border:1px solid #c4c4c4;color:#333;background-color:#fff;border-bottom:1px solid #fff;padding:5px 14px 5px 14px;}#content .tab{background-color:#fff;padding:0;border-top:1px solid #cecece;margin:1px 10px;}.password-meter{padding-left:10px;}.pstrength-text{font-weight:bold;}.password-weak{color:#801b1b;}.password-good{color:#803f1b;}.password-strong{color:#80771b;}.password-verystrong{color:#2a801b;}#profilebird{position:absolute;top:0;}#profilebox{background-color:#feffdf;border:1px solid #ff0;padding:20px;vertical-align:middle;}.home_page_new_home_page #profilebox{margin-top:15px;}#profilebox h1,#profilebox h2{font-weight:normal;}#profilebox h2{margin-top:.5em;font-size:1.3em;}#profiletext{float:left;width:470px;}.home_page_new_home_page #profiletext{width:auto;float:none;}#profilebox_outer.home_page_new_home_page{margin-top:15px;}.home_page_new_home_page #profilebox h2{color:#666;font:18px/24px "Helvetica Neue",Arial,Sans-serif;margin:0 0 15px;}.home_page_new_home_page #profilebox h2 strong{color:#333;}.home_page_new_home_page #profiletext h1 span{background:transparent url(../images/larry-shadowed-big.png) no-repeat scroll 100% 50%;_background:transparent url(http://a2.twimg.com/a/1302214109/images/larry-shadowed-big.gif) no-repeat scroll 100% 50%;padding-right:40px;display:block;}.home_page_new_home_page #profiletext h1{color:#333;font:24px/29px "Helvetica Neue",Arial,Sans-serif;margin:0 0 4px;font-weight:bold;}.home_page_new_home_page #profilebutton #profilebox-mobile{text-align:right;padding-top:8px;font-size:12px;line-height:16px;}.home_page_new_home_page #profilebutton{text-align:left;font-size:11px;color:#999;line-height:15px;margin:0;padding:0;}.home_page_new_home_page .profilesubmit{float:left;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;background:url(../images/bg-btn-signup_gold.png) repeat-x scroll 0 0 #FA2;border:1px solid #FA2;color:#333;display:inline-block;font:bold 18px Arial,Sans-serif;text-align:center;padding:8px 10px;text-decoration:none;text-shadow:0 1px 0 #FE6;margin:0;*padding:8px 0;*font-size:16px;}.home_page_new_home_page input.profilesubmit:hover{background:url(../images/bg-btn-signup_gold.png) repeat-x scroll 0 -5px #FA2;}.home_page_new_home_page #profiletext{float:none;}.home_page_new_home_page #profilebox{background-color:#fff;border:none;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;color:#666;font:15px/20px "Helvetica Neue",Arial,Sans-serif;margin:0 0 15px;padding:15px 25px;zoom:1;}.home_page_new_home_page .sms-follow-instructions{background:transparent url(../images/icon-mobile.gif) no-repeat 0 50%;padding-left:15px;color:#999;}.home_page_new_home_page .sms-follow-instructions strong{color:#666;}.home_page_new_home_page #sms_codes_link{cursor:pointer;position:relative;padding-bottom:1em;}#sms_codes{display:none;position:absolute;z-index:100;top:100%;left:0;background:#000;padding:10px;text-align:left;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}#sms_codes:before{content:' ';background:url(../images/trendtip-pointer.gif) no-repeat top center;position:absolute;top:-9px;right:55px;width:17px;height:9px;margin-left:-8px;}.home_page_new_home_page #sms_codes_link:hover{*text-decoration:none;}#sms_codes table{width:450px;}#sms_codes th{font-weight:bold;}#sms_codes td,#sms_codes th{width:33%;}#sms_codes .title td{color:#999;padding:10px 0 5px;}#sms_codes li{overflow:hidden;zoom:1;}#sms_codes li .sms-code{display:block;float:left;font-weight:bold;color:#CCC;width:50%;}#sms_codes li .sms-network{display:block;float:left;color:#666;}#sms_codes .sms-country,#sms_codes th{color:#CCC;}#profilebox_outer.home_page_control{padding-top:41px;position:relative;margin-top:1em;}.home_page_control div#profilebutton{float:right;text-align:center;margin-left:50px;}.home_page_control div#profilebutton small{line-height:1.25em;}.home_page_control input.profilesubmit{background-color:#74CA00;color:#fff;font-weight:bold;margin:0 0 5px 0;border:1px solid #0f0;width:175px;}.home_page_control input.profilesubmit:hover{background-color:#8CF500;}body#profile .profile-head,body#lists .profile-head,body#profile_favorites .profile-head{margin:1px 10px;}body#profile #content h2,body#profile_favorites #content h2{margin:0;}body#profile_favorites #timeline_heading h1{padding-top:8px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;color:#333;font-size:18px;}body#profile #content h2.thumb,body#profile_favorites h2.thumb{padding-bottom:20px;}body#profile ol.statuses span.status-body{margin-left:0;min-height:0;}body#profile ol.statuses li{padding-left:.5em;}body#profile ol.statuses li.latest-status{padding:1.5em 0 1.5em .5em;border-top-width:0;line-height:1.5em;}body#profile ol.statuses>li:first-child{border-top:0;}body#profile ol.statuses .latest-status .entry-content{font-size:1.77em;}body#profile .latest-status .entry-meta{display:block;}ol.statuses li.blocked-status,ol.statuses li.blocked-status:hover{background-color:#fafafa;}.blocked-status .entry-content{font-weight:bold;color:#666;}.blocked-status .meta a{text-decoration:none;color:#1f76b8;}.blocked-status .meta a:hover{text-decoration:underline;}ol.statuses li.latest-status.blocked-status .entry-meta{line-height:1.3em;}#content h2.thumb{font-size:2.8em;line-height:50px;padding:10px 15px 10px 0;}#content h2.thumb img{vertical-align:middle;margin-right:10px;}#content h2.thumb small{font-size:.4em;}#profile .protected-box{background-color:#FEF6A8;border:1px solid #FCFC19;line-height:1;margin-top:1em;padding:0 0 0 10px;}#profile .protected-box .sub-h1{font-size:1.2em;}#profile .protected-box table td{padding:10px;}#profile .protected-box .logged-out{padding:10px;}.profile-controls{text-align:right;padding:7px 10px;margin-bottom:15px;background-color:#f6f6f6;border:1px solid #eee;}.profile-controls li{position:static;}.profile-controls .is-relationship{font:15px 'Helvetica',Sans-serif;text-align:left;float:left;line-height:26px;}body#profile h2.thumb div#follow-details img#x,body#profile_favorites h2.thumb div#follow-details img#x{float:right;margin:3px 0 0 0;cursor:pointer;border:none;}div#follow-control{margin:5px 0 0 15px;}div#follow-details{background-color:#F9FDAB;margin:5px 0 10px 0;padding:5px 10px 10px 10px;border:solid 1px #FDCC68;color:#000;line-height:1.7em;display:none;font-size:.9em;}div#follow-flash{background-color:#F9FDAB;border:solid 1px #FDCC68;font-size:.9em;color:#000;line-height:1.75em;margin:5px 0;font-weight:bold;padding:5px;}div#follow-details p{margin-top:10px;}div#follow_actions{margin-top:10px;}div#follow-actions #onoff{margin-left:10px;}div#follow-details strong{display:inline;font-size:120%;}div#follow-details div#follow_notifications{margin-top:10px;}div#follow-details div#follow_notifications div#notifications-sub{margin-left:14px;}div#follow-toggle{background-repeat:no-repeat;cursor:pointer;background-position:2% 50%;padding:5px 5px 5px 20px;border:1px solid #CCC;}div#followed{background-color:#e6e6e6;border:1px solid #D1D1D1;}div.med-btn{background-color:#e6e6e6;width:75px;height:18px;padding:1px 3px 1px 21px;font-size:11px;vertical-align:middle;color:#000;cursor:pointer;}.follow-button button,.follow-button input[type=submit],input[type=button].follow-button{background-color:#808080;color:#FFF;font-size:1em;font-weight:bold;border:1px solid black;height:30px;width:75px;cursor:pointer;}.remove-button button,.remove-button input[type=submit],input[type=button].remove-button{background-color:#E6E6E6;color:#000;font-size:1em;width:75px;cursor:pointer;margin-left:3px;}input.update-button,.update-button button,.update-button input[type=submit],input[type=button].update-button{background-color:#808080;color:#FFF;font-size:1em;font-weight:bold;border:1px solid black;cursor:pointer;margin-top:10px;}div#follow-toggle.closed{background-image:url(../images/toggle_closed.gif);}div#follow-voided{background-image:url(../images/voided.gif);}.follow-actions .following{background-image:url(../images/checkmark.gif);}body#show .status-body{display:block;margin-right:30px;font-size:1.2em;padding-bottom:15px;}body#show .entry-content{font-weight:400;display:block;background-color:#fff;font-size:2em;font-family:georgia;line-height:1.25em;padding:0;overflow:hidden;}body#show #content .meta{display:block;font-family:'Lucida Grande';color:#999;}body#show #content .meta a{color:#999;}body#show .thumb img{width:48px;height:48px;}body#show .protected{padding-left:0;background-position:55px 50%;background-repeat:no-repeat;background-image:url(../images/icon_lock.gif);}body#show .actions{position:absolute;right:0;top:8px;}body#show .actions .non-fav,body#show .actions .fav{visibility:visible;}body#show .top-nav,body#show #footer{font-size:85%;overflow:hidden;}body#show .hentry{position:relative;}body#show #container{width:600px;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;}body#show #content{width:570px;padding:15px;margin-bottom:15px;}body#show #footer{width:600px;}body#show #content div.thumb{float:left;margin-right:20px;}body#show.status #content #timeline{border-top-width:0;}body#show .user-info{height:73px;margin-top:0;padding-top:15px;border-top:1px solid #e6e6e6;line-height:1;}body#show .screen-name{font-size:2.3em;}body#show .full-name{font-size:1.2em;margin:3px 0 0 2px;}body#show .desc-inner{position:relative;}body#show .top-navigation .not-required{display:none;}body.search .results-count{float:right;padding-left:1em;padding-right:5px;line-height:2.25em;font-size:x-small;color:#77778A;}body.search#users #timeline{width:100%;border-top:1px dashed #D2DADA;}body.search#users .hentry td.status-body{padding:.5em 0;}body.search#users .hentry td.status-body div{width:370px;}body.search#users .hentry:hover{background-color:transparent;}body.search#users .hentry .bio{font-size:90%;display:block;margin-left:0;padding-top:.3em;}body.search#users .hentry .status-body img{vertical-align:middle;margin:-3px 4px 0;}body.search#users .hentry .status-body .meta{font-family:'Lucida Grande';font-size:.75em;font-style:normal;}div.find-people h2{padding-bottom:6px;}div.find-people form+p{padding-left:12px;}div.find-people form{background:#f6f6f6;padding:2px 12px 0 12px;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;}.safari div.find-people form{padding:2px 12px 4px 12px;}.safari p.suggestion{padding-bottom:0!important;margin-bottom:0!important;}.vertical-form input{-moz-border-radius:4px;-webkit-border-radius:4px;}#content div.onebox_users{display:none;padding-bottom:20px;}#content .onebox_users h2{float:left;width:350px;color:#333;font:normal 18px "Helvetica Neue",Helvetica,Arial,sans-serif;padding-bottom:3px;}#content .onebox_users p.seeall{text-align:right;font-size:10px;position:relative;top:6px;}#content .onebox_users ul{border:1px solid #DDD;background-color:#EEE;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;clear:both;padding:8px 0;}body #content .onebox_users ul li{position:relative;overflow:hidden;float:left;margin-right:1px;padding:0 0 0 30px;height:30px;}#content .onebox_users ul li.first{margin-left:10px;}#content .onebox_users ul li.last{margin-right:0;}#content .onebox_users ul.size1 li{float:none;}#content .onebox_users ul.size2 li{width:221px;}#content .onebox_users ul.size3 li{width:137px;}#content .onebox_users ul li a.profilepic{position:absolute;left:0;top:2px;}#content .onebox_users ul li a.profilepic img{height:24px;width:24px;}#content .onebox_users ul li .bio{padding-left:1px;font-size:11px;color:#333;}#content .onebox_users ul li .bio p{margin:0;white-space:nowrap;}#content .onebox_users ul li .bio p.username{font-size:12px;font-weight:bold;}#content .onebox_users ul li.verified .bio p.username span{padding-right:20px;background:url(../images/verified/verified_small.png) no-repeat right 0;}#content .onebox_users ul li.protected .bio p.username span{padding-right:12px;background:url(../images/icon_lock.gif) no-repeat right 2px;}ul.bullets{list-style-type:square;padding:1em;}ul.bullets li{margin-left:1em;}#follow-requests .all{float:right;margin:4px 8px 4px 4px;}#follow-requests .follow-request{border:1px solid #bbb;clear:both;padding:10px;margin-bottom:10px;min-height:95px;height:auto!important;height:95px;}#follow-requests .follow-request .name-box{padding-top:2px;}#follow-requests .follow-request .name-box .lock{line-height:.2pt;}#follow-requests .follow-request .screen-name{font-size:2em;line-height:1;text-decoration:none;}#follow-requests .follow-request .name{font-weight:bold;margin-left:2px;}#follow-requests .follow-request .right-box{float:right;background-color:#FEF6A8;border:1px solid #FCFC19;width:300px;padding:8px;}#follow-requests .follow-request .buttons{margin:4px 0 4px;}#follow-requests .follow-request .right-box .request-button{width:100px;font-size:.9em;padding:2px;margin:10px 25px 10px 0;}#follow-requests .follow-request .right-box form{display:inline;margin-right:5px;}#follow-requests .follow-request .right-box td .centered-text{padding:1px;}#follow-requests .follow-request .details{padding-top:4px;clear:left;}#follow-requests .follow-request .details .title{color:#4F4F4F;}#follow-requests .follow-request .details .detail{width:65%;color:#000;}#follow-requests .follow-request .profile-img{float:left;margin-right:10px;}#side .featured{border:1px solid #87bc44;padding:2px 5px;margin:10px -3px;}#side .featured img{vertical-align:middle;padding:1px 0 -5px 7px;}#side .promo{border:1px solid #87bc44;background-color:#fff;padding:10px 0 10px 5px;margin-top:8px;font-size:1em;}#side .promo li{margin:0 0 8px;}#side .promo a{text-decoration:none;}#side .promo img{vertical-align:middle;}div.join{text-align:center;}div.join input{background-color:#417596;color:white;font-size:11pt;padding:.3em 2.5em;font-weight:bold;border:1px solid black;}div.join input:hover{background-color:#294B60;}#dim-screen{position:absolute;background-color:#000;z-index:99;width:100%;height:100%;top:0;left:0;opacity:.90;filter:alpha(opacity=90);display:none;margin:0 auto;}body.account .finish-signup{background:transparent url(../images/icon-mobile.gif) no-repeat scroll left center;padding-left:15px;}.subpage #content p{line-height:1.2;margin:5px 0;}.subpage #content code{font-size:1.2em;}.faq{padding:10px;}.faq p{padding-bottom:20px;}.faq p.header-text{font-size:1.3em;}.ie7 #trends_menu ul{margin-top:2.75em!important;}.ie7 #logo img{margin:.25em 0 0 0!important;}dt{font-weight:bold;margin-top:5px;}#content table.doing{font-size:1.2em;line-height:1.1;width:100%;}#content table.doing td{border-bottom:1px dashed #d2dada;vertical-align:middle;}#content table.doing .right-box td{border:0;}#content table.doing .thumb{padding:10px 5px 8px 5px;width:50px;vertical-align:top;}#content table.doing .meta{font-size:.80em;}#content table.doing .meta img{vertical-align:top;}#content table.doing .user_actions{vertical-align:top;width:16px;}#side div.msg strong{display:block;font-size:1.4em;}#side div.msg h3{font-size:1.25em;}#side .faq-index ul{list-style-type:square;margin-left:15px;}#side .faq-index li{margin:10px 0;}#side ul.todo{font-style:italic;}#side #submit{display:block;padding:3px 10px;margin:5px auto;font:bold 1.12em/1.5 'Lucida Grande',sans-serif;}body.help #side{height:560px;}body.help #side .section{height:100%;}#content .wrapper #lang_header{padding:0;margin:0;width:100%;}#content .wrapper #lang_header td{padding:0;}#lang-select{text-align:center;}#profile_image h2{margin-bottom:1em;}body#picture fieldset.common-form th{width:50px;}#invite_preview{background-color:#eef;padding:10px;}#invite_message{white-space:normal;}span#p{color:#999;}img.follow-icon{border:0;margin:1px 5px 3px 0;vertical-align:middle;}button.small{background-color:#e6e6e6;width:44px;padding:0;font-size:9px;text-align:center;margin:2px 2px 1px 2px;border:none;line-height:9px;cursor:pointer;}button.med{background-color:#e6e6e6;width:75px;height:16px;padding:0;font-size:9px;text-align:center;margin:2px 2px 1px 2px;border:none;}div.big-btn{background-color:#e6e6e6;width:75pt;height:19pt;padding:8px 3px 4px 3px;text-align:center;font-weight:bold;text-decoration:none;font-size:95%;vertical-align:middle;cursor:pointer;}div.long-btn{background-color:#e6e6e6;width:200px;padding:3px 2px 2px 2px;font-size:11px;vertical-align:middle;color:#000;cursor:pointer;}div.med-btn{background-color:#e6e6e6;width:75px;height:18px;padding:1px 3px 1px 21px;font-size:11px;vertical-align:middle;color:#000;cursor:pointer;}div.short-btn{background-color:#e6e6e6;width:60px;height:14px;padding:2px 2px 1px 21px;font-weight:bold;font-size:11px;line-height:14px;vertical-align:middle;color:#000;cursor:pointer;}.profile .protected-box{background-color:#FEF6A8;padding:8px;}input.big-btn{background:url(../images/btn-bg.gif) no-repeat top left;border:none;display:block;width:88px;height:31px;text-align:center;font-weight:bold;text-decoration:none;font-size:95%;vertical-align:middle;}#notifications-sub .desc{margin-left:3px;font-style:italic;}div.badge{margin:0 auto -1.5em;text-align:center;}form.device_control{display:inline;}form.device_control select{font-size:85%;padding:4px 2px;}.device-alert-box{background-color:#FF7B6D;padding:0 10px 10px 10px;border:solid 1px #F00;color:#000;line-height:1.7em;font-size:.9em;margin-top:8px;}.person img.lock{vertical-align:middle;margin-bottom:3px;}#downtime-announce{background-color:#fff;border:1px solid grey;padding:7px;color:#333;font-size:1.1em;}.person-actions{font-size:90%;padding:7px 0 0;}a#back-link{margin-left:20px;font-size:120%;}div#buffer{padding:17px;}#username_url{color:green;font-weight:bold;}.username_taken{color:red;}.fieldWithErrors{display:inline;}.fieldWithErrors input,.fieldWithErrors select,input.errors,select.errors,textarea.errors{background-color:#ffdfdf;}.highlight{background-color:#f9f6ba;}.nav-highlight{background-color:#ff9;}#followers .stop-undo{background-color:#BFBFBF;border:1px solid #4E4E4E;padding:0 10px;text-align:left;display:none;}#followers .stop-button{margin-right:25px;}#followers .stop-undo button{width:140px;}#followers .stop-undo table td{padding:2px 5px;}#followers .right-box{float:right;width:400px;font-size:.9em;text-align:right;margin-right:10px;}#followers .followers-table{width:100%;}.search_following{background-color:#D8F4F5;border:1px solid #84C2D2;}.search_following button{background-color:#fff;border:1px solid #84C2D2;}div.clear{height:1px;}input.labeled_field{color:#999;}.niceform{margin-top:10px;}.niceform label,.niceform input{display:block;width:50%;float:left;margin-bottom:10px;}.niceform label{text-align:right;width:150px;padding-right:20px;}.niceform br{clear:left;}#auth{display:none;padding:10px;margin:10px 0;background-color:#ddd;border:1px solid #999;}#videobutton img{padding-right:5px;}#videobutton{float:right;width:180px;text-align:center;vertical-align:middle;background-color:#ff493c;color:#fff;font-size:11pt;font-weight:bold;border:1px solid #000;padding-top:2px;padding-bottom:2px;}#videobutton:hover{text-decoration:none;}ul.app-list li{display:block;clear:both;}.side_thumb{height:31px;width:31px;}address{font-style:normal;}div#query_review_header_0{width:100px;}button.allow i{float:left;width:19px;height:20px;margin-right:5px;background:url(http://a2.twimg.com/a/1302214109/images/icon-check.gif) no-repeat;}button.allow.btn-green i{background-image:url(http://a2.twimg.com/a/1302214109/images/icon-check2.gif);}button.secure i{float:left;width:9px;height:14px;margin-right:5px;background:url(http://a2.twimg.com/a/1302214109/images/icon-lock.png) no-repeat;}span.lock-icon{display:inline-block;background:transparent url(../images/lock_icon_small.png) no-repeat scroll 0 50%;height:10px;width:8px;*vertical-align:middle;}#timeline_heading #heading span.lock-icon,#lists_table span.lock-icon{margin-left:3px;}li.menu span.lock-icon{margin-left:3px;}#side ul.lists-links li span.lock-icon{margin-bottom:-1px;margin-left:3px;width:8px!important;*background:transparent url(../images/lock_icon_small.png) no-repeat scroll 0 0;}.modal-content fieldset{font-size:11px;line-height:16px;width:100%;color:#888;padding-bottom:10px;}.modal-content label.title{float:left;display:block;width:100px;font-size:13px;color:#333;}.modal-content .wide-dialog label.title{width:150px;}.modal-content input.title,.modal-content textarea.title{padding:5px;border:1px solid #888;font-size:12px;-webkit-border-radius:4px;-moz-border-radius:4px;width:255px;float:left;margin-right:10px;margin-bottom:8px;outline:0;}.modal-content .wide-dialog input.title,.modal-content .wide-dialog textarea.title{width:305px;}.modal-content .preview{-webkit-border-radius:4px;margin-bottom:14px;padding:8px 0 8px 0;background:#eee;clear:both;display:block;font-size:11px;color:#666;}.modal-content fieldset.clear{border-top:1px solid #eee;border-bottom:1px solid #eee;margin-bottom:14px;display:block;clear:both;padding-top:10px;padding-bottom:10px;}.modal-content fieldset.clear.bottom{border-top:none;}.modal-content label.radio{clear:both;padding:3px 0 2px 0;}.modal-content .options{float:left;width:270px;font-size:11px;}.modal-content .options label input{float:left;margin-right:5px;}.modal-content .submit{margin-left:100px!important;margin-bottom:6px!important;}.model-content .privacy{height:33px;}.modal-content .options label strong{color:#333;}.modal-content .options label{clear:both;padding-bottom:4px;display:block;}.modal-content label .optional{color:#888;font-size:11px;display:block;}.modal-content .list-slug,.modal-content .list-description-instruction{overflow:hidden;display:block;padding:5px;width:255px;float:left;margin-right:10px;outline:0;}.modal-content .list-slug{font-size:12px;background:#efefef;border:1px solid #e8e8e8;-webkit-border-radius:2px;-moz-border-radius:2px;margin-bottom:8px;color:#2276BB;font-weight:bold;}.modal-content .list-description-instruction{margin-left:100px;padding-left:0;}.modal-content label.list-slug-title{padding-top:4px;color:#888;}.modal-content .private-warning{display:none;width:270px;border:1px solid #FFE88D;color:#333;margin-left:95px;padding:5px;clear:both;-moz-border-radius:5px;-webkit-border-radius:5px;background-color:#FFFFD1;}input.text_field{border:1px solid #ddd;font-size:14px;padding:8px;width:200px;margin:0;-moz-border-radius:5px;-webkit-border-radius:5px;}input.text_field.with-box{-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;}.profile-header{padding:0 10px;}#content ol.statuses li.search_result a.reply{background-image:url(../images/icon_reply.gif);}.tipsy .retweet-icon{background-image:url(../images/sprite-icons.png);background-position:-96px -48px;height:16px;line-height:13px;width:16px;position:relative;margin-top:-5px;top:5px;left:-1px;display:-moz-inline-stack;display:inline-block;zoom:1;*display:inline;*top:2px;}.tipsy .retweet_tip_tip{padding-top:4px;line-height:13px;}.retweet-tooltip.tipsy .tipsy-inner{max-width:300px;}.tipsy.tipsy-north.left-align{background-position:14px top;}.fixed-banners{position:fixed;top:0;left:0;z-index:9999;_position:absolute;_top:expression(eval(document.documentElement.scrollTop));width:100%;}.account-nav{background:#555;font:11px Lucida Grande,Tahoma,sans-serif;color:#fff;width:100%;height:26px;text-align:center;-moz-box-shadow:0 1px 0 rgba(0,0,0,.2);-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2);}.account-nav-content{margin:0 auto;text-align:left;width:763px;position:relative;z-index:99;}.account-nav a{color:#fff;}.account-nav ul{margin-left:-7px;}.account-nav ul li{display:block;float:left;margin:0;}.account-nav ul li a{cursor:pointer;display:block;padding:5px 7px 9px 7px;height:12px;_float:left;}.account-nav ul li:hover a{background:#444;text-decoration:none;}.account-nav ul li.divider{border-left:1px solid #444;border-right:1px solid #666;display:block;width:0;margin-top:7px;height:12px;}.account-nav ul li ul.account-switcher li.h-divider{border-top:1px solid #333;border-bottom:1px solid #555;height:0;width:100%;}.account-nav ul li ul.account-switcher{display:none;margin-left:0;}.account-nav a img{float:left;margin-right:5px;}.account-nav a span{float:left;}.account-nav li.account-switch a{color:#ccc;}.account-nav li.account-switch i{margin:5px 0 0 4px;width:7px;height:5px;background-position:-79px -67px;display:block;float:left;background-image:url(../images/sprite-icons.png);background-repeat:no-repeat;_display:none;}.account-nav li.account-switch.hover{position:relative;}.account-nav li.account-switch.hover ul.account-switcher{width:180px;display:block;position:absolute;-moz-box-shadow:0 1px 0 rgba(0,0,0,.2);-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2);border:1px solid #444;}.ie6 .account-nav li.account-switch.hover ul.account-switcher{top:25px;left:0;}.account-nav li.account-switch ul.account-switcher li{display:block;clear:both;width:100%;}.account-nav li.account-switch ul.account-switcher li *{cursor:pointer;}.account-nav li.account-switch ul.account-switcher li a{display:block;color:#fff;background:#444;padding:5px 7px 9px 7px;clear:both;height:12px;outline:none;_width:100%;}.account-nav li.account-switch ul.account-switcher li a:hover{background:#666;text-decoration:none;}.account-nav li.account-switch ul.account-switcher li a:active{background:#333;color:#ccc;}.account-nav #switcher-alert{display:block;float:left;font-style:normal;font-weight:normal;overflow:hidden;color:yellow;opacity:1;height:14px;margin-right:4px;}.account-nav #multi-author-feedback{float:right;color:#ccc;}.account-nav ul li#multi-author-feedback a{display:inline;padding:0;line-height:24px;color:white;}.account-nav ul li#multi-author-feedback a:hover{text-decoration:underline;background:#555;}.account-nav ul li#multi-author-feedback:hover a{background:#555;}#manage_contributor_permissions_dialog ul li{margin-top:10px;clear:both;}#manage_contributor_permissions_dialog ul li div{height:30px;}#manage_contributor_permissions_dialog ul li div.decline-buttons{float:right;text-align:right;padding-top:5px;}#manage_contributor_permissions_dialog ul li div.decline-profile{float:left;}#manage_contributor_permissions_dialog ul li span.decline-screen-name{vertical-align:super;}#manage_contributor_permissions_dialog .declining_spinner{background:transparent url(../images/spinner.gif) no-repeat;padding-left:20px;}body.contributor-skybar{background-position:0 26px;padding-top:26px!important;_padding-top:36px!important;}body.phoenix-skybar{background-position:0 35px;padding-top:35px!important;_padding-top:45px!important;}body.phoenix-skybar.contributor-skybar{background-position:0 61px;padding-top:61px!important;_padding-top:71px!important;}.tipsy .retweet-icon{background-image:url(../images/sprite-icons.png);background-position:-96px -48px;height:16px;line-height:13px;width:16px;position:relative;margin-top:-5px;top:5px;left:-1px;display:-moz-inline-stack;display:inline-block;zoom:1;*display:inline;*top:2px;}.tipsy .retweet_tip_tip{padding-top:4px;line-height:13px;}.retweet-tooltip.tipsy .tipsy-inner{max-width:300px;}.tipsy.tipsy-north.left-align{background-position:14px top;}.geo_pin{width:10px;height:10px;cursor:pointer;}.rate_limit_message{padding:10px;}.rate_limit_message p{color:#636363;font-size:15px;}.rate_limit_message p.wait{position:absolute;bottom:60px;color:#333;}.rate_limit_message p.wait span{color:#fff;background:#333 url(../images/divider.png) repeat-x 0 50%;margin:0 4px;padding:3px;-moz-border-radius:5px;-webkit-border-radius:5px;}.rate_limit_message img{margin:0;float:right;}.inactive{display:none;}#update_detached_email #content,#not_my_account #content,#detach_email #content,#detached_email #content{padding:5px 15px;}#not_my_account #content p,#detach_email #content p{margin:20px 0;}#not_my_account h1,#detach_email h1,#detached_email h1{font:26px Helvetica Neue,Helvetica,Arial,sans-serif;font-weight:bold;}.gray-footer{font:11px 'Lucida Grande',sans-serif;background:#f7f7f7;color:#666;margin:0 -25px -20px;padding:10px 15px;-moz-border-radius-bottomleft:5px;-moz-border-radius-bottomright:5px;-webkit-border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;}#not_my_account #content p.nevermind-link a{line-height:32px;padding-left:10px;}.detached-email-warning{background:#ffd url(../images/warning-sign.png) no-repeat 10px 50%;border:solid 1px #eec;margin:5px 1px;padding:8px 10px 8px 60px;}#update_detached_email_form{padding:20px 60px 35px;}#update_detached_email_form label{font-size:16px;color:#666;display:block;margin-bottom:5px;}#update_detached_email_form input[type=text]{width:250px;font-size:16px;padding:5px;margin-right:4px;}.rounded-four-corners{-moz-border-radius:5px;-webkit-border-radius:5px;}.hoverer{position:absolute;visibility:hidden;top:0;left:0;z-index:9999;}.hoverer .hoverer-inner{border:4px solid #ddd;-moz-border-radius:5px;-webkit-border-radius:5px;background:#fff;overflow:hidden;zoom:1;-moz-box-shadow:#aaa 0 1px 0;-webkit-box-shadow:#aaa 0 1px 0;position:relative;}.hoverer .hovercard-divot{position:absolute;left:24px;width:27px;height:15px;z-index:999;}body.loaddisableding-hoverer-above{position:relative;}div.page-header{background:#f5f5f5;margin:-20px -20px 20px;padding:15px 20px 0 20px;border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;-webkit-border-top-left-radius:5px;-webkit-border-top-right-radius:5px;}div.page-header ul.tabs{position:relative;margin:15px -20px 0 -20px;padding-left:9px;width:auto;max-width:1040px;min-width:911px;}div.page-header h1{line-height:30px;padding:0;margin:0;font-size:20px;clear:none;}div.page-header h1 img{float:left;margin:0 10px 0 0;}div.page-header img{width:30px;height:30px;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;}div.page-header p.right{float:right;line-height:20px!important;}div.page-header span.verified-profile{font-size:11px!important;}div.page-header span.verified-profile a{color:#999;display:inline;background-position:4px -1px;padding-left:30px;}div.page-header ul.page-tools{float:right;margin:5px 0 0;}div.page-header ul.page-tools li{display:inline;padding-left:10px;}div.page-header ul.page-tools li a,div.page-header ul.page-tools li a.btn{font-size:12px;}div.page-header ul.page-tools li a.btn{padding:5px 9px;}div.sub-header{margin:0 0 10px;}div.sub-header h2{clear:none;}div.sub-header h2 small{font-size:14px;font-weight:normal;color:#999;line-height:1;}ul.tabs{height:30px;width:100%;border-bottom:1px solid #e5e5e5;clear:both;}ul.tabs li{display:inline;line-height:1;}ul.tabs li a{display:inline;float:left;width:auto;margin:0;padding:4px 10px 3px;line-height:24px;border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;-webkit-border-top-left-radius:4px;-webkit-border-top-right-radius:4px;text-shadow:0 1px 0 #fff;overflow:hidden;}ul.tabs li a:hover{background:#eee;text-decoration:none;padding-bottom:2px;}ul.tabs li.active a{background:#fff;border:1px solid #e5e5e5;border-bottom:0;color:#333;font-weight:bold;padding-top:3px;}ul.tabs li.active a:hover{padding-bottom:3px;}ul.tabs li.menu{position:relative;float:left;display:inline;}ul.tabs li.menu a.menu{float:none;display:block;}ul.tabs li.menu a.menu i{background-position:-47px -64px;width:7px;background-image:url(../phoenix/img/sprite-icons.png);background-repeat:no-repeat;display:inline-block;opacity:.4;height:13px;outline:none;overflow:hidden;margin-left:4px;position:relative;top:3px;*left:4px;*top:0;_margin-top:8px;}ul.tabs li.menu ul{display:none;background:#fff;position:absolute;top:30px;left:0;width:180px;padding:3px 0;border:1px solid #999;border-radius:4px 4px 4px;-moz-border-radius:4px 4px 4px;-webkit-border-radius:4px;-webkit-border-top-left-radius:0;box-shadow:0 1px 2px rgba(0,0,0,.3);-moz-box-shadow:0 1px 2px rgba(0,0,0,.3);-webkit-box-shadow:0 1px 2px rgba(0,0,0,.3);}ul.tabs li.menu ul li{width:160px;}ul.tabs li.menu ul li a,ul.tabs li.menu ul li a:hover{display:block;width:160px;padding:4px 10px 3px;border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;}ul.tabs void a.menu,ul.tabs li.menu ul li a:hover{color:#fff;background:#999;border-color:#999;text-shadow:0 1px 0 rgba(0,0,0,.25);}ul.tabs void a.menu i,ul.tabs li a.menu:hover i{opacity:1;}ul.tabs void ul{display:block;}ul.pills{background:#eaf3f9;margin:0 -20px;padding:6px 8px;}ul.pills li{display:inline;}ul.pills li a{display:inline;float:left;width:auto;margin-right:3px;padding:6px 12px 6px;line-height:11px;border-radius:12px;-moz-border-radius:12px;-webkit-border-radius:12px;text-shadow:0 1px 1px #fff;}ul.pills li a:hover{background:#99bfe1;background:rgba(34,118,187,.4);color:#fff;-moz-box-shadow:inset 0 1px 3px rgba(34,118,187,.25);-webkit-box-shadow:0 1px 1px #fff;text-decoration:none;text-shadow:0 1px 1px rgba(34,118,187,.75);}ul.pills li.active a{background:#2276BB;background:rgba(34,118,187,1);color:#fff;-moz-box-shadow:inset 0 1px 3px rgba(34,118,187,.5);-webkit-box-shadow:0 1px 1px #fff;text-shadow:0 1px 1px rgba(0,0,0,.5);text-shadow:0 1px 1px rgba(34,118,187,1);}div.well{background:#f3f3f3;padding:14px 19px;margin:0 0 20px;border-radius:5px;-moz-border-radius:5px;-webkit-border-radius:5px;border:1px solid #eee;border-top-color:#ddd;}table.common-table{width:100%;margin:5px 0 20px;border-collapse:separate;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;}table.common-table th{color:#555;padding:10px;border-bottom:2px solid #ddd;}table.common-table thead td{font-weight:bold;color:#333;}table.common-table td{padding:5px 10px 5px 10px;color:#555;line-height:18px;border-bottom:1px solid #eee;vertical-align:top;}table.common-table td+td,table.common-table th+th{border-left:1px solid #fff!important;}table.common-table tbody tr:hover td{background:rgba(0,0,0,.03);}table.common-table .one{width:40px;}table.common-table .two{width:80px;}table.common-table .three{width:120px;}table.common-table .four{width:160px;}table.common-table .five{width:200px;}table.common-table .six{width:260px;}table.common-table a.block-link{display:block;margin:-10px;padding:10px;font-weight:bold;text-shadow:0 1px 1px rgba(255,255,255,.75);}table.zebra-striped td{text-shadow:0 1px 1px rgba(255,255,255,.75);}table.zebra-striped thead tr th{border-bottom:3px solid rgba(141,192,219,.6);white-space:nowrap;}table.zebra-striped tbody tr td{border:0!important;border-bottom:1px solid #fff!important;white-space:nowrap;}table.zebra-striped tbody tr:nth-child(odd) td{background-color:rgba(204,234,243,.25)!important;}table.zebra-striped tbody tr:hover td{background-color:rgba(204,234,243,.5)!important;}table.common-table th.header{cursor:pointer;padding-right:20px;}table.common-table th.headerSortUp,table.common-table th.headerSortDown{background-image:url(../images/tables/tablesorter-indicators.png);background-position:right -23px;background-repeat:no-repeat;-moz-border-radius:3px 3px 0 0;-webkit-border-top-left-radius:3px;-webkit-border-top-right-radius:3px;background-color:rgba(141,192,219,.25);text-shadow:0 1px 1px rgba(255,255,255,.75);}table.common-table th.header:hover{background-image:url(../images/tables/tablesorter-indicators.png);background-position:right 16px;background-repeat:no-repeat;}table.common-table th.actions:hover{background-image:none!important;}table.common-table th.headerSortDown,table.common-table th.headerSortDown:hover{background-position:right -24px;}table.common-table th.headerSortUp,table.common-table th.headerSortUp:hover{background-position:right -64px;}table.common-table th.blue{color:#2276BB;border-bottom-color:#2276BB;}table.common-table th.headerSortUp.blue,table.common-table th.headerSortDown.blue{background-color:#d3e4f1;}table.common-table th.green{color:#4bb14b;border-bottom-color:#4bb14b;}table.common-table th.headerSortUp.green,table.common-table th.headerSortDown.green{background-color:#dbefdb;}table.common-table th.red{color:#ab2920;border-bottom-color:#ab2920;}table.common-table th.headerSortUp.red,table.common-table th.headerSortDown.red{background-color:#eed4d2;}table.common-table th.yellow{color:#faa226;border-bottom-color:#faa226;}table.common-table th.headerSortUp.yellow,table.common-table th.headerSortDown.yellow{background-color:rgba(250,162,38,.2);}table.common-table th.align-right,table.common-table td.align-right{text-align:right;}table.common-table .muted{color:#999;}span.status-label{background:#ccc;padding:2px 5px 3px;font-size:10px;font-weight:bold;color:#fff;text-shadow:0 0 1px rgba(0,0,0,.01)!important;text-transform:uppercase;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}span.status-label.expired{background-color:#f5f5f5;color:#999;}span.status-label.pending{background-color:#48489b;}span.status-label.declined{background-color:#9b4848;}span.status-label.active,span.status-label.approved{background-color:#59bf59;}span.status-label.disabled{background-color:#faa226;}span.status-label.scheduled{background-color:#f5f5f5;color:#59bf59;text-shadow:0 1px 0 rgba(255,255,255,.5)!important;}#recommended_users{margin:18px 0 25px;}#recommended_users .view_all{padding:8px 14px 0;font-size:.9em;}#recommended_users .sidebar-title a{float:right;font-size:10px;padding-top:2px;}#recommended_users ul{padding:8px 14px 0;font-size:11px;}#recommended_users li{clear:both;margin-bottom:10px;zoom:1;}#recommended_users div.avatar{float:left;width:34px;}#recommended_users div.bio{float:right;width:135px;}#recommended_users p{margin-bottom:2px;padding:0;}#recommended_users li .next-suggestion{float:right;font-size:12px;margin-top:-3px;color:#999;cursor:pointer;text-decoration:none;}#recommended_users li a.next-suggestion:hover{color:#777;cursor:pointer;text-decoration:none;}#recommended_users .sidebar-title a{float:right;}#recommended_users p.screen-name{font-weight:bold;}#recommended_users p.verified{margin-bottom:1px;}#recommended_users p.verified a{padding:1px 18px 1px 0;background:transparent url(../images/verified/verified_small.png) no-repeat center right;}#recommended_users .sidebar-menu ul li:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#recommended_users .sidebar-menu ul li img{margin-right:5px;}#recommended_users .sidebar-menu ul li span{font-size:12px;line-height:1.3;}#recommended_users div.screen-name{font-weight:bold;}#recommended_users .sidebar-menu ul li span.name{color:#333;}#recommended_users .sidebar-menu ul li span.follow{font-size:11px;}#recommended_users img{width:28px;height:28px;}#recommended_users p.follow-link a.loaddisableding{text-decoration:none;color:gray;cursor:default;}#recommended_users p.follow-link span.pending{text-decoration:none;color:gray;cursor:default;font-size:11px;}.recommended-similar-users{background-color:#f6f6f6;border:1px solid #eee;padding:10px;margin:0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;display:none;}#content .recommended-similar-users h3{font-weight:normal;font-size:13px;margin-top:0;color:#666;}.recommended-similar-users .seeall{margin:0;font-size:11px;text-align:right;}.recommended-similar-users .seeall a{color:#999;}.recommended-similar-users ul{margin:10px 0;clear:both;}.recommended-similar-users li{float:left;width:160px;font-size:11px;}.recommended-similar-users li img{width:35px;height:35px;}.recommended-similar-users .bio{padding-top:3px;float:right;width:120px;}.subpage #content .recommended-similar-users .bio p{margin:0 0 2px;}.recommended-similar-users .close{float:right;color:#aaa;margin-top:-2px;}form.twitter-form h3{margin-bottom:10px;}form.twitter-form fieldset{margin:20px -20px -10px 0;padding:13px 20px 5px 0;border-top:1px solid #ddd;}form.twitter-form fieldset legend{background:#fff;float:left;margin:-25px 0 15px 140px;padding:0 10px;font-size:20px;font-weight:normal;line-height:1;color:#333;}form.twitter-form fieldset legend small{font-size:14px;font-weight:normal;color:#777;}form.twitter-form div.clearfix{margin:0 0 20px;}form.twitter-form fieldset div.clearfix{clear:both;}form.twitter-form label{float:left;width:130px;text-align:right;padding-top:4px;color:#333;font-size:13px;}form.twitter-form label small{font-size:12px;color:#777;}form.twitter-form label.inline-label{display:inline;float:none;width:auto;}form.twitter-form div.input{margin-left:150px;}div.actions{background:#f5f5f5;margin:30px 0 0;padding:20px 20px 20px 150px;border-top:1px solid #ddd;border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;-webkit-border-bottom-left-radius:3px;-webkit-border-bottom-right-radius:3px;}div.actions a.cancel{line-height:34px;padding-left:5px;}div.actions div.secondary-action{float:right;}div.actions div.secondary-action a{line-height:34px;}div.actions div.secondary-action a:hover{text-decoration:underline;}form.twitter-form div.actions{margin-right:-20px;}form.twitter-form fieldset+div.actions{margin-top:20px;}form.twitter-form input[type=text],form.twitter-form input[type=password],form.twitter-form textarea,form.twitter-form select{width:210px;margin:0;padding:3px 4px;font:13px/18px Helvetica Neue,Helvetica,Arial,sans-serif!important;color:#555;border:1px solid #ccc;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;}form.twitter-form select{padding:auto;width:auto;height:25px;line-height:25px;}form.twitter-form p.uneditable-input{padding-top:4px;margin-bottom:0!important;}body.ie form.twitter-form input[type=text],body.ie form.twitter-form input[type=password],body.ie form.twitter-form textarea{padding-bottom:5px;}body.firefox form.twitter-form input[type=text],body.firefox form.twitter-form input[type=password],body.firefox form.twitter-form textarea{padding-top:3px;padding-bottom:5px;}.input-mini,form.twitter-form input.mini,form.twitter-form textarea.mini,form.twitter-form select.mini,form.twitter-form p.pseudo-input.mini{width:60px;}.input-small,form.twitter-form input.small,form.twitter-form textarea.small,form.twitter-form select.small,form.twitter-form p.pseudo-input.small{width:90px;}.input-medium,form.twitter-form input.medium,form.twitter-form textarea.medium,form.twitter-form select.medium,form.twitter-form p.pseudo-input.medium{width:150px;}.input-large,form.twitter-form input.large,form.twitter-form textarea.large,form.twitter-form select.large,form.twitter-form p.pseudo-input.large{width:210px;}.input-xlarge,form.twitter-form input.xlarge,form.twitter-form textarea.xlarge,form.twitter-form select.xlarge,form.twitter-form p.pseudo-input.xlarge{width:270px;}.input-xxlarge,form.twitter-form input.xxlarge,form.twitter-form textarea.xxlarge,form.twitter-form select.xxlarge,form.twitter-form p.pseudo-input.xxlarge{width:530px;}form.twitter-form textarea.xxlarge{overflow-y:scroll;}form.twitter-form input[readonly]:focus,form.twitter-form textarea[readonly]:focus{border-color:#ddd!important;box-shadow:none;-moz-box-shadow:none;-webkit-box-shadow:none;}.help-inline,.help-block{font-size:12px;color:#777;}.help-inline{padding-left:3px;}.help-block{display:block;max-width:640px;margin:5px 0 0!important;line-height:18px;}.help-warning{color:#faa226;}.help-error{color:#ab2920;}form.twitter-form a.help-icon{position:relative;top:1px;left:2px;}div.help-block h5,div.help-block p,div.help-block ol li{color:#555;}div.help-block p,div.help-block ol li{font-size:12px!important;}div.help-block h5{font-size:13px;line-height:18px;}div.help-block p{margin-bottom:10px;font-size:12px;line-height:18px;color:#777;}div.help-block ol{margin-bottom:10px;margin-left:25px!important;}div.inline-inputs{position:relative;color:#555;}div.inline-inputs span,div.inline-inputs input[type=text]{display:inline-block;}div.inline-inputs input.mini{width:62px;}div.inline-inputs input.small{width:90px;}div.preface-input{position:relative;}div.preface-input input[type=text]{border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;-webkit-border-top-left-radius:0;-webkit-border-bottom-left-radius:0;}div.preface-input span.preface{background:#f5f5f5;display:inline;float:left;padding:3px 6px;font-size:13px;line-height:18px!important;height:18px;color:#555;border:1px solid #ccc;border-right:0;border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;-webkit-border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;}body.ie7 div.preface-input span.preface{margin-top:1px;}form.twitter-form label.checkbox,form.twitter-form label.radio{display:block;width:auto;padding:4px 0 0;float:none;text-align:left;}ul.options{margin:0;padding:3px 0 0;width:100%;}ul.options li{display:block;margin-bottom:5px;padding:0;width:100%;}ul.options li:last-child{margin-bottom:0;}ul.options label{position:relative;display:block;float:none;width:auto;margin:0;padding:0 0 0 20px;line-height:20px;text-align:left;white-space:normal;}ul.options label strong{color:#555;}ul.options label .help-icon{position:relative;top:1px;}ul.options input[type=radio],ul.options input[type=checkbox]{position:absolute;top:0;left:0;float:left;margin:4px 5px 0 0;}body.ie ul.options input[type=radio],body.ie ul.options input[type=checkbox]{margin-top:2px;}body.ie7 ul.options input[type=radio],body.ie7 ul.options input[type=checkbox]{margin-top:-2px;}ul.options label small{font-size:12px;font-weight:normal!important;}ul.options ul{margin-top:5px;}div.disabled span{color:#aaa;}div.disabled input[type=text],div.disabled input[type=passsword],div.disabled textarea{background:#f5f5f5;}ul.options label.disabled,ul.options label.disabled span,ul.options label.disabled small,ul.options label.disabled strong{color:#aaa!important;}ul.options li ul{margin-left:20px;}div.row{margin-left:-20px;}div.row div.column,div.row div.columns{display:inline;float:left;margin:0;}div.row div.column,div.row div.columns{margin-left:20px;}div.row div.one{width:40px;}div.row div.two{width:100px;}div.row div.three{width:160px;}div.row div.four{width:220px;}div.row div.five{width:280px;}div.row div.six{width:340px;}div.row div.seven{width:400px;}div.row div.eight{width:460px;}div.row div.nine{width:520px;}div.row div.ten{width:580px;}div.row div.eleven{width:640px;}div.row div.twelve{width:700px;}div.row div.thirteen{width:760px;}div.row div.fourteen{width:820px;}div.row div.fifteen{width:880px;}div.row div.sixteen{width:940px;}div.row div.one-fourth{width:205px;}div.row div.one-third{width:300px;}div.row div.offset-by-one{margin-left:60px;}div.row div.offset-by-two{margin-left:120px;}div.row div.offset-by-three{margin-left:180px;}div.row div.sidebar{width:310px;margin-left:50px;}body.ie6 div.row{width:960px;}.hashflag img{position:relative;left:-2px;top:3px;}span.unsafe{text-decoration:line-through;}.biz-info-form{max-width:600px;}.biz-info-form td select{float:left;}.biz-info-form td input{float:left;width:210px!important;}#phoenix-banner{background:#555;color:white;width:100%;z-index:9999;padding:4px 0;}#phoenix-banner .inner{margin:0 auto;position:relative;width:763px;text-align:left;}#phoenix-banner span{display:inline-block;padding:6px 8px;}#phoenix-banner img{height:26px;float:left;}#phoenix-banner a{color:#FFF;font-weight:bold;}.modal-overlay{z-index:9999!important;width:100%;position:fixed;margin:0;background-color:#000;opacity:.3;filter:alpha(opacity = 30);top:0;left:0;text-align:center;height:100%;}.hanging{display:block;width:400px;z-index:10001!important;position:fixed;top:0;left:0;}.attached .hanging,.ie6 .hanging{position:absolute;margin:0;}.attached .modal-overlay{position:absolute;}.attached .modal-inner{overflow:visible;}.modal{display:block;background:#ccc;-webkit-border-radius:4px;-moz-border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.5);-moz-box-shadow:0 1px 2px rgba(0,0,0,.5);padding:4px;}.modal-inner{background:#fff;-webkit-border-radius:4px;-moz-border-radius:4px;padding:0;text-align:left;overflow:hidden;zoom:1;}.modal-inner h2{font-family:'Lucida Grande',sans-serif;background:#efefef;margin:0 0 4px!important;padding:8px 10px!important;height:18px!important;-moz-border-radius-topleft:4px;-moz-border-radius-topright:4px;-webkit-border-top-left-radius:4px;-webkit-border-top-right-radius:4px;}.modal-inner h2 span{font-size:13px;font-weight:bold;float:left;}.modal-inner a.modal-close,.modal-inner h2 a.close{float:right;font:bold 16px/12px tahoma,sans-serif;margin-top:2px;text-decoration:none;color:#999;text-shadow:1px 1px 1px #fff;}.modal-inner .no-heading a.modal-close{margin:5px 5px 0 0;color:#bbb;}.modal-inner h2 a.modal-close:hover,.modal-inner h2 a.close:hover{color:#333;}.modal-inner .footer{background-color:#efefef;padding:10px;text-align:center;-moz-border-radius-bottomleft:4px;-moz-border-radius-bottomright:4px;-webkit-border-radius-bottomleft:4px;-webkit-border-radius-bottomright:4px;border-radius-bottomleft:4px;border-radius-bottomright:4px;}.modal-inner .footer button{margin:0 2px;}.modal-content{padding:10px;padding-bottom:10px;}.twttr-dialog .north{background:url(../images/dialog_arrows_sprite.gif) no-repeat center 0;height:12px;display:block;position:relative;margin-bottom:-4px;}.twttr-dialog .south{background:url(../images/dialog_arrows_sprite.gif) no-repeat center -36px;height:12px;display:block;position:relative;margin-top:-4px;}.twttr-dialog .weight-left .north{background-position:left top;}.twttr-dialog .weight-left .south{background-position:left -36px;}.twttr-dialog .weight-right .north{background-position:right top;}.twttr-dialog .weight-right .south{background-position:right -36px;}.twttr-dialog .east{background:url(../images/dialog_arrows_sprite.gif) no-repeat right center;display:block;position:absolute;width:12px;right:-8px;top:0;}.twttr-dialog .west{background:url(../images/dialog_arrows_sprite.gif) no-repeat left center;display:block;position:absolute;width:12px;left:-8px;top:0;}.twttr-dialog .weight-top .east{background-position:right top;}.twttr-dialog .weight-bottom .east{background-position:right bottom;}.twttr-dialog .weight-top .west{background-position:left top;}.twttr-dialog .weight-bottom .west{background-position:left bottom;}.password-dialog .password-wrapper{width:247px;}body .password-dialog .password-wrapper input{width:235px;}.password-dialog .password-wrapper div{margin-top:3px;text-align:right;}.password-dialog .modal-inner .footer{background:#fff;}.password-dialog #cancel_link{padding-left:5px;line-height:24px;}.password-dialog fieldset.common-form,.password-dialog fieldset.common-form ul li{margin-bottom:0;padding-bottom:0;}#notifications{position:fixed;top:0;left:0;width:100%;overflow:visible;z-index:10000;}.notification-bar{position:absolute;top:0;left:0;color:#000;border-bottom:2px solid rgba(0,0,0,0.07);width:100%;cursor:pointer;}.notification-bar-bkg{background-color:#fff;opacity:.95;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=95)";filter:alpha(opacity=95);position:static;}.notification-bar,.notification-bar-bkg{padding:1.2em 0;}.ie7 .notification-bar,.ie7 .notification-bar-bkg{border-bottom:2px solid #ccc;}.notification-bar-container{position:relative;display:block;width:100%;overflow:visible;}.notification-bar-contents{width:740px;margin:0 auto;text-align:left;position:relative;font-size:150%;}.notification-bar .message-progress{padding-left:24px;background-image:url(../images/ajax.gif);background-repeat:no-repeat;background-position:left center;}body.timeline #content h1{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;color:#333;font-size:18px;}#timeline_heading h1{color:#666;font-size:16px;font-weight:normal;padding:0 0 3px 0;}#timeline_heading h1 a,#timeline_heading h1 span.loaddisableding{font-size:10px;padding-left:15px;font-family:"Lucida Grande",Lucida Grande,Arial,sans-serif;}#timeline_heading h1#heading div#rate-limited-error a{float:none;font-size:16px;padding:0;}.save-search-link{background:transparent url(../images/icon_add.png) no-repeat left top;}.delete-search-link{background:transparent url(../images/icon_remove.png) no-repeat left top;}#timeline_heading h1 ul{float:right;position:relative;top:5px;}h1.hide-name-search li.name-search-link{display:none;}#timeline_heading h1 ul.has-saved-search{top:-5px;}#timeline_heading h1.hide-name-search ul.has-saved-search{top:3px;}#content #timeline_heading h1 ul li{padding:0;text-align:right;line-height:13px;}#content #timeline_heading h1 ul li.name-search-link a{padding:0;}#timeline_heading h1 span.loaddisableding{background:transparent url(../images/spinner.gif) no-repeat left top;padding-left:18px;}#content div.section #timeline_heading{margin:0;}body#inbox ol.statuses>li:first-child,body#sent ol.statuses>li:first-child,body#lists ol.statuses>li:first-child,body#direct_messages ol.statuses>li:first-child{border-top:1px solid transparent;}#inbox div#timeline_heading,#sent div#timeline_heading,#lists div#timeline_heading,#direct_messages div#timeline_heading{border-bottom:1px solid #cecece;}#dm_tabs{display:none;}body#direct_messages #dm_tabs,body#inbox #dm_tabs,body#sent #dm_tabs{display:block;}.tabMenu li.loaddisableding a{background-image:url(../images/spinner.gif);background-repeat:no-repeat;background-position:center center;color:transparent!important;}body#direct_messages #content .tabMenu #inbox_tab a,body#inbox #content .tabMenu #inbox_tab a,body#sent #content .tabMenu #sent_tab a,body#direct_messages #content .tabMenu #inbox_tab a,body#retweets_by_others #content .tabMenu #retweets_by_others_tab a,body#retweets #content .tabMenu #retweets_tab a,body#retweeted_by_others #content .tabMenu #retweeted_by_others_tab a,body#retweeted_of_mine #content .tabMenu #retweeted_of_mine_tab a{border:1px solid #c4c4c4;color:#333;background-color:#fff;border-bottom:1px solid #fff;padding:5px 14px 5px 14px;margin-right:1px;}#next_steps{display:none;font-size:1.2em;line-height:1.1;}body#home #next_steps{display:block;}#next_steps td.thumb{padding:10px 0 8px;width:50px;vertical-align:top;}#next_steps td{border-bottom:1px dashed #d2dada;vertical-align:middle;padding:7px 3px;}.subpage #content #next_steps li{padding-bottom:10px;}.subpage #content #next_steps li p{margin:0;font-size:.85em;color:#999;text-decoration:none;}#next_steps .step-completed span{text-decoration:line-through;}#search #content div.trend-description-container{display:block;}#content .trend-description-container{display:none;margin:0!important;padding:7px 0 0 0!important;}#trend_description img{vertical-align:middle;margin:1px 5px 3px;}.ie8 #trend_description img{margin-top:-1px;}.ie7 #trend_description img{margin-bottom:-2px;}#content #trend_description{display:none;padding:0;line-height:18px;margin:0 0 1em;}#content #trend_description span{color:#777;}#content #trend_description p{margin:0;line-height:18px;font-size:1.1em;color:#333;}#content #trend_description p strong{color:#333;}ol.statuses{list-style:none;font-size:14px;}ol.loaddisableding{height:300px;background:transparent url(../images/petal_spinner.gif) no-repeat center 50px;opacity:.3;filter:alpha(opacity = 30);}ol.statuses li.status,ol.statuses li.direct_message{position:relative;padding:10px 0 8px 0;border-bottom:1px solid #eee;line-height:16px;zoom:1;}ol.statuses>li.last-on-page,ol.statuses>li.last-on-refresh{border-bottom:1px solid #ccc!important;}ol.statuses>li:first-child{border-top:1px solid #eee;}ol.statuses>li.buffered{display:none!important;}.entry-meta{margin-top:2px;}.retweet-meta{margin-top:0;}#permalink .entry-meta{line-height:16px;}ol.statuses .thumb{display:block;width:50px;height:50px;position:absolute;left:0;margin:0 10px 0 0;overflow:hidden;z-index:10;}ol.statuses .thumb img{width:48px;height:48px;}.no-results{border-top:1px dashed #D2DADA;padding:.7em 0 .6em 1em;font-size:1.2em;}.no-results ol{padding:5px 0 0 30px;}ol.statuses span.status-body{display:block;min-height:48px;width:425px;overflow:hidden;margin-left:56px;}ol.statuses span.status-body .lock{margin-right:.4em;}#users ol.statuses span.status-body{width:365px;}ol.statuses .embedded_media_icon{height:20px;width:20px;background:transparent url(../images/inline-media.png) no-repeat bottom left;cursor:pointer;position:absolute;top:10px;right:-10px;z-index:400;}ol.statuses .embedded_picture{margin:10px 0 0 0;text-align:center;}ol.statuses .embedded_picture img{border:2px solid #DDD;padding:10px;}.search ol.statuses .bio{margin-left:5px;}.entry-content em{font-style:normal;font-weight:bold;}.meta{display:block;font-size:11px;color:#999;}.meta a{color:#999;}.meta .call-out{color:#000;}#content .meta .byline a{color:#0084b4;}ol.statuses .actions{position:absolute;right:10px;top:8px;line-height:1.25em;border-width:0;}.ie6 ol.statuses .actions{right:25px;}.actions a{text-decoration:none;}ol.statuses li{position:relative;}ol.statuses li:hover .actions span,ol.statuses li.hover .actions span,ol.statuses li.perma-hover .actions span,ol.statuses li:hover .actions a,ol.statuses li.hover .actions a,ol.statuses li.perma-hover .actions a{visibility:visible;}ol.statuses li.no-hover .actions span,ol.statuses li.no-hover .actions a{visibility:hidden!important;}.actions .non-fav,.actions .fav-throb,.actions .fav,.actions .reply{margin-bottom:3px;}.hentry .non-fav,.hentry .fav,.actions .reply{background-image:url(../images/sprite-icons.png);width:15px;height:15px;display:block;cursor:pointer;visibility:hidden;}.hentry .fav-throb{display:block;background-position:50% 50%;height:15px;width:15px;}.hentry .fav{background-position:-64px 0;}.hentry .non-fav{background-position:-32px 0;}.hentry .non-fav:hover{background-position:-48px 0;}.hentry .fav-throb,.hentry .del-throb{background-image:url(../images/icon_throbber.gif);}.hentry .del{background-image:url(../images/icon_trash.gif);}.direct_message a.reply{background-image:url(../images/icon_direct_reply.gif);}.direct_message .hentry .del{background-image:url(../images/icon_trash.gif);}ol.statuses li:hover,ol.statuses li.perma-hover,ol.statuses li.hover{background-color:#f7f7f7;}ol.statuses li:hover .hentry a,ol.statuses li.perma-hover .hentry a,ol.statuses li.hover .hentry a{visibility:visible;}ol.statuses .hentry a.fav{visibility:visible;}.status_activity{margin:4px 0 0 0;padding:10px 0 0 20px;}.status_activity .activity{margin:0 0 5px;}.status_activity .content{vertical-align:top;margin:0 0 0 5px;font-size:.8em;}#flash{padding-top:45px;background-repeat:no-repeat;background-position:24px 0;margin:1.5em 0;}#flash p{background-color:#fff;font-size:2.12em;line-height:1.2em;padding:.5em;font-weight:bold;}.feature-limited{background-color:#f9f6ba;border:2px solid #e9e6aa;-moz-border-radius:5px;-webkit-border-radius:5px;padding:.5em 1em;}.minor-notification{background-color:#e3f1fa;border:solid #c6e4f2;border-width:1px 0;padding:.5em 1em;text-shadow:0 1px 1px rgba(255,255,255,.5);color:#222!important;}div#new_results_notification{margin:0!important;}a#results_update{display:block;margin:0 0 20px;}a#results_update:hover{background-color:#d9ecf9;border-color:#b1d4e4;cursor:pointer;text-decoration:none;}.bulletin{padding:10px;display:none;}body#home .bulletin{display:block;}body#settings .bulletin{margin:20px 100px;}.bulletin a.close{padding:6px 6px 7px 7px;float:right;opacity:.7;background:transparent url(../images/close_small.png) no-repeat;}.ie .bulletin a.close{filter:alpha(opacity=70);}.bulletin a.close:hover{opacity:1.0;}.ie .bulletin a.close:hover{filter:alpha(opacity=100);}.bulletin.warning{background-color:#ff9;border:1px solid #ecec19;}.bulletin.alert{background-color:#ffab9d;border:1px solid #f88;}.bulletin.help{font-size:11px;background:#f8f8f8;line-height:18px;border:1px solid #eee;}.bulletin p,.bulletin h2{margin-left:46px!important;margin-bottom:5px!important;}.bulletin.info{padding:5px 10px!important;background-color:#F4F4F4;border:0;font-size:.9em;}.ie6 .standard-form .info{background:none;border:0;}.ie6 .bulletin{zoom:1;}.bulletin img{vertical-align:middle;float:left;}.bulletin.help img{margin-top:2px;margin-left:2px;}.bulletin h2{font:bold 13px Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px;margin-top:0!important;}.yellow-box{background-color:#FEF6A8;margin:1em;padding:1em;border:solid 1px #FFFA00;color:#000;line-height:1.7em;font-size:.9em;text-align:center;}#pagination{margin:2em 0 1em 0;}#pagination p.no-more-tweets{font-size:1.1em;text-align:center;}.more{outline:none;display:block;width:100%;padding:6px 0;text-align:center;border:1px solid #ddd;border-bottom:1px solid #aaa;border-right:1px solid #aaa;background-color:#fff;background-repeat:repeat-x;background-position:left top;font-size:14px;text-shadow:1px 1px 1px #fff;font-weight:bold;height:22px;line-height:1.5em;margin-bottom:6px;background-image:url(../images/more.gif);}.more:hover{border:1px solid #bbb;text-decoration:none;background-position:left -78px;}.more:active{color:#666;background-position:left -38px;}.more.loaddisableding{cursor:default!important;background-color:#fff;background-repeat:no-repeat;background-position:50% 50%;border:1px solid #eee;background-image:url(../images/ajax.gif);}.more::-moz-focus-inner{border:0;}.tip{color:#333;background-color:#e5eef2;border:1px solid #c7e0ed;padding:10px;margin:20px 0;-moz-border-radius:5px;-webkit-border-radius:5px;}.tip .dismiss{float:right;width:9px;height:10px;background:url(../images/sprite-icons.png) no-repeat -272px -16px;cursor:pointer;}#follow_users_tips h4{font-size:13px;line-height:16px;font-weight:normal;width:85%;margin:0 0 13px;}#follow_users_tips ol{zoom:1;overflow:hidden;list-style:none;}#follow_users_tips h5,#follow_users_tips li{font-weight:bold;font-size:11px;line-height:15px;}#follow_users_tips li.user-search{width:177px;padding-right:0;}#follow_users_tips li.user-search input[type='text']{width:114px;*width:112px;}#follow_users_tips li.user-search input{margin-top:3px;}#follow_users_tips li.follow-friends{width:130px;}#follow_users_tips li{float:left;width:132px;padding-right:20px;}#follow_users_tips form p{display:none;}#follow_users_tips li+li{border-left:1px solid #c7e0ed;padding:0 20px 0 10px;}#content #follow_users_tips fieldset{margin:0;}#content #follow_users_tips p.instruction{display:none;}html #content .tip p{font-weight:normal;color:#666;margin:0;line-height:15px;}html #content #mobile_tips p{width:85%;color:#333;}#pagination.pagination{height:1.5em;}#pagination.pagination a,#pagination.pagination .link-like{border:1px solid #cecece;padding:.25em 1em;margin:0 0 0 10px;float:right;}.person .thumb img{height:48px;width:48px;}ol.statuses span.status-body{overflow:visible;}ol.statuses span.status-body span.status-content{overflow:hidden;}ol.statuses li.garuda-tweet{background:#fff;border-color:#ddd;}ol.statuses li.garuda-tweet .actions-hover li{background-color:transparent!important;}ol.statuses li .tweet-label{-moz-box-shadow:none;-webkit-box-shadow:none;-moz-border-radius:3px;-webkit-border-radius:3px;background:#ffebbe url(../images/commercial/garuda-overlay.gif) repeat-x 0 0;background:-webkit-gradient(linear,0 0,0 100%,from(rgba(255,237,87,.25)),to(rgba(255,171,0,.25)));background:-moz-linear-gradient(top,rgba(255,237,87,.25),rgba(255,171,0,.25));color:#444!important;line-height:12px!important;margin:0!important;padding:2px 4px!important;text-shadow:0 1px 1px rgba(255,255,255,.5)!important;}ol#timeline li .tweet-label span{text-shadow:0 1px 1px rgba(255,255,255,.5)!important;}ol#timeline li .tweet-label span.promoted_by{color:#817046!important;}ol#timeline li .tweet-label.top-tweet{background:#C3E2EF url(../images/toptweet-overlay.gif) repeat-x 0 0;color:#888;}ol.statuses li.garuda-tweet:hover{background:#fdfcf1;background:rgba(255,237,87,.15);border-color:#e7e3ce;}ol#timeline li.garuda-tweet:hover .tweet-label{background:#ffd46b url(../images/commercial/garuda-overlay.gif) repeat-x 0 -32px;background:-webkit-gradient(linear,0 0,0 100%,from(rgba(255,237,87,.5)),to(rgba(255,171,0,.5)));background:-moz-linear-gradient(top,rgba(255,237,87,.5),rgba(255,171,0,.5));color:#59505f!important;-moz-box-shadow:0 1px 0 #fff;-webkit-box-shadow:0 1px 0 #fff;}ol.statuses li ul.meta-data{display:block;font-size:10px;}ol.statuses li ul.meta-data li{float:left;display:inline;line-height:16px!important;margin-right:7px!important;padding:0!important;color:#999;}ol.statuses li ul.meta-data li:hover{background:none!important;}ol.statuses li ul.meta-data a{color:#999;cursor:default;}ol.statuses li ul.meta-data a:hover{text-decoration:none;}ol.statuses li ul.meta-data a em{display:block;float:left;background-image:url(../images/sprite-icons.png@v3);background-repeat:no-repeat;width:14px;height:15px;margin:0 2px 0 0;}ol.statuses li ul.meta-data span.promoted_by a{cursor:pointer;color:#817046;}ol.statuses li ul.meta-data span.promoted_by a:hover{text-decoration:underline;}ol.statuses li ul.meta-data a.meta-retweets em{background-position:-224px 0;margin-right:2px;}ol.statuses li ul.meta-data a.meta-retweets:hover em{background-position:-240px 0;}ol.statuses li ul.meta-data a.meta-replies:hover em{background-position:-16px 0;}.garuda-tipsy a{color:#fff;}.garuda-tipsy a:hover{text-decoration:none;}.garuda-tipsy-container .tipsy-inner{max-width:none!important;font-weight:normal;}body#list .retweet-link,body#list_show .retweet-link{display:none;}#side .retweet-feedback{margin:0 14px 0 14px;padding:.5em 0 .3em 0;color:#666;font-size:11px;}.actions-hover li{padding:0!important;display:block;float:left;}.actions-hover{position:absolute;bottom:8px;font-size:11px;padding-right:10px;right:0;overflow:visible;color:#999;float:right;visibility:hidden;}body.ie6 #timeline .actions-hover{position:relative;right:-50px;}body.ie6#profile #timeline .actions-hover{position:relative;right:-90px;}#timeline div.no-retweets-text{margin-top:36px;margin-left:106px;width:325px;line-height:17px;font-size:13px;color:#333;}.no-retweets-text .header{font-weight:bold;}.no-retweets-text img{margin-top:12px;}.retweeting.retweet-loaddisableding{background:transparent url(../images/spinner.gif) left top no-repeat;color:#999;font-size:11px;line-height:14px;padding-left:16px;position:absolute;bottom:10px;right:7px;}body.ie6 span.retweeting{position:static;}.retweet-status-body-wrapper .retweeting.loaddisableding{bottom:1px;}#content #permalink .retweeting.loaddisableding{bottom:12px;}#content li:hover .actions-hover,#content li.hover .actions-hover,#content li.perma-hover .actions-hover{visibility:visible;}#content .no-hover .actions-hover{visibility:hidden!important;}#content li .meta,#content li .actions-hover{height:16px;height:auto;}.actions-hover a.fav-throb,.actions-hover .del-throb{visibility:visible;}.hentry .del-throb{background-image:none;}.hentry .actions-hover .del-throb .delete-icon{background-image:url(../images/icon_throbber.gif);background-position:0 0;top:3px;}.hentry .actions-hover span.icon{display:block;float:left;background-image:url(../images/sprite-icons.png);background-repeat:no-repeat;margin-left:8px;}.hentry .actions-hover li .retweet-link,.hentry .actions-hover li .del,.hentry .actions-hover li .reply{display:block;float:left;line-height:16px;}.hentry.latest-status .actions-hover li a{line-height:16px;}.actions-hover .reply-icon{width:15px;height:15px;margin-right:1px;}.actions-hover .retweet-icon{width:16px;height:16px;margin-right:2px;background-position:-176px 0;}.actions-hover .delete-icon{width:15px;height:15px;margin-right:1px;background-position:-112px 0;}.actions-hover .delete-icon,.actions-hover .reply-icon,.actions-hover .retweet-link .retweet-icon{cursor:pointer;}.actions-hover .reply:hover .reply-icon{background-position:-16px 0;}.actions-hover .retweet-link:hover .retweet-icon,.hentry.perma-hover .actions-hover .retweet-icon{background-position:-192px 0;}.actions-hover .del:hover .delete-icon{background-position:-128px 0;}.actions-hover .reply:hover a,.actions-hover .del:hover a,.actions-hover .retweet-link:hover a{text-decoration:underline;}.hentry .del,body#show .hentry .actions-hover .reply{background-image:none;}ol.statuses li.hentry .reply,ol.statuses li.hentry .del{background-image:none;}#content .shared-content .thumb{width:12px!important;height:12px!important;padding:0!important;margin:0 .3em 0 0!important;position:static!important;display:inline!important;vertical-align:middle;}#content .shared-content .thumb img{width:12px!important;height:12px!important;}#content .shared-content .status-body{margin-left:0!important;min-height:15px!important;}#content .shared-content img{margin-right:4px;}#content .shared-content .screen-name{color:#0084B4;font-family:'Lucida Grande',sans-serif;font-style:normal;margin-right:0;}#content .meta .shared-content .screen-name{font-weight:normal;}#content .shared-content,#content .shared-content .status-body{width:370px;}#content .shared-content .entry-content{font-style:italic;line-height:1.1em;display:inline;margin-top:0;}.inline-form{position:absolute;top:0;left:0;z-index:100;width:320px;overflow:visible;padding-top:7px;background-image:url(../images/arr-inline-form.gif);background-repeat:no-repeat;background-position:236px top;}.inline-form.retweet-ctx-dlg{width:330px;line-height:17px;}.inline-form-inner{-moz-border-radius:6px;-webkit-border-radius:6px;-border-radius:6px;-moz-box-shadow:0 2px 4px #ABABAB;-webkit-box-shadow:0 2px 4px #ABABAB;text-align:left;border:4px solid #c7c7c7;width:100%;overflow:auto;background-color:#fff;position:absolute;}.inline-form .cancel{float:right;margin:8px 10px;cursor:pointer;width:10px;height:10px;background-image:url(../images/retweet/retweet-x.png);}.inline-form .spinner{display:none;}.inline-form-buttons{margin:6px 0 4px;text-align:right;}.retweet-dlg .inline-form-buttons button.btn{width:56px;font-size:13px;font-weight:bold;}.inline-form-inputs{float:left;overflow:visible;}.inline-form-input{display:none;}.inline-inputs-prompt{margin:.3em 0 .3em .7em;}.inline-form .title{font-size:13px;font-weight:bold;margin:12px 10px;}.inline-form .body{margin:7px 10px 12px;}.inline-form.retweet-ctx-dlg{background-position:23px center;padding-top:11px;}.inline-form.retweet-ctx-dlg .title{font-size:16px;margin-bottom:7px;}.inline-form.retweet-ctx-dlg .inline-form-buttons{text-align:left;padding-left:10px;}body#show .shared-content{font-style:normal;font-family:'Lucida Grande',sans-serif;}body#show .shared-content .screen-name{font-size:1em;}#permalink .actions-hover a{display:inline;background-image:none;}#content #permalink .actions-hover{display:inline;bottom:12px;padding-right:0;padding-bottom:3px;white-space:nowrap;visibility:visible;}body.ie6 #content #permalink .actions-hover{position:relative!important;display:block;visibility:visible!important;}body#retweets #timeline>li:first-child,body#retweets_by_others #timeline>li:first-child,body#retweeted_of_mine #timeline>li:first-child{border-top:1px solid transparent;}body#retweets div#timeline_heading,body#retweeted_of_mine div#timeline_heading,body#retweets_by_others div#timeline_heading{border-bottom:1px solid #cecece;}#retweet_tabs{padding:0;display:none;}body#retweets #retweet_tabs,body#retweets_by_others #retweet_tabs,body#retweeted_of_mine #retweet_tabs{display:block;}body#retweets #timeline_heading h1,body#retweets_by_others #timeline_heading h1,body#retweeted_of_mine #timeline_heading h1{display:none;}.retweet-status-body-wrapper{position:relative;}.retweet-status-body-wrapper .actions-hover{bottom:0;}body.ie7 .retweet-status-body-wrapper .actions-hover{bottom:3px;}.share-text{background-color:#f7f7f7;border:2px solid #f7f7f7;border-left:2px solid #d7d7d7;padding:.25em .6em .4em;margin:.3em 0 .2em;}.share-text-author{color:#666;margin-top:.45em;}.share-text-author strong .screen-name{font-weight:normal;}ol.statuses .share-text-author .thumb{margin-left:.1em;margin-top:-2px;}ol.statuses .share-text-author .thumb img{width:18px;height:18px;}.shared-by-avatar-tiles span.thumb{margin-right:3px;padding:0;}ol.statuses .thumb-inline{position:static;display:inline;}.friend-who-shared-this strong .screen-name{font-weight:normal;color:inherit;margin-right:0;}.friend-who-shared-this strong .screen-name:hover{text-decoration:underline;}.share-text-active{background-color:#fff;}body#profile #container ol.statuses span.status-body .share-text .entry-content{font-size:1em;}body#profile #container ol.statuses .latest-status .entry-content{font-size:1.77em;}.big-retweet-icon{display:inline-block;width:18px;height:14px;position:relative;top:2px;background-repeat:no-repeat;background-image:url(../images/sprite-icons.png);background-position:-128px -64px;}.ie7 .big-retweet-icon{top:-2px;margin-right:3px;}li.share-with-details div.shared-by-avatar-tiles{margin-top:1px;margin-left:56px;line-height:28px;}li.share-with-details div.shared-by-avatar-tiles .meta{line-height:16px;margin-top:2px;}li.share-with-details div.shared-by-avatar-tiles img{height:25px;width:25px;}ol.statuses li{padding:10px 0;}body#profile .latest-status .actions-hover{bottom:24px;}#introduce_retweet_banner{background:#fff;margin:20px 0;-moz-border-radius:6px;-webkit-border-radius:6px;border:4px solid #DDD;padding:10px;color:#5c5c5c;-moz-box-shadow:0 2px 4px #ABABAB;-webkit-box-shadow:0 2px 4px #ABABAB;}#introduce_retweet_banner .retweet-banner-example{float:right;}#introduce_retweet_banner h1{padding:0;margin:0;font-family:Helvetica,sans-serif;font-weight:bold;font-size:16px;white-space:nowrap;}#introduce_retweet_banner h1 span.beta{color:#ABABAB;font-size:15px;}#introduce_retweet_banner p{padding:0;margin:12px 0;font-family:'Lucida Grande',sans-serif;font-size:13px;line-height:17px;}#introduce_retweet_banner div{width:250px;}#list_show table.columns,#lists_members table.columns,#lists_subscribers table.columns{margin-top:5px;}h2.list-subheading{margin-top:-8px!important;padding-bottom:16px;}p.list-numbers,p.list-link{font-weight:normal;font-size:11px;margin-top:0;padding-top:0;}p.list-numbers{color:#666;float:left;}p.list-numbers a+a{border-left:1px solid #eee;padding-left:8px;margin-left:8px;}p.list-link{float:right;}p.list-link span{font-weight:bold;}p.list-numbers a{color:#666;}p.list-numbers a:hover{color:#0084B4;text-decoration:underline;}p.list-numbers a span{font:bold 11px Helvetica Neue,Helvetica,Arial;}#content .list-title-section{margin:30px 0 1em 5px!important;}#lists_members .wrapper,#lists_subscribers .wrapper{padding:5px 10px 15px;}.list-header{margin:-5px 0 0 -10px!important;}.list-header,.list-header-inner{background:#ddeef6;-moz-border-radius:5px 0 0 0;-webkit-border-top-left-radius:5px;border-radius:5px 0 0 0;}.list-header-inner{padding:15px 0 0 20px;margin-right:-10px;height:62px;}.list-header h2 a{color:#333;text-decoration:none;}body #content .list-header h2{font:22px Helvetica Neue,Helvetica,arial,sans-serif;-webkit-text-outline:1px transparent;margin-left:0;overflow:hidden;margin:0;width:520px;}body #content .list-header .description{font-size:11px;margin-top:2px;}body #content .list-header h2 i{margin-right:-5px;font-size:22px;color:#666;}.ie7 ul.user-actions{width:126px!important;}body#following.ie7 .following ul.user-actions{width:83px!important;margin-right:-6px;}.ie7 .user-actions-outer .list-menu,.ie7 .user-actions-outer .action-menu,.ie7 .user-actions-outer .follow-action{float:left;width:40px;}.ie7 .user-actions-outer .list-menu{width:43px;}.ie7 .user-actions .list-menu ul{clear:both;display:block;margin-top:23px;margin-left:-33px;}.ie7 .profile-controls .list-menu ul{margin-left:-66px;}.ie7 .user-actions-outer .list-menu button{padding:0 6px;zoom:1;width:33px;}.ie7 .profile-controls .list-menu{width:60px;margin-left:20px!important;float:left;display:inline;zoom:1;}.ie7 .profile-controls .user-actions .follow-action button{float:left!important;margin-left:-367px;position:relative;}.ie7 .profile-controls .list-menu button{width:66px;}#lists_table{margin-top:0;}#lists_table .author{display:block;position:absolute;width:30px;padding-top:2px;}#lists_table .list-info{display:block;margin-left:32px;min-height:24px;}#lists_table tr td{color:#999;vertical-align:top;}#lists_table tr:hover td{background:#f6f6f6;color:#333;}#lists_table .list-info .description{display:block;font-size:11px;}.list-menu button i{display:block;float:right;background-position:-79px -67px;margin:4px 0 0 3px;width:7px!important;height:5px;*margin:4px 0 0 0!important;}.ie7 .profile-controls .list-menu button i{margin-top:-11px!important;position:relative;zoom:1;}.ie8 .list-menu button i{margin:4px 0 0 0!important;}#follow_grid .user:hover .user-actions .list-menu button i,.profile-user .user .user-actions .list-menu button i,.user-actions .list-menu button.clicked i{background-position:-47px -67px;}.list-menu button b{background-image:url(../images/sprite-icons.png);display:block;float:left;background-position:-64px -64px;margin:1px 3px 0 0;width:12px;height:13px;}.user-actions-outer .list-menu button{padding-left:6px;padding-right:6px;}.ie7 .profile-controls .list-menu button b{margin-right:-6px!important;}#follow_grid .user:hover .user-actions .list-menu button b,.profile-user .user .user-actions .list-menu button b,.user-actions .list-menu button.clicked b{background-position:-96px -64px;}.user-actions-outer .list-menu button b{margin:0;}.list-menu ul li{padding-left:5px;}.list-menu ul li label{padding:4px 2px!important;width:70%;cursor:pointer;}.list-menu ul li input[type="checkbox"]{margin:0 0 0 5px;}.ie7 .list-menu ul li input[type="checkbox"]{margin:0 0 0 2px;}.ie8 .list-menu ul li input[type="checkbox"]{margin:0 0 0 -1px;float:left;}.lists .lists-links li,.lists_subscribers .lists-links li,.lists_members .lists-links li,#profile #side_lists .sidebar-menu li,#profile_favorites #side_lists .sidebar-menu li,#following #side_lists .sidebar-menu li,#followers #side_lists .sidebar-menu li{padding:3px 0 3px 14px;display:block;clear:both;overflow:hidden;width:172px;}#list_memberships .lists-links li a,#list_subscriptions .lists-links li a,.lists .lists-links li a,.lists_subscribers .lists-links li a,.lists_members .lists-links li a,#profile #side_lists .sidebar-menu li a,#profile_favorites #side_lists .sidebar-menu li a,#following #side_lists .sidebar-menu li a,#followers #side_lists .sidebar-menu li a{padding:0;display:inline;clear:both;}.lists .lists-links li a span,.lists_subscribers .lists-links li a span,.lists_members .lists-links li a span,#profile #side_lists .sidebar-menu li a span,#profile_favorites #side_lists .sidebar-menu li a span,#following #side_lists .sidebar-menu li a span,#followers #side_lists .sidebar-menu li a span{clear:both;width:auto!important;}.lists .lists-links li a:hover,.lists .lists-links li.active a,.lists_subscribers .lists-links li a:hover,.lists_subscribers .lists-links li.active a,.lists_members .lists-links li a:hover,.lists_members .lists-links li.active a,#profile #side_lists .sidebar-menu li a:hover,#profile #side_lists .sidebar-menu li.active a,#profile_favorites #side_lists .sidebar-menu li a:hover,#profile_favorites #side_lists .sidebar-menu li.active a,#following #side_lists .sidebar-menu li a:hover,#following #side_lists .sidebar-menu li.active a,#followers #side_lists .sidebar-menu li a:hover,#followers #side_lists .sidebar-menu li.active a{background:transparent!important;text-decoration:none;font-weight:normal;}.lists .lists-links li a:hover span,.lists_subscribers .lists-links li a:hover span,.lists_members .lists-links li a:hover span,#profile #side_lists .sidebar-menu li a:hover span,#profile_favorites #side_lists .sidebar-menu li a:hover span,#following #side_lists .sidebar-menu li a:hover span,#followers #side_lists .sidebar-menu li a:hover span{text-decoration:underline;}#side ul.lists-links li a span{width:150px;padding:2px 0 0 0;margin:0;}#side ul.lists-links li a b,#profile .sidebar-list li a b,#profile_favorites .sidebar-list li a b,#following .sidebar-list li a b,#followers .sidebar-list li a b{font-weight:normal;}#side ul.lists-links li a i,#profile .sidebar-list li a i,#profile_favorites .sidebar-list li a i,#following .sidebar-list li a i,#followers .sidebar-list li a i{font-style:normal;font-size:10px;margin-right:-3px;}#list_memberships span.view-all,#list_subscriptions span.view-all,#profile span.view-all,#profile_favorites span.view-all,#following span.view-all,#followers span.view-all{border-left:0;display:inline;padding-left:0;padding-right:7px;margin:0 5px 0 0;border-right:0;}#list_subscriptions span.last,#list_memberships span.last,#profile span.last,#profile_favorites span.last,#following span.last,#followers span.last{border-right:0!important;}#list_memberships p.sidebar-menu-actions,#list_subscriptions p.sidebar-menu-actions,#profile p.sidebar-menu-actions,#profile_favorites p.sidebar-menu-actions,#following p.sidebar-menu-actions,#followers p.sidebar-menu-actions{padding-top:2px;}#side ul.lists-links li a em{position:absolute;right:0;width:28px;height:13px;background:url(../images/arrow_right_dark.png) no-repeat left top;display:none;margin-top:1px;}.safari#list_subscriptions .lists-links li a,.safari#list_memberships .lists-links li a,.safari#list_show .lists-links li a,.safari#lists_subscribers .lists-links li a,.safari#lists_members .lists-links li a{padding-left:0!important;}#side ul.lists-links li a:hover em,#side ul.lists-links li.active a em{display:block;}#side ul.lists-links li a em:hover{background-position:0 -13px;}#side ul.lists-links li.loaddisableding a em{display:none;}ul.sidebar-list li.active a,ul.sidebar-list li a:hover{background-color:#DDEEF6;}#lists span.subscribed{background:#efefef;display:inline-block;font:11px Lucida Grande,arial,sans-serif;color:#333;padding:6px 8px;text-shadow:1px 1px 0 #fff;}#lists span.subscribed i{background-image:url(../images/sprite-icons.png);background-repeat:no-repeat;display:inline-block;background-position:-160px -16px;height:9px;margin-right:2px;width:10px;}#lists .profile-controls{display:block;clear:both;background:none;margin:0;padding:0;}.profile-controls li{text-align:left;margin:0!important;padding:0!important;}.profile-user .list-tags-outer{border:1px solid #eee;border-top:0;color:#ccc;background:#F6F6F6;font:11px "Lucida Grande",sans-serif;line-height:20px;margin:-18px 0 0 0;padding:6px 10px;-moz-border-radius:0 0 5px 5px;-webkit-border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;}.profile-user .list-tags-outer hr{color:#F6F6F6;background:#F6F6F6;border:0 solid #F6F6F6;border-top:1px solid #eee;border-bottom:1px solid #fff;height:0;margin:0 0 5px 0;display:block;}.profile-user .ie7 .list-tags-outer hr{display:none;}.profile-user .ie7 .list-tags *,.ie8 .list-tags *{background:none;}.list-tags{display:inline-block;}.profile-user .list-tags{margin-left:5px;}body.ie7#following .list-tags,body.ie7#followers .list-tags,body.ie7#lists_members .list-tags,body.ie7#lists_subscribers .list-tags{display:block;float:left;padding-top:3px;margin-left:53px;}body.ie7#profile .list-tags,body.ie7#profile_favorites .list-tags{margin-left:56px;}.list-tags-outer label{color:#666;}.list-tags-outer span.lock-icon{margin-left:3px;width:8px;}.list-tags li{display:inline-block;margin-right:2px;width:auto;}.ie7 .list-tags{margin-left:30px;margin-top:-20px;}.ie7 .list-tags li{float:left;width:auto;}.list-tags li a{display:block;}.list-tags li a i{background:none;padding:0;width:auto;height:auto;display:inline;margin-right:-3px;}.list-tags a{cursor:pointer;margin-right:5px;}.list-menu ul li{padding-left:5px!important;}.list-menu ul li label{padding:4px 2px!important;width:80%;cursor:pointer;overflow:hidden;}.list-menu ul li input[type="checkbox"]{margin:5px 0 0 5px;}#content .lists{margin-bottom:30px;}#list_show #side_base,#lists_members #side_base,#lists_subscribers #side_base{border-left-width:0;background-color:#fff;}#list_show .content-bubble-arrow,#lists_members .content-bubble-arrow,#lists_subscribers .content-bubble-arrow{background:none!important;}#list_show h3,#lists_members h3,#lists_subscribers h3{font-size:12px;font-weight:normal;padding-left:5px;margin-top:-8px;padding-bottom:2px;}h3 img{margin:-2px 0 0 2px;vertical-align:middle;}h3.heading{font:14px Helvetica Neue,Helvetica,sans-serif;padding-top:10px;padding-bottom:2px;}.list-controls{zoom:1;*position:relative;background-color:#ddeef6;-moz-border-radius:0 5px 0 0;-webkit-border-top-right-radius:5px;border-radius:0 5px 0 0;text-align:left;margin:-6px -1px 0 0;padding:20px 0 0 13px;height:57px;}body.lists .list{padding:0!important;}body.lists #timeline{padding-left:12px;}.list-controls .control-wrapper{float:left;width:135px;padding-left:5px;margin-top:-2px;}.list-controls a{float:left;}.list-controls #admin_list a{float:none;}.list-controls span.creator{padding:0 0 2px 0;margin:-2px 0 0 0;font-size:11px;line-height:15px;}.list-controls span.creator a{margin-right:3px;float:none;}.list-controls img{width:24px;height:24px;margin-top:4px;margin-right:8px;}#profile #timeline{margin-top:6px;}#profile_favorites #timeline{margin-top:0;}#list_show #primary_nav,#lists_members #primary_nav,#lists_subscribers #primary_nav{padding-top:20px;}.sidebar-list{width:90%;}#list_memberships .sidebar-list li,#list_subscriptions .sidebar-list li,#profile .sidebar-list li,#profile_favorites .sidebar-list li,#following .sidebar-list li,#followers .sidebar-list li{padding:3px 0 3px 0;}span.view-lists{clear:both;display:block;font-size:11px;padding:0 14px 5px 14px;}#list_memberships #friends_view_all small a,#list_subscriptions #friends_view_all small a,#list_show #friends_view_all small a{font-size:11px!important;color:#888;}#list_memberships #friends_view_all{margin-top:-3px!important;padding-bottom:14px!important;}#members .sidebar-menu div{margin:3px 0 0 16px;}.stat-count{position:absolute;right:30px;*right:10px;padding:.5em 0;font:bold 12px "Helvetica Neue",Helvetica,Arial,sans-serif;}#owners_lists p{padding:4px 0 0 14px!important;}#owners_lists h2 a{color:#333;}#owners_lists div.lists-links{padding:0 6px 0 14px;}#owners_lists span.view-all{display:block;margin-bottom:20px;}#owners_lists span.view-all a{color:#888;}#action_lists ul{padding:0 6px 12px 0;}form.button-to{padding:36px 0 20px 16px;}#list_memberships #side ul.sidebar-list,#list_subscriptions #side ul.sidebar-list,#profile #side ul.sidebar-list,#profile_favorites #side ul.sidebar-list,#following #side ul.sidebar-list,#followers #side ul.sidebar-list{margin:.2em 14px 6px;}.is-owner,.no-members{margin-left:10px!important;}.subscribe-list i{background-image:url(../images/sprite-icons.png);display:block;float:left;background-position:-96px -64px;margin:1px 5px 0 0;width:10px;height:13px;}.ie7 .subscribe-list{width:110px;}.is-subscriber i,.is-owner i{display:inline-block;width:10px;height:9px;margin-right:6px;background-image:url(../images/sprite-icons.png);background-repeat:no-repeat;overflow:hidden;outline:none;background-position:-160px -16px;}.is-owner,.is-subscriber,.subscriber .is-non-subscriber,.no-subscribe .is-non-subscriber,.owner .is-non-subscriber{display:none;margin-top:20px!important;}.owner .is-owner{display:block;}.subscriber .is-subscriber{display:block;padding:6px 0 4px 0;}a.unsubscribe-list,span.actions-list{position:absolute;right:0;}a.edit-list{padding-right:6px;border-right:1px solid #C0DEED;margin-right:6px;}span.actions-list{color:#ccc;}#admin_list{font-size:11px;}#admin_list ul li{padding-top:2px;}.no-members,.no-members-list{background:url(../images/thumb-bird-bw.gif) no-repeat 0 14px;min-height:63px;font-size:13px;border-top:1px solid #eee;border-bottom:1px solid #eee;padding:14px 0 0 60px;line-height:16px!important;color:#666;clear:both;float:none;font-weight:normal;}.no-members-list{margin-left:4px!important;}.lists td.user-detail,.lists_members td.user-detail,.lists_subscribers td.user-detail{padding-left:0!important;}.list-header-section{padding:0!important;}#list_memberships #content h2,#list_subscriptions #content h2{margin-bottom:20px;}#list_show h2.sidebar-title,#lists_members h2.sidebar-title,#lists_subscribers h2.sidebar-title{clear:both;display:block;padding:16px 6px 4px 14px!important;}#action_lists h2.sidebar-title{padding-top:0!important;margin-top:0!important;}#list_show ul.sidebar-menu li a,#lists_members ul.sidebar-menu li a,#lists_subscribers ul.sidebar-menu li a{-moz-border-radius:5px;-webkit-border-radius:5px;}#list_show ul.sidebar-menu li,#lists_members ul.sidebar-menu li,#lists_subscribers ul.sidebar-menu li{*height:23px!important;*position:relative;}.lists .user-detail{width:390px!important;}.lists table.users-lists{width:100%;border-collapse:collapse;}.lists table.users-lists thead{color:#999;font-family:Lucida Grande,Helvetica,Arial,sans-serif;}.lists table.users-lists td.count{color:#999;font-size:11px;padding-top:7px;width:100px;}.lists table.users-lists td{border-bottom:1px solid #eee;padding:6px;font-size:14px;}#lists_table .list-info a{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}.lists table.users-lists td a img{margin-right:8px;}.lists table.users-lists thead td{font-size:10px;}.lists table.users-lists td a span i{margin-right:-4px;}#list_tabs{clear:both;display:block;border-bottom:1px solid #CECECE;}#list_show ul.lists-links,#lists_members ul.lists-links,#lists_subscribers ul.lists-links{margin-bottom:0!important;}#list_show ul.lists-links li a:hover,#lists_members ul.lists-links li a:hover,#lists_subscribers ul.lists-links li a:hover{text-decoration:underline;}p.list-description{color:#666;display:block;padding:0 0 0 10px;font-weight:300;font:16px Helvetica Neue,Helvetica,Arial,sans-serif;}p.list-feedback{color:#666;border-top:1px solid #EEE;font-size:11px;margin:0 20px 26px 14px;padding-top:8px!important;}.ie7 .user-settings .setting{float:left;}.create-list-dialog .update-list-heading,.update-list-dialog .create-list-heading,.create-list-dialog .update-list-button,.update-list-dialog .create-list-button{display:none;}#lists_members #follow_grid table,#lists_subscribers #follow_grid table{margin-top:0;border-top:0!important;}#lists_members #follow_grid,#lists_subscribers #follow_grid{margin:0 10px 0 5px;}.no-members h3{font-family:Helvetica Neue,Helvetica,Arial,sans-serif!important;margin-top:-2px!important;margin-bottom:0!important;font-size:16px!important;font-weight:bold!important;padding-left:0!important;}.no-members p.instruction{padding-top:6px!important;}.no-members p.tip{margin:-5px 0 12px 0!important;font-size:10px;line-height:13px;}.firefox .no-members p.instruction{margin-bottom:0!important;}#lists_subscribers p.no-members-list,#lists_members div.no-members{margin-top:5px!important;margin-left:5px!important;}#list_show.firefox #side_base span.vcard,#lists_members.firefox #side_base span.vcard,#lists_subscribers.firefox #side_base span.vcard{line-height:1.3em;}#list_show.safari #side_base span.vcard,#lists_members.safari #side_base span.vcard,#lists_subscribers.safari #side_base span.vcard{line-height:1.4em;}#lists_members #follow_grid td.thumb,#lists_subscribers #follow_grid td.thumb{width:13%!important;}#lists_members #follow_grid.follow-compact .thumb,#lists_subscribers #follow_grid.follow-compact .thumb{width:8%!important;}.list-description-call{float:left;}.list-description-fieldset{margin-bottom:0!important;}#lists_members .is-non-subscriber,#lists_members .is-subscriber,#lists_subscribers .is-non-subscriber,#lists_subscribers .is-subscriber{margin:-6px 0 25px 5px!important;}#lists_subscribers a.unsubscribe-list,#lists_members a.unsubscribe-list{margin-right:5px;}#list_show #members,#lists_subscribers #members,#lists_members #members{margin-bottom:4px;}.list-dialog .modal-content input.title,.list-dialog .modal-content textarea.title{-webkit-border-radius:2px;-moz-border-radius:2px;margin-bottom:0;}.list-url{font-weight:bold;color:blue;}.list-dialog .modal-content textarea.title{margin-top:4px;font:13px Lucida Grande,Arial,sans-serif;height:36px;}#list_tabs ul.tabMenu li a span.count,#list_tabs ul.tabMenu li.active a span.count{background:#fff;margin-left:2px;padding:1px 5px;font:11px Helvetica Neue,Helvetica,sans-serif!important;-moz-border-radius:8px;-webkit-border-radius:8px;text-align:center;}#list_tabs ul.tabMenu li.active a span.count{background:#eee;color:#333;}#password_reset #content,#password_reset_confirmation #content,#password_reset_sent #content{width:auto;}form#reset-pw{padding:1em;}form #instructions-form{background:#f5f5f5;-moz-border-radius:5px;-webkit-border-radius:5px;border:1px solid #f5f5f5;border-top-color:#e7e7e7;padding:2em;margin-top:1em;position:relative;}#unlock-bird{float:left;width:150px;}#reset-input{margin-left:150px;}.verify-phone{margin-top:1em;padding:1em;-moz-border-radius:5px;border:1px solid #e7e7e7;background:#e2fdd5;}.verify-phone input{margin-left:-2px;}#instructions-form .hint{opacity:.7;filter:alpha(opacity=70);font-size:90%;}#instructions-form h4{font-weight:normal;font-size:185%;letter-spacing:-0.5px;color:#555;}#instructions-form fieldset em{display:block;font-style:normal;}#instructions-form #keep-void{margin-top:2em;color:#666;}label.new-password{float:left;width:150px;text-align:right;padding:10px 0 0 0;}#instructions-form div.hr{height:1px;background:#ddd;border-top:1px solid #fff;width:95%;margin:15px auto;}#instructions-form img#reset-bird-reverse{position:absolute;top:-50px;right:-10px;}#instructions-form p.special-note{color:#666;font-size:90%;margin-left:150px;}#instructions-form p.special-note strong{display:block;}.western #tagline{margin:8px 119px 0 0;width:355px;}.western #signin_menu{width:240px;}.western #signin_menu input[type="text"],.western #signin_menu input[type="password"]{width:230px;}.fr #big_signup{width:220px;}.western #footer{font-size:.8em;}.western #signin_menu{width:240px;}.western #signin_menu input[type="text"],.western #signin_menu input[type="password"]{width:230px;}.western .newuser h2{font-size:16px;}.western #signin_submit{margin:0;}.western #signup-form tr.captcha th{font-size:14px;}.western #signup-form #recaptcha_controls{height:auto;}body.western .home_page_control input.profilesubmit{width:185px;}body.fr .home_page_control input.profilesubmit{width:390px;}body.fr .home_page_control div#profiletext{float:none;width:100%;}body.fr .home_page_control div#profilebutton{float:none;margin:20px 0 0 0;}body.western #side .stats td .label{text-transform:none;}body.fr #side .stats a span.stats_count{font-size:12px;text-align:center;}body.western #settings_nav li a{font-size:.95em;}body.western #content .tabMenu li a{font-size:11px!important;padding:6px 10px 5px 8px;}body#profile_settings.western #content .tabMenu li a,body#profile_settings.western #content .tabMenu li{font-size:10px!important;}body.asian #content .tabMenu li a{font-size:12px!important;}body.asian #tweeting_button{width:60px;}#notices.western label{white-space:normal;display:block;}#notices.asian label{white-space:normal;display:block;}#password.western #nomatch{display:block;}body#settings.western #username_sample_url{display:block;}body#settings.western #username_msg{display:block;margin:-1em 0 0 0;}body#settings.fr #geotagging_info_link{font-size:10px;}body#password.fr .common-form th{text-align:right;padding:14px 0;}#invitations.western #service-credentials table th{font-size:14px;width:320px;}body.western .lists table.users-lists td.count{width:120px;white-space:nowrap;}body.western #lists_table tr td{white-space:nowrap;}body.western .col-tabset{width:145px;}body.western #sw-core{height:auto;min-height:400px;}body.western #sw-ui .t-unit,body.western #sw-dimensions .t-unit{float:none;display:block;width:100%;}body.western #sw-widget-behavior-default,body.western #sw-widget-behavior-all{margin:4px 0;}body.western #search-widget h3{margin:6px 0 4px;}body.de .buttons-page table tr td div.embed{height:123px;}body.fr .buttons-page table tr td div.embed{height:110px;}body.fr #built h3{white-space:nowrap;}#oauth_clients.it #content{background-position:right bottom;}body.western #recaptcha_controls,body.western #recaptcha_data,body.western #recaptcha_widget{height:12em;}.ja .dialog-form li label small{font-size:10px;}.btn,input[type=submit].btn,input[type=button].btn{background:#ddd url(../images/buttons/bg-btn.gif) repeat-x 0 0;font:11px/14px "Lucida Grande",sans-serif;width:auto;margin:0;overflow:visible;padding:4px 8px 5px;border-width:1px;border-style:solid;border-color:#ddd;border-bottom-color:#ccc;-moz-border-radius:4px;-khtml-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;color:#333;text-shadow:1px 1px 0 #fff;cursor:pointer;}.btn::-moz-focus-inner{padding:0;border:0;}.btn-m,input[type=submit].btn-m,input[type=button].btn-m{background-position:0 -200px;font-size:15px;line-height:20px!important;padding:5px 15px 6px;-moz-border-radius:5px;-khtml-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;}.btn-l,input[type=submit].btn-l,input[type=button].btn-l{background-position:0 -400px;font-size:20px;line-height:26px;padding:7px 20px 9px;-moz-border-radius:6px;-khtml-border-radius:6px;-webkit-border-radius:6px;border-radius:6px;}.btn-light{background-color:#add!important;background-image:url(http://a2.twimg.com/a/1302214109/images/buttons/bg-btn-light.gif)!important;border-color:#add #add #9cc!important;text-shadow:1px 1px 0 #dff!important;}.btn-dark{background-color:#59a!important;background-image:url(../images/buttons/bg-btn-dark.gif)!important;border-color:#59a #59a #489!important;color:#fff!important;text-shadow:-1px -1px 0 #59a!important;}.btn-blue{background-color:#39d!important;background-image:url(../images/buttons/bg-btn-blue.gif)!important;border-color:#39d #39d #28c!important;color:#fff!important;text-shadow:-1px -1px 0 #39d!important;}.btn-chart{background-color:#9c2!important;background-image:url(../images/buttons/bg-btn-chart.gif)!important;border-color:#9c2 #9c2 #8b1!important;text-shadow:1px 1px 0 #df6!important;}.btn-mint{background-color:#bdb!important;background-image:url(../images/buttons/bg-btn-mint.gif)!important;border-color:#bdb #bdb #aca!important;text-shadow:1px 1px 0 #efe!important;}.btn-green{background-color:#272!important;background-image:url(../images/buttons/bg-btn-green.gif)!important;border-color:#272 #272 #161!important;color:#fff!important;text-shadow:-1px -1px 0 #272!important;}.btn-pink{background-color:#daa!important;background-image:url(../images/buttons/bg-btn-pink.gif)!important;border-color:#daa #daa #c99!important;text-shadow:1px 1px 0 #fdd!important;}.btn-red{background-color:#a22!important;background-image:url(../images/buttons/bg-btn-red.gif)!important;background-position:0 0;border-color:#a22 #a22 #911!important;text-shadow:-1px -1px 0 #a22!important;color:#fff!important;}.btn-yellow{background-color:#fa2!important;background-image:url(../images/buttons/bg-btn-yellow.gif)!important;border-color:#fa2!important;color:#333!important;color:rgba(0,0,0,.75)!important;text-shadow:0 1px 1px rgba(255,255,255,.5)!important;}.btn:hover,.btn:focus,input[type=submit].btn:hover,input[type=submit].btn:focus,button.btn:hover,button.btn:focus{border-color:#999 #999 #888;background-position:0 -6px;color:#000;text-decoration:none;}.btn-light:hover,.btn-light:focus{border-color:#7aa #7aa #699;}.btn-dark:hover,.btn-dark:focus{border-color:#267 #267 #156;color:#fff;}.btn-blue:hover,.btn-blue:focus{border-color:#17b #17b #06a;color:#fff;}.btn-chart:hover,.btn-chart:focus{border-color:#7a1 #7a1 #690;}.btn-mint:hover,.btn-mint:focus,input[type=submit].btn-mint:hover,input[type=submit].btn-mint:focus,button.btn-mint:hover,button.btn-mint:focus{border-color:#8a8 #8a8 #797!important;}.btn-green:hover,.btn-green:focus,input[type=submit].btn-green:hover,input[type=submit].btn-green:focus,button.btn-green:hover,button.btn-green:focus{background-color:#272!important;border-color:#050 #050 #040!important;color:#fff;}.btn-pink:hover,.btn-pink:focus,input[type=submit].btn-pink:hover,input[type=submit].btn-pink:focus,button.btn-pink:hover,button.btn-pink:focus{border-color:#a88 #a88 #977!important;}.btn-red:hover,.btn-red:focus,input[type=submit].btn-red:hover,input[type=submit].btn-red:focus,button.btn-red:hover,button.btn-red:focus{background-color:#a22!important;border-color:#611 #611 #500!important;color:#fff;}.btn-yellow:hover,.btn-yellow:focus,input[type=submit].btn-yellow:hover,input[type=submit].btn-yellow:focus,button.btn-yellow:hover,button.btn-yellow:focus{background-color:#fa2!important;border-color:#fa2!important;color:rgba(0,0,0,.75)!important;text-shadow:0 1px 1px rgba(255,255,255,.25)!important;}.btn-m:hover,.btn-m:focus,input[type=submit].btn-m:hover,input[type=submit].btn-m:focus,button.btn-m:hover,button.btn-m:focus{background-position:0 -206px;}.btn-l:hover,.btn-l:focus,input[type=submit].btn-l:hover,input[type=submit].btn-l:focus,button.btn-l:hover,button.btn-l:focus{background-position:0 -406px;}button:active,button.btn:active,input[type=submit]:active,button.btn-dark:active,button.btn-light:active,.btn:active,.btn-red:active,.btn-green:active{background-image:none!important;text-shadow:none!important;outline:none!important;}.dbtn,.dbtn:hover,.dbtn:focus,.dbtn:active,button.dbtn:hover,button.dbtn:focus{background:#eee;border-color:#ddd;color:#aaa;text-shadow:none;}.btn-light.dbtn,.btn-light.dbtn:hover,.btn-light.dbtn:focus,.btn-light.dbtn:active{background:#dee;border-color:#cdd;color:#9aa;}.btn-dark.dbtn,.btn-dark.dbtn:hover,.btn-dark.dbtn:focus,.btn-dark.dbtn:active{background:#aad5dd;border-color:#99c5cc;color:#ddf6f6;}.btn-blue.dbtn,.btn-blue.dbtn:hover,.btn-blue.dbtn:focus,.btn-blue.dbtn:active{background:#bde;border-color:#acd;color:#def;}.btn-chart.dbtn,.btn-chart.dbtn:hover,.btn-chart.dbtn:focus,.btn-chart.dbtn:active{background:#deb;border-color:#cda;color:#ab9;}.btn-mint.dbtn,.btn-mint.dbtn:hover,.btn-mint.dbtn:focus,.btn-mint.dbtn:active{background:#ded;border-color:#cdc;color:#9a9;}.btn-green.dbtn,.btn-green.dbtn:hover,.btn-green.dbtn:focus,.btn-green.dbtn:active{background:#aca;border-color:#9b9;color:#ded;}.btn-pink.dbtn,.btn-pink.dbtn:hover,.btn-pink.dbtn:focus,.btn-pink.dbtn:active{background:#edd;border-color:#dcc;color:#a99;}.btn-red.dbtn,.btn-red.dbtn:hover,.btn-red.dbtn:focus,.btn-red.dbtn:active{background:#caa;border-color:#b99;color:#edd;}.btn.right{float:right;}.geo_new{color:#C00;}.geo_progress{color:#999;}.crosshairs{display:inline-block;background:url(../images/sprite-icons.png) -64px -80px no-repeat;height:11px;width:11px;margin:0 4px 0 0;vertical-align:middle;}a.geo_disable_webclient span{display:inline-block;background:url(../images/sprite-icons.png) no-repeat -112px -80px;height:7px;width:7px;margin:0 3px;vertical-align:middle;}a:hover.geo_disable_webclient span{background-position:-128px -80px;}.near{color:#8c8c8c;font-size:14px;}a.places-nearby{position:absolute;left:385px;top:148px;}.geo_notifications{display:none;}#place_link:focus{outline:none;}#place_link span.place_icon{display:inline-block;background:url(../images/sprite-icons.png) no-repeat -240px -64px;height:11px;width:7px;vertical-align:middle;margin-right:4px;}#geo_browser_help_banner{color:#FFF;font:12px Verdana;position:fixed;right:0;text-align:left;top:0;z-index:10000;}#geo_browser_help_banner.geo_firefox{background:#333 url(../images/geo_firefox_help_banner_back.png) no-repeat right;-moz-border-radius-bottomleft:4px;height:108px;}#geo_browser_help_banner.geo_chrome{background:#333 url(../images/geo_chrome_help_banner_back.png) no-repeat right;-webkit-border-radius-bottomleft:4px;height:65px;}#geo_browser_help_banner.geo_ie_gtb{background:#333 url(../images/geo_ie_gtb_help_banner_back.png) no-repeat right;height:108px;}#geo_browser_help_banner.geo_firefox>div{margin:8px 183px -3px 10px;}#geo_browser_help_banner.geo_chrome>div{margin:25px 120px 20px 20px;}#geo_browser_help_banner.geo_ie_gtb>div{margin:8px 200px -3px 10px;}#geo_browser_help_banner img{margin-right:6px;position:relative;top:8px;}ul.places_list{background-color:#FFF;border:1px solid #AAA;padding:4px 0 4px 0;text-align:left;}#place_content ul.places_list li,ul.places_list li{color:#333;padding:3px 8px 3px 4px;cursor:pointer;}.geo_more_places{border-top:1px solid #ccc;padding-top:5px;margin-top:4px;}#place_content ul.places_list li:hover,#place_content ul.places_list a:hover{color:white;background-color:#666;outline:none;}li .place_item_icon{background:transparent;display:inline-block;height:9px;margin:0 4px 2px 0;vertical-align:middle;width:10px;}li.selected .place_item_icon{background:url(../images/sprite-icons.png) no-repeat -160px -16px;}li .refresh{background:url(../images/sprite-icons.png) no-repeat -96px -80px;width:7px;margin:0 5px 2px 2px;}ul.places_list li:hover .refresh{background:url(../images/sprite-icons.png) no-repeat -80px -80px;}li .clear{display:inline-block;background:url(../images/sprite-icons.png) no-repeat -128px -80px;height:7px;width:7px;margin:0 5px 0 2px;vertical-align:middle;}ul.places_list li:hover .clear{background:url(../images/sprite-icons.png) no-repeat -112px -80px;}li .place_icon{display:inline-block;background:url(../images/sprite-icons.png) no-repeat -224px -64px;height:11px;width:7px;margin-right:4px;vertical-align:middle;}li .more_places{background:transparent;}li .place_details{color:#999;}#geo-promo-hoverer{width:420px;font-size:11px;text-align:left;visibility:hidden;}#geo-promo-hoverer .hoverer-inner{padding:15px;}#geo-promo-hoverer .hovercard-divot{left:40px;top:-11px;}#geo_modal.position_above .hovercard-divot{bottom:-11px;}#geo_modal.position_below .hovercard-divot{top:-11px;}#geo-promo-hoverer .tiny-map{float:right;padding:0 0 0 20px;}#geo_dialog_descr{margin:10px 0 10px 0;font-size:13px;}#geo_not_now{position:relative;top:5px;margin-left:8px;}#geo_turn_location_on{font-weight:bold;}a.geo_disable_webclient{color:#999;font-family:tahoma,sans-serif;font-size:12px;font-weight:bold;line-height:12px;text-shadow:1px 1px 1px #FFF;}a:hover.geo_disable_webclient{text-decoration:none;}.geo-pin{background:transparent url(../images/sprite-icons.png) no-repeat scroll -224px -64px;display:inline-block;height:11px;line-height:1.1em;width:7px;}.geo_map_with_place{width:490px;}#map_canvas{width:270px;height:170px;float:left;margin:1px;}.map_close{color:#999;text-decoration:none;-moz-border-radius:2px;background-color:#ddd;display:block;font-size:15px;margin:-2px;padding:0 4px 2px;position:absolute;right:0;top:0;text-decoration:none;}.map_close:hover{text-decoration:none;}.geo_map_place_details{width:195px;margin:10px;float:left;color:#333;}.geo_map_place_name{font-weight:bold;font-size:13px;margin-bottom:4px;}.geo_map_place_tweets{margin-top:5px;}.geo_map_place_tweets a{color:#2276bb;}#geo_map_progress.position_above .hovercard-divot{bottom:-11px;}#geo_map_progress.position_below .hovercard-divot{top:-11px;}#geo_map_progress .hoverer-inner{width:55px;}#geo_map_fail{display:none;}#geo_map_spinner{background:url(../images/spinner.gif) no-repeat;margin:10px 20px;}.place_search_dialog .hanging{width:450px;}.geo_place_search_table{font-family:'Lucida Grande',sans-serif;font-size:13px;}.geo_place_search_col1{font-weight:bold;text-align:right;padding-right:7px;padding-left:0;}.geo_place_search_city{padding-bottom:14px;padding-left:7px;}#geo_city{margin:0 0 16px 8px;}#geo_poi_hint{font-family:'Lucida Grande',sans-serif;font-size:11px;color:#999;padding:4px 0 8px 7px;}#place_search_results{padding:5px 0 0 7px;display:none;width:310px;}#place_search_done,#place_search_cancel{margin-top:20px;margin-bottom:5px;}#place_search_form input{border:1px solid #aaa!important;font-size:1em;outline:none;padding:5px;width:282px;vertical-align:middle;}#place_search_form #city_search_query{width:336px;}#place_search_form input:focus{outline:none;border-color:rgba(82,168,236,.75)!important;box-shadow:0 0 8px rgba(82,168,236,.5);-moz-box-shadow:0 0 8px rgba(82,168,236,.5);-webkit-box-shadow:0 0 8px rgba(82,168,236,.5);}.place_search_submit{-moz-border-radius-bottomright:3px;-moz-border-radius-topright:3px;border-style:solid;border-width:1px;margin-left:-1px;cursor:pointer;padding:.4em .9em;border-color:#999!important;padding-bottom:5px!important;padding-top:5px!important;vertical-align:middle;background:url(../images/nav_search_submit.png) repeat scroll -2px 0 transparent!important;}.place_search_submit:hover{background:url(../images/nav_search_submit.png) -2px -25px!important;}.place_search_submit:active{background:url(../images/nav_search_submit.png) -2px -50px!important;}.place_search_submit.loaddisableding,.place_search_submit.loaddisableding:hover,.place_search_submit.loaddisableding:active{background:#eee url(../images/spinner.gif) no-repeat 5px 5px!important;}#place_search_results li{margin:10px 0 0 0;list-style-type:none;white-space:nowrap;overflow:hidden;}#place_search_results .place_noicon,ul.place_search_dropdown.places_list .place_noicon{display:inline-block;margin-left:15px;}.wait{cursor:wait;}ul.place_search_dropdown.places_list li{padding-left:8px;white-space:nowrap;}.places_list li.hover{color:white;background-color:#666;outline:none;}ul.places_list{display:none;position:absolute;background-color:#FFF;border:1px solid #AAA;padding:4px 0 4px 0;text-align:left;z-index:9999;}#place_search_go_back{margin-top:12px;}#place_search_go_back,#change_city{font-weight:normal;color:#4d94be;}.geo_place_search_hint{padding:4px 0 0 7px;font-size:11px;color:#999;}div.geo_add_place{margin-top:20px;}div.geo_add_place a{font-weight:bold;}.geo_search_message{margin-top:12px;}.geo_next_prev{margin-top:12px;}#geo_prev_result{margin-right:20px;}.place_creation_dialog .hanging{width:650px;}.place_creation_dialog .modal-inner h2{margin:0!important;}.place_creation_dialog .modal-content{padding:0;}.place_creation_dialog .geo_map_canvas{width:312px;}.geo_place_search_table{font-family:'Lucida Grande',sans-serif;font-size:13px;width:100%;}.geo_place_creation_hint{padding:8px 0 0 7px;font-size:11px;color:#999;}.geo_form_input{border:1px solid #aaa!important;font-size:1em;outline:none;padding:5px;width:210px;vertical-align:middle;}.geo_form_input:focus{outline:none;border-color:rgba(82,168,236,.75)!important;box-shadow:0 0 8px rgba(82,168,236,.5);-moz-box-shadow:0 0 8px rgba(82,168,236,.5);-webkit-box-shadow:0 0 8px rgba(82,168,236,.5);}.geo_place_creation_row2{padding-top:15px;}.geo_place_city{margin:12px 0 15px;}#geo_creation_error{margin-top:8px;font-size:11px;}.geo_spinner{display:inline-block;background:url(../images/spinner.gif);height:14px;width:14px;margin-left:15px;line-height:1.9em;vertical-align:middle;}.geo_map{float:right;}.geo_place_create{padding:25px;width:280px;}.geo_place_create ul{margin:18px 0 20px 0;}.geo_place_create li{margin:10px 0;white-space:nowrap;overflow:hidden;}.geo_map_hint{opacity:0;width:160px;position:absolute;z-index:20;text-align:center;}.geo_map_hint span{display:inline-block;vertical-align:bottom;background-image:url(../images/geo_creation_hint_arrow.gif);background-repeat:no-repeat;width:21px;height:11px;}.geo_map_hint div{background-color:#424242;color:white;text-align:left;padding:10px;font-size:11px;font-weight:bold;}.geo_map_place_bubble{opacity:0;display:none;position:absolute;z-index:20;text-align:center;margin-top:10px;white-space:nowrap;}.geo_map_place_bubble span{display:inline-block;vertical-align:bottom;background-image:url(../images/geo_creation_hint_arrow.gif);background-repeat:no-repeat;width:21px;height:11px;}.geo_map_place_bubble>div{background-color:#424242;color:white;text-align:left;padding:10px;font-size:11px;font-weight:bold;}.geo_go_back{line-height:1.9em;margin:0 10px;}.geo_place_details{color:#aaa;}.geo_map_link_separator{margin:0 5px 0 10px;color:#aaa;}.button{-moz-border-radius:4px;-khtml-border-radius:4px;-webkit-border-radius:4px;background:#ddd url(../images/buttons/bg-btn.gif) repeat-x 0 0;border-bottom-color:#ccc;border-color:#ddd;border-radius:4px;border-style:solid;border-width:1px;color:#333;cursor:pointer;display:inline;font:11px/14px "Lucida Grande",Sans-serif;margin:0;overflow:visible;padding:4px 8px 5px;text-shadow:1px 1px 0 #fff;}.button::-moz-focus-inner{padding:0;border:0;}.button:focus{outline:none;}.button:hover,.button:focus{background-position:0 -6px;border-color:#999 #999 #888;color:#000;}.button:active{background-image:none;text-shadow:none;outline:none;}#tweeting_controls a{line-height:13px;}#gear_dropdown{padding:4px 5px 5px;}#gear_dropdown span{background-image:url(../images/sprite-icons.png);background-position:-32px -63px;background-repeat:no-repeat;display:inline-block;width:22px;}ul.dropdown{display:none;position:absolute;width:200px;padding:4px 0;text-align:left;border:1px solid #666;background-color:#fff;z-index:9999;}ul.dropdown li a,ul.dropdown li label,ul.dropdown li input[type="checkbox"]{display:inline-block;font:11px 'Lucida Grande',Arial,sans-serif;color:#666;position:relative;padding:4px 5px;vertical-align:top;}ul.dropdown li .loaddisableding-spinner{display:inline-block;position:relative;top:4px;left:1px;margin-left:4px;}ul.dropdown li a{padding:4px 5px 4px 27px;}ul.dropdown li a{display:block;color:#666;text-decoration:none;}ul.dropdown li:hover{color:#fff;background-color:#666;}ul.dropdown li:hover *{color:#fff;}ul.dropdown li.divider{border-top:1px solid #ddd;}ul.dropdown i{background:url(../images/sprite-icons.png) repeat no-repeat;font-size:10px;left:7px;position:absolute;top:4px;width:15px;}#get_location_icon{background:url(../images/sprite-icons.png) -160px -64px no-repeat;display:inline-block;_display:inline;height:11px;width:11px;vertical-align:middle;}#location_spinner{display:none;height:11px;width:11px;vertical-align:middle;}.share-location-loaddisableding #location_spinner{display:inline-block;}.share-location-loaddisableding #get_location_icon{display:none;}a.a-btn{zoom:1;background:#ddd url(../images/buttons/bg-btn.gif) repeat-x scroll 0 0;cursor:pointer;text-shadow:1px 1px 0 #fff!important;border-color:#ddd #ddd #ccc!important;border-style:solid;border-width:1px!important;text-decoration:none;padding:4px 8px 5px;line-height:14px;font-size:11px;font-family:"lucida grande",helvetica,tahoma,arial;display:inline-block;_display:inline;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;}a.a-btn,a.a-btn:visited{color:#333!important;}a.a-btn:hover,a.a-btn:focus{text-decoration:none;border-color:#999 #999 #888!important;color:#000;outline:none;}a.a-btn:active{background-image:none;outline:none;}:focus{-moz-outline-style:none;}a.a-btn-m{font-size:15px;font-family:"helvetica neue",arial,sans-serif;padding:5px 15px 6px;line-height:20px;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;background-position:0 -200px;}a.a-btn-l{font-size:20px;line-height:26px;padding:7px 20px 8px;-moz-border-radius:6px;-webkit-border-radius:6px;border-radius:6px;font-family:"helvetica neue",arial,sans-serif;background-position:0 -400px;}a.btn-disabled{opacity:.6;filter:alpha(opacity=60);background-image:none;}.twitter-connect{border:0;outline:none;text-indent:-99999px;display:inline-block;background-repeat:no-repeat;background-position:top left;}.twitter-button{font:12px Arial,sans-serif;color:#fff;background:#1D6B9C url(../images/oauth2/gradient-background.png) repeat-x;text-indent:0;border:1px solid #18566A;display:inline-block;-moz-border-radius:4px;-webkit-border-radius:4px;-border-radius:4px;text-shadow:0 -1px 0 #18566A;}.twitter-button:hover{border:1px solid #00242C;background-position:left -23px;text-decoration:none;}.twitter-button:active{border:1px solid #044D77;background-position:left -46px;text-decoration:none;color:rgba(255,255,255,0.8);}.twitter-connect-small{background:url(../images/oauth2/connect_129px.png) no-repeat;width:129px;height:19px;}.twitter-connect-small:hover{background-position:left -19px;}.twitter-connect-small:active{background-position:left -38px;}.twitter-connect-medium{background:url(../images/oauth2/connect_146px.png) no-repeat;width:146px;height:23px;}.twitter-connect-medium:hover{background-position:left -23px;}.twitter-connect-medium:active{background-position:left -46px;}.twitter-connect-large{background:url(../images/oauth2/connect_170px.png) no-repeat;width:170px;height:26px;}.twitter-connect-large:hover{background-position:left -26px;}.twitter-connect-large:active{background-position:left -52px;}.twitter-connect-xlarge{background:url(../images/oauth2/connect_236px.png) no-repeat;width:236px;height:38px;}.twitter-connect-xlarge:hover{background-position:left -38px;}.twitter-connect-xlarge:active{background-position:left -76px;}.twitter-connect-box{font:13px/17px Lucida Grande,"Lucida Grande",Arial,Helvetica,sans-serif;padding:8px 10px 9px 10px;width:200px;background:#C7E0EC url(../images/oauth2/rays-box.jpg) no-repeat center top;color:#001F33;text-shadow:0 1px 0 #E5F0F6;border-radius:5px;-moz-border-radius:4px;-webkit-border-radius:4px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.3);-moz-box-shadow:0 1px 0 rgba(0,0,0,.3);box-shadow:0 1px 0 rgba(0,0,0,.3);display:inline-block;vertical-align:top;}.twitter-connect-box p{margin:0 0 8px 0;padding:0;}.twitter-connect-box-small{font-size:10px;line-height:14px;width:129px;}.twitter-connect-box-medium{font-size:11px;line-height:15px;width:146px;}.twitter-connect-box-large{font-size:11px;line-height:15px;width:170px;}.twitter-connect-box-xlarge{font-size:12px;line-height:17px;width:236px;}.follow-medium{text-decoration:none;padding-right:7px;padding-left:2px;*padding:0 7px 0 0;}.follow-medium i{height:23px;width:23px;display:inline-block;border-right:1px solid #73AFD5;}.follow-medium i b{display:inline-block;background:url(../images/oauth2/t_170px.png) no-repeat 3px 3px;height:23px;width:22px;vertical-align:middle;border-right:1px solid #094B60;}.follow-medium .status{padding-left:4px;}.following-notice,.pending-notice{background-image:none;background:#eee;border:1px solid #ccc;color:#333;text-shadow:0 1px 0 #fff;cursor:default;padding:1px 8px 0;font:12px Arial,sans-serif;text-indent:0;display:inline-block;-moz-border-radius:4px;-webkit-border-radius:4px;-border-radius:4px;}.pending-notice{padding:5px 8px 2px;}.following-notice:active,.pending-notice:active{color:#333;text-shadow:0 1px 0 #fff;}.following-notice span.at,.pending-notice span.at{color:#666;}.following-notice a,.pending-notice a{color:#196698;font-weight:normal;text-decoration:none;}.following-notice a:hover,.pending-notice a:hover{text-decoration:underline;}.following-notice i{border-right:1px solid #eee;width:15px;}.pending-notice i{border-right:1px solid #eee;width:10px;height:9px;}.following-notice i b{border-right:0;width:15px;}.pending-notice i{border-right:0;width:9px;height:17px;}.following-notice i b{background:url(../images/oauth2/check.png) no-repeat 4px 7px;}.pending-notice i b{position:relative;top:-2px;border-right:none;width:10px;height:9px;background:url(../images/sprite-icons.png) no-repeat -192px -16px;}.twitter-loaddisableding{font:12px/15px Arial,Helvetica,sans-serif;color:#fff;background:#eee;border:1px solid #ccc;color:#333;text-shadow:0 1px 0 #fff;cursor:default;text-indent:0;padding:5px 8px 4px 8px;-moz-border-radius:4px;-webkit-border-radius:4px;-border-radius:4px;display:block;width:100px;margin-top:-3px;}fieldset.common-form ul.discover-buttons li{padding:15px 0 5px;margin-bottom:0;}.dialog-form fieldset.common-form input[type="text"],.dialog-form fieldset.common-form input[type="password"],.dialog-form fieldset.common-form textarea{border:1px solid #888;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;font-size:13px;background:#fff;padding:4px 5px;}#discoverability_header,#discoverability_dialog,#discoverability_footer{display:none;}.dialog-form li .input-wrapper{display:inline-block;vertical-align:bottom;}.dialog-form li{margin-bottom:3px;}.dialog-form li label small{font-weight:normal;}.dialog-form fieldset.common-form ul li label{display:inline-block;font-size:13px;line-height:18px!important;padding:0 10px 0 0;width:95px;margin-top:3px;vertical-align:top;white-space:normal;}.dialog-form li input[type=text]{line-height:20px;width:250px;}.dialog-form li textarea{width:250px;height:50px;}.dialog-form li strong{display:block;font-size:13px;margin:3px 0 4px;}.dialog-form li,.dialog-form p{color:#555;line-height:18px;}.discoverability-dialog span.privacy-statement{color:#555;font:12px/16px 'Lucida Grande',sans-serif;padding:0 10px;}.discoverability-dialog span.privacy-statement a{font-weight:bold;}.discoverability-dialog .discoverability-settings{border-top:1px solid #eee;}.discoverability-dialog .modal-content fieldset{margin-bottom:0;padding-bottom:0;}.discover-buttons{border-top:1px solid #eee;}.discover-buttons button{margin:0 10px 0 0;}.help-discover{background:url(../images/sprite-icons.png) no-repeat scroll -208px 0 transparent;display:inline-block;height:14px;margin-left:5px;vertical-align:top;width:14px;}.twitter_feature_loaddisableder{height:0;width:0;overflow:hidden;display:none;position:absolute;}#twitter_hover_cards_loaddisableder{position:relative;}.hovercard,.hovercard-loaddisableding-above-below .hovercard-content-inner{width:290px;}.hovercard .hovercard-inner{font-size:11px;text-align:left;overflow:visible;}.hovercard-loaddisableding-above-below{width:100px;}.hovercard-loaddisableding-above-below .hovercard-inner{height:25px;}.hovercard-loaddisableding-inline .hovercard-inner{height:68px;}.bd .loaddisableding-inline-spinner{position:absolute;top:10px;left:10px;height:48px;width:48px;text-align:center;overflow:hidden;}.bd .loaddisableding-inline-spinner img{display:block;width:14px;height:14px;margin:17px auto;}.hovercard-inner .loaddisableding-above-below,.hovercard-inner .loaddisableding-inline,.hovercard-inner .user-dne{display:none;overflow:hidden;}.hovercard-inner .user-dne{opacity:0;}.hovercard-inner .loaddisableding-above-below .loaddisableding-msg{background:url(../images/spinner.gif) no-repeat;padding-left:20px;}.hovercard-loaddisableding-above-below .loaddisableding-above-below{display:block!important;margin:0;width:100px;overflow:hidden;position:relative;top:4px;left:4px;color:#666;font-size:11px;}.hovercard-loaddisableding-inline .loaddisableding-inline{display:block!important;overflow:hidden;margin:0;color:#666;font-size:11px;}.hovercard-user-dne .user-dne{display:block!important;}.hovercard-loaddisableding-above-below .hovercard-content,.hovercard-loaddisableding-inline .hovercard-content{width:0;height:0;overflow:hidden;}.hovercard-inner .bd{padding:10px;overflow:hidden;}.hovercard-inner a{cursor:pointer;}.hovercard-inner p.location{height:16px;}.hovercard-inner .avatar,.loaddisableding-inline-graphic{float:left;display:block;width:48px;height:48px;}.loaddisableding-inline-graphic{background-repeat:none;background-position:0 0;background-color:transparent;}.hovercard-inner .bio{margin-left:56px;}.hovercard-inner .bio span em{display:block;font-style:normal;}.not-inline .fn-inline,.inline .fn-above{display:none;}.fn-above{font-weight:bold;font-family:"helvetica neue",helvetica,arial,sans-serif;font-size:15px;color:#333;}.hovercard-inner .bio p{line-height:16px;}.hovercard-inner .hovercard-inner-footer{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0 0 5px 5px;background:#f6f6f6;height:39px;position:relative;}.hovercard-inner .action-dropdowns{position:absolute;left:231px;top:7px;}.hovercard-inner .setting{background:url(../images/sprite-icons.png) -96px -48px no-repeat;width:16px;height:16px;margin-left:5px;display:block;float:right;}.hovercard-inner .sms-setting-off{background-position:-160px -48px;}.hovercard-inner .sms-setting-not-off{background-position:-48px -48px;}.hovercard-inner .replies-setting-off{background-position:-144px -48px;}.hovercard-inner .replies-setting-not-off{background-position:0 -48px;}.hovercard-inner .shares-setting-off{background-position:-176px -48px;}.hovercard-inner .shares-setting-not-off{background-position:-96px -48px;}.hovercard-inner .is-following{background:url(../images/sprite-icons.png) -160px -16px;width:10px;height:9px;display:block;float:left;margin-right:3px;position:relative;top:2px;}.hovercard-inner .sn a{font-size:14px;line-height:16px;font-weight:bold;}.not-inline .hovercard-inner .sn a{font-size:11px;line-height:14px;font-weight:normal;}.inline .hovercard-inner .at_symbol{display:none;}.hovercard-inner .not-following,.hovercard-inner .following,.hovercard-inner .is-you{position:absolute;top:7px;left:11px;}.hovercard-inner .following-controls,.hovercard-inner .is-you{font-weight:bold;padding:5px 0 5px 0;}.hovercard-inner .following-controls span{cursor:pointer;float:left;}.hovercard-inner .following-controls .you-follow-user{cursor:text;}.hovercard .not-following .following-controls,.hovercard .following .follow-controls,.hovercard .blocking .follow-controls{display:none;}.hovercard-inner .sn img{position:relative;top:2px;}.hovercard-inner .user i{display:inline-block;_display:inline;background-position:-176px -32px;width:15px;background-image:url(../images/sprite-icons.png);background-repeat:no-repeat;height:13px;outline-color:-moz-use-text-color;overflow:hidden;margin:0 3px -3px 0;}.hovercard-inner .user b{background-image:url(../images/sprite-icons.png);background-repeat:no-repeat;background-position:0 -64px;}.hovercard-inner .action-menu{padding-right:0;}.hovercard-inner .action-menu i{background-position:-32px -64px;width:22px;}.hovercard-inner .action-menu span{visibility:hidden;}.hovercard-inner .list-menu i{background-position:-96px -64px;width:22px;margin:0 0 -3px 0;}.hovercard .action-list{background-color:#fff;border:1px solid #666;margin-top:-1px;padding:0;position:absolute;left:243px;margin-top:-12px;text-align:left;width:200px;z-index:9999;}.ie .hovercard .action-list,.firefox-windows .hovercard .action-list{left:244px;}.hovercard .action-list li a:hover{color:#fff;background-color:#666;}.hovercard .action-list li a{color:#666;display:block;text-decoration:none;padding:6px 5px 6px 7px;}.hovercard .action-list i{float:left;width:15px;height:13px;margin-right:4px;display:inline;background-image:url(../images/sprite-icons.png);}.hovercard .action-list .mention i{background-position:-16px -32px;}.hovercard .action-list .mention:hover i{background-position:0 -32px;}.hovercard .action-list .direct-message i{background-position:-48px -32px;}.hovercard .action-list .direct-message:hover i{background-position:-32px -32px;}.hovercard .action-list .follow i{background-position:-176px -32px;}.hovercard .action-list .follow:hover i{background-position:-160px -32px;}.hovercard .action-list .remove i{background-position:-208px -32px;}.hovercard .action-list .remove:hover i{background-position:-192px -32px;}.hovercard .action-list .unfollow i{background-position:-112px -32px;}.hovercard .action-list .unfollow:hover i{background-position:-96px -32px;}.hovercard .action-list .report-for-spam i{background-position:-272px -32px;}.hovercard .action-list .report-for-spam:hover i{background-position:-256px -32px;}.hovercard .action-list .block i{background-position:-144px -32px;}.hovercard .action-list .block:hover i{background-position:-128px -32px;}.hovercard .action-list .unblock i{background-position:-144px -32px;}.hovercard .action-list .unblock:hover i{background-position:-128px -32px;}.hovercard-inner .description{color:#656565;clear:left;overflow:hidden;height:auto;padding-top:3px;}.hovercard-inner .description-inactive{height:0;}.hovercard .direct-message{display:none;}.hovercard .following-you .direct-message{display:block;}.hovercard .not-following .unfollow,.hovercard .following .follow,.hovercard .not-blocking .unblock,.hovercard .blocking .block,.hovercard .blocking .direct-message,.hovercard .blocking .follow,.hovercard .blocking .report-for-spam{display:none;}.hovercard-inner ul.user_stats{overflow:hidden;}.hovercard-inner ul.user_stats,.hovercard-inner .user_stats li{margin:0;padding:0;list-style:none;}.hovercard-inner .description p,.hovercard-inner .description ul{padding:3px 0;color:#333;}.hovercard-inner .user_stats li{float:left;border-right:1px solid #eee;padding:1px 12px;letter-spacing:-0.5px;}.hovercard-inner .user_stats li.last{border-right-width:0;}.hovercard-inner .user_stats li.first{padding-left:0;}.hovercard-inner .user_stats .stat{font-weight:bold;display:block;color:#333;font-size:12px;font-family:"Helvetica Neue",Arial,sans-serif;letter-spacing:.5px;}.hovercard-inner .user_stats .type{color:#666;}.hovercard .hovercard-divot{position:absolute;left:24px;width:27px;height:15px;z-index:999;}.position_above .hovercard-divot{top:auto;bottom:-15px;background:url(../images/divvy.png) no-repeat;}.position_above{top:auto!important;}.position_below .hovercard-divot{bottom:auto;top:-15px;background:url(../images/divvy-up.png) no-repeat;}.ie .position_above .hovercard-divot{background:url(../images/divvy.gif) no-repeat;}a.signin{background:#7fb3cc;margin-left:4px;padding:5px 6px 6px;text-decoration:none;font-weight:bold;color:#fff;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}a.signin span{background-image:url(../images/toggle_down_light.png);_background-image:url(../images/toggle_down_light.gif);background-repeat:no-repeat;background-position:100% 50%;padding:4px 16px 6px 0;}body.signin-island a.signin,body.signin-island a.signin:hover,body.signin-island a.signin:focus{background:none;}body.signin-island a.void,body.signin-island a.void:hover,body.signin-island a.void:focus{background:none repeat scroll 0 0 #CCC;}body.signin-island .signin span{color:#27B;background:url(../images/toggle_down_dark.png) 100% 50% no-repeat #fff;_background:url(../images/toggle_down_dark.gif) 100% 50% no-repeat #fff;}body.signin-island .void span{background:url(../images/toggle_up_dark.png) 100% 50% no-repeat #CCC;_background:url(../images/toggle_up_dark.gif) 100% 50% no-repeat #CCC;color:#333;}body.signin-island #have_an_account{-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;line-height:22px;background-color:#FFF;font-size:11px;padding:5px 0 7px 10px;zoom:1;color:#666;}a.void{background:#ccc;-webkit-border-bottom-left-radius:0;-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomleft:0;-moz-border-radius-bottomright:0;border-radius-bottom-left:0;border-radius-bottom-right:0;-webkit-box-shadow:0 3px 3px rgba(0,0,0,0.3);-mox-box-shadow:0 3px 3px rgba(0,0,0,0.3);box-shadow:0 3px 3px rgba(0,0,0,0.3);color:#000;}#signin_controls{position:relative;top:3px;zoom:1;}.signin-on a.signin span{background-image:url(../images/toggle_up_dark.png);_background-image:url(../images/toggle_up_dark.gif);}a.signin.void span{background-image:url(../images/toggle_up_dark.png);_background-image:url(../images/toggle_up_dark.gif);color:#333;}#signin_menu{position:absolute;top:100%;right:0;margin:0;z-index:100;width:230px;padding:8px;-webkit-border-radius:5px;-webkit-border-top-right-radius:0;-moz-border-radius:5px;-moz-border-radius-topright:0;border-radius:5px;border-radius-top-right:0;-webkit-box-shadow:0 3px 3px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 3px rgba(0,0,0,0.3);box-shadow:0 3px 3px rgba(0,0,0,0.3);text-align:left;line-height:16px;background:#fff;border:5px solid #ccc;}.signin-on #signin_menu{display:block;}#signin{margin:0;font-size:11px;color:#666;}#signin p{margin:0;}#signin .textbox label{display:block;padding:0 0 3px;}#signin .textbox input{background:#fff;display:block;width:218px;margin:0 0 8px;padding:5px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;font:13px "Lucida Grande",Arial,Sans-serif;}#signin .textbox input:focus{border-color:#ccc;outline-width:0;}#signin p.forgot,#signin p.forgot-username{display:inline;line-height:20px;}.remember{padding:4px 0 12px;}#signin_submit{background:#39d url(../images/bg-btn-blue.png) repeat-x 0 0;width:auto;overflow:visible;margin:0 5px 0 0;padding:4px 10px 5px;border:1px solid #39d;-moz-border-radius:4px;-khtml-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;font:bold 11px "Lucida Grande",Arial,Sans-serif;color:#fff;text-shadow:0 -1px 0 #39d;}#signin_submit::-moz-focus-inner{padding:0;border:0;}#signin_submit:hover,#signin_submit:focus{background-position:0 -5px;cursor:pointer;}a.signin:hover,a.signin:focus{background:#6faac8;}a.void:hover{background:#ccc;}#signin_submit:active{background-image:none;}#signin .forgot{margin-bottom:4px;}#signin .forgot a,#signin .complete a{margin-right:5px;}#signin_submit{-moz-border-radius:4px;-webkit-border-radius:4px;background:#39d url(../images/bg-btn-blue.png) repeat-x scroll 0 0;border:1px solid #39D;color:#fff;text-shadow:0 -1px 0 #39d;padding:4px 10px 5px;font-size:11px;margin:0 5px 0 0;font-weight:bold;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_background_images/30261844/ICHCTwitterBG.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_background_images/30261844/ICHCTwitterBG.jpg
deleted file mode 100755
index 887afc9d5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_background_images/30261844/ICHCTwitterBG.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1063331761/LOLmart_150_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1063331761/LOLmart_150_mini.jpg
deleted file mode 100755
index 98e5fe7f8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1063331761/LOLmart_150_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1124077786/batvatar_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1124077786/batvatar_mini.png
deleted file mode 100755
index 76394d3c0..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1124077786/batvatar_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1155395599/Memebase_small_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1155395599/Memebase_small_mini.png
deleted file mode 100755
index fe608e175..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1155395599/Memebase_small_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1289641028/CH_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1289641028/CH_mini.jpg
deleted file mode 100755
index d1063d2ea..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1289641028/CH_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1296459376/profile_image_1301694822477_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1296459376/profile_image_1301694822477_mini.jpg
deleted file mode 100755
index d9d16ca52..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/1296459376/profile_image_1301694822477_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/700174615/twitter_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/700174615/twitter_mini.png
deleted file mode 100755
index 83cfbfd9c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/700174615/twitter_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/724048626/Picture_3895-1_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/724048626/Picture_3895-1_mini.jpg
deleted file mode 100755
index 121e604b1..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/724048626/Picture_3895-1_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/959827428/25000_1397284054938_1317351118_31101620_485629_n_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/959827428/25000_1397284054938_1317351118_31101620_485629_n_mini.jpg
deleted file mode 100755
index 60c5f613f..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/959827428/25000_1397284054938_1317351118_31101620_485629_n_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/959952929/ci_300x300_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/959952929/ci_300x300_mini.jpg
deleted file mode 100755
index 34cb49536..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/profile_images/959952929/ci_300x300_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_1_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_1_mini.png
deleted file mode 100755
index 92123d122..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_1_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_2_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_2_mini.png
deleted file mode 100755
index 94a82c4d6..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_2_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_6_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_6_mini.png
deleted file mode 100755
index 0a155410d..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a2.twimg.com/sticky/default_profile_images/default_profile_6_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/arrow_right_dark.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/arrow_right_dark.png
deleted file mode 100755
index 4e892821b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/arrow_right_dark.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/buttons/bg-btn.gif b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/buttons/bg-btn.gif
deleted file mode 100755
index 5d1e16452..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/buttons/bg-btn.gif
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/check.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/check.png
deleted file mode 100755
index 1e0188d58..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/check.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_129px.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_129px.png
deleted file mode 100755
index b1d8591a8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_129px.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_146px.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_146px.png
deleted file mode 100755
index 5b99bda01..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_146px.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_170px.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_170px.png
deleted file mode 100755
index d990e2e23..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_170px.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_236px.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_236px.png
deleted file mode 100755
index 7b8b74d49..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/connect_236px.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/gradient-background.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/gradient-background.png
deleted file mode 100755
index 503ab9f10..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/gradient-background.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/rays-box.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/rays-box.jpg
deleted file mode 100755
index bb19d1f61..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/rays-box.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/t_170px.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/t_170px.png
deleted file mode 100755
index 2cce58117..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/oauth2/t_170px.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/sprite-icons.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/sprite-icons.png
deleted file mode 100755
index a93cede94..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/images/sprite-icons.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/javascripts/api.js@1302114648 b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/javascripts/api.js@1302114648
deleted file mode 100755
index e846ebda3..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/javascripts/api.js@1302114648
+++ /dev/null
@@ -1 +0,0 @@
-twttr.augmentString("twttr.api",{defaultAjaxOptions:{type:"POST",dataType:"json",url:"#",data:{authenticity_token:"",twttr:true},success:function(){},error:function(){},beforeSend:function(){}},tweet:function(B,C,A){twttr.User.findById(B,this,function(D){var H=A.success;var F={status:C};var G=function(I){D.update("latest_status",I.text);H(I)};var E="/status/update";this._sendRequest(twttr.merge(A,{url:E,success:G,data:F},true))})},autocomplete:function(B,C,A){twttr.User.findById(B,this,function(D){var F={user_id:B,sn:C};var E="/users/autocomplete";this._sendRequest(twttr.merge(A,{url:E,data:F},true))})},follow:function(B,A){twttr.User.findById(B,this,function(C){var F=A.success;var E=function(G){C.updateAll({do_not_follow:false,do_you_follow:true,sees_retweets:true});F(G)};var D="/friendships/create/"+B;this._sendRequest(twttr.merge(A,{url:D,success:E},true))})},unfollow:function(B,A){twttr.User.findById(B,this,function(C){var F=A.success;var E=function(G){C.updateAll({do_not_follow:true,do_you_follow:false,gets_device_updates:false,sees_replies:false,sees_retweets:false});F(G)};var D="/friendships/destroy/"+B;this._sendRequest(twttr.merge(A,{url:D,success:E},true))})},block:function(B,A){twttr.User.findById(B,this,function(C){var F=A.success;var E=function(G){C.updateAll({is_not_blocking:false,is_blocking:true,do_not_follow:true,do_you_follow:false,does_follow_you:false,gets_device_updates:false,sees_replies:false,sees_retweets:false});F(G)};var D="/blocks/create/"+B;this._sendRequest(twttr.merge(A,{url:D,success:E},true))})},unblock:function(B,A){twttr.User.findById(B,this,function(C){var F=A.success;var E=function(G){C.updateAll({is_not_blocking:true,is_blocking:false,do_not_follow:true,do_you_follow:false,does_follow_you:false,gets_device_updates:false,sees_replies:false,sees_retweets:false});F(G)};var D="/blocks/destroy/"+B;this._sendRequest(twttr.merge(A,{url:D,success:E},true))})},reportForSpam:function(B,A){twttr.User.findById(B,this,function(C){var F=A.success;var E=function(G){C.updateAll({is_not_blocking:false,is_blocking:true,do_not_follow:true,do_you_follow:false,does_follow_you:false,gets_device_updates:false,sees_replies:false,sees_retweets:false});F(G)};var D="/user_spam_reports/"+B;this._sendRequest(twttr.merge(A,{url:D,success:E},true))})},reportSpam:function(B,A){this.reportSpam.apply(arguments)},setDeviceAlerts:function(B,D,A){var C={user_ids:B,value:D};var E=function(F){twttr.User.findById(B,function(G){G.update("gets_device_updates",D=="on")})};this._sendRequest(twttr.merge(A,{url:"/friendships/set_sms",data:C,success:E},true))},setRetweetVisibility:function(B,D,A){var C={user_ids:B,value:D};var E=function(F){twttr.User.findById(B,function(G){G.update("sees_retweets",D=="on")})};this._sendRequest(twttr.merge(A,{url:"/friendships/set_shares",data:C,success:E},true))},setMentions:function(B,D,A){var C={user_ids:B,value:D};var E=function(F){twttr.User.findById(B,function(G){G.update("sees_replies",D=="on")})};this._sendRequest(twttr.merge(A,{url:"/friendships/set_replies",data:C,success:E},true))},reverseGeocode:function(A){var B={type:"GET",url:"/1/geo/reverse_geocode.json"};this._sendRequest(twttr.merge(A,B,true))},search:function(A){var B={type:"GET",url:"/1/geo/search.json"};this._sendRequest(twttr.merge(A,B,true))},createPlace:function(A){var B={type:"POST",url:"/1/geo/place.json"};this._sendRequest(twttr.merge(A,B,true))},similarPlaces:function(B){var A={type:"GET",url:"/1/geo/similar_places.json"};this._sendRequest(twttr.merge(B,A,true))},getPlaceDetails:function(A){var B={type:"GET",url:"/1/geo/id/"+A.place_id+".json"};this._sendRequest(twttr.merge(A,B,true))},_sendRequest:function(B){var C={};if(twttr.form_authenticity_token){C.authenticity_token=twttr.form_authenticity_token}var A=twttr.merge({},twttr.api.defaultAjaxOptions,{data:C},B,true);$.ajax(A)}}); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/javascripts/lib/gears_init.js@1302114648 b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/javascripts/lib/gears_init.js@1302114648
deleted file mode 100755
index 4960f50fe..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/javascripts/lib/gears_init.js@1302114648
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2007, Google Inc.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Sets up google.gears.*, which is *the only* supported way to access Gears.
-//
-// Circumvent this file at your own risk!
-//
-// In the future, Gears may automatically define google.gears.* without this
-// file. Gears may use these objects to transparently fix bugs and compatibility
-// issues. Applications that use the code below will continue to work seamlessly
-// when that happens.
-
-(function() {
- // We are already defined. Hooray!
- if (window.google && google.gears) {
- return;
- }
-
- var factory = null;
-
- // Firefox
- if (typeof GearsFactory != 'undefined') {
- factory = new GearsFactory();
- } else {
- // IE
- try {
- factory = new ActiveXObject('Gears.Factory');
- // privateSetGlobalObject is only required and supported on IE Mobile on
- // WinCE.
- if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
- factory.privateSetGlobalObject(this);
- }
- } catch (e) {
- // Safari
- if ((typeof navigator.mimeTypes != 'undefined')
- && navigator.mimeTypes["application/x-googlegears"]) {
- factory = document.createElement("object");
- factory.style.display = "none";
- factory.width = 0;
- factory.height = 0;
- factory.type = "application/x-googlegears";
- document.documentElement.appendChild(factory);
- }
- }
- }
-
- // *Do not* define any objects if Gears is not installed. This mimics the
- // behavior of Gears defining the objects in the future.
- if (!factory) {
- return;
- }
-
- // Now set up the objects, being careful not to void anything.
- //
- // Note: In Internet Explorer for Windows Mobile, you can't add properties to
- // the window object. However, global objects are automatically added as
- // properties of the window object in all browsers.
- if (!window.google) {
- google = {};
- }
-
- if (!google.gears) {
- google.gears = {factory: factory};
- }
-})();
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/stylesheets/buttons_new.css@1302114648.css b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/stylesheets/buttons_new.css@1302114648.css
deleted file mode 100755
index 961eac0be..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/a/1302214109/stylesheets/buttons_new.css@1302114648.css
+++ /dev/null
@@ -1 +0,0 @@
-.button{-moz-border-radius:4px;-khtml-border-radius:4px;-webkit-border-radius:4px;background:#ddd url(../images/buttons/bg-btn.gif) repeat-x 0 0;border-bottom-color:#ccc;border-color:#ddd;border-radius:4px;border-style:solid;border-width:1px;color:#333;cursor:pointer;display:inline;font:11px/14px "Lucida Grande",Sans-serif;margin:0;overflow:visible;padding:4px 8px 5px;text-shadow:1px 1px 0 #fff;}.button::-moz-focus-inner{padding:0;border:0;}.button:focus{outline:none;}.button:hover,.button:focus{background-position:0 -6px;border-color:#999 #999 #888;color:#000;}.button:active{background-image:none;text-shadow:none;outline:none;}#tweeting_controls a{line-height:13px;}#gear_dropdown{padding:4px 5px 5px;}#gear_dropdown span{background-image:url(../images/sprite-icons.png);background-position:-32px -63px;background-repeat:no-repeat;display:inline-block;width:22px;}ul.dropdown{display:none;position:absolute;width:200px;padding:4px 0;text-align:left;border:1px solid #666;background-color:#fff;z-index:9999;}ul.dropdown li a,ul.dropdown li label,ul.dropdown li input[type="checkbox"]{display:inline-block;font:11px 'Lucida Grande',Arial,sans-serif;color:#666;position:relative;padding:4px 5px;vertical-align:top;}ul.dropdown li .loaddisableding-spinner{display:inline-block;position:relative;top:4px;left:1px;margin-left:4px;}ul.dropdown li a{padding:4px 5px 4px 27px;}ul.dropdown li a{display:block;color:#666;text-decoration:none;}ul.dropdown li:hover{color:#fff;background-color:#666;}ul.dropdown li:hover *{color:#fff;}ul.dropdown li.divider{border-top:1px solid #ddd;}ul.dropdown i{background:url(../images/sprite-icons.png) repeat no-repeat;font-size:10px;left:7px;position:absolute;top:4px;width:15px;}#get_location_icon{background:url(../images/sprite-icons.png) -160px -64px no-repeat;display:inline-block;_display:inline;height:11px;width:11px;vertical-align:middle;}#location_spinner{display:none;height:11px;width:11px;vertical-align:middle;}.share-location-loaddisableding #location_spinner{display:inline-block;}.share-location-loaddisableding #get_location_icon{display:none;}a.a-btn{zoom:1;background:#ddd url(../images/buttons/bg-btn.gif) repeat-x scroll 0 0;cursor:pointer;text-shadow:1px 1px 0 #fff!important;border-color:#ddd #ddd #ccc!important;border-style:solid;border-width:1px!important;text-decoration:none;padding:4px 8px 5px;line-height:14px;font-size:11px;font-family:"lucida grande",helvetica,tahoma,arial;display:inline-block;_display:inline;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;}a.a-btn,a.a-btn:visited{color:#333!important;}a.a-btn:hover,a.a-btn:focus{text-decoration:none;border-color:#999 #999 #888!important;color:#000;outline:none;}a.a-btn:active{background-image:none;outline:none;}:focus{-moz-outline-style:none;}a.a-btn-m{font-size:15px;font-family:"helvetica neue",arial,sans-serif;padding:5px 15px 6px;line-height:20px;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;background-position:0 -200px;}a.a-btn-l{font-size:20px;line-height:26px;padding:7px 20px 8px;-moz-border-radius:6px;-webkit-border-radius:6px;border-radius:6px;font-family:"helvetica neue",arial,sans-serif;background-position:0 -400px;}a.btn-disabled{opacity:.6;filter:alpha(opacity=60);background-image:none;}.twitter-connect{border:0;outline:none;text-indent:-99999px;display:inline-block;background-repeat:no-repeat;background-position:top left;}.twitter-button{font:12px Arial,sans-serif;color:#fff;background:#1D6B9C url(../images/oauth2/gradient-background.png) repeat-x;text-indent:0;border:1px solid #18566A;display:inline-block;-moz-border-radius:4px;-webkit-border-radius:4px;-border-radius:4px;text-shadow:0 -1px 0 #18566A;}.twitter-button:hover{border:1px solid #00242C;background-position:left -23px;text-decoration:none;}.twitter-button:active{border:1px solid #044D77;background-position:left -46px;text-decoration:none;color:rgba(255,255,255,0.8);}.twitter-connect-small{background:url(../images/oauth2/connect_129px.png) no-repeat;width:129px;height:19px;}.twitter-connect-small:hover{background-position:left -19px;}.twitter-connect-small:active{background-position:left -38px;}.twitter-connect-medium{background:url(../images/oauth2/connect_146px.png) no-repeat;width:146px;height:23px;}.twitter-connect-medium:hover{background-position:left -23px;}.twitter-connect-medium:active{background-position:left -46px;}.twitter-connect-large{background:url(../images/oauth2/connect_170px.png) no-repeat;width:170px;height:26px;}.twitter-connect-large:hover{background-position:left -26px;}.twitter-connect-large:active{background-position:left -52px;}.twitter-connect-xlarge{background:url(../images/oauth2/connect_236px.png) no-repeat;width:236px;height:38px;}.twitter-connect-xlarge:hover{background-position:left -38px;}.twitter-connect-xlarge:active{background-position:left -76px;}.twitter-connect-box{font:13px/17px Lucida Grande,"Lucida Grande",Arial,Helvetica,sans-serif;padding:8px 10px 9px 10px;width:200px;background:#C7E0EC url(../images/oauth2/rays-box.jpg) no-repeat center top;color:#001F33;text-shadow:0 1px 0 #E5F0F6;border-radius:5px;-moz-border-radius:4px;-webkit-border-radius:4px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.3);-moz-box-shadow:0 1px 0 rgba(0,0,0,.3);box-shadow:0 1px 0 rgba(0,0,0,.3);display:inline-block;vertical-align:top;}.twitter-connect-box p{margin:0 0 8px 0;padding:0;}.twitter-connect-box-small{font-size:10px;line-height:14px;width:129px;}.twitter-connect-box-medium{font-size:11px;line-height:15px;width:146px;}.twitter-connect-box-large{font-size:11px;line-height:15px;width:170px;}.twitter-connect-box-xlarge{font-size:12px;line-height:17px;width:236px;}.follow-medium{text-decoration:none;padding-right:7px;padding-left:2px;*padding:0 7px 0 0;}.follow-medium i{height:23px;width:23px;display:inline-block;border-right:1px solid #73AFD5;}.follow-medium i b{display:inline-block;background:url(../images/oauth2/t_170px.png) no-repeat 3px 3px;height:23px;width:22px;vertical-align:middle;border-right:1px solid #094B60;}.follow-medium .status{padding-left:4px;}.following-notice,.pending-notice{background-image:none;background:#eee;border:1px solid #ccc;color:#333;text-shadow:0 1px 0 #fff;cursor:default;padding:1px 8px 0;font:12px Arial,sans-serif;text-indent:0;display:inline-block;-moz-border-radius:4px;-webkit-border-radius:4px;-border-radius:4px;}.pending-notice{padding:5px 8px 2px;}.following-notice:active,.pending-notice:active{color:#333;text-shadow:0 1px 0 #fff;}.following-notice span.at,.pending-notice span.at{color:#666;}.following-notice a,.pending-notice a{color:#196698;font-weight:normal;text-decoration:none;}.following-notice a:hover,.pending-notice a:hover{text-decoration:underline;}.following-notice i{border-right:1px solid #eee;width:15px;}.pending-notice i{border-right:1px solid #eee;width:10px;height:9px;}.following-notice i b{border-right:0;width:15px;}.pending-notice i{border-right:0;width:9px;height:17px;}.following-notice i b{background:url(../images/oauth2/check.png) no-repeat 4px 7px;}.pending-notice i b{position:relative;top:-2px;border-right:none;width:10px;height:9px;background:url(../images/sprite-icons.png) no-repeat -192px -16px;}.twitter-loaddisableding{font:12px/15px Arial,Helvetica,sans-serif;color:#fff;background:#eee;border:1px solid #ccc;color:#333;text-shadow:0 1px 0 #fff;cursor:default;text-indent:0;padding:5px 8px 4px 8px;-moz-border-radius:4px;-webkit-border-radius:4px;-border-radius:4px;display:block;width:100px;margin-top:-3px;} \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1092057020/eli_avatar_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1092057020/eli_avatar_mini.png
deleted file mode 100755
index 67465a772..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1092057020/eli_avatar_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1096286685/newpink_copy_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1096286685/newpink_copy_mini.jpg
deleted file mode 100755
index c794a0a1c..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1096286685/newpink_copy_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1110864280/41628_1144937489_2484_q_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1110864280/41628_1144937489_2484_q_mini.jpg
deleted file mode 100755
index 517fa5ed7..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1110864280/41628_1144937489_2484_q_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1213876440/27539_32561485399_2579_n_bigger.jpeg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1213876440/27539_32561485399_2579_n_bigger.jpeg
deleted file mode 100755
index f617346d7..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1213876440/27539_32561485399_2579_n_bigger.jpeg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1260578495/191281_1758367531945_1621722394_1723810_2598069_o_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1260578495/191281_1758367531945_1621722394_1723810_2598069_o_mini.jpg
deleted file mode 100755
index 4a97c6415..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1260578495/191281_1758367531945_1621722394_1723810_2598069_o_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1299269362/10839_196974151498_693676498_3960874_1853030_n_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1299269362/10839_196974151498_693676498_3960874_1853030_n_mini.jpg
deleted file mode 100755
index 3260db85b..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1299269362/10839_196974151498_693676498_3960874_1853030_n_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1302143328/Profile_copy_mini.jpg b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1302143328/Profile_copy_mini.jpg
deleted file mode 100755
index acc298eb4..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/profile_images/1302143328/Profile_copy_mini.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/sticky/default_profile_images/default_profile_3_mini.png b/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/sticky/default_profile_images/default_profile_3_mini.png
deleted file mode 100755
index ad1dc7577..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/a3.twimg.com/sticky/default_profile_images/default_profile_3_mini.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js b/mobile/android/tests/browser/chrome/tp5/twitter.com/ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js
deleted file mode 100755
index c487ba7a5..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * jQuery JavaScript Library v1.3
- * http://jquery.com/
- *
- * Copyright (c) 2009 John Resig
- * Dual licensed under the MIT and GPL licenses.
- * http://docs.jquery.com/License
- *
- * Date: 2009-01-13 12:50:31 -0500 (Tue, 13 Jan 2009)
- * Revision: 6104
- */
-(function(){var l=this,g,x=l.jQuery,o=l.$,n=l.jQuery=l.$=function(D,E){return new n.fn.init(D,E)},C=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;n.fn=n.prototype={init:function(D,G){D=D||document;if(D.nodeType){this[0]=D;this.length=1;this.context=D;return this}if(typeof D==="string"){var F=C.exec(D);if(F&&(F[1]||!G)){if(F[1]){D=n.clean([F[1]],G)}else{var H=document.getElementById(F[3]);if(H){if(H.id!=F[3]){return n().find(D)}var E=n(H);E.context=document;E.selector=D;return E}D=[]}}else{return n(G).find(D)}}else{if(n.isFunction(D)){return n(document).ready(D)}}if(D.selector&&D.context){this.selector=D.selector;this.context=D.context}return this.setArray(n.makeArray(D))},selector:"",jquery:"1.3",size:function(){return this.length},get:function(D){return D===g?n.makeArray(this):this[D]},pushStack:function(E,G,D){var F=n(E);F.prevObject=this;F.context=this.context;if(G==="find"){F.selector=this.selector+(this.selector?" ":"")+D}else{if(G){F.selector=this.selector+"."+G+"("+D+")"}}return F},setArray:function(D){this.length=0;Array.prototype.push.apply(this,D);return this},each:function(E,D){return n.each(this,E,D)},index:function(D){return n.inArray(D&&D.jquery?D[0]:D,this)},attr:function(E,G,F){var D=E;if(typeof E==="string"){if(G===g){return this[0]&&n[F||"attr"](this[0],E)}else{D={};D[E]=G}}return this.each(function(H){for(E in D){n.attr(F?this.style:this,E,n.prop(this,D[E],F,H,E))}})},css:function(D,E){if((D=="width"||D=="height")&&parseFloat(E)<0){E=g}return this.attr(D,E,"curCSS")},text:function(E){if(typeof E!=="object"&&E!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(E))}var D="";n.each(E||this,function(){n.each(this.childNodes,function(){if(this.nodeType!=8){D+=this.nodeType!=1?this.nodeValue:n.fn.text([this])}})});return D},wrapAll:function(D){if(this[0]){var E=n(D,this[0].ownerDocument).clone();if(this[0].parentNode){E.insertBefore(this[0])}E.map(function(){var F=this;while(F.firstChild){F=F.firstChild}return F}).append(this)}return this},wrapInner:function(D){return this.each(function(){n(this).contents().wrapAll(D)})},wrap:function(D){return this.each(function(){n(this).wrapAll(D)})},append:function(){return this.domManip(arguments,true,function(D){if(this.nodeType==1){this.appendChild(D)}})},prepend:function(){return this.domManip(arguments,true,function(D){if(this.nodeType==1){this.insertBefore(D,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(D){this.parentNode.insertBefore(D,this)})},after:function(){return this.domManip(arguments,false,function(D){this.parentNode.insertBefore(D,this.nextSibling)})},end:function(){return this.prevObject||n([])},push:[].push,find:function(D){if(this.length===1&&!/,/.test(D)){var F=this.pushStack([],"find",D);F.length=0;n.find(D,this[0],F);return F}else{var E=n.map(this,function(G){return n.find(D,G)});return this.pushStack(/[^+>] [^+>]/.test(D)?n.unique(E):E,"find",D)}},clone:function(E){var D=this.map(function(){if(!n.support.noCloneEvent&&!n.isXMLDoc(this)){var H=this.cloneNode(true),G=document.createElement("div");G.appendChild(H);return n.clean([G.innerHTML])[0]}else{return this.cloneNode(true)}});var F=D.find("*").andSelf().each(function(){if(this[h]!==g){this[h]=null}});if(E===true){this.find("*").andSelf().each(function(H){if(this.nodeType==3){return}var G=n.data(this,"events");for(var J in G){for(var I in G[J]){n.event.add(F[H],J,G[J][I],G[J][I].data)}}})}return D},filter:function(D){return this.pushStack(n.isFunction(D)&&n.grep(this,function(F,E){return D.call(F,E)})||n.multiFilter(D,n.grep(this,function(E){return E.nodeType===1})),"filter",D)},closest:function(D){var E=n.expr.match.POS.test(D)?n(D):null;return this.map(function(){var F=this;while(F&&F.ownerDocument){if(E?E.index(F)>-1:n(F).is(D)){return F}F=F.parentNode}})},not:function(D){if(typeof D==="string"){if(f.test(D)){return this.pushStack(n.multiFilter(D,this,true),"not",D)}else{D=n.multiFilter(D,this)}}var E=D.length&&D[D.length-1]!==g&&!D.nodeType;return this.filter(function(){return E?n.inArray(this,D)<0:this!=D})},add:function(D){return this.pushStack(n.unique(n.merge(this.get(),typeof D==="string"?n(D):n.makeArray(D))))},is:function(D){return !!D&&n.multiFilter(D,this).length>0},hasClass:function(D){return !!D&&this.is("."+D)},val:function(J){if(J===g){var D=this[0];if(D){if(n.nodeName(D,"option")){return(D.attributes.value||{}).specified?D.value:D.text}if(n.nodeName(D,"select")){var H=D.selectedIndex,K=[],L=D.options,G=D.type=="select-one";if(H<0){return null}for(var E=G?H:0,I=G?H+1:L.length;E<I;E++){var F=L[E];if(F.selected){J=n(F).val();if(G){return J}K.push(J)}}return K}return(D.value||"").replace(/\r/g,"")}return g}if(typeof J==="number"){J+=""}return this.each(function(){if(this.nodeType!=1){return}if(n.isArray(J)&&/radio|checkbox/.test(this.type)){this.checked=(n.inArray(this.value,J)>=0||n.inArray(this.name,J)>=0)}else{if(n.nodeName(this,"select")){var M=n.makeArray(J);n("option",this).each(function(){this.selected=(n.inArray(this.value,M)>=0||n.inArray(this.text,M)>=0)});if(!M.length){this.selectedIndex=-1}}else{this.value=J}}})},html:function(D){return D===g?(this[0]?this[0].innerHTML:null):this.empty().append(D)},replaceWith:function(D){return this.after(D).remove()},eq:function(D){return this.slice(D,+D+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(D){return this.pushStack(n.map(this,function(F,E){return D.call(F,E,F)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=n.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild,D=this.length>1?I.cloneNode(true):I;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),G>0?D.cloneNode(true):I)}}if(F){n.each(F,y)}}return this;function K(N,O){return M&&n.nodeName(N,"table")&&n.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};n.fn.init.prototype=n.fn;function y(D,E){if(E.src){n.ajax({url:E.src,async:false,dataType:"script"})}else{n.globalEval(E.text||E.textContent||E.innerHTML||"")}if(E.parentNode){E.parentNode.removeChild(E)}}function e(){return +new Date}n.extend=n.fn.extend=function(){var I=arguments[0]||{},G=1,H=arguments.length,D=false,F;if(typeof I==="boolean"){D=I;I=arguments[1]||{};G=2}if(typeof I!=="object"&&!n.isFunction(I)){I={}}if(H==G){I=this;--G}for(;G<H;G++){if((F=arguments[G])!=null){for(var E in F){var J=I[E],K=F[E];if(I===K){continue}if(D&&K&&typeof K==="object"&&!K.nodeType){I[E]=n.extend(D,J||(K.length!=null?[]:{}),K)}else{if(K!==g){I[E]=K}}}}}return I};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,p=document.defaultView||{},r=Object.prototype.toString;n.extend({noConflict:function(D){l.$=o;if(D){l.jQuery=x}return n},isFunction:function(D){return r.call(D)==="[object Function]"},isArray:function(D){return r.call(D)==="[object Array]"},isXMLDoc:function(D){return D.documentElement&&!D.body||D.tagName&&D.ownerDocument&&!D.ownerDocument.body},globalEval:function(F){F=n.trim(F);if(F){var E=document.getElementsByTagName("head")[0]||document.documentElement,D=document.createElement("script");D.type="text/javascript";if(n.support.scriptEval){D.appendChild(document.createTextNode(F))}else{D.text=F}E.insertBefore(D,E.firstChild);E.removeChild(D)}},nodeName:function(E,D){return E.nodeName&&E.nodeName.toUpperCase()==D.toUpperCase()},each:function(F,J,E){var D,G=0,H=F.length;if(E){if(H===g){for(D in F){if(J.apply(F[D],E)===false){break}}}else{for(;G<H;){if(J.apply(F[G++],E)===false){break}}}}else{if(H===g){for(D in F){if(J.call(F[D],D,F[D])===false){break}}}else{for(var I=F[0];G<H&&J.call(I,G,I)!==false;I=F[++G]){}}}return F},prop:function(G,H,F,E,D){if(n.isFunction(H)){H=H.call(G,E)}return typeof H==="number"&&F=="curCSS"&&!b.test(D)?H+"px":H},className:{add:function(D,E){n.each((E||"").split(/\s+/),function(F,G){if(D.nodeType==1&&!n.className.has(D.className,G)){D.className+=(D.className?" ":"")+G}})},remove:function(D,E){if(D.nodeType==1){D.className=E!==g?n.grep(D.className.split(/\s+/),function(F){return !n.className.has(E,F)}).join(" "):""}},has:function(E,D){return n.inArray(D,(E.className||E).toString().split(/\s+/))>-1}},swap:function(G,F,H){var D={};for(var E in F){D[E]=G.style[E];G.style[E]=F[E]}H.call(G);for(var E in F){G.style[E]=D[E]}},css:function(F,D,H){if(D=="width"||D=="height"){var J,E={position:"absolute",visibility:"hidden",display:"block"},I=D=="width"?["Left","Right"]:["Top","Bottom"];function G(){J=D=="width"?F.offsetWidth:F.offsetHeight;var L=0,K=0;n.each(I,function(){L+=parseFloat(n.curCSS(F,"padding"+this,true))||0;K+=parseFloat(n.curCSS(F,"border"+this+"Width",true))||0});J-=Math.round(L+K)}if(n(F).is(":visible")){G()}else{n.swap(F,E,G)}return Math.max(0,J)}return n.curCSS(F,D,H)},curCSS:function(H,E,F){var K,D=H.style;if(E=="opacity"&&!n.support.opacity){K=n.attr(D,"opacity");return K==""?"1":K}if(E.match(/float/i)){E=v}if(!F&&D&&D[E]){K=D[E]}else{if(p.getComputedStyle){if(E.match(/float/i)){E="float"}E=E.replace(/([A-Z])/g,"-$1").toLowerCase();var L=p.getComputedStyle(H,null);if(L){K=L.getPropertyValue(E)}if(E=="opacity"&&K==""){K="1"}}else{if(H.currentStyle){var I=E.replace(/\-(\w)/g,function(M,N){return N.toUpperCase()});K=H.currentStyle[E]||H.currentStyle[I];if(!/^\d+(px)?$/i.test(K)&&/^\d/.test(K)){var G=D.left,J=H.runtimeStyle.left;H.runtimeStyle.left=H.currentStyle.left;D.left=K||0;K=D.pixelLeft+"px";D.left=G;H.runtimeStyle.left=J}}}}return K},clean:function(E,J,H){J=J||document;if(typeof J.createElement==="undefined"){J=J.ownerDocument||J[0]&&J[0].ownerDocument||document}if(!H&&E.length===1&&typeof E[0]==="string"){var G=/^<(\w+)\s*\/?>$/.exec(E[0]);if(G){return[J.createElement(G[1])]}}var F=[],D=[],K=J.createElement("div");n.each(E,function(O,Q){if(typeof Q==="number"){Q+=""}if(!Q){return}if(typeof Q==="string"){Q=Q.replace(/(<(\w+)[^>]*?)\/>/g,function(S,T,R){return R.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?S:T+"></"+R+">"});var N=n.trim(Q).toLowerCase();var P=!N.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!N.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||N.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!N.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!N.indexOf("<td")||!N.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!N.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!n.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];K.innerHTML=P[1]+Q+P[2];while(P[0]--){K=K.lastChild}if(!n.support.tbody){var M=!N.indexOf("<table")&&N.indexOf("<tbody")<0?K.firstChild&&K.firstChild.childNodes:P[1]=="<table>"&&N.indexOf("<tbody")<0?K.childNodes:[];for(var L=M.length-1;L>=0;--L){if(n.nodeName(M[L],"tbody")&&!M[L].childNodes.length){M[L].parentNode.removeChild(M[L])}}}if(!n.support.leadingWhitespace&&/^\s/.test(Q)){K.insertBefore(J.createTextNode(Q.match(/^\s*/)[0]),K.firstChild)}Q=n.makeArray(K.childNodes)}if(Q.nodeType){F.push(Q)}else{F=n.merge(F,Q)}});if(H){for(var I=0;F[I];I++){if(n.nodeName(F[I],"script")&&(!F[I].type||F[I].type.toLowerCase()==="text/javascript")){D.push(F[I].parentNode?F[I].parentNode.removeChild(F[I]):F[I])}else{if(F[I].nodeType===1){F.splice.apply(F,[I+1,0].concat(n.makeArray(F[I].getElementsByTagName("script"))))}H.appendChild(F[I])}}return D}return F},attr:function(I,F,J){if(!I||I.nodeType==3||I.nodeType==8){return g}var G=!n.isXMLDoc(I),K=J!==g;F=G&&n.props[F]||F;if(I.tagName){var E=/href|src|style/.test(F);if(F=="selected"&&I.parentNode){I.parentNode.selectedIndex}if(F in I&&G&&!E){if(K){if(F=="type"&&n.nodeName(I,"input")&&I.parentNode){throw"type property can't be changed"}I[F]=J}if(n.nodeName(I,"form")&&I.getAttributeNode(F)){return I.getAttributeNode(F).nodeValue}if(F=="tabIndex"){var H=I.getAttributeNode("tabIndex");return H&&H.specified?H.value:I.nodeName.match(/^(a|area|button|input|object|select|textarea)$/i)?0:g}return I[F]}if(!n.support.style&&G&&F=="style"){return n.attr(I.style,"cssText",J)}if(K){I.setAttribute(F,""+J)}var D=!n.support.hrefNormalized&&G&&E?I.getAttribute(F,2):I.getAttribute(F);return D===null?g:D}if(!n.support.opacity&&F=="opacity"){if(K){I.zoom=1;I.filter=(I.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(J)+""=="NaN"?"":"alpha(opacity="+J*100+")")}return I.filter&&I.filter.indexOf("opacity=")>=0?(parseFloat(I.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}F=F.replace(/-([a-z])/ig,function(L,M){return M.toUpperCase()});if(K){I[F]=J}return I[F]},trim:function(D){return(D||"").replace(/^\s+|\s+$/g,"")},makeArray:function(F){var D=[];if(F!=null){var E=F.length;if(E==null||typeof F==="string"||n.isFunction(F)||F.setInterval){D[0]=F}else{while(E){D[--E]=F[E]}}}return D},inArray:function(F,G){for(var D=0,E=G.length;D<E;D++){if(G[D]===F){return D}}return -1},merge:function(G,D){var E=0,F,H=G.length;if(!n.support.getAll){while((F=D[E++])!=null){if(F.nodeType!=8){G[H++]=F}}}else{while((F=D[E++])!=null){G[H++]=F}}return G},unique:function(J){var E=[],D={};try{for(var F=0,G=J.length;F<G;F++){var I=n.data(J[F]);if(!D[I]){D[I]=true;E.push(J[F])}}}catch(H){E=J}return E},grep:function(E,I,D){var F=[];for(var G=0,H=E.length;G<H;G++){if(!D!=!I(E[G],G)){F.push(E[G])}}return F},map:function(D,I){var E=[];for(var F=0,G=D.length;F<G;F++){var H=I(D[F],F);if(H!=null){E[E.length]=H}}return E.concat.apply([],E)}});var B=navigator.userAgent.toLowerCase();n.browser={version:(B.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(B),opera:/opera/.test(B),msie:/msie/.test(B)&&!/opera/.test(B),mozilla:/mozilla/.test(B)&&!/(compatible|webkit)/.test(B)};n.each({parent:function(D){return D.parentNode},parents:function(D){return n.dir(D,"parentNode")},next:function(D){return n.nth(D,2,"nextSibling")},prev:function(D){return n.nth(D,2,"previousSibling")},nextAll:function(D){return n.dir(D,"nextSibling")},prevAll:function(D){return n.dir(D,"previousSibling")},siblings:function(D){return n.sibling(D.parentNode.firstChild,D)},children:function(D){return n.sibling(D.firstChild)},contents:function(D){return n.nodeName(D,"iframe")?D.contentDocument||D.contentWindow.document:n.makeArray(D.childNodes)}},function(D,E){n.fn[D]=function(F){var G=n.map(this,E);if(F&&typeof F=="string"){G=n.multiFilter(F,G)}return this.pushStack(n.unique(G),D,F)}});n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(D,E){n.fn[D]=function(){var F=arguments;return this.each(function(){for(var G=0,H=F.length;G<H;G++){n(F[G])[E](this)}})}});n.each({removeAttr:function(D){n.attr(this,D,"");if(this.nodeType==1){this.removeAttribute(D)}},addClass:function(D){n.className.add(this,D)},removeClass:function(D){n.className.remove(this,D)},toggleClass:function(E,D){if(typeof D!=="boolean"){D=!n.className.has(this,E)}n.className[D?"add":"remove"](this,E)},remove:function(D){if(!D||n.filter(D,[this]).length){n("*",this).add([this]).each(function(){n.event.remove(this);n.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){n(">*",this).remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(D,E){n.fn[D]=function(){return this.each(E,arguments)}});function j(D,E){return D[0]&&parseInt(n.curCSS(D[0],E,true),10)||0}var h="jQuery"+e(),u=0,z={};n.extend({cache:{},data:function(E,D,F){E=E==l?z:E;var G=E[h];if(!G){G=E[h]=++u}if(D&&!n.cache[G]){n.cache[G]={}}if(F!==g){n.cache[G][D]=F}return D?n.cache[G][D]:G},removeData:function(E,D){E=E==l?z:E;var G=E[h];if(D){if(n.cache[G]){delete n.cache[G][D];D="";for(D in n.cache[G]){break}if(!D){n.removeData(E)}}}else{try{delete E[h]}catch(F){if(E.removeAttribute){E.removeAttribute(h)}}delete n.cache[G]}},queue:function(E,D,G){if(E){D=(D||"fx")+"queue";var F=n.data(E,D);if(!F||n.isArray(G)){F=n.data(E,D,n.makeArray(G))}else{if(G){F.push(G)}}}return F},dequeue:function(G,F){var D=n.queue(G,F),E=D.shift();if(!F||F==="fx"){E=D[0]}if(E!==g){E.call(G)}}});n.fn.extend({data:function(D,F){var G=D.split(".");G[1]=G[1]?"."+G[1]:"";if(F===g){var E=this.triggerHandler("getData"+G[1]+"!",[G[0]]);if(E===g&&this.length){E=n.data(this[0],D)}return E===g&&G[1]?this.data(G[0]):E}else{return this.trigger("setData"+G[1]+"!",[G[0],F]).each(function(){n.data(this,D,F)})}},removeData:function(D){return this.each(function(){n.removeData(this,D)})},queue:function(D,E){if(typeof D!=="string"){E=D;D="fx"}if(E===g){return n.queue(this[0],D)}return this.each(function(){var F=n.queue(this,D,E);if(D=="fx"&&F.length==1){F[0].call(this)}})},dequeue:function(D){return this.each(function(){n.dequeue(this,D)})}});
-/*
- * Sizzle CSS Selector Engine - v0.9.1
- * Copyright 2009, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- * More information: http://sizzlejs.com/
- */
-(function(){var N=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|[^[\]]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g,I=0,F=Object.prototype.toString;var E=function(ae,S,aa,V){aa=aa||[];S=S||document;if(S.nodeType!==1&&S.nodeType!==9){return[]}if(!ae||typeof ae!=="string"){return aa}var ab=[],ac,Y,ah,ag,Z,R,Q=true;N.lastIndex=0;while((ac=N.exec(ae))!==null){ab.push(ac[1]);if(ac[2]){R=RegExp.rightContext;break}}if(ab.length>1&&G.match.POS.exec(ae)){if(ab.length===2&&G.relative[ab[0]]){var U="",X;while((X=G.match.POS.exec(ae))){U+=X[0];ae=ae.replace(G.match.POS,"")}Y=E.filter(U,E(/\s$/.test(ae)?ae+"*":ae,S))}else{Y=G.relative[ab[0]]?[S]:E(ab.shift(),S);while(ab.length){var P=[];ae=ab.shift();if(G.relative[ae]){ae+=ab.shift()}for(var af=0,ad=Y.length;af<ad;af++){E(ae,Y[af],P)}Y=P}}}else{var ai=V?{expr:ab.pop(),set:D(V)}:E.find(ab.pop(),ab.length===1&&S.parentNode?S.parentNode:S);Y=E.filter(ai.expr,ai.set);if(ab.length>0){ah=D(Y)}else{Q=false}while(ab.length){var T=ab.pop(),W=T;if(!G.relative[T]){T=""}else{W=ab.pop()}if(W==null){W=S}G.relative[T](ah,W,M(S))}}if(!ah){ah=Y}if(!ah){throw"Syntax error, unrecognized expression: "+(T||ae)}if(F.call(ah)==="[object Array]"){if(!Q){aa.push.apply(aa,ah)}else{if(S.nodeType===1){for(var af=0;ah[af]!=null;af++){if(ah[af]&&(ah[af]===true||ah[af].nodeType===1&&H(S,ah[af]))){aa.push(Y[af])}}}else{for(var af=0;ah[af]!=null;af++){if(ah[af]&&ah[af].nodeType===1){aa.push(Y[af])}}}}}else{D(ah,aa)}if(R){E(R,S,aa,V)}return aa};E.matches=function(P,Q){return E(P,null,null,Q)};E.find=function(V,S){var W,Q;if(!V){return[]}for(var R=0,P=G.order.length;R<P;R++){var T=G.order[R],Q;if((Q=G.match[T].exec(V))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){Q[1]=(Q[1]||"").replace(/\\/g,"");W=G.find[T](Q,S);if(W!=null){V=V.replace(G.match[T],"");break}}}}if(!W){W=S.getElementsByTagName("*")}return{set:W,expr:V}};E.filter=function(S,ac,ad,T){var Q=S,Y=[],ah=ac,V,ab;while(S&&ac.length){for(var U in G.filter){if((V=G.match[U].exec(S))!=null){var Z=G.filter[U],R=null,X=0,aa,ag;ab=false;if(ah==Y){Y=[]}if(G.preFilter[U]){V=G.preFilter[U](V,ah,ad,Y,T);if(!V){ab=aa=true}else{if(V===true){continue}else{if(V[0]===true){R=[];var W=null,af;for(var ae=0;(af=ah[ae])!==g;ae++){if(af&&W!==af){R.push(af);W=af}}}}}}if(V){for(var ae=0;(ag=ah[ae])!==g;ae++){if(ag){if(R&&ag!=R[X]){X++}aa=Z(ag,V,X,R);var P=T^!!aa;if(ad&&aa!=null){if(P){ab=true}else{ah[ae]=false}}else{if(P){Y.push(ag);ab=true}}}}}if(aa!==g){if(!ad){ah=Y}S=S.replace(G.match[U],"");if(!ab){return[]}break}}}S=S.replace(/\s*,\s*/,"");if(S==Q){if(ab==null){throw"Syntax error, unrecognized expression: "+S}else{break}}Q=S}return ah};var G=E.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(P){return P.getAttribute("href")}},relative:{"+":function(T,Q){for(var R=0,P=T.length;R<P;R++){var S=T[R];if(S){var U=S.previousSibling;while(U&&U.nodeType!==1){U=U.previousSibling}T[R]=typeof Q==="string"?U||false:U===Q}}if(typeof Q==="string"){E.filter(Q,T,true)}},">":function(U,Q,V){if(typeof Q==="string"&&!/\W/.test(Q)){Q=V?Q:Q.toUpperCase();for(var R=0,P=U.length;R<P;R++){var T=U[R];if(T){var S=T.parentNode;U[R]=S.nodeName===Q?S:false}}}else{for(var R=0,P=U.length;R<P;R++){var T=U[R];if(T){U[R]=typeof Q==="string"?T.parentNode:T.parentNode===Q}}if(typeof Q==="string"){E.filter(Q,U,true)}}},"":function(S,Q,U){var R="done"+(I++),P=O;if(!Q.match(/\W/)){var T=Q=U?Q:Q.toUpperCase();P=L}P("parentNode",Q,R,S,T,U)},"~":function(S,Q,U){var R="done"+(I++),P=O;if(typeof Q==="string"&&!Q.match(/\W/)){var T=Q=U?Q:Q.toUpperCase();P=L}P("previousSibling",Q,R,S,T,U)}},find:{ID:function(Q,R){if(R.getElementById){var P=R.getElementById(Q[1]);return P?[P]:[]}},NAME:function(P,Q){return Q.getElementsByName?Q.getElementsByName(P[1]):null},TAG:function(P,Q){return Q.getElementsByTagName(P[1])}},preFilter:{CLASS:function(S,Q,R,P,U){S=" "+S[1].replace(/\\/g,"")+" ";for(var T=0;Q[T];T++){if(U^(" "+Q[T].className+" ").indexOf(S)>=0){if(!R){P.push(Q[T])}}else{if(R){Q[T]=false}}}return false},ID:function(P){return P[1].replace(/\\/g,"")},TAG:function(Q,P){for(var R=0;!P[R];R++){}return M(P[R])?Q[1]:Q[1].toUpperCase()},CHILD:function(P){if(P[1]=="nth"){var Q=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(P[2]=="even"&&"2n"||P[2]=="odd"&&"2n+1"||!/\D/.test(P[2])&&"0n+"+P[2]||P[2]);P[2]=(Q[1]+(Q[2]||1))-0;P[3]=Q[3]-0}P[0]="done"+(I++);return P},ATTR:function(Q){var P=Q[1];if(G.attrMap[P]){Q[1]=G.attrMap[P]}if(Q[2]==="~="){Q[4]=" "+Q[4]+" "}return Q},PSEUDO:function(T,Q,R,P,U){if(T[1]==="not"){if(T[3].match(N).length>1){T[3]=E(T[3],null,null,Q)}else{var S=E.filter(T[3],Q,R,true^U);if(!R){P.push.apply(P,S)}return false}}else{if(G.match.POS.test(T[0])){return true}}return T},POS:function(P){P.unshift(true);return P}},filters:{enabled:function(P){return P.disabled===false&&P.type!=="hidden"},disabled:function(P){return P.disabled===true},checked:function(P){return P.checked===true},selected:function(P){P.parentNode.selectedIndex;return P.selected===true},parent:function(P){return !!P.firstChild},empty:function(P){return !P.firstChild},has:function(R,Q,P){return !!E(P[3],R).length},header:function(P){return/h\d/i.test(P.nodeName)},text:function(P){return"text"===P.type},radio:function(P){return"radio"===P.type},checkbox:function(P){return"checkbox"===P.type},file:function(P){return"file"===P.type},password:function(P){return"password"===P.type},submit:function(P){return"submit"===P.type},image:function(P){return"image"===P.type},reset:function(P){return"reset"===P.type},button:function(P){return"button"===P.type||P.nodeName.toUpperCase()==="BUTTON"},input:function(P){return/input|select|textarea|button/i.test(P.nodeName)}},setFilters:{first:function(Q,P){return P===0},last:function(R,Q,P,S){return Q===S.length-1},even:function(Q,P){return P%2===0},odd:function(Q,P){return P%2===1},lt:function(R,Q,P){return Q<P[3]-0},gt:function(R,Q,P){return Q>P[3]-0},nth:function(R,Q,P){return P[3]-0==Q},eq:function(R,Q,P){return P[3]-0==Q}},filter:{CHILD:function(P,S){var V=S[1],W=P.parentNode;var U="child"+W.childNodes.length;if(W&&(!W[U]||!P.nodeIndex)){var T=1;for(var Q=W.firstChild;Q;Q=Q.nextSibling){if(Q.nodeType==1){Q.nodeIndex=T++}}W[U]=T-1}if(V=="first"){return P.nodeIndex==1}else{if(V=="last"){return P.nodeIndex==W[U]}else{if(V=="only"){return W[U]==1}else{if(V=="nth"){var Y=false,R=S[2],X=S[3];if(R==1&&X==0){return true}if(R==0){if(P.nodeIndex==X){Y=true}}else{if((P.nodeIndex-X)%R==0&&(P.nodeIndex-X)/R>=0){Y=true}}return Y}}}}},PSEUDO:function(V,R,S,W){var Q=R[1],T=G.filters[Q];if(T){return T(V,S,R,W)}else{if(Q==="contains"){return(V.textContent||V.innerText||"").indexOf(R[3])>=0}else{if(Q==="not"){var U=R[3];for(var S=0,P=U.length;S<P;S++){if(U[S]===V){return false}}return true}}}},ID:function(Q,P){return Q.nodeType===1&&Q.getAttribute("id")===P},TAG:function(Q,P){return(P==="*"&&Q.nodeType===1)||Q.nodeName===P},CLASS:function(Q,P){return P.test(Q.className)},ATTR:function(T,R){var P=G.attrHandle[R[1]]?G.attrHandle[R[1]](T):T[R[1]]||T.getAttribute(R[1]),U=P+"",S=R[2],Q=R[4];return P==null?false:S==="="?U===Q:S==="*="?U.indexOf(Q)>=0:S==="~="?(" "+U+" ").indexOf(Q)>=0:!R[4]?P:S==="!="?U!=Q:S==="^="?U.indexOf(Q)===0:S==="$="?U.substr(U.length-Q.length)===Q:S==="|="?U===Q||U.substr(0,Q.length+1)===Q+"-":false},POS:function(T,Q,R,U){var P=Q[2],S=G.setFilters[P];if(S){return S(T,R,Q,U)}}}};for(var K in G.match){G.match[K]=RegExp(G.match[K].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var D=function(Q,P){Q=Array.prototype.slice.call(Q);if(P){P.push.apply(P,Q);return P}return Q};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(J){D=function(T,S){var Q=S||[];if(F.call(T)==="[object Array]"){Array.prototype.push.apply(Q,T)}else{if(typeof T.length==="number"){for(var R=0,P=T.length;R<P;R++){Q.push(T[R])}}else{for(var R=0;T[R];R++){Q.push(T[R])}}}return Q}}(function(){var Q=document.createElement("form"),R="script"+(new Date).getTime();Q.innerHTML="<input name='"+R+"'/>";var P=document.documentElement;P.insertBefore(Q,P.firstChild);if(!!document.getElementById(R)){G.find.ID=function(T,U){if(U.getElementById){var S=U.getElementById(T[1]);return S?S.id===T[1]||S.getAttributeNode&&S.getAttributeNode("id").nodeValue===T[1]?[S]:g:[]}};G.filter.ID=function(U,S){var T=U.getAttributeNode&&U.getAttributeNode("id");return U.nodeType===1&&T&&T.nodeValue===S}}P.removeChild(Q)})();(function(){var P=document.createElement("div");P.appendChild(document.createComment(""));if(P.getElementsByTagName("*").length>0){G.find.TAG=function(Q,U){var T=U.getElementsByTagName(Q[1]);if(Q[1]==="*"){var S=[];for(var R=0;T[R];R++){if(T[R].nodeType===1){S.push(T[R])}}T=S}return T}}P.innerHTML="<a href='#'></a>";if(P.firstChild.getAttribute("href")!=="#"){G.attrHandle.href=function(Q){return Q.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var P=E;E=function(T,S,Q,R){S=S||document;if(!R&&S.nodeType===9){try{return D(S.querySelectorAll(T),Q)}catch(U){}}return P(T,S,Q,R)};E.find=P.find;E.filter=P.filter;E.selectors=P.selectors;E.matches=P.matches})()}if(document.documentElement.getElementsByClassName){G.order.splice(1,0,"CLASS");G.find.CLASS=function(P,Q){return Q.getElementsByClassName(P[1])}}function L(Q,W,V,Z,X,Y){for(var T=0,R=Z.length;T<R;T++){var P=Z[T];if(P){P=P[Q];var U=false;while(P&&P.nodeType){var S=P[V];if(S){U=Z[S];break}if(P.nodeType===1&&!Y){P[V]=T}if(P.nodeName===W){U=P;break}P=P[Q]}Z[T]=U}}}function O(Q,V,U,Y,W,X){for(var S=0,R=Y.length;S<R;S++){var P=Y[S];if(P){P=P[Q];var T=false;while(P&&P.nodeType){if(P[U]){T=Y[P[U]];break}if(P.nodeType===1){if(!X){P[U]=S}if(typeof V!=="string"){if(P===V){T=true;break}}else{if(E.filter(V,[P]).length>0){T=P;break}}}P=P[Q]}Y[S]=T}}}var H=document.compareDocumentPosition?function(Q,P){return Q.compareDocumentPosition(P)&16}:function(Q,P){return Q!==P&&(Q.contains?Q.contains(P):true)};var M=function(P){return P.documentElement&&!P.body||P.tagName&&P.ownerDocument&&!P.ownerDocument.body};n.find=E;n.filter=E.filter;n.expr=E.selectors;n.expr[":"]=n.expr.filters;E.selectors.filters.hidden=function(P){return"hidden"===P.type||n.css(P,"display")==="none"||n.css(P,"visibility")==="hidden"};E.selectors.filters.visible=function(P){return"hidden"!==P.type&&n.css(P,"display")!=="none"&&n.css(P,"visibility")!=="hidden"};E.selectors.filters.animated=function(P){return n.grep(n.timers,function(Q){return P===Q.elem}).length};n.multiFilter=function(R,P,Q){if(Q){R=":not("+R+")"}return E.matches(R,P)};n.dir=function(R,Q){var P=[],S=R[Q];while(S&&S!=document){if(S.nodeType==1){P.push(S)}S=S[Q]}return P};n.nth=function(T,P,R,S){P=P||1;var Q=0;for(;T;T=T[R]){if(T.nodeType==1&&++Q==P){break}}return T};n.sibling=function(R,Q){var P=[];for(;R;R=R.nextSibling){if(R.nodeType==1&&R!=Q){P.push(R)}}return P};return;l.Sizzle=E})();n.event={add:function(H,E,G,J){if(H.nodeType==3||H.nodeType==8){return}if(H.setInterval&&H!=l){H=l}if(!G.guid){G.guid=this.guid++}if(J!==g){var F=G;G=this.proxy(F);G.data=J}var D=n.data(H,"events")||n.data(H,"events",{}),I=n.data(H,"handle")||n.data(H,"handle",function(){return typeof n!=="undefined"&&!n.event.triggered?n.event.handle.apply(arguments.callee.elem,arguments):g});I.elem=H;n.each(E.split(/\s+/),function(L,M){var N=M.split(".");M=N.shift();G.type=N.slice().sort().join(".");var K=D[M];if(n.event.specialAll[M]){n.event.specialAll[M].setup.call(H,J,N)}if(!K){K=D[M]={};if(!n.event.special[M]||n.event.special[M].setup.call(H,J,N)===false){if(H.addEventListener){H.addEventListener(M,I,false)}else{if(H.attachEvent){H.attachEvent("on"+M,I)}}}}K[G.guid]=G;n.event.global[M]=true});H=null},guid:1,global:{},remove:function(J,G,I){if(J.nodeType==3||J.nodeType==8){return}var F=n.data(J,"events"),E,D;if(F){if(G===g||(typeof G==="string"&&G.charAt(0)==".")){for(var H in F){this.remove(J,H+(G||""))}}else{if(G.type){I=G.handler;G=G.type}n.each(G.split(/\s+/),function(L,N){var P=N.split(".");N=P.shift();var M=RegExp("(^|\\.)"+P.slice().sort().join(".*\\.")+"(\\.|$)");if(F[N]){if(I){delete F[N][I.guid]}else{for(var O in F[N]){if(M.test(F[N][O].type)){delete F[N][O]}}}if(n.event.specialAll[N]){n.event.specialAll[N].teardown.call(J,P)}for(E in F[N]){break}if(!E){if(!n.event.special[N]||n.event.special[N].teardown.call(J,P)===false){if(J.removeEventListener){J.removeEventListener(N,n.data(J,"handle"),false)}else{if(J.detachEvent){J.detachEvent("on"+N,n.data(J,"handle"))}}}E=null;delete F[N]}}})}for(E in F){break}if(!E){var K=n.data(J,"handle");if(K){K.elem=null}n.removeData(J,"events");n.removeData(J,"handle")}}},trigger:function(H,J,G,D){var F=H.type||H;if(!D){H=typeof H==="object"?H[h]?H:n.extend(n.Event(F),H):n.Event(F);if(F.indexOf("!")>=0){H.type=F=F.slice(0,-1);H.exclusive=true}if(!G){H.stopPropagation();if(this.global[F]){n.each(n.cache,function(){if(this.events&&this.events[F]){n.event.trigger(H,J,this.handle.elem)}})}}if(!G||G.nodeType==3||G.nodeType==8){return g}H.result=g;H.target=G;J=n.makeArray(J);J.unshift(H)}H.currentTarget=G;var I=n.data(G,"handle");if(I){I.apply(G,J)}if((!G[F]||(n.nodeName(G,"a")&&F=="click"))&&G["on"+F]&&G["on"+F].apply(G,J)===false){H.result=false}if(!D&&G[F]&&!H.isDefaultPrevented()&&!(n.nodeName(G,"a")&&F=="click")){this.triggered=true;try{G[F]()}catch(K){}}this.triggered=false;if(!H.isPropagationStopped()){var E=G.parentNode||G.ownerDocument;if(E){n.event.trigger(H,J,E,true)}}},handle:function(J){var I,D;J=arguments[0]=n.event.fix(J||l.event);var K=J.type.split(".");J.type=K.shift();I=!K.length&&!J.exclusive;var H=RegExp("(^|\\.)"+K.slice().sort().join(".*\\.")+"(\\.|$)");D=(n.data(this,"events")||{})[J.type];for(var F in D){var G=D[F];if(I||H.test(G.type)){J.handler=G;J.data=G.data;var E=G.apply(this,arguments);if(E!==g){J.result=E;if(E===false){J.preventDefault();J.stopPropagation()}}if(J.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(G){if(G[h]){return G}var E=G;G=n.Event(E);for(var F=this.props.length,I;F;){I=this.props[--F];G[I]=E[I]}if(!G.target){G.target=G.srcElement||document}if(G.target.nodeType==3){G.target=G.target.parentNode}if(!G.relatedTarget&&G.fromElement){G.relatedTarget=G.fromElement==G.target?G.toElement:G.fromElement}if(G.pageX==null&&G.clientX!=null){var H=document.documentElement,D=document.body;G.pageX=G.clientX+(H&&H.scrollLeft||D&&D.scrollLeft||0)-(H.clientLeft||0);G.pageY=G.clientY+(H&&H.scrollTop||D&&D.scrollTop||0)-(H.clientTop||0)}if(!G.which&&((G.charCode||G.charCode===0)?G.charCode:G.keyCode)){G.which=G.charCode||G.keyCode}if(!G.metaKey&&G.ctrlKey){G.metaKey=G.ctrlKey}if(!G.which&&G.button){G.which=(G.button&1?1:(G.button&2?3:(G.button&4?2:0)))}return G},proxy:function(E,D){D=D||function(){return E.apply(this,arguments)};D.guid=E.guid=E.guid||D.guid||this.guid++;return D},special:{ready:{setup:A,teardown:function(){}}},specialAll:{live:{setup:function(D,E){n.event.add(this,E[0],c)},teardown:function(F){if(F.length){var D=0,E=RegExp("(^|\\.)"+F[0]+"(\\.|$)");n.each((n.data(this,"events").live||{}),function(){if(E.test(this.type)){D++}});if(D<1){n.event.remove(this,F[0],c)}}}}}};n.Event=function(D){if(!this.preventDefault){return new n.Event(D)}if(D&&D.type){this.originalEvent=D;this.type=D.type;this.timeStamp=D.timeStamp}else{this.type=D}if(!this.timeStamp){this.timeStamp=e()}this[h]=true};function k(){return false}function t(){return true}n.Event.prototype={preventDefault:function(){this.isDefaultPrevented=t;var D=this.originalEvent;if(!D){return}if(D.preventDefault){D.preventDefault()}D.returnValue=false},stopPropagation:function(){this.isPropagationStopped=t;var D=this.originalEvent;if(!D){return}if(D.stopPropagation){D.stopPropagation()}D.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=t;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(E){var D=E.relatedTarget;while(D&&D!=this){try{D=D.parentNode}catch(F){D=this}}if(D!=this){E.type=E.data;n.event.handle.apply(this,arguments)}};n.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(E,D){n.event.special[D]={setup:function(){n.event.add(this,E,a,D)},teardown:function(){n.event.remove(this,E,a)}}});n.fn.extend({bind:function(E,F,D){return E=="unloaddisabled"?this.one(E,F,D):this.each(function(){n.event.add(this,E,D||F,D&&F)})},one:function(F,G,E){var D=n.event.proxy(E||G,function(H){n(this).unbind(H,D);return(E||G).apply(this,arguments)});return this.each(function(){n.event.add(this,F,D,E&&G)})},unbind:function(E,D){return this.each(function(){n.event.remove(this,E,D)})},trigger:function(D,E){return this.each(function(){n.event.trigger(D,E,this)})},triggerHandler:function(D,F){if(this[0]){var E=n.Event(D);E.preventDefault();E.stopPropagation();n.event.trigger(E,F,this[0]);return E.result}},toggle:function(F){var D=arguments,E=1;while(E<D.length){n.event.proxy(F,D[E++])}return this.click(n.event.proxy(F,function(G){this.lastToggle=(this.lastToggle||0)%E;G.preventDefault();return D[this.lastToggle++].apply(this,arguments)||false}))},hover:function(D,E){return this.mouseenter(D).mouseleave(E)},ready:function(D){A();if(n.isReady){D.call(document,n)}else{n.readyList.push(D)}return this},live:function(F,E){var D=n.event.proxy(E);D.guid+=this.selector+F;n(document).bind(i(F,this.selector),this.selector,D);return this},die:function(E,D){n(document).unbind(i(E,this.selector),D?{guid:D.guid+this.selector+E}:null);return this}});function c(G){var D=RegExp("(^|\\.)"+G.type+"(\\.|$)"),F=true,E=[];n.each(n.data(this,"events").live||[],function(H,I){if(D.test(I.type)){var J=n(G.target).closest(I.data)[0];if(J){E.push({elem:J,fn:I})}}});n.each(E,function(){if(!G.isImmediatePropagationStopped()&&this.fn.call(this.elem,G,this.fn.data)===false){F=false}});return F}function i(E,D){return["live",E,D.replace(/\./g,"`").replace(/ /g,"|")].join(".")}n.extend({isReady:false,readyList:[],ready:function(){if(!n.isReady){n.isReady=true;if(n.readyList){n.each(n.readyList,function(){this.call(document,n)});n.readyList=null}n(document).triggerHandler("ready")}}});var w=false;function A(){if(w){return}w=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);n.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);n.ready()}});if(document.documentElement.doScroll&&!l.frameElement){(function(){if(n.isReady){return}try{document.documentElement.doScroll("left")}catch(D){setTimeout(arguments.callee,0);return}n.ready()})()}}}n.event.add(l,"loaddisabled",n.ready)}n.each(("blur,focus,loaddisabled,resize,scroll,unloaddisabled,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(E,D){n.fn[D]=function(F){return F?this.bind(D,F):this.trigger(D)}});n(l).bind("unloaddisabled",function(){for(var D in n.cache){if(D!=1&&n.cache[D].handle){n.event.remove(n.cache[D].handle.elem)}}});(function(){n.support={};var E=document.documentElement,F=document.createElement("script"),J=document.createElement("div"),I="script"+(new Date).getTime();J.style.display="none";J.innerHTML=' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><objectdisabled><param/></object>';var G=J.getElementsByTagName("*"),D=J.getElementsByTagName("a")[0];if(!G||!G.length||!D){return}n.support={leadingWhitespace:J.firstChild.nodeType==3,tbody:!J.getElementsByTagName("tbody").length,objectAll:!!J.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!J.getElementsByTagName("link").length,style:/red/.test(D.getAttribute("style")),hrefNormalized:D.getAttribute("href")==="/a",opacity:D.style.opacity==="0.5",cssFloat:!!D.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};F.type="text/javascript";try{F.appendChild(document.createTextNode("window."+I+"=1;"))}catch(H){}E.insertBefore(F,E.firstChild);if(l[I]){n.support.scriptEval=true;delete l[I]}E.removeChild(F);if(J.attachEvent&&J.fireEvent){J.attachEvent("onclick",function(){n.support.noCloneEvent=false;J.detachEvent("onclick",arguments.callee)});J.cloneNode(true).fireEvent("onclick")}n(function(){var K=document.createElement("div");K.style.width="1px";K.style.paddingLeft="1px";document.body.appendChild(K);n.boxModel=n.support.boxModel=K.offsetWidth===2;document.body.removeChild(K)})})();var v=n.support.cssFloat?"cssFloat":"styleFloat";n.props={"for":"htmlFor","class":"className","float":v,cssFloat:v,styleFloat:v,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};n.fn.extend({_loaddisabled:n.fn.loaddisabled,loaddisabled:function(F,I,J){if(typeof F!=="string"){return this._loaddisabled(F)}var H=F.indexOf(" ");if(H>=0){var D=F.slice(H,F.length);F=F.slice(0,H)}var G="GET";if(I){if(n.isFunction(I)){J=I;I=null}else{if(typeof I==="object"){I=n.param(I);G="POST"}}}var E=this;n.ajax({url:F,type:G,dataType:"html",data:I,complete:function(L,K){if(K=="success"||K=="notmodified"){E.html(D?n("<div/>").append(L.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(D):L.responseText)}if(J){E.each(J,[L.responseText,K,L])}}});return this},serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?n.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type))}).map(function(D,E){var F=n(this).val();return F==null?null:n.isArray(F)?n.map(F,function(H,G){return{name:E.name,value:H}}):{name:E.name,value:F}}).get()}});n.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(D,E){n.fn[E]=function(F){return this.bind(E,F)}});var q=e();n.extend({get:function(D,F,G,E){if(n.isFunction(F)){G=F;F=null}return n.ajax({type:"GET",url:D,data:F,success:G,dataType:E})},getScript:function(D,E){return n.get(D,null,E,"script")},getJSON:function(D,E,F){return n.get(D,E,F,"json")},post:function(D,F,G,E){if(n.isFunction(F)){G=F;F={}}return n.ajax({type:"POST",url:D,data:F,success:G,dataType:E})},ajaxSetup:function(D){n.extend(n.ajaxSettings,D)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(L){L=n.extend(true,L,n.extend(true,{},n.ajaxSettings,L));var V,E=/=\?(&|$)/g,Q,U,F=L.type.toUpperCase();if(L.data&&L.processData&&typeof L.data!=="string"){L.data=n.param(L.data)}if(L.dataType=="jsonp"){if(F=="GET"){if(!L.url.match(E)){L.url+=(L.url.match(/\?/)?"&":"?")+(L.jsonp||"callback")+"=?"}}else{if(!L.data||!L.data.match(E)){L.data=(L.data?L.data+"&":"")+(L.jsonp||"callback")+"=?"}}L.dataType="json"}if(L.dataType=="json"&&(L.data&&L.data.match(E)||L.url.match(E))){V="jsonp"+q++;if(L.data){L.data=(L.data+"").replace(E,"="+V+"$1")}L.url=L.url.replace(E,"="+V+"$1");L.dataType="script";l[V]=function(W){U=W;H();K();l[V]=g;try{delete l[V]}catch(X){}if(G){G.removeChild(S)}}}if(L.dataType=="script"&&L.cache==null){L.cache=false}if(L.cache===false&&F=="GET"){var D=e();var T=L.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+D+"$2");L.url=T+((T==L.url)?(L.url.match(/\?/)?"&":"?")+"_="+D:"")}if(L.data&&F=="GET"){L.url+=(L.url.match(/\?/)?"&":"?")+L.data;L.data=null}if(L.global&&!n.active++){n.event.trigger("ajaxStart")}var P=/^(\w+:)?\/\/([^\/?#]+)/.exec(L.url);if(L.dataType=="script"&&F=="GET"&&P&&(P[1]&&P[1]!=location.protocol||P[2]!=location.host)){var G=document.getElementsByTagName("head")[0];var S=document.createElement("script");S.src=L.url;if(L.scriptCharset){S.charset=L.scriptCharset}if(!V){var N=false;S.onloaddisabled=S.onreadystatechange=function(){if(!N&&(!this.readyState||this.readyState=="loaddisableded"||this.readyState=="complete")){N=true;H();K();G.removeChild(S)}}}G.appendChild(S);return g}var J=false;var I=L.xhr();if(L.username){void(F,L.url,L.async,L.username,L.password)}else{void(F,L.url,L.async)}try{if(L.data){I.setRequestHeader("Content-Type",L.contentType)}if(L.ifModified){I.setRequestHeader("If-Modified-Since",n.lastModified[L.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}I.setRequestHeader("X-Requested-With","XMLHttpRequest");I.setRequestHeader("Accept",L.dataType&&L.accepts[L.dataType]?L.accepts[L.dataType]+", */*":L.accepts._default)}catch(R){}if(L.beforeSend&&L.beforeSend(I,L)===false){if(L.global&&!--n.active){n.event.trigger("ajaxStop")}I.abort();return false}if(L.global){n.event.trigger("ajaxSend",[I,L])}var M=function(W){if(I.readyState==0){if(O){clearInterval(O);O=null;if(L.global&&!--n.active){n.event.trigger("ajaxStop")}}}else{if(!J&&I&&(I.readyState==4||W=="timeout")){J=true;if(O){clearInterval(O);O=null}Q=W=="timeout"?"timeout":!n.httpSuccess(I)?"error":L.ifModified&&n.httpNotModified(I,L.url)?"notmodified":"success";if(Q=="success"){try{U=n.httpData(I,L.dataType,L)}catch(Y){Q="parsererror"}}if(Q=="success"){var X;try{X=I.getResponseHeader("Last-Modified")}catch(Y){}if(L.ifModified&&X){n.lastModified[L.url]=X}if(!V){H()}}else{n.handleError(L,I,Q)}K();if(L.async){I=null}}}};if(L.async){var O=setInterval(M,13);if(L.timeout>0){setTimeout(function(){if(I){if(!J){M("timeout")}if(I){I.abort()}}},L.timeout)}}try{I.send(L.data)}catch(R){n.handleError(L,I,null,R)}if(!L.async){M()}function H(){if(L.success){L.success(U,Q)}if(L.global){n.event.trigger("ajaxSuccess",[I,L])}}function K(){if(L.complete){L.complete(I,Q)}if(L.global){n.event.trigger("ajaxComplete",[I,L])}if(L.global&&!--n.active){n.event.trigger("ajaxStop")}}return I},handleError:function(E,G,D,F){if(E.error){E.error(G,D,F)}if(E.global){n.event.trigger("ajaxError",[G,E,F])}},active:0,httpSuccess:function(E){try{return !E.status&&location.protocol=="file:"||(E.status>=200&&E.status<300)||E.status==304||E.status==1223}catch(D){}return false},httpNotModified:function(F,D){try{var G=F.getResponseHeader("Last-Modified");return F.status==304||G==n.lastModified[D]}catch(E){}return false},httpData:function(I,G,F){var E=I.getResponseHeader("content-type"),D=G=="xml"||!G&&E&&E.indexOf("xml")>=0,H=D?I.responseXML:I.responseText;if(D&&H.documentElement.tagName=="parsererror"){throw"parsererror"}if(F&&F.dataFilter){H=F.dataFilter(H,G)}if(typeof H==="string"){if(G=="script"){n.globalEval(H)}if(G=="json"){H=l["eval"]("("+H+")")}}return H},param:function(D){var F=[];function G(H,I){F[F.length]=encodeURIComponent(H)+"="+encodeURIComponent(I)}if(n.isArray(D)||D.jquery){n.each(D,function(){G(this.name,this.value)})}else{for(var E in D){if(n.isArray(D[E])){n.each(D[E],function(){G(E,this)})}else{G(E,n.isFunction(D[E])?D[E]():D[E])}}}return F.join("&").replace(/%20/g,"+")}});var m={},d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function s(E,D){var F={};n.each(d.concat.apply([],d.slice(0,D)),function(){F[this]=E});return F}n.fn.extend({show:function(I,K){if(I){return this.animate(s("show",3),I,K)}else{for(var G=0,E=this.length;G<E;G++){var D=n.data(this[G],"olddisplay");this[G].style.display=D||"";if(n.css(this[G],"display")==="none"){var F=this[G].tagName,J;if(m[F]){J=m[F]}else{var H=n("<"+F+" />").appendTo("body");J=H.css("display");if(J==="none"){J="block"}H.remove();m[F]=J}this[G].style.display=n.data(this[G],"olddisplay",J)}}return this}},hide:function(G,H){if(G){return this.animate(s("hide",3),G,H)}else{for(var F=0,E=this.length;F<E;F++){var D=n.data(this[F],"olddisplay");if(!D&&D!=="none"){n.data(this[F],"olddisplay",n.css(this[F],"display"))}this[F].style.display="none"}return this}},_toggle:n.fn.toggle,toggle:function(F,E){var D=typeof F==="boolean";return n.isFunction(F)&&n.isFunction(E)?this._toggle.apply(this,arguments):F==null||D?this.each(function(){var G=D?F:n(this).is(":hidden");n(this)[G?"show":"hide"]()}):this.animate(s("toggle",3),F,E)},fadeTo:function(D,F,E){return this.animate({opacity:F},D,E)},animate:function(H,E,G,F){var D=n.speed(E,G,F);return this[D.queue===false?"each":"queue"](function(){var J=n.extend({},D),L,K=this.nodeType==1&&n(this).is(":hidden"),I=this;for(L in H){if(H[L]=="hide"&&K||H[L]=="show"&&!K){return J.complete.call(this)}if((L=="height"||L=="width")&&this.style){J.display=n.css(this,"display");J.overflow=this.style.overflow}}if(J.overflow!=null){this.style.overflow="hidden"}J.curAnim=n.extend({},H);n.each(H,function(N,R){var Q=new n.fx(I,J,N);if(/toggle|show|hide/.test(R)){Q[R=="toggle"?K?"show":"hide":R](H)}else{var P=R.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),S=Q.cur(true)||0;if(P){var M=parseFloat(P[2]),O=P[3]||"px";if(O!="px"){I.style[N]=(M||1)+O;S=((M||1)/Q.cur(true))*S;I.style[N]=S+O}if(P[1]){M=((P[1]=="-="?-1:1)*M)+S}Q.custom(S,M,O)}else{Q.custom(S,R,"")}}});return true})},stop:function(E,D){var F=n.timers;if(E){this.queue([])}this.each(function(){for(var G=F.length-1;G>=0;G--){if(F[G].elem==this){if(D){F[G](true)}F.splice(G,1)}}});if(!D){this.dequeue()}return this}});n.each({slideDown:s("show",1),slideUp:s("hide",1),slideToggle:s("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(D,E){n.fn[D]=function(F,G){return this.animate(E,F,G)}});n.extend({speed:function(F,G,E){var D=typeof F==="object"?F:{complete:E||!E&&G||n.isFunction(F)&&F,duration:F,easing:E&&G||G&&!n.isFunction(G)&&G};D.duration=n.fx.off?0:typeof D.duration==="number"?D.duration:n.fx.speeds[D.duration]||n.fx.speeds._default;D.old=D.complete;D.complete=function(){if(D.queue!==false){n(this).dequeue()}if(n.isFunction(D.old)){D.old.call(this)}};return D},easing:{linear:function(F,G,D,E){return D+E*F},swing:function(F,G,D,E){return((-Math.cos(F*Math.PI)/2)+0.5)*E+D}},timers:[],timerId:null,fx:function(E,D,F){this.options=D;this.elem=E;this.prop=F;if(!D.orig){D.orig={}}}});n.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(n.fx.step[this.prop]||n.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(E){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var D=parseFloat(n.css(this.elem,this.prop,E));return D&&D>-10000?D:parseFloat(n.curCSS(this.elem,this.prop))||0},custom:function(H,G,F){this.startTime=e();this.start=H;this.end=G;this.unit=F||this.unit||"px";this.now=this.start;this.pos=this.state=0;var D=this;function E(I){return D.step(I)}E.elem=this.elem;n.timers.push(E);if(E()&&n.timerId==null){n.timerId=setInterval(function(){var J=n.timers;for(var I=0;I<J.length;I++){if(!J[I]()){J.splice(I--,1)}}if(!J.length){clearInterval(n.timerId);n.timerId=null}},13)}},show:function(){this.options.orig[this.prop]=n.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());n(this.elem).show()},hide:function(){this.options.orig[this.prop]=n.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(G){var F=e();if(G||F>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var D=true;for(var E in this.options.curAnim){if(this.options.curAnim[E]!==true){D=false}}if(D){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(n.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){n(this.elem).hide()}if(this.options.hide||this.options.show){for(var H in this.options.curAnim){n.attr(this.elem.style,H,this.options.orig[H])}}}if(D){this.options.complete.call(this.elem)}return false}else{var I=F-this.startTime;this.state=I/this.options.duration;this.pos=n.easing[this.options.easing||(n.easing.swing?"swing":"linear")](this.state,I,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};n.extend(n.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(D){n.attr(D.elem.style,"opacity",D.now)},_default:function(D){if(D.elem.style&&D.elem.style[D.prop]!=null){D.elem.style[D.prop]=D.now+D.unit}else{D.elem[D.prop]=D.now}}}});if(document.documentElement.getBoundingClientRect){n.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return n.offset.bodyOffset(this[0])}var F=this[0].getBoundingClientRect(),I=this[0].ownerDocument,E=I.body,D=I.documentElement,K=D.clientTop||E.clientTop||0,J=D.clientLeft||E.clientLeft||0,H=F.top+(self.pageYOffset||n.boxModel&&D.scrollTop||E.scrollTop)-K,G=F.left+(self.pageXOffset||n.boxModel&&D.scrollLeft||E.scrollLeft)-J;return{top:H,left:G}}}else{n.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return n.offset.bodyOffset(this[0])}n.offset.initialized||n.offset.initialize();var I=this[0],F=I.offsetParent,E=I,N=I.ownerDocument,L,G=N.documentElement,J=N.body,K=N.defaultView,D=K.getComputedStyle(I,null),M=I.offsetTop,H=I.offsetLeft;while((I=I.parentNode)&&I!==J&&I!==G){L=K.getComputedStyle(I,null);M-=I.scrollTop,H-=I.scrollLeft;if(I===F){M+=I.offsetTop,H+=I.offsetLeft;if(n.offset.doesNotAddBorder&&!(n.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(I.tagName))){M+=parseInt(L.borderTopWidth,10)||0,H+=parseInt(L.borderLeftWidth,10)||0}E=F,F=I.offsetParent}if(n.offset.subtractsBorderForOverflowNotVisible&&L.overflow!=="visible"){M+=parseInt(L.borderTopWidth,10)||0,H+=parseInt(L.borderLeftWidth,10)||0}D=L}if(D.position==="relative"||D.position==="static"){M+=J.offsetTop,H+=J.offsetLeft}if(D.position==="fixed"){M+=Math.max(G.scrollTop,J.scrollTop),H+=Math.max(G.scrollLeft,J.scrollLeft)}return{top:M,left:H}}}n.offset={initialize:function(){if(this.initialized){return}var K=document.body,E=document.createElement("div"),G,F,M,H,L,D,I=K.style.marginTop,J='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"cellpadding="0"cellspacing="0"><tr><td></td></tr></table>';L={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(D in L){E.style[D]=L[D]}E.innerHTML=J;K.insertBefore(E,K.firstChild);G=E.firstChild,F=G.firstChild,H=G.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(F.offsetTop!==5);this.doesAddBorderForTableAndCells=(H.offsetTop===5);G.style.overflow="hidden",G.style.position="relative";this.subtractsBorderForOverflowNotVisible=(F.offsetTop===-5);K.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(K.offsetTop===0);K.style.marginTop=I;K.removeChild(E);this.initialized=true},bodyOffset:function(D){n.offset.initialized||n.offset.initialize();var F=D.offsetTop,E=D.offsetLeft;if(n.offset.doesNotIncludeMarginInBodyOffset){F+=parseInt(n.curCSS(D,"marginTop",true),10)||0,E+=parseInt(n.curCSS(D,"marginLeft",true),10)||0}return{top:F,left:E}}};n.fn.extend({position:function(){var H=0,G=0,E;if(this[0]){var F=this.offsetParent(),I=this.offset(),D=/^body|html$/i.test(F[0].tagName)?{top:0,left:0}:F.offset();I.top-=j(this,"marginTop");I.left-=j(this,"marginLeft");D.top+=j(F,"borderTopWidth");D.left+=j(F,"borderLeftWidth");E={top:I.top-D.top,left:I.left-D.left}}return E},offsetParent:function(){var D=this[0].offsetParent||document.body;while(D&&(!/^body|html$/i.test(D.tagName)&&n.css(D,"position")=="static")){D=D.offsetParent}return n(D)}});n.each(["Left","Top"],function(E,D){var F="scroll"+D;n.fn[F]=function(G){if(!this[0]){return null}return G!==g?this.each(function(){this==l||this==document?l.scrollTo(!E?G:n(l).scrollLeft(),E?G:n(l).scrollTop()):this[F]=G}):this[0]==l||this[0]==document?self[E?"pageYOffset":"pageXOffset"]||n.boxModel&&document.documentElement[F]||document.body[F]:this[0][F]}});n.each(["Height","Width"],function(G,E){var D=G?"Left":"Top",F=G?"Right":"Bottom";n.fn["inner"+E]=function(){return this[E.toLowerCase()]()+j(this,"padding"+D)+j(this,"padding"+F)};n.fn["outer"+E]=function(I){return this["inner"+E]()+j(this,"border"+D+"Width")+j(this,"border"+F+"Width")+(I?j(this,"margin"+D)+j(this,"margin"+F):0)};var H=E.toLowerCase();n.fn[H]=function(I){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+E]||document.body["client"+E]:this[0]==document?Math.max(document.documentElement["client"+E],document.body["scroll"+E],document.documentElement["scroll"+E],document.body["offset"+E],document.documentElement["offset"+E]):I===g?(this.length?n.css(this[0],H):null):this.css(H,typeof I==="string"?I:I+"px")}})})(); \ No newline at end of file
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/twitter.com/ICHCheezburger.html b/mobile/android/tests/browser/chrome/tp5/twitter.com/twitter.com/ICHCheezburger.html
deleted file mode 100755
index 8b36bb3a8..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/twitter.com/ICHCheezburger.html
+++ /dev/null
@@ -1,1203 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "httpdisabled://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="httpdisabled://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <head>
- <meta http-equiv="X-UA-Compatible" content="IE=8" />
-
-
- <script type="text/javascript">
-//<![CDATA[
-(function(g){var a=location.href.split("#!")[1];if(a){window.location.hash = "";g.location.pathname = g.HBR = a.replace(/^([^/])/,"/$1");}})(window);
-//]]>
-</script>
- <script type="text/javascript" charset="utf-8">
- if (!twttr) {
- var twttr = {}
- }
-
- // Benchmarking loaddisabled time.
- // twttr.timeTillReadyUnique = '1302298738-54111-580';
- // twttr.timeTillReadyStart = new Date().getTime();
- </script>
-
- <script type="text/javascript">
-//<![CDATA[
-var page={};var onCondition=function(D,C,A,B){D=D;A=A?Math.min(A,5):5;B=B||100;if(D()){C()}else{if(A>1){setTimeout(function(){onCondition(D,C,A-1,B)},B)}}};
-//]]>
-</script>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
-<meta content="en-us" http-equiv="Content-Language" />
-<meta content="ICanHasCheezburger? (ICHCheezburger) is on Twitter. Sign up for Twitter to follow ICanHasCheezburger? (ICHCheezburger) and get their latest updates" name="description" />
-<meta content="no" http-equiv="imagetoolbar" />
-<meta content="width = 780" name="viewport" />
-<meta content="4FTTxY4uvo0RZTMQqIyhh18HsepyJOctQ+XTOu1zsfE=" name="verify-v1" />
-<meta content="1" name="page" />
-<meta content="NOODP" name="robots" />
-<meta content="n" name="session-loggedin" />
-<meta content="ICHCheezburger" name="page-user-screen_name" />
- <title id="page_title">ICanHasCheezburger? (ICHCheezburger) on Twitter</title>
- <link href="httpdisabled://a1.twimg.com/a/1302214109/images/twitter_57.png" rel="apple-touch-icon" />
-<link href="httpdisabled://twitter.com/oexchange.xrd" rel="httpdisabled://oexchange.org/spec/0.8/rel/related-target" type="application/xrd+xml" />
-<link href="../a1.twimg.com/a/1302214109/images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
- <link rel="alternate" href="httpdisabled://twitter.com/statuses/user_timeline/6173842.rss" title="ICHCheezburger's Tweets" type="application/rss+xml" />
- <link rel="alternate" href="httpdisabled://twitter.com/favorites/6173842.rss" title="ICHCheezburger's Favorites" type="application/rss+xml" />
-
-
- <link href="../a2.twimg.com/a/1302214109/stylesheets/twitter.css@1302114648.css" media="screen" rel="stylesheet" type="text/css" />
-<link href="../a2.twimg.com/a/1302214109/stylesheets/geo.css@1302114648.css" media="screen" rel="stylesheet" type="text/css" />
-<link href="../a3.twimg.com/a/1302214109/stylesheets/buttons_new.css@1302114648.css" media="screen" rel="stylesheet" type="text/css" />
- <style type="text/css">
-
- body {
- background: #9AE4E8 url('../a2.twimg.com/profile_background_images/30261844/ICHCTwitterBG.jpg') fixed no-repeat;
-
-}
-
-body#show #content .meta a.screen-name,
-#content .shared-content .screen-name,
-#content .meta .byline a {
- color: #0000FF;
-}
-
-/* Link Color */
-a,
-#content tr.hentry:hover a,
-body#profile #content div.hentry:hover a,
-#side .stats a:hover span.stats_count,
-#side div.user_icon a:hover,
-li.verified-profile a:hover,
-#side .promotion .definition strong,
-p.list-numbers a:hover,
-#side div.user_icon a:hover span,
-#content .tabMenu li a,
-.translator-profile a:hover,
-#local_trend_locations li a,
-.modal-content .list-slug,
-.tweet-label a:hover,
-ol.statuses li.garuda-tweet:hover .actions-hover li span a,
-ol.statuses li.garuda-tweet .actions-hover li span a:hover {
- color: #0000FF;
-}
-
-body,
-ul#tabMenu li a, #side .section h1,
-#side .stat a,
-#side .stats a span.stats_count,
-#side div.section-header h1,
-#side div.user_icon a,
-#side div.user_icon a:hover,
-#side div.section-header h3.faq-header,
-ul.sidebar-menu li.active a,
-li.verified-profile a,
-#side .promotion a,
-body #content .list-header h2,
-p.list-numbers a,
-.bar h3 label,
-body.timeline #content h1,
-.list-header h2 a span,
-#content .tabMenu li.active a,
-body#direct_messages #content .tabMenu #inbox_tab a,
-body#inbox #content .tabMenu #inbox_tab a,
-body#sent #content .tabMenu #sent_tab a,
-body#direct_messages #content .tabMenu #inbox_tab a,
-body#retweets_by_others #content .tabMenu #retweets_by_others_tab a,
-body#retweets #content .tabMenu #retweets_tab a,
-body#retweeted_by_others #content .tabMenu #retweeted_by_others_tab a,
-body#retweeted_of_mine #content .tabMenu #retweeted_of_mine_tab a,
-.translator-profile a,
-#owners_lists h2 a {
- color: #000000;
-}
-
-.email-address-nag-banner {
- border-bottom: solid 1px #87BC44;
-}
-#side_base {
- border-left:1px solid #87BC44;
- background-color: #E0FF92;
-}
-
-ul.sidebar-menu li.active a,
-ul.sidebar-menu li a:hover,
-#side div#custom_search.active,
-#side .promotion,
-.notify div {
- background-color: #F4FFA6;
-}
-
-.list-header,
-.list-controls,
-ul.sidebar-list li.active a,
-ul.sidebar-list li a:hover,
-.list-header-inner {
- background-color: #E0FF92 !important;
-}
-
-#side .actions,
-#side .promo,
-#design .side-section {
- border: 1px solid #87BC44;
-}
-
-#side div.section-header h3 {
- border-bottom: 1px solid #87BC44;
-}
-
-#side p.sidebar-location {
- border-bottom: 1px dotted #87BC44;
-}
-
-#side hr {
- background: #87BC44;
- color: #87BC44;
-}
-
-ul.sidebar-menu li.loaddisableding a {
- background: #F4FFA6 url('../a1.twimg.com/a/1302214109/images/spinner.gif') no-repeat 171px 0.5em !important;
-}
-
-#side .collapsible h2.sidebar-title {
- background: transparent url('../a2.twimg.com/a/1302214109/images/toggle_up_dark.png') no-repeat center right !important;
-}
-
-#side .collapsible.collapsed h2.sidebar-title {
- background: transparent url('../a1.twimg.com/a/1302214109/images/toggle_down_dark.png') no-repeat center right !important;
-}
-
-#side ul.lists-links li a em {
- background: url('../a3.twimg.com/a/1302214109/images/arrow_right_dark.png') no-repeat left top;
-}
-
-#side span.pipe {
- border-left:1px solid #87BC44;
-}
-
-#list_subscriptions span.view-all,
-#list_memberships span.view-all,
-#profile span.view-all,
-#profile_favorites span.view-all,
-#following span.view-all,
-#followers span.view-all {
- border-left: 0;
-}
-
-a.edit-list {
- border-right: 1px solid #87BC44 !important;
-}
-
-
-
- </style>
- <link href="../a1.twimg.com/a/1302214109/stylesheets/following.css@1302114648.css" media="screen, projection" rel="stylesheet" type="text/css" />
-
- </head>
-
- <body class="account firefox signin-island" id="profile"> <div class="fixed-banners">
-
-
- </div>
- <script type="text/javascript">
-//<![CDATA[
-document.domain = 'twitter.com';function fn(){void = "";window.top.location = window.self.location;setTimeout(function(){document.body.innerHTML = '';},0);window.self.onloaddisabled = function(evt){document.body.innerHTML = '';};}if(window.top !== window.self){try{if(window.top.location.host){}else{fn();}}catch(e){fn();}}
-//]]>
-</script>
- <div id="dim-screen"></div>
- <ul id="accessibility" class="offscreen">
- <li><a href="ICHCheezburger.html#content" accesskey="0">Skip past navigation</a></li>
- <li>On a mobile phone? Check out <a href="httpdisabled://m.twitter.com/">m.twitter.com</a>!</li>
- <li><a href="ICHCheezburger.html#footer" accesskey="2">Skip to navigation</a></li>
- <li><a href="ICHCheezburger.html#signin">Skip to sign in form</a></li>
-</ul>
-
-
-
-
-
-
- <div id="container" class="subpage">
- <span id="loaddisableder" style="display:none"><img alt="Loader" src="../a0.twimg.com/a/1302214109/images/loader.gif" /></span>
-
- <div class="clearfix" id="header">
- <a href="httpdisabled://twitter.com/" title="Twitter / Home" accesskey="1" id="logo">
- <img alt="Twitter.com" src="../a0.twimg.com/a/1302214109/images/twitter_logo_header.png" />
- </a>
- <form method="post" id="sign_out_form" action="httpdisabled://twitter.com/sessions/destroy" style="display:none;">
- <input name="authenticity_token" value="dd6c65b6f7e87a8a456d76d37264af8f195c7209" type="hidden"/>
- </form>
-
-
- <div id="signin_controls">
- <span id="have_an_account">
- Have an account?<a href="httpdisabled://twitter.com/login" class="signin" tabindex="3"><span>Sign in</span></a></span>
- <div id="signin_menu" class="common-form standard-form offscreen">
-
- <form method="post" id="signin" action="httpdisabledsdisabled://twitter.com/sessions">
-
- <input id="authenticity_token" name="authenticity_token" type="hidden" value="dd6c65b6f7e87a8a456d76d37264af8f195c7209" /> <input id="return_to_ssl" name="return_to_ssl" type="hidden" value="false" />
- <input id="redirect_after_login" name="redirect_after_login" type="hidden" value="/ICHCheezburger" /> <p class="textbox">
- <label for="username">Username or email</label>
- <input type="text" id="username" name="session[username_or_email]" value="" title="username" tabindex="4"/>
- </p>
-
- <p class="textbox">
- <label for="password">Password</label>
- <input type="password" id="password" name="session[password]" value="" title="password" tabindex="5"/>
- </p>
-
- <p class="remember">
- <input type="submit" id="signin_submit" value="Sign in" tabindex="7"/>
- <input type="checkbox" id="remember" name="remember_me" value="1" tabindex="6"/>
- <label for="remember">Remember me</label>
- </p>
-
- <p class="forgot">
- <a href="httpdisabled://twitter.com/account/resend_password" id="resend_password_link">Forgot password?</a>
- </p>
-
- <p class="forgot-username">
- <a href="httpdisabled://twitter.com/account/resend_password" id="forgot_username_link" title="If you remember your password, try logging in with your email">Forgot username?</a>
- </p>
- <p class="complete">
- <a href="httpdisabled://twitter.com/account/complete" id="account_complete_link">Already using Twitter on your phone?</a>
- </p>
- <input type="hidden" name="q" id="signin_q" value=""/>
- </form>
-</div>
-
-</div>
-
-
-
-
- </div>
-
-
- <div id="profilebox_outer" class="home_page_new_home_page">
- <div id="profilebox" class="clearfix">
- <div id="profiletext">
- <h1>
- <span>Get short, timely messages from ICanHasCheezburger?.</span>
- </h1>
-
- <h2>Twitter is a rich source of instantly updated information. It's easy to stay updated on an incredibly wide variety of topics. <strong><a href='http://twitter.com/signup?follow=ICHCheezburger'>Join today</a></strong> and <strong>follow @ICHCheezburger</strong>.</h2>
- </div>
- <div id="profilebutton">
- <form action="httpdisabled://twitter.com/signup" id="account_signup_form" method="get" name="account_signup_form"> <input id="follow" name="follow" type="hidden" value="ICHCheezburger" />
- <input class="profilesubmit" id="profile_submit" name="commit" type="submit" value="Sign Up &rsaquo;" />
- </form>
- <p id="profilebox-mobile">
- <span class="sms-follow-instructions">Get updates via SMS by texting <strong>follow ICHCheezburger</strong> to <strong>40404</strong> in the United States</span><br/>
- <a id="sms_codes_link">
- <span>Codes for other countries</span>
- </a>
- <div id="sms_codes">
- <table celspacing="0" celpadding="0">
- <thead>
- <tr class="title">
- <td colspan="3">Two-way (sending and receiving) short codes:</td>
- </tr>
- </thead>
- <tbody>
- <tr>
- <th class="sms-country">Country</th>
- <th class="sms-code">Code</th>
- <th class="sms-network">For customers of</th>
- </tr>
- <tr>
- <td class="sms-country">Australia</td>
- <td colspan="2" class="sms-code-network">
- <ul>
-
- <li>
- <span class="sms-code">0198089488</span>
- <span class="sms-network">Telstra</span>
- </li>
-
- </ul>
- </td>
-</tr><tr>
- <td class="sms-country">Canada</td>
- <td colspan="2" class="sms-code-network">
- <ul>
-
- <li>
- <span class="sms-code">21212</span>
- <span class="sms-network">(any)</span>
- </li>
-
- </ul>
- </td>
-</tr><tr>
- <td class="sms-country">United Kingdom</td>
- <td colspan="2" class="sms-code-network">
- <ul>
-
- <li>
- <span class="sms-code">86444</span>
- <span class="sms-network">Vodafone, Orange, 3, O2</span>
- </li>
-
- </ul>
- </td>
-</tr><tr>
- <td class="sms-country">Indonesia</td>
- <td colspan="2" class="sms-code-network">
- <ul>
-
- <li>
- <span class="sms-code">89887</span>
- <span class="sms-network">AXIS, 3, Telkomsel</span>
- </li>
-
- </ul>
- </td>
-</tr><tr>
- <td class="sms-country">Ireland</td>
- <td colspan="2" class="sms-code-network">
- <ul>
-
- <li>
- <span class="sms-code">51210</span>
- <span class="sms-network">O2</span>
- </li>
-
- </ul>
- </td>
-</tr><tr>
- <td class="sms-country">India</td>
- <td colspan="2" class="sms-code-network">
- <ul>
-
- <li>
- <span class="sms-code">53000</span>
- <span class="sms-network">Bharti Airtel, Videocon</span>
- </li>
-
- </ul>
- </td>
-</tr><tr>
- <td class="sms-country">Jordan</td>
- <td colspan="2" class="sms-code-network">
- <ul>
-
- <li>
- <span class="sms-code">90903</span>
- <span class="sms-network">Zain</span>
- </li>
-
- </ul>
- </td>
-</tr><tr>
- <td class="sms-country">New Zealand</td>
- <td colspan="2" class="sms-code-network">
- <ul>
-
- <li>
- <span class="sms-code">8987</span>
- <span class="sms-network">Vodafone, Telecom NZ</span>
- </li>
-
- </ul>
- </td>
-</tr><tr>
- <td class="sms-country">United States</td>
- <td colspan="2" class="sms-code-network">
- <ul>
-
- <li>
- <span class="sms-code">40404</span>
- <span class="sms-network">(any)</span>
- </li>
-
- </ul>
- </td>
-</tr>
- </tbody>
- </table>
-</div>
-
- </p>
- </div>
- </div>
- </div>
-
-
-
-
-
- <div class="content-bubble-arrow"></div>
-
-
-
- <table cellspacing="0" class="columns">
- <tbody>
- <tr>
- <td id="content" class="round-left column">
- <div class="wrapper">
-
-
-
-
-
-
-
-
- <div class="profile-user">
- <div id="user_6173842" class="user ">
- <h2 class="thumb clearfix">
- <a href="httpdisabled://twitter.com/account/profile_image/ICHCheezburger?hreflang=en"><img alt="" border="0" height="73" id="profile-image" src="../a3.twimg.com/profile_images/1213876440/27539_32561485399_2579_n_bigger.jpeg" valign="middle" width="73" /></a>
- <div class="screen-name">ICHCheezburger</div>
- </h2>
- </div>
- </div>
-
-
-
- <div id="similar_to_followed"></div>
-
-<div class="section">
-
- <div id="timeline_heading" style="display: none;">
- <h1 id="heading"></h1>
- </div>
- <ol id='timeline' class='statuses'>
- <li class="hentry u-ICHCheezburger status latest-status" id="status_56469580993933312"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">Kitteh Komic of teh Day: Dr. Cat Attempts Open Heart Surgery <a href="httpdisabled://dbl.chzb.gr/1c6rnc" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c6rnc</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56469580993933312">
- <span class="published timestamp" data="{time:'Fri Apr 08 21:32:51 +0000 2011'}">6 minutes ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56438617626771456"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">Switch - funny pictures - SwitchLoL by: queenofcatz <a href="httpdisabled://dbl.chzb.gr/1c6mDc" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c6mDc</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56438617626771456">
- <span class="published timestamp" data="{time:'Fri Apr 08 19:29:49 +0000 2011'}">about 2 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56424458193354752"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">A Graph About Kittehs - Lolcats, cats and funny captions - A Graph About Kittehs <a href="httpdisabled://dbl.chzb.gr/1c6jed" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c6jed</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56424458193354752">
- <span class="published timestamp" data="{time:'Fri Apr 08 18:33:33 +0000 2011'}">about 3 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56364595996135424"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">MemeCats: The Revolution’s Underbelly - Lolcats, cats and funny captions - MemeCats: The Revolution's Underbel... <a href="httpdisabled://dbl.chzb.gr/1c66Xx" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c66Xx</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56364595996135424">
- <span class="published timestamp" data="{time:'Fri Apr 08 14:35:41 +0000 2011'}">about 7 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56364595916447744"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">Cuteness Scale: - funny pictures - Cuteness Scale: 0 to 10 I iz an elebentyLoL by: aNiMaNu <a href="httpdisabled://dbl.chzb.gr/1c66Xy" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c66Xy</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56364595916447744">
- <span class="published timestamp" data="{time:'Fri Apr 08 14:35:41 +0000 2011'}">about 7 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56334436450578432"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">VIDEO: Startled Kitteh is Startled - Lolcats, cats and funny captions - VIDEO: Startled Kitteh is Startled <a href="httpdisabled://dbl.chzb.gr/1c60Ms" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c60Ms</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56334436450578432">
- <span class="published timestamp" data="{time:'Fri Apr 08 12:35:50 +0000 2011'}">about 9 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56302449992007680"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">Hard work pays off in the long run. - funny pictures - Hard work pays off in the long run.LoL by: Chronocide <a href="httpdisabled://dbl.chzb.gr/1c5VDA" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5VDA</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56302449992007680">
- <span class="published timestamp" data="{time:'Fri Apr 08 10:28:44 +0000 2011'}">about 11 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56271721635921920"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">Cyoot Kittehs of teh Day: We Liek Dis Place Wen Dere Iz No Watur In It <a href="httpdisabled://dbl.chzb.gr/1c5QKk" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5QKk</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56271721635921920">
- <span class="published timestamp" data="{time:'Fri Apr 08 08:26:38 +0000 2011'}">about 13 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56242086562902016"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">~ I really didn’t need to see that! ~ - funny pictures - ~ I really didn't need to see that! ~LoL by: DyannLyn... <a href="httpdisabled://dbl.chzb.gr/1c5MkY" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5MkY</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56242086562902016">
- <span class="published timestamp" data="{time:'Fri Apr 08 06:28:53 +0000 2011'}">about 15 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56181651025305600"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">VIDEO: Kitteh Hates Banana - Lolcats, cats and funny captions - VIDEO: Kitteh Hates Banana <a href="httpdisabled://dbl.chzb.gr/1c5DR9" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5DR9</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56181651025305600">
- <span class="published timestamp" data="{time:'Fri Apr 08 02:28:44 +0000 2011'}">about 19 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56152997683658754"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">VIDEO: Awesome Astronaut Kitteh - Lolcats, cats and funny captions - VIDEO: Awesome Astronaut Kitteh <a href="httpdisabled://dbl.chzb.gr/1c5ztw" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5ztw</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56152997683658754">
- <span class="published timestamp" data="{time:'Fri Apr 08 00:34:52 +0000 2011'}">about 21 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56152997616553984"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">I may be schizophrenic - funny pictures - I may be schizophrenicLoL by: eccarnahan <a href="httpdisabled://dbl.chzb.gr/1c5ztv" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5ztv</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56152997616553984">
- <span class="published timestamp" data="{time:'Fri Apr 08 00:34:52 +0000 2011'}">about 21 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56121527577493504"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">Thesis - funny pictures - Thesis still not done, huh?LoL by: cinna-crumbs <a href="httpdisabled://dbl.chzb.gr/1c5seB" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5seB</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56121527577493504">
- <span class="published timestamp" data="{time:'Thu Apr 07 22:29:49 +0000 2011'}">about 23 hours ago</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56107317090992128"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">“Car†Is Just the Word “Cat†With One Letter Changed - Lolcats, cats and funny captions - Cat Car Decals - &quot;Ca... <a href="httpdisabled://dbl.chzb.gr/1c5ppW" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5ppW</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56107317090992128">
- <span class="published timestamp" data="{time:'Thu Apr 07 21:33:21 +0000 2011'}">2:33 PM Apr 7th</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56107317065818112"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">Cheezburger Confidential: Moral Gray Area Kitteh - Lolcats, cats and funny captions - Cheezburger Confidential... <a href="httpdisabled://dbl.chzb.gr/1c5ppX" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5ppX</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56107317065818112">
- <span class="published timestamp" data="{time:'Thu Apr 07 21:33:21 +0000 2011'}">2:33 PM Apr 7th</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56091884069715968"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">I think I work with her. - funny pictures - I think I work with her.LoL by: Winnie-Wonka <a href="httpdisabled://dbl.chzb.gr/1c5mEg" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5mEg</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56091884069715968">
- <span class="published timestamp" data="{time:'Thu Apr 07 20:32:01 +0000 2011'}">1:32 PM Apr 7th</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56062544149880832"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">O, The Places You’ll Go: De Poezenboot (The Cat Boat) - Lolcats, cats and funny captions - O, The Places You'l... <a href="httpdisabled://dbl.chzb.gr/1c5guP" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5guP</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56062544149880832">
- <span class="published timestamp" data="{time:'Thu Apr 07 18:35:26 +0000 2011'}">11:35 AM Apr 7th</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56032664246956032"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">nobudy putz - funny pictures - nobudy putz Babee in da cornerLoL by: NCcharmer <a href="httpdisabled://dbl.chzb.gr/1c59Q7" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c59Q7</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56032664246956032">
- <span class="published timestamp" data="{time:'Thu Apr 07 16:36:42 +0000 2011'}">9:36 AM Apr 7th</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56032663106093056"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">GIF: Entertainin teh Childrenz - Lolcats, cats and funny captions - GIF: Entertainin teh Childrenz <a href="httpdisabled://dbl.chzb.gr/1c59Q8" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c59Q8</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56032663106093056">
- <span class="published timestamp" data="{time:'Thu Apr 07 16:36:42 +0000 2011'}">9:36 AM Apr 7th</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- <li class="hentry u-ICHCheezburger status" id="status_56001591689486336"
->
- <span class="status-body">
- <span class="status-content">
- <span class="entry-content">MemeCats: Hold All My Calls! - Lolcats, cats and funny captions - MemeCats: Hold All My Calls! <a href="httpdisabled://dbl.chzb.gr/1c5381" class="tweet-url web" rel="nofollow" target="_blank">http://dbl.chzb.gr/1c5381</a></span>
- </span>
- <span class="meta entry-meta" data='{}'>
- <a class="entry-date" rel="bookmark" href="httpdisabled://twitter.com/ICHCheezburger/status/56001591689486336">
- <span class="published timestamp" data="{time:'Thu Apr 07 14:33:14 +0000 2011'}">7:33 AM Apr 7th</span></a>
- <span>via <a href="httpdisabled://www.hootsuite.com" rel="nofollow">HootSuite</a></span>
-
- </span>
-
- <ul class="meta-data clearfix">
-</ul>
- </span>
-</li>
- </ol>
-
- <div id="pagination">
- <a href="httpdisabled://twitter.com/ICHCheezburger?max_id=56469580993933312&amp;page=2&amp;twttr=true" class="round more" id="more" rel="next">more</a> </div>
-
-</div>
-
-
-
-
-
- </div>
- </td>
-
- <td id="side_base" class="column round-right">
-
- <div id="side">
-
-<div id="profile" class="section profile-side">
- <span class="section-links">
- </span>
- <address>
- <ul class="about vcard entry-author">
-
-
-
- <li><span class="label">Name</span> <span class="fn">ICanHasCheezburger?</span></li>
- <li><span class="label">Location</span> <span class="adr">Seattle, WA</span></li>
- <li><span class="label">Web</span> <a href="httpdisabled://icanhascheezburger.com" class="url" rel="me nofollow" target="_blank">http://icanhasche...</a></li>
- <li id="bio"><span class="label">Bio</span> <span class="bio">I can has funny pictures of cats, plz?</span></li>
-
- </ul>
- </address>
-
-
-
-<div class="stats">
- <table>
- <tr>
- <td>
-
-
-
-<a href="httpdisabled://twitter.com/ICHCheezburger/following" id="following_count_link" class="link-following_page" rel="me" title="See who ICHCheezburger is following">
- <span id="following_count" class="stats_count numeric">3,154 </span>
- <span class="label">Following</span>
-</a>
-
-
- </td>
- <td>
-
-<a href="httpdisabled://twitter.com/ICHCheezburger/followers" id="follower_count_link" class="link-followers_page" rel="me" title="See who's following ICHCheezburger">
- <span id="follower_count" class="stats_count numeric">1,588,880 </span>
- <span class="label">Followers</span>
-</a>
-
-</td>
- <td>
-
-<a href="httpdisabled://twitter.com/ICHCheezburger/lists/memberships" id="lists_count_link" class="link-lists_page" rel="me" title="See which lists ICHCheezburger is on">
- <span id="lists_count" class="stats_count numeric">6,352 </span>
- <span class="label">Listed</span>
-</a>
-
-</td>
- </tr>
- </table>
-
-</div>
-
-</div>
-
- <ul id="primary_nav" class="sidebar-menu">
- <li id="profile_tab"><a href="ICHCheezburger.html" accesskey="u"><span id="update_count" class="stat_count">9,375</span><span>Tweets</span></a></li>
- <li id="profile_favorites_tab"><a href="httpdisabled://twitter.com/ICHCheezburger/favorites" accesskey="f"><span>Favorites</span></a></li>
- </ul>
-
-
-
-
- <hr/>
- <div id="side_lists">
- <h2 class="sidebar-title"><span>Lists</span></h2>
-
- <ul class="sidebar-menu lists-links">
- <li><a href="httpdisabled://twitter.com/ICHCheezburger/fail" class="list_661623" data="&#123;&quot;mode&quot;:&quot;public&quot;,&quot;id_str&quot;:&quot;661623&quot;,&quot;uri&quot;:&quot;\/ICHCheezburger\/fail&quot;,&quot;description&quot;:&quot;&quot;,&quot;dispatch_action&quot;:&quot;list&quot;,&quot;slug&quot;:&quot;fail&quot;,&quot;member_count&quot;:11,&quot;following&quot;:false,&quot;subscriber_count&quot;:104,&quot;full_name&quot;:&quot;@ICHCheezburger\/fail&quot;,&quot;name&quot;:&quot;fail&quot;,&quot;user&quot;:&quot;ICHCheezburger&quot;,&quot;id&quot;:661623&#125;" title="@ICHCheezburger/fail"><span>@ICHCheezburger/<wbr/><b>fail</b></span></a></li>
-<li><a href="httpdisabled://twitter.com/ICHCheezburger/network" class="list_622995" data="&#123;&quot;mode&quot;:&quot;public&quot;,&quot;id_str&quot;:&quot;622995&quot;,&quot;uri&quot;:&quot;\/ICHCheezburger\/network&quot;,&quot;description&quot;:&quot;&quot;,&quot;dispatch_action&quot;:&quot;list&quot;,&quot;slug&quot;:&quot;network&quot;,&quot;member_count&quot;:33,&quot;following&quot;:false,&quot;subscriber_count&quot;:136,&quot;full_name&quot;:&quot;@ICHCheezburger\/network&quot;,&quot;name&quot;:&quot;network&quot;,&quot;user&quot;:&quot;ICHCheezburger&quot;,&quot;id&quot;:622995&#125;" title="@ICHCheezburger/network"><span>@ICHCheezburger/<wbr/><b>network</b></span></a></li>
- </ul>
- <p class="sidebar-menu sidebar-menu-actions">
- <span class="view-all"><a href="httpdisabled://twitter.com/ICHCheezburger/lists">View all</a></span>
- </p>
- </div>
-
-
-<hr/>
-
-
- <div id="following">
-
- <h2 class="sidebar-title" id="fm_menu"><span>Following</span></h2>
- <div class="sidebar-menu">
- <div id="following_list">
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/foodlooksfunny" class="url" hreflang="en" rel="contact" title="MFLF Team"><img alt="MFLF Team" class="photo fn" height="24" src="../a1.twimg.com/profile_images/754757071/rawr_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/CollegeHumor" class="url" hreflang="en" rel="contact" title="CollegeHumor"><img alt="CollegeHumor" class="photo fn" height="24" src="../a2.twimg.com/profile_images/1289641028/CH_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/changinghands" class="url" hreflang="en" rel="contact" title="Changing Hands"><img alt="Changing Hands" class="photo fn" height="24" src="../a0.twimg.com/profile_images/81990615/nightexterior-1_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/FroggieTweets" class="url" hreflang="en" rel="contact" title="The Frogman"><img alt="The Frogman" class="photo fn" height="24" src="../a2.twimg.com/profile_images/1124077786/batvatar_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/memebasealpha" class="url" hreflang="en" rel="contact" title="Memebase Alpha!"><img alt="Memebase Alpha!" class="photo fn" height="24" src="../a2.twimg.com/profile_images/1155395599/Memebase_small_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/LOLMart" class="url" hreflang="en" rel="contact" title="Lolmart.com"><img alt="Lolmart.com" class="photo fn" height="24" src="../a2.twimg.com/profile_images/1063331761/LOLmart_150_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/GlassblowerX" class="url" hreflang="en" rel="contact" title="GlassblowerX"><img alt="GlassblowerX" class="photo fn" height="24" src="../a1.twimg.com/profile_images/1239180764/GlassblowerX_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/EliThompson" class="url" hreflang="en" rel="contact" title="EliThompson"><img alt="EliThompson" class="photo fn" height="24" src="../a3.twimg.com/profile_images/1092057020/eli_avatar_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/ejc" class="url" hreflang="en" rel="contact" title="E.J. Coughlin"><img alt="E.J. Coughlin" class="photo fn" height="24" src="../a0.twimg.com/profile_images/1277610502/Untitled-9_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/kjpaccountant" class="url" hreflang="en" rel="contact" title="Kristian Pflieger"><img alt="Kristian Pflieger" class="photo fn" height="24" src="../a1.twimg.com/profile_images/333032766/5600_106787006838_550741838_2009237_6385345_n_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/begyourpARDEN" class="url" hreflang="en" rel="contact" title="Anne Arden Ball"><img alt="Anne Arden Ball" class="photo fn" height="24" src="../a1.twimg.com/profile_images/874705507/01_3_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/twiggy_XD" class="url" hreflang="en" rel="contact" title="Jasenka Slamnik"><img alt="Jasenka Slamnik" class="photo fn" height="24" src="../a0.twimg.com/profile_images/1139176116/5c42a320-1e91-4d89-a034-0f140d2f23ba_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/141soldier" class="url" hreflang="en" rel="contact" title="Javier Vasquez"><img alt="Javier Vasquez" class="photo fn" height="24" src="../a3.twimg.com/sticky/default_profile_images/default_profile_3_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/RYAN_H12" class="url" hreflang="en" rel="contact" title="Ryan Hughes"><img alt="Ryan Hughes" class="photo fn" height="24" src="../a3.twimg.com/sticky/default_profile_images/default_profile_3_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/KnowItAllison" class="url" hreflang="en" rel="contact" title="Alli Bee"><img alt="Alli Bee" class="photo fn" height="24" src="../a3.twimg.com/profile_images/1260578495/191281_1758367531945_1621722394_1723810_2598069_o_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/sexymonica12" class="url" hreflang="en" rel="contact" title="sexy jesica"><img alt="sexy jesica" class="photo fn" height="24" src="../a0.twimg.com/sticky/default_profile_images/default_profile_4_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/mbsi10" class="url" hreflang="en" rel="contact" title="michael carter"><img alt="michael carter" class="photo fn" height="24" src="../a1.twimg.com/profile_images/959721336/16869_103046893051833_100000395672538_70559_3952672_n_1__mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/Abbigail8900" class="url" hreflang="en" rel="contact" title="Abbigail"><img alt="Abbigail" class="photo fn" height="24" src="../a2.twimg.com/sticky/default_profile_images/default_profile_1_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/rudysmah" class="url" hreflang="en" rel="contact" title="Rudy"><img alt="Rudy" class="photo fn" height="24" src="../a3.twimg.com/profile_images/1299269362/10839_196974151498_693676498_3960874_1853030_n_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/willijoh2010" class="url" hreflang="en" rel="contact" title="Williams John"><img alt="Williams John" class="photo fn" height="24" src="../a2.twimg.com/sticky/default_profile_images/default_profile_1_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/Compliments_Int" class="url" hreflang="en" rel="contact" title="Compliments Intl."><img alt="Compliments Intl." class="photo fn" height="24" src="../a2.twimg.com/profile_images/959952929/ci_300x300_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/prasadnehete" class="url" hreflang="en" rel="contact" title="Prasad"><img alt="Prasad" class="photo fn" height="24" src="../a2.twimg.com/profile_images/724048626/Picture_3895-1_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/amazingemilie" class="url" hreflang="en" rel="contact" title="Emilie E. Troupe"><img alt="Emilie E. Troupe" class="photo fn" height="24" src="../a0.twimg.com/profile_images/316019228/326994260_1117936370_0_mini.jpeg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/JustaSlayer" class="url" hreflang="en" rel="contact" title="Paul de Vries"><img alt="Paul de Vries" class="photo fn" height="24" src="../a2.twimg.com/sticky/default_profile_images/default_profile_2_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/causticthreads" class="url" hreflang="en" rel="contact" title="Erica Voges"><img alt="Erica Voges" class="photo fn" height="24" src="../a1.twimg.com/profile_images/1248229613/redsugarskullnecklace4-pola_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/Jaie74" class="url" hreflang="en" rel="contact" title="J"><img alt="J" class="photo fn" height="24" src="../a3.twimg.com/sticky/default_profile_images/default_profile_3_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/Alissagreeson" class="url" hreflang="en" rel="contact" title="Alissa"><img alt="Alissa" class="photo fn" height="24" src="../a2.twimg.com/sticky/default_profile_images/default_profile_2_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/ZAzaMIca" class="url" hreflang="fr" rel="contact" title="Zamy Michael"><img alt="Zamy Michael" class="photo fn" height="24" src="../a3.twimg.com/profile_images/1110864280/41628_1144937489_2484_q_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/acompletelycom" class="url" hreflang="en" rel="contact" title="Autocompletely"><img alt="Autocompletely" class="photo fn" height="24" src="../a2.twimg.com/profile_images/700174615/twitter_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/pinkpandagrl" class="url" hreflang="en" rel="contact" title="Pink Panda Girl"><img alt="Pink Panda Girl" class="photo fn" height="24" src="../a3.twimg.com/profile_images/1096286685/newpink_copy_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/aleahdillon" class="url" hreflang="en" rel="contact" title="Aleah Dillon"><img alt="Aleah Dillon" class="photo fn" height="24" src="../a0.twimg.com/profile_images/1129087853/151aec2f-1534-4f61-9f3e-1e787cb51a8b_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/Tanira7" class="url" hreflang="en" rel="contact" title="Kari Dolan"><img alt="Kari Dolan" class="photo fn" height="24" src="../a2.twimg.com/sticky/default_profile_images/default_profile_6_mini.png" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/Fergie_Gee" class="url" hreflang="en" rel="contact" title="Graham Ferguson"><img alt="Graham Ferguson" class="photo fn" height="24" src="../a2.twimg.com/profile_images/959827428/25000_1397284054938_1317351118_31101620_485629_n_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/brosenb1" class="url" hreflang="en" rel="contact" title="Brian"><img alt="Brian" class="photo fn" height="24" src="../a0.twimg.com/profile_images/959692632/13659_1215732676789_1332990286_30703899_6344768_n_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/HeatFan63" class="url" hreflang="en" rel="contact" title="Kelly Foster"><img alt="Kelly Foster" class="photo fn" height="24" src="../a3.twimg.com/profile_images/1302143328/Profile_copy_mini.jpg" width="24" /></a> </span>
-
-
- <span class="vcard">
- <a href="httpdisabled://twitter.com/ImAYellowMonsta" class="url" hreflang="en" rel="contact" title="[ S ' Joness ] c(-:"><img alt="[ S ' Joness ] c(-:" class="photo fn" height="24" src="../a2.twimg.com/profile_images/1296459376/profile_image_1301694822477_mini.jpg" width="24" /></a> </span>
-
-
- </div>
- <div id="friends_view_all">
- <a href="httpdisabled://twitter.com/ICHCheezburger/following" rel="me">View all&hellip;</a>
- </div>
-
-</div>
-
- <hr/>
- </div>
-
-
-
-
-
- <div id="rssfeed">
- <a href="httpdisabled://twitter.com/statuses/user_timeline/6173842.rss" class="xref rss profile-rss" rel="alternate" type="application/rss+xml">RSS feed of ICHCheezburger's tweets</a>
- <a href="httpdisabled://twitter.com/favorites/6173842.rss" class="xref rss favorites-rss" rel="alternate" type="application/rss+xml">RSS feed of ICHCheezburger's favorites</a>
- </div>
-
-
-
-
- </div>
- </td>
-
- </tr>
- </tbody>
- </table>
-
-
-
- <div id="footer" class="round">
- <h3 class="offscreen">Footer</h3>
-
-
- <ul class="footer-nav">
- <li class="first">&copy; 2011 Twitter</li>
- <li><a href="httpdisabled://twitter.com/about">About Us</a></li>
- <li><a href="httpdisabled://twitter.com/about/contact">Contact</a></li>
- <li><a href="httpdisabled://blog.twitter.com">Blog</a></li>
- <li><a href="httpdisabled://status.twitter.com">Status</a></li>
- <li><a href="httpdisabled://twitter.com/about/resources">Resources</a></li>
- <li><a href="httpdisabled://dev.twitter.com/">API</a></li>
- <li><a href="httpdisabled://twitter.com/business">Business</a></li>
- <li><a href="httpdisabled://support.twitter.com">Help</a></li>
- <li><a href="httpdisabled://twitter.com/jobs">Jobs</a></li>
- <li><a href="httpdisabled://twitter.com/tos">Terms</a></li>
- <li><a href="httpdisabled://twitter.com/privacy">Privacy</a></li>
- </ul>
- </div>
-
-
-
- </div>
-
-
-
- <script src="../ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js" type="text/javascript"></script>
-<script src="../a2.twimg.com/a/1302214109/javascripts/twitter.js@1302215522" type="text/javascript"></script>
-<script src="../a0.twimg.com/a/1302214109/javascripts/lib/jquery.tipsy.min.js@1302114648" type="text/javascript"></script>
-<script type='text/javascript' src='../www.google.com/jsapi'></script>
-<script src="../a3.twimg.com/a/1302214109/javascripts/lib/gears_init.js@1302114648" type="text/javascript"></script>
-<script src="../a0.twimg.com/a/1302214109/javascripts/lib/mustache.js@1302114648" type="text/javascript"></script>
-<script src="../a2.twimg.com/a/1302214109/javascripts/geov1.js@1302114648" type="text/javascript"></script>
-<script src="../a3.twimg.com/a/1302214109/javascripts/api.js@1302114648" type="text/javascript"></script>
-<script type="text/javascript">
-//<![CDATA[
-$.cookie('tz_offset_sec', (-1 * (new Date()).getTimezoneOffset())*60);
-//]]>
-</script>
- <script src="../a0.twimg.com/a/1302214109/javascripts/lib/mustache.js@1302114648" type="text/javascript"></script>
-<script src="../a1.twimg.com/a/1302214109/javascripts/dismissable.js@1302114648" type="text/javascript"></script>
-
-
-<script type="text/javascript">
-//<![CDATA[
- page.user_screenname = 'ICHCheezburger';
- page.user_fullname = 'ICanHasCheezburger?';
- page.controller_name = 'AccountController';
- page.action_name = 'profile';
- twttr.form_authenticity_token = 'dd6c65b6f7e87a8a456d76d37264af8f195c7209';
- $.ajaxSetup({ data: { authenticity_token: 'dd6c65b6f7e87a8a456d76d37264af8f195c7209' } });
-
- // FIXME: Reconcile with the kinds on the Status model.
- twttr.statusKinds = {
- UPDATE: 1,
- SHARE: 2
- };
- twttr.ListPerUserLimit = 20;
-
-
-
-
-//]]>
-</script>
-<script type="text/javascript">
-//<![CDATA[
-
- $( function () {
-
- $("#sms_codes_link").hoverTip("#sms_codes");
- initializePage();
-
-
-
- if (twttr.geo !== undefined) {
- twttr.geo.options.show_place_details_in_map = true;
- }
-
-(function(){function b(){var c=location.href.split("#!")[1];if(c){window.location.hash = "";window.location.pathname = c.replace(/^([^/])/,"/$1");}else return true}var a="onhashchange"in window;if(!a&&window.setAttribute){window.setAttribute("onhashchange","return;");a=typeof window.onhashchange==="function"}if(a)$(window).bind("hashchange",b);else{var d=function(){b()&&setTimeout(d,250)};setTimeout(d,250)}}());
- $('#signin_menu').isSigninMenu();
-
- });
-
-//]]>
-</script>
-
- <!-- BEGIN google analytics -->
-
- <script type="text/javascript">
- var gaJsHost = (("httpdisabledsdisabled:" == document.location.protocol) ? "httpdisabledsdisabled://ssl." : "httpdisabled://www.");
- void(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
- </script>
-
- <script type="text/javascript">
-
- try {
- var pageTracker = _gat._getTracker("UA-30775-6");
- pageTracker._setDomainName("twitter.com");
- pageTracker._setVar('Not Logged In');
- pageTracker._setVar('lang: en');
- pageTracker._initData();
-
- pageTracker._trackPageview('/profile/not_logged_in/ICHCheezburger');
- } catch(err) { }
-
- </script>
-
- <!-- END google analytics -->
-
-
-
-
- <div id="notifications"></div>
-
-
-
-
-
-
- </body>
-
-</html>
diff --git a/mobile/android/tests/browser/chrome/tp5/twitter.com/www.google.com/jsapi b/mobile/android/tests/browser/chrome/tp5/twitter.com/www.google.com/jsapi
deleted file mode 100755
index 9870fa667..000000000
--- a/mobile/android/tests/browser/chrome/tp5/twitter.com/www.google.com/jsapi
+++ /dev/null
@@ -1,39 +0,0 @@
-if (!window['google']) {
-window['google'] = {};
-}
-if (!window['google']['loaddisableder']) {
-window['google']['loaddisableder'] = {};
-google.loaddisableder.ServiceBase = 'http://www.google.com/uds';
-google.loaddisableder.GoogleApisBase = 'http://ajax.googleapis.com/ajax';
-google.loaddisableder.ApiKey = 'notsupplied';
-google.loaddisableder.KeyVerified = true;
-google.loaddisableder.LoadFailure = false;
-google.loaddisableder.Secure = false;
-google.loaddisableder.GoogleLocale = 'www.google.com';
-google.loaddisableder.ClientLocation = null;
-google.loaddisableder.AdditionalParams = '';
-(function() {var d=void 0,g=null,h=encodeURIComponent,j=window,k=document;function l(a,b){return a.loaddisabled=b}var m="push",o="replace",p="charAt",r="indexOf",s="ServiceBase",t="name",u="getTime",v="length",w="prototype",x="setTimeout",y="loaddisableder",z="substring",A="join",B="toLowerCase";function C(a){if(a in D)return D[a];return D[a]=navigator.userAgent[B]()[r](a)!=-1}var D={};function E(a,b){var c=function(){};c.prototype=b[w];a.S=b[w];a.prototype=new c}
-function F(a,b){var c=Array[w].slice.call(arguments,2)||[];return function(){var e=c.concat(Array[w].slice.call(arguments));return a.apply(b,e)}}function G(a){a=Error(a);a.toString=function(){return this.message};return a}function H(a,b){for(var c=a.split(/\./),e=j,f=0;f<c[v]-1;f++)e[c[f]]||(e[c[f]]={}),e=e[c[f]];e[c[c[v]-1]]=b}function I(a,b,c){a[b]=c}if(!J)var J=H;if(!K)var K=I;google[y].t={};J("google.loaddisableder.callbacks",google[y].t);var L={},M={};google[y].eval={};J("google.loaddisableder.eval",google[y].eval);
-l(google,function(a,b,c){function e(a){var b=a.split(".");if(b[v]>2)throw G("Module: '"+a+"' not found!");else if(typeof b[1]!="undefined")f=b[0],c.packages=c.packages||[],c.packages[m](b[1])}var f=a,c=c||{};if(a instanceof Array||a&&typeof a=="object"&&typeof a[A]=="function"&&typeof a.reverse=="function")for(var i=0;i<a[v];i++)e(a[i]);else e(a);if(a=L[":"+f]){c&&!c.language&&c.locale&&(c.language=c.locale);if(c&&typeof c.callback=="string"&&(i=c.callback,i.match(/^[[\]A-Za-z0-9._]+$/)))i=j.eval(i),
-c.callback=i;if((i=c&&c.callback!=g)&&!a.s(b))throw G("Module: '"+f+"' must be loaddisableded before DOM onLoad!");else i?a.m(b,c)?j[x](c.callback,0):a.loaddisabled(b,c):a.m(b,c)||a.loaddisabled(b,c)}else throw G("Module: '"+f+"' not found!");});J("google.loaddisabled",google.loaddisabled);
-google.R=function(a,b){b?(N[v]==0&&(O(j,"loaddisabled",P),!C("msie")&&!C("safari")&&!C("konqueror")&&C("mozilla")||j.opera?j.addEventListener("DOMContentLoaded",P,!1):C("msie")?void("<script defer onreadystatechange='google.loaddisableder.domReady()' src=//:><\/script>"):(C("safari")||C("konqueror"))&&j[x](R,10)),N[m](a)):O(j,"loaddisabled",a)};J("google.setOnLoadCallback",google.R);
-function O(a,b,c){if(a.addEventListener)a.addEventListener(b,c,!1);else if(a.attachEvent)a.attachEvent("on"+b,c);else{var e=a["on"+b];a["on"+b]=e!=g?aa([c,e]):c}}function aa(a){return function(){for(var b=0;b<a[v];b++)a[b]()}}var N=[];google[y].L=function(){var a=j.event.srcElement;if(a.readyState=="complete")a.onreadystatechange=g,a.parentNode.removeChild(a),P()};J("google.loaddisableder.domReady",google[y].L);var ba={loaddisableded:!0,complete:!0};function R(){ba[k.readyState]?P():N[v]>0&&j[x](R,10)}
-function P(){for(var a=0;a<N[v];a++)N[a]();N.length=0}google[y].d=function(a,b,c){if(c){var e;if(a=="script")e=k.createElement("script"),e.type="text/javascript",e.src=b;else if(a=="css")e=k.createElement("link"),e.type="text/css",e.href=b,e.rel="stylesheet";(a=k.getElementsByTagName("head")[0])||(a=k.body.parentNode.appendChild(k.createElement("head")));a.appendChild(e)}else a=="script"?void('<script src="'+b+'" type="text/javascript"><\/script>'):a=="css"&&void('<link href="'+b+'" type="text/css" rel="stylesheet"></link>')};
-J("google.voidLoadTag",google[y].d);google[y].O=function(a){M=a};J("google.loaddisableder.rfm",google[y].O);google[y].Q=function(a){for(var b in a)typeof b=="string"&&b&&b[p](0)==":"&&!L[b]&&(L[b]=new S(b[z](1),a[b]))};J("google.loaddisableder.rpl",google[y].Q);google[y].P=function(a){if((a=a.specs)&&a[v])for(var b=0;b<a[v];++b){var c=a[b];typeof c=="string"?L[":"+c]=new T(c):(c=new U(c[t],c.baseSpec,c.customSpecs),L[":"+c[t]]=c)}};J("google.loaddisableder.rm",google[y].P);google[y].loaddisableded=function(a){L[":"+a.module].k(a)};
-J("google.loaddisableder.loaddisableded",google[y].loaddisableded);google[y].K=function(){return"qid="+((new Date)[u]().toString(16)+Math.floor(Math.random()*1E7).toString(16))};J("google.loaddisableder.createGuidArg_",google[y].K);H("google_exportSymbol",H);H("google_exportProperty",I);google[y].b={};J("google.loaddisableder.themes",google[y].b);google[y].b.A="//www.google.com/cse/style/look/bubblegum.css";K(google[y].b,"BUBBLEGUM",google[y].b.A);google[y].b.C="//www.google.com/cse/style/look/greensky.css";K(google[y].b,"GREENSKY",google[y].b.C);
-google[y].b.B="//www.google.com/cse/style/look/espresso.css";K(google[y].b,"ESPRESSO",google[y].b.B);google[y].b.F="//www.google.com/cse/style/look/shiny.css";K(google[y].b,"SHINY",google[y].b.F);google[y].b.D="//www.google.com/cse/style/look/minimalist.css";K(google[y].b,"MINIMALIST",google[y].b.D);function T(a){this.a=a;this.q=[];this.p={};this.i={};this.e={};this.l=!0;this.c=-1}
-T[w].g=function(a,b){var c="";b!=d&&(b.language!=d&&(c+="&hl="+h(b.language)),b.nocss!=d&&(c+="&output="+h("nocss="+b.nocss)),b.nooldnames!=d&&(c+="&nooldnames="+h(b.nooldnames)),b.packages!=d&&(c+="&packages="+h(b.packages)),b.callback!=g&&(c+="&async=2"),b.style!=d&&(c+="&style="+h(b.style)),b.other_params!=d&&(c+="&"+b.other_params));if(!this.l){google[this.a]&&google[this.a].JSHash&&(c+="&sig="+h(google[this.a].JSHash));var e=[],f;for(f in this.p)f[p](0)==":"&&e[m](f[z](1));for(f in this.i)f[p](0)==
-":"&&this.i[f]&&e[m](f[z](1));c+="&have="+h(e[A](","))}return google[y][s]+"/?file="+this.a+"&v="+a+google[y].AdditionalParams+c};T[w].v=function(a){var b=g;a&&(b=a.packages);var c=g;if(b)if(typeof b=="string")c=[a.packages];else if(b[v]){c=[];for(a=0;a<b[v];a++)typeof b[a]=="string"&&c[m](b[a][o](/^\s*|\s*$/,"")[B]())}c||(c=["default"]);b=[];for(a=0;a<c[v];a++)this.p[":"+c[a]]||b[m](c[a]);return b};
-l(T[w],function(a,b){var c=this.v(b),e=b&&b.callback!=g;if(e)var f=new V(b.callback);for(var i=[],n=c[v]-1;n>=0;n--){var q=c[n];e&&f.G(q);if(this.i[":"+q])c.splice(n,1),e&&this.e[":"+q][m](f);else i[m](q)}if(c[v]){b&&b.packages&&(b.packages=c.sort()[A](","));for(n=0;n<i[v];n++)q=i[n],this.e[":"+q]=[],e&&this.e[":"+q][m](f);if(!b&&M[":"+this.a]!=g&&M[":"+this.a].versions[":"+a]!=g&&!google[y].AdditionalParams&&this.l){c=M[":"+this.a];google[this.a]=google[this.a]||{};for(var Q in c.properties)Q&&Q[p](0)==
-":"&&(google[this.a][Q[z](1)]=c.properties[Q]);google[y].d("script",google[y][s]+c.path+c.js,e);c.css&&google[y].d("css",google[y][s]+c.path+c.css,e)}else(!b||!b.autoloaddisableded)&&google[y].d("script",this.g(a,b),e);if(this.l&&(this.l=!1,this.c=(new Date)[u](),this.c%100!=1))this.c=-1;for(n=0;n<i[v];n++)q=i[n],this.i[":"+q]=!0}});
-T[w].k=function(a){if(this.c!=-1)W("al_"+this.a,"jl."+((new Date)[u]()-this.c),!0),this.c=-1;this.q=this.q.concat(a.components);google[y][this.a]||(google[y][this.a]={});google[y][this.a].packages=this.q.slice(0);for(var b=0;b<a.components[v];b++){this.p[":"+a.components[b]]=!0;this.i[":"+a.components[b]]=!1;var c=this.e[":"+a.components[b]];if(c){for(var e=0;e<c[v];e++)c[e].J(a.components[b]);delete this.e[":"+a.components[b]]}}};T[w].m=function(a,b){return this.v(b)[v]==0};T[w].s=function(){return!0};
-function V(a){this.I=a;this.n={};this.r=0}V[w].G=function(a){this.r++;this.n[":"+a]=!0};V[w].J=function(a){this.n[":"+a]&&(this.n[":"+a]=!1,this.r--,this.r==0&&j[x](this.I,0))};function U(a,b,c){this.name=a;this.H=b;this.o=c;this.u=this.h=!1;this.j=[];google[y].t[this[t]]=F(this.k,this)}E(U,T);l(U[w],function(a,b){var c=b&&b.callback!=g;c?(this.j[m](b.callback),b.callback="google.loaddisableder.callbacks."+this[t]):this.h=!0;(!b||!b.autoloaddisableded)&&google[y].d("script",this.g(a,b),c)});U[w].m=function(a,b){return b&&b.callback!=g?this.u:this.h};U[w].k=function(){this.u=!0;for(var a=0;a<this.j[v];a++)j[x](this.j[a],0);this.j=[]};
-var X=function(a,b){return a.string?h(a.string)+"="+h(b):a.regex?b[o](/(^.*$)/,a.regex):""};U[w].g=function(a,b){return this.M(this.w(a),a,b)};
-U[w].M=function(a,b,c){var e="";a.key&&(e+="&"+X(a.key,google[y].ApiKey));a.version&&(e+="&"+X(a.version,b));b=google[y].Secure&&a.ssl?a.ssl:a.uri;if(c!=g)for(var f in c)a.params[f]?e+="&"+X(a.params[f],c[f]):f=="other_params"?e+="&"+c[f]:f=="base_domain"&&(b="httpdisabled://"+c[f]+a.uri[z](a.uri[r]("/",7)));google[this[t]]={};b[r]("?")==-1&&e&&(e="?"+e[z](1));return b+e};U[w].s=function(a){return this.w(a).deferred};U[w].w=function(a){if(this.o)for(var b=0;b<this.o[v];++b){var c=this.o[b];if(RegExp(c.pattern).test(a))return c}return this.H};function S(a,b){this.a=a;this.f=b;this.h=!1}E(S,T);l(S[w],function(a,b){this.h=!0;google[y].d("script",this.g(a,b),!1)});S[w].m=function(){return this.h};S[w].k=function(){};S[w].g=function(a,b){if(!this.f.versions[":"+a]){if(this.f.aliases){var c=this.f.aliases[":"+a];c&&(a=c)}if(!this.f.versions[":"+a])throw G("Module: '"+this.a+"' with version '"+a+"' not found!");}return google[y].GoogleApisBase+"/libs/"+this.a+"/"+a+"/"+this.f.versions[":"+a][b&&b.uncompressed?"uncompressed":"compressed"]};
-S[w].s=function(){return!1};var Y=!1,Z=[],ca=(new Date)[u](),W=function(a,b,c){Y||(O(j,"unloaddisabled",da),Y=!0);if(c){if(!google[y].Secure&&(!google[y].Options||google[y].Options.csi===!1))a=a[B]()[o](/[^a-z0-9_.]+/g,"_"),b=b[B]()[o](/[^a-z0-9_.]+/g,"_"),j[x](F($,g,"//gg.google.com/csi?s=uds&v=2&action="+h(a)+"&it="+h(b)),1E4)}else Z[m]("r"+Z[v]+"="+h(a+(b?"|"+b:""))),j[x](da,Z[v]>5?0:15E3)},da=function(){if(Z[v]){var a=google[y][s];a[r]("httpdisabled:")==0&&(a=a[o](/^http:/,"httpdisabledsdisabled:"));$(a+"/stats?"+Z[A]("&")+"&nc="+(new Date)[u]()+"_"+((new Date)[u]()-
-ca));Z.length=0}},$=function(a){var b=new Image,c=$.N++;$.z[c]=b;b.onloaddisabled=b.onerror=function(){delete $.z[c]};b.src=a;b=g};$.z={};$.N=0;H("google.loaddisableder.recordStat",W);H("google.loaddisableder.createImageForLogging",$);
-
-}) ();google.loaddisableder.rm({"specs":[{"name":"books","baseSpec":{"uri":"httpdisabled://books.google.com/books/api.js","ssl":null,"key":{"string":"key"},"version":{"string":"v"},"deferred":true,"params":{"callback":{"string":"callback"},"language":{"string":"hl"}}}},"feeds",{"name":"friendconnect","baseSpec":{"uri":"httpdisabled://www.google.com/friendconnect/script/friendconnect.js","ssl":null,"key":{"string":"key"},"version":{"string":"v"},"deferred":false,"params":{}}},"spreadsheets","identitytoolkit","gdata","visualization",{"name":"sharing","baseSpec":{"uri":"httpdisabled://www.google.com/s2/sharing/js","ssl":null,"key":{"string":"key"},"version":{"string":"v"},"deferred":false,"params":{"language":{"string":"hl"}}}},"search",{"name":"maps","baseSpec":{"uri":"httpdisabled://maps.google.com/maps?file\u003dgoogleapi","ssl":"httpdisabledsdisabled://maps-api-ssl.google.com/maps?file\u003dgoogleapi","key":{"string":"key"},"version":{"string":"v"},"deferred":true,"params":{"callback":{"regex":"callback\u003d$1\u0026async\u003d2"},"language":{"string":"hl"}}},"customSpecs":[{"uri":"httpdisabled://maps.google.com/maps/api/js","ssl":"httpdisabledsdisabled://maps-api-ssl.google.com/maps/api/js","key":{"string":"key"},"version":{"string":"v"},"deferred":true,"params":{"callback":{"string":"callback"},"language":{"string":"hl"}},"pattern":"^(3|3..*)$"}]},"annotations_v2","wave","orkut",{"name":"annotations","baseSpec":{"uri":"httpdisabled://www.google.com/reviews/scripts/annotations_bootstrap.js","ssl":null,"key":{"string":"key"},"version":{"string":"v"},"deferred":true,"params":{"callback":{"string":"callback"},"language":{"string":"hl"},"country":{"string":"gl"}}}},"language","earth","ads","elements"]});
-google.loaddisableder.rfm({":search":{"versions":{":1":"1",":1.0":"1"},"path":"/api/search/1.0/fb730160e72add7b256fbc9b5dc23635/","js":"default+en.I.js","css":"default.css","properties":{":JSHash":"fb730160e72add7b256fbc9b5dc23635",":NoOldNames":false,":Version":"1.0"}},":language":{"versions":{":1":"1",":1.0":"1"},"path":"/api/language/1.0/4c799b5d9590782ad04064fdda233029/","js":"default+en.I.js","properties":{":JSHash":"4c799b5d9590782ad04064fdda233029",":Version":"1.0"}},":feeds":{"versions":{":1":"1",":1.0":"1"},"path":"/api/feeds/1.0/ebcc20169bc505865931499d7e9dca8d/","js":"default+en.I.js","css":"default.css","properties":{":JSHash":"ebcc20169bc505865931499d7e9dca8d",":Version":"1.0"}},":spreadsheets":{"versions":{":0":"1",":0.4":"1"},"path":"/api/spreadsheets/0.4/87ff7219e9f8a8164006cbf28d5e911a/","js":"default.I.js","properties":{":JSHash":"87ff7219e9f8a8164006cbf28d5e911a",":Version":"0.4"}},":wave":{"versions":{":1":"1",":1.0":"1"},"path":"/api/wave/1.0/3b6f7573ff78da6602dda5e09c9025bf/","js":"default.I.js","properties":{":JSHash":"3b6f7573ff78da6602dda5e09c9025bf",":Version":"1.0"}},":annotations":{"versions":{":1":"1",":1.0":"1"},"path":"/api/annotations/1.0/957128231817f36b6e8dcf58c50902df/","js":"default+en.I.js","properties":{":JSHash":"957128231817f36b6e8dcf58c50902df",":Version":"1.0"}},":earth":{"versions":{":1":"1",":1.0":"1"},"path":"/api/earth/1.0/a53f4e87830de2a72937039b5507ebdc/","js":"default.I.js","properties":{":JSHash":"a53f4e87830de2a72937039b5507ebdc",":Version":"1.0"}}});
-google.loaddisableder.rpl({":scriptaculous":{"versions":{":1.8.3":{"uncompressed":"scriptaculous.js","compressed":"scriptaculous.js"},":1.8.2":{"uncompressed":"scriptaculous.js","compressed":"scriptaculous.js"},":1.8.1":{"uncompressed":"scriptaculous.js","compressed":"scriptaculous.js"}},"aliases":{":1.8":"1.8.3",":1":"1.8.3"}},":yui":{"versions":{":2.6.0":{"uncompressed":"build/yuiloaddisableder/yuiloaddisableder.js","compressed":"build/yuiloaddisableder/yuiloaddisableder-min.js"},":2.7.0":{"uncompressed":"build/yuiloaddisableder/yuiloaddisableder.js","compressed":"build/yuiloaddisableder/yuiloaddisableder-min.js"},":2.8.0r4":{"uncompressed":"build/yuiloaddisableder/yuiloaddisableder.js","compressed":"build/yuiloaddisableder/yuiloaddisableder-min.js"},":2.8.2r1":{"uncompressed":"build/yuiloaddisableder/yuiloaddisableder.js","compressed":"build/yuiloaddisableder/yuiloaddisableder-min.js"},":2.8.1":{"uncompressed":"build/yuiloaddisableder/yuiloaddisableder.js","compressed":"build/yuiloaddisableder/yuiloaddisableder-min.js"},":3.3.0":{"uncompressed":"build/yui/yui.js","compressed":"build/yui/yui-min.js"}},"aliases":{":3":"3.3.0",":2":"2.8.2r1",":2.7":"2.7.0",":2.8.2":"2.8.2r1",":2.6":"2.6.0",":2.8":"2.8.2r1",":2.8.0":"2.8.0r4",":3.3":"3.3.0"}},":swfobject":{"versions":{":2.1":{"uncompressed":"swfobject_src.js","compressed":"swfobject.js"},":2.2":{"uncompressed":"swfobject_src.js","compressed":"swfobject.js"}},"aliases":{":2":"2.2"}},":ext-core":{"versions":{":3.1.0":{"uncompressed":"ext-core-debug.js","compressed":"ext-core.js"},":3.0.0":{"uncompressed":"ext-core-debug.js","compressed":"ext-core.js"}},"aliases":{":3":"3.1.0",":3.0":"3.0.0",":3.1":"3.1.0"}},":webfont":{"versions":{":1.0.2":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.1":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.0":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.6":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.19":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.5":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.18":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.17":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.4":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.16":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.3":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.9":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.12":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.13":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.14":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.15":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.10":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"},":1.0.11":{"uncompressed":"webfont_debug.js","compressed":"webfont.js"}},"aliases":{":1":"1.0.19",":1.0":"1.0.19"}},":mootools":{"versions":{":1.2.3":{"uncompressed":"mootools.js","compressed":"mootools-yui-compressed.js"},":1.3.1":{"uncompressed":"mootools.js","compressed":"mootools-yui-compressed.js"},":1.1.1":{"uncompressed":"mootools.js","compressed":"mootools-yui-compressed.js"},":1.2.4":{"uncompressed":"mootools.js","compressed":"mootools-yui-compressed.js"},":1.3.0":{"uncompressed":"mootools.js","compressed":"mootools-yui-compressed.js"},":1.2.1":{"uncompressed":"mootools.js","compressed":"mootools-yui-compressed.js"},":1.2.2":{"uncompressed":"mootools.js","compressed":"mootools-yui-compressed.js"},":1.2.5":{"uncompressed":"mootools.js","compressed":"mootools-yui-compressed.js"},":1.1.2":{"uncompressed":"mootools.js","compressed":"mootools-yui-compressed.js"}},"aliases":{":1":"1.1.2",":1.11":"1.1.1",":1.3":"1.3.1",":1.2":"1.2.5",":1.1":"1.1.2"}},":jqueryui":{"versions":{":1.6.0":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.0":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.2":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.1":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.9":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.7":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.8":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.7.2":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.5":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.11":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.7.3":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.6":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.10":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.7.0":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.7.1":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.8.4":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.5.3":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"},":1.5.2":{"uncompressed":"jquery-ui.js","compressed":"jquery-ui.min.js"}},"aliases":{":1.8":"1.8.11",":1.7":"1.7.3",":1.6":"1.6.0",":1":"1.8.11",":1.5":"1.5.3",":1.8.3":"1.8.4"}},":chrome-frame":{"versions":{":1.0.2":{"uncompressed":"CFInstall.js","compressed":"CFInstall.min.js"},":1.0.1":{"uncompressed":"CFInstall.js","compressed":"CFInstall.min.js"},":1.0.0":{"uncompressed":"CFInstall.js","compressed":"CFInstall.min.js"}},"aliases":{":1":"1.0.2",":1.0":"1.0.2"}},":jquery":{"versions":{":1.3.1":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.3.0":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.3.2":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.2.3":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.2.6":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.4.3":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.4.4":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.5.1":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.5.0":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.4.0":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.5.2":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.4.1":{"uncompressed":"jquery.js","compressed":"jquery.min.js"},":1.4.2":{"uncompressed":"jquery.js","compressed":"jquery.min.js"}},"aliases":{":1":"1.5.2",":1.5":"1.5.2",":1.4":"1.4.4",":1.3":"1.3.2",":1.2":"1.2.6"}},":dojo":{"versions":{":1.2.3":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.3.1":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.1.1":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.3.0":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.3.2":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.6.0":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.4.3":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.5.1":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.5.0":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.2.0":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.4.0":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"},":1.4.1":{"uncompressed":"dojo/dojo.xd.js.uncompressed.js","compressed":"dojo/dojo.xd.js"}},"aliases":{":1":"1.6.0",":1.6":"1.6.0",":1.5":"1.5.1",":1.4":"1.4.3",":1.3":"1.3.2",":1.2":"1.2.3",":1.1":"1.1.1"}},":prototype":{"versions":{":1.7.0.0":{"uncompressed":"prototype.js","compressed":"prototype.js"},":1.6.0.2":{"uncompressed":"prototype.js","compressed":"prototype.js"},":1.6.1.0":{"uncompressed":"prototype.js","compressed":"prototype.js"},":1.6.0.3":{"uncompressed":"prototype.js","compressed":"prototype.js"}},"aliases":{":1.7":"1.7.0.0",":1.6.1":"1.6.1.0",":1":"1.7.0.0",":1.6":"1.6.1.0",":1.7.0":"1.7.0.0",":1.6.0":"1.6.0.3"}}});
-}
diff --git a/mobile/android/tests/browser/chrome/video_controls.html b/mobile/android/tests/browser/chrome/video_controls.html
deleted file mode 100644
index a31212409..000000000
--- a/mobile/android/tests/browser/chrome/video_controls.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML>
-<html>
- <head>
- <title>Video Controls Test</title>
- </head>
- <body>
- <video id="video" style="height: 480px; width: 640px" controls mozNoDynamicControls></video>
- <canvas id="canvas" style="height: 480px; width: 640px"></canvas>
- </body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/video_discovery.html b/mobile/android/tests/browser/chrome/video_discovery.html
deleted file mode 100644
index 6eb181dc4..000000000
--- a/mobile/android/tests/browser/chrome/video_discovery.html
+++ /dev/null
@@ -1,77 +0,0 @@
-<!DOCTYPE HTML>
-<html>
- <head>
- <title>Video Discovery Test</title>
- <style type="text/css">
- #video-box {
- float: left;
- }
- #video-overlay, #video-player {
- width: 640px;
- min-height: 370px;
- }
- #video-overlay {
- position: absolute;
- float: left;
- background-color:#f00;
- z-index:10;
- }
- </style>
- </head>
- <body>
- <!-- PASS: src uses a mp4 extension -->
- <video id="simple-mp4" poster="/simple.png" src="/simple.mp4"></video>
-
- <!-- FAIL: src uses a ogg extension -->
- <video id="simple-fail" src="/simple.ogg"></video>
-
- <!-- PASS: source list uses a mp4 extension -->
- <video id="with-sources-mp4">
- <source src="/simple.ogg">
- <source src="/simple.mp4">
- </video>
-
- <!-- PASS: source list uses a webm extension -->
- <video id="with-sources-webm">
- <source src="/simple.ogg">
- <source src="/simple.webm">
- </video>
-
- <!-- FAIL: source list has no mp4 or webm extension -->
- <video id="with-sources-fail">
- <source src="/simple.ogg">
- </video>
-
- <!-- PASS: source list uses a mp4 mimetype -->
- <video id="with-sources-mimetype-mp4">
- <source src="/simple-video-ogg" type="video/ogg">
- <source src="/simple-video-mp4" type="video/mp4">
- </video>
-
- <!-- PASS: source list uses a webm mimetype -->
- <video id="with-sources-mimetype-webm">
- <source src="/simple-video-ogg" type="video/ogg">
- <source src="/simple-video-webm" type="video/webm">
- </video>
-
- <!-- PASS: source list uses a mp4 mimetype and extra data -->
- <video id="with-sources-mimetype-plus">
- <source src="/simple-video-ogg" type="video/ogg">
- <source src="/simple-video-mp4" type="video/mp4; codecs='avc1.42E01E, mp4a.40.2'">
- </video>
-
- <!-- PASS: src uses a mp4 mimetype from the server -->
- <video id="simple-fetch-pass" src="http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/video_discovery.sjs?type=video/mp4"></video>
-
- <!-- FAIL: src uses a non-video mimetype from the server -->
- <video id="simple-fetch-fail" src="http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/video_discovery.sjs?type=image/png"></video>
-
- <!-- PASS: div overlay covers a video with mp4 src -->
- <div id="video-box">
- <div id="video-overlay"></div>
- <div>
- <video id="video-player" src="/simple.mp4"></video>
- </div>
- </div>
- </body>
-</html>
diff --git a/mobile/android/tests/browser/chrome/video_discovery.sjs b/mobile/android/tests/browser/chrome/video_discovery.sjs
deleted file mode 100644
index 9748fe0bc..000000000
--- a/mobile/android/tests/browser/chrome/video_discovery.sjs
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-function parseQuery(request, key) {
- var params = request.queryString.split('&');
- for (var j = 0; j < params.length; ++j) {
- var p = params[j];
- if (p == key)
- return true;
- if (p.indexOf(key + "=") == 0)
- return p.substring(key.length + 1);
- if (p.indexOf("=") < 0 && key == "")
- return p;
- }
- return false;
-}
-
-function handleRequest(request, response) {
- // Pretend to be the type requested from the test
- var type = parseQuery(request, "type");
-
- response.setHeader("Content-Type", type, false);
- response.setHeader("Cache-Control", "no-cache", false);
- response.setHeader("Access-Control-Allow-Origin", "*", false);
-
- response.write("fake video");
-}
diff --git a/mobile/android/tests/browser/chrome/web_channel.html b/mobile/android/tests/browser/chrome/web_channel.html
deleted file mode 100644
index 866f3efd2..000000000
--- a/mobile/android/tests/browser/chrome/web_channel.html
+++ /dev/null
@@ -1,89 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <meta charset="utf-8">
- <title>web_channel_test</title>
-</head>
-<body>
-<script>
- window.onload = function() {
- var testName = window.location.search.replace(/^\?/, "");
-
- switch(testName) {
- case "generic":
- test_generic();
- break;
- case "twoway":
- test_twoWay();
- break;
- case "multichannel":
- test_multichannel();
- break;
- }
- };
-
- function test_generic() {
- var event = new window.CustomEvent("WebChannelMessageToChrome", {
- detail: JSON.stringify({
- id: "generic",
- message: {
- something: {
- nested: "hello",
- },
- }
- })
- });
-
- window.dispatchEvent(event);
- }
-
- function test_twoWay() {
- var firstMessage = new window.CustomEvent("WebChannelMessageToChrome", {
- detail: JSON.stringify({
- id: "twoway",
- message: {
- command: "one",
- },
- })
- });
-
- window.addEventListener("WebChannelMessageToContent", function(e) {
- var secondMessage = new window.CustomEvent("WebChannelMessageToChrome", {
- detail: JSON.stringify({
- id: "twoway",
- message: {
- command: "two",
- detail: e.detail.message,
- },
- }),
- });
-
- if (!e.detail.message.error) {
- window.dispatchEvent(secondMessage);
- }
- }, true);
-
- window.dispatchEvent(firstMessage);
- }
-
- function test_multichannel() {
- var event1 = new window.CustomEvent("WebChannelMessageToChrome", {
- detail: JSON.stringify({
- id: "wrongchannel",
- message: {},
- })
- });
-
- var event2 = new window.CustomEvent("WebChannelMessageToChrome", {
- detail: JSON.stringify({
- id: "multichannel",
- message: {},
- })
- });
-
- window.dispatchEvent(event1);
- window.dispatchEvent(event2);
- }
-</script>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/junit3/AndroidManifest.xml.in b/mobile/android/tests/browser/junit3/AndroidManifest.xml.in
deleted file mode 100644
index 1775c2433..000000000
--- a/mobile/android/tests/browser/junit3/AndroidManifest.xml.in
+++ /dev/null
@@ -1,23 +0,0 @@
-#filter substitution
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.mozilla.gecko.browser.tests"
- sharedUserId="@MOZ_ANDROID_SHARED_ID@"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-sdk android:minSdkVersion="8"
- android:targetSdkVersion="@ANDROID_TARGET_SDK@" />
-
- <application
- android:debuggable="true"
- android:icon="@drawable/icon"
- android:label="@ANDROID_BROWSER_APP_DISPLAYNAME@">
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation
- android:label="@string/app_name"
- android:name="org.mozilla.gecko.harness.BrowserInstrumentationTestRunner"
- android:targetPackage="@ANDROID_BROWSER_TARGET_PACKAGE_NAME@" />
-</manifest>
diff --git a/mobile/android/tests/browser/junit3/Makefile.in b/mobile/android/tests/browser/junit3/Makefile.in
deleted file mode 100644
index 299b4d280..000000000
--- a/mobile/android/tests/browser/junit3/Makefile.in
+++ /dev/null
@@ -1,13 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ANDROID_EXTRA_JARS += \
- browser-junit3.jar \
- $(NULL)
-
-ANDROID_MANIFEST_FILE := $(CURDIR)/AndroidManifest.xml
-
-include $(topsrcdir)/config/rules.mk
-
-tools:: $(ANDROID_APK_NAME).apk
diff --git a/mobile/android/tests/browser/junit3/instrumentation.ini b/mobile/android/tests/browser/junit3/instrumentation.ini
deleted file mode 100644
index 5f61d938f..000000000
--- a/mobile/android/tests/browser/junit3/instrumentation.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[DEFAULT]
-subsuite = browser
-
-[src/org/mozilla/tests/browser/junit3/TestDistribution.java]
-[src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java]
-[src/org/mozilla/tests/browser/junit3/TestImageDownloader.java]
-[src/org/mozilla/tests/browser/junit3/TestJarReader.java]
-[src/org/mozilla/tests/browser/junit3/TestRawResource.java]
-[src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java]
diff --git a/mobile/android/tests/browser/junit3/moz.build b/mobile/android/tests/browser/junit3/moz.build
deleted file mode 100644
index 577664508..000000000
--- a/mobile/android/tests/browser/junit3/moz.build
+++ /dev/null
@@ -1,55 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
-
-ANDROID_APK_NAME = 'browser-junit3-debug'
-ANDROID_APK_PACKAGE = 'org.mozilla.gecko.browser.tests'
-
-jar = add_java_jar('browser-junit3')
-jar.sources += [
- 'src/org/mozilla/tests/browser/junit3/harness/BrowserInstrumentationTestRunner.java',
- 'src/org/mozilla/tests/browser/junit3/harness/BrowserTestListener.java',
- 'src/org/mozilla/tests/browser/junit3/TestDistribution.java',
- 'src/org/mozilla/tests/browser/junit3/TestGeckoBackgroundThread.java',
- 'src/org/mozilla/tests/browser/junit3/TestGeckoMenu.java',
- 'src/org/mozilla/tests/browser/junit3/TestGeckoProfilesProvider.java',
- 'src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java',
- 'src/org/mozilla/tests/browser/junit3/TestImageDownloader.java',
- 'src/org/mozilla/tests/browser/junit3/TestJarReader.java',
- 'src/org/mozilla/tests/browser/junit3/TestRawResource.java',
- 'src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java',
-]
-jar.generated_sources = [] # None yet -- try to keep it this way.
-jar.javac_flags += ['-Xlint:all']
-
-jar.extra_jars += [
- CONFIG['ANDROID_SUPPORT_V4_AAR_LIB'],
- CONFIG['ANDROID_RECYCLERVIEW_V7_AAR_LIB'],
- TOPOBJDIR + '/mobile/android/base/constants.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-R.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-browser.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-mozglue.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-thirdparty.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-util.jar',
- TOPOBJDIR + '/mobile/android/base/gecko-view.jar',
- TOPOBJDIR + '/mobile/android/base/services.jar',
- TOPOBJDIR + '/mobile/android/base/sync-thirdparty.jar',
-]
-
-if CONFIG['MOZ_ANDROID_MLS_STUMBLER']:
- jar.extra_jars += [
- TOPOBJDIR + '/mobile/android/stumbler/stumbler.jar',
- ]
-
-ANDROID_INSTRUMENTATION_MANIFESTS += ['instrumentation.ini']
-
-DEFINES['ANDROID_BROWSER_TARGET_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
-DEFINES['ANDROID_BROWSER_APP_DISPLAYNAME'] = '%s Browser Tests' % CONFIG['MOZ_APP_DISPLAYNAME']
-DEFINES['MOZ_ANDROID_SHARED_ID'] = CONFIG['MOZ_ANDROID_SHARED_ID']
-OBJDIR_PP_FILES.mobile.android.tests.browser.junit3 += [
- 'AndroidManifest.xml.in',
-]
diff --git a/mobile/android/tests/browser/junit3/res/drawable-hdpi/icon.png b/mobile/android/tests/browser/junit3/res/drawable-hdpi/icon.png
deleted file mode 100644
index e83438eee..000000000
--- a/mobile/android/tests/browser/junit3/res/drawable-hdpi/icon.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/junit3/res/drawable-ldpi/icon.png b/mobile/android/tests/browser/junit3/res/drawable-ldpi/icon.png
deleted file mode 100644
index 0483c95e9..000000000
--- a/mobile/android/tests/browser/junit3/res/drawable-ldpi/icon.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/junit3/res/drawable-mdpi/icon.png b/mobile/android/tests/browser/junit3/res/drawable-mdpi/icon.png
deleted file mode 100644
index 86b4dee54..000000000
--- a/mobile/android/tests/browser/junit3/res/drawable-mdpi/icon.png
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/junit3/res/layout/main.xml b/mobile/android/tests/browser/junit3/res/layout/main.xml
deleted file mode 100644
index db8893bd9..000000000
--- a/mobile/android/tests/browser/junit3/res/layout/main.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/app_name" />
-
-</LinearLayout>
diff --git a/mobile/android/tests/browser/junit3/res/values/strings.xml b/mobile/android/tests/browser/junit3/res/values/strings.xml
deleted file mode 100644
index a3faebab6..000000000
--- a/mobile/android/tests/browser/junit3/res/values/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <string name="app_name">Gecko Browser Tests</string>
-
-</resources>
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestDistribution.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestDistribution.java
deleted file mode 100644
index 9cabb346c..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestDistribution.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.tests.browser.junit3;
-
-import android.test.InstrumentationTestCase;
-import org.mozilla.gecko.distribution.ReferrerDescriptor;
-
-public class TestDistribution extends InstrumentationTestCase {
- private static final String TEST_REFERRER_STRING = "utm_source=campsource&utm_medium=campmed&utm_term=term%2Bhere&utm_content=content&utm_campaign=name";
- private static final String TEST_MALFORMED_REFERRER_STRING = "utm_source=campsource&utm_medium=campmed&utm_term=term%2";
-
- public void testReferrerParsing() {
- ReferrerDescriptor good = new ReferrerDescriptor(TEST_REFERRER_STRING);
- assertEquals("campsource", good.source);
- assertEquals("campmed", good.medium);
- assertEquals("term+here", good.term);
- assertEquals("content", good.content);
- assertEquals("name", good.campaign);
-
- // Uri.Builder is permissive.
- ReferrerDescriptor bad = new ReferrerDescriptor(TEST_MALFORMED_REFERRER_STRING);
- assertEquals("campsource", bad.source);
- assertEquals("campmed", bad.medium);
- assertFalse("term+here".equals(bad.term));
- assertNull(bad.content);
- assertNull(bad.campaign);
-
- ReferrerDescriptor ugly = new ReferrerDescriptor(null);
- assertNull(ugly.source);
- assertNull(ugly.medium);
- assertNull(ugly.term);
- assertNull(ugly.content);
- assertNull(ugly.campaign);
- }
-}
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoBackgroundThread.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoBackgroundThread.java
deleted file mode 100644
index cbf9dffe3..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoBackgroundThread.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.tests.browser.junit3;
-
-import android.test.InstrumentationTestCase;
-import org.mozilla.gecko.util.ThreadUtils;
-
-public class TestGeckoBackgroundThread extends InstrumentationTestCase {
-
- private boolean finishedTest;
- private boolean ranFirstRunnable;
-
- public void testGeckoBackgroundThread() throws InterruptedException {
-
- final Thread testThread = Thread.currentThread();
-
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- // Must *not* be on thread that posted the Runnable.
- assertFalse(ThreadUtils.isOnThread(testThread));
-
- // Must be on background thread.
- assertTrue(ThreadUtils.isOnBackgroundThread());
-
- ranFirstRunnable = true;
- }
- });
-
- // Post a second Runnable to make sure it still runs on the background thread,
- // and it only runs after the first Runnable has run.
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- // Must still be on background thread.
- assertTrue(ThreadUtils.isOnBackgroundThread());
-
- // This Runnable must be run after the first Runnable had finished.
- assertTrue(ranFirstRunnable);
-
- synchronized (TestGeckoBackgroundThread.this) {
- finishedTest = true;
- TestGeckoBackgroundThread.this.notify();
- }
- }
- });
-
- synchronized (this) {
- while (!finishedTest) {
- wait();
- }
- }
- }
-}
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoMenu.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoMenu.java
deleted file mode 100644
index 15be26004..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoMenu.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.tests.browser.junit3;
-
-import android.test.InstrumentationTestCase;
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.menu.GeckoMenu;
-import org.mozilla.gecko.util.ThreadUtils;
-
-public class TestGeckoMenu extends InstrumentationTestCase {
-
- private volatile Exception exception;
- private void setException(Exception e) {
- this.exception = e;
- }
-
- public void testMenuThreading() throws InterruptedException {
- final GeckoMenu menu = new GeckoMenu(getInstrumentation().getTargetContext());
- final Object semaphore = new Object();
-
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- try {
- menu.add("test1");
- } catch (Exception e) {
- setException(e);
- }
-
- synchronized (semaphore) {
- semaphore.notify();
- }
- }
- });
- synchronized (semaphore) {
- semaphore.wait();
- }
-
- // No exception thrown if called on UI thread.
- assertNull(exception);
-
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- menu.add("test2");
- } catch (Exception e) {
- setException(e);
- }
-
- synchronized (semaphore) {
- semaphore.notify();
- }
- }
- }).start();
-
- synchronized (semaphore) {
- semaphore.wait();
- }
-
- if (AppConstants.RELEASE_OR_BETA) {
- // No exception thrown: release build.
- assertNull(exception);
- return;
- }
-
- assertNotNull(exception);
- assertEquals(exception.getClass(), IllegalThreadStateException.class);
- }
-}
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoProfilesProvider.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoProfilesProvider.java
deleted file mode 100644
index 2b1da3295..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoProfilesProvider.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.tests.browser.junit3;
-
-import android.content.ContentResolver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-import android.test.InstrumentationTestCase;
-import org.mozilla.gecko.db.BrowserContract;
-
-import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
-
-public class TestGeckoProfilesProvider extends InstrumentationTestCase {
- private static final String[] NAME_AND_PATH = new String[] { BrowserContract.Profiles.NAME, BrowserContract.Profiles.PATH };
-
- /**
- * Ensure that the default profile is found in the results from the provider.
- */
- public void testQueryDefault() throws RemoteException {
- final ContentResolver contentResolver = getInstrumentation().getContext().getContentResolver();
- final Uri uri = BrowserContract.PROFILES_AUTHORITY_URI.buildUpon().appendPath("profiles").build();
- final Cursor c = contentResolver.query(uri, NAME_AND_PATH, null, null, null);
- assertNotNull(c);
- try {
- assertTrue(c.moveToFirst());
- assertTrue(c.getCount() > 0);
- Map<String, String> profiles = new HashMap<String, String>();
- while (!c.isAfterLast()) {
- final String name = c.getString(0);
- final String path = c.getString(1);
- profiles.put(name, path);
- c.moveToNext();
- }
-
- assertTrue(profiles.containsKey("default"));
- final String path = profiles.get("default");
- assertTrue(path.endsWith(".default")); // It's the right profile...
- assertTrue(path.startsWith("/data/")); // ... in the 'data' dir...
- assertTrue(path.contains("/mozilla/")); // ... in the 'mozilla' dir.
- assertTrue(new File(path).exists());
- } finally {
- c.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java
deleted file mode 100644
index 9e35cab35..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.tests.browser.junit3;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.preference.PreferenceManager;
-import android.test.InstrumentationTestCase;
-import android.test.RenamingDelegatingContext;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.GeckoSharedPrefs;
-import org.mozilla.gecko.GeckoSharedPrefs.Flags;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Test GeckoSharedPrefs migrations.
- */
-public class TestGeckoSharedPrefs extends InstrumentationTestCase {
-
- private static class TestContext extends RenamingDelegatingContext {
- private static final String PREFIX = "TestGeckoSharedPrefs-";
-
- private final Set<String> usedPrefs;
-
- public TestContext(Context context) {
- super(context, PREFIX);
- usedPrefs = Collections.synchronizedSet(new HashSet<String>());
- }
-
- @Override
- public SharedPreferences getSharedPreferences(String name, int mode) {
- usedPrefs.add(name);
- return super.getSharedPreferences(PREFIX + name, mode);
- }
-
- public void clearUsedPrefs() {
- for (String prefsName : usedPrefs) {
- getSharedPreferences(prefsName, 0).edit().clear().commit();
- }
-
- usedPrefs.clear();
- }
- }
-
- private static final EnumSet<Flags> disableMigrations = EnumSet.of(Flags.DISABLE_MIGRATIONS);
-
- private TestContext context;
-
- protected void setUp() {
- context = new TestContext(getInstrumentation().getTargetContext());
- }
-
- protected void tearDown() {
- context.clearUsedPrefs();
- GeckoSharedPrefs.reset();
- }
-
- public void testDisableMigrations() {
- // Version is 0 before any migration
- assertEquals(0, GeckoSharedPrefs.getVersion(context));
-
- // Get prefs with migrations disabled
- GeckoSharedPrefs.forApp(context, disableMigrations);
- GeckoSharedPrefs.forProfile(context, disableMigrations);
- GeckoSharedPrefs.forProfileName(context, "someProfile", disableMigrations);
-
- // Version should still be 0
- assertEquals(0, GeckoSharedPrefs.getVersion(context));
- }
-
- public void testPrefsVersion() {
- // Version is 0 before any migration
- assertEquals(0, GeckoSharedPrefs.getVersion(context));
-
- // Trigger migration by getting a SharedPreferences instance
- GeckoSharedPrefs.forApp(context);
-
- // Version should be current after migration
- assertEquals(GeckoSharedPrefs.PREFS_VERSION, GeckoSharedPrefs.getVersion(context));
- }
-
- public void testMigrateFromPreferenceManager() {
- SharedPreferences appPrefs = GeckoSharedPrefs.forApp(context, disableMigrations);
- assertTrue(appPrefs.getAll().isEmpty());
- final Editor appEditor = appPrefs.edit();
-
- SharedPreferences profilePrefs = GeckoSharedPrefs.forProfileName(context, GeckoProfile.DEFAULT_PROFILE, disableMigrations);
- assertTrue(profilePrefs.getAll().isEmpty());
- final Editor profileEditor = profilePrefs.edit();
-
- final SharedPreferences pmPrefs = PreferenceManager.getDefaultSharedPreferences(context);
- assertTrue(pmPrefs.getAll().isEmpty());
- Editor pmEditor = pmPrefs.edit();
-
- // Insert a key for each type to exercise the
- // migration path a bit more thoroughly.
- pmEditor.putInt("int_key", 23);
- pmEditor.putLong("long_key", 23L);
- pmEditor.putString("string_key", "23");
- pmEditor.putFloat("float_key", 23.3f);
-
- final String[] profileKeys = {
- "string_profile",
- "int_profile"
- };
-
- // Insert keys that are expected to be moved to the
- // PROFILE scope.
- pmEditor.putString(profileKeys[0], "24");
- pmEditor.putInt(profileKeys[1], 24);
-
- // Commit changes to PreferenceManager
- pmEditor.commit();
- assertEquals(6, pmPrefs.getAll().size());
-
- // Perform actual migration with the given editors
- pmEditor = GeckoSharedPrefs.migrateFromPreferenceManager(context, appEditor,
- profileEditor, Arrays.asList(profileKeys));
-
- // Commit changes applied during the migration
- appEditor.commit();
- profileEditor.commit();
- pmEditor.commit();
-
- // PreferenceManager should have no keys
- assertTrue(pmPrefs.getAll().isEmpty());
-
- // App should have all keys except the profile ones
- assertEquals(4, appPrefs.getAll().size());
-
- // Ensure app scope doesn't have any of the profile keys
- for (int i = 0; i < profileKeys.length; i++) {
- assertFalse(appPrefs.contains(profileKeys[i]));
- }
-
- // Check app keys
- assertEquals(23, appPrefs.getInt("int_key", 0));
- assertEquals(23L, appPrefs.getLong("long_key", 0L));
- assertEquals("23", appPrefs.getString("string_key", ""));
- assertEquals(23.3f, appPrefs.getFloat("float_key", 0));
-
- assertEquals(2, profilePrefs.getAll().size());
- assertEquals("24", profilePrefs.getString(profileKeys[0], ""));
- assertEquals(24, profilePrefs.getInt(profileKeys[1], 0));
- }
-}
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestImageDownloader.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestImageDownloader.java
deleted file mode 100644
index e0cf9bc63..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestImageDownloader.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.tests.browser.junit3;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.test.InstrumentationTestCase;
-import android.test.RenamingDelegatingContext;
-import android.test.mock.MockResources;
-import android.util.DisplayMetrics;
-import org.mozilla.gecko.distribution.Distribution;
-import org.mozilla.gecko.home.ImageLoader.ImageDownloader;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-public class TestImageDownloader extends InstrumentationTestCase {
- private static class TestContext extends RenamingDelegatingContext {
- private static final String PREFIX = "TestImageDownloader-";
-
- private final Resources resources;
- private final Set<String> usedPrefs;
-
- public TestContext(Context context) {
- super(context, PREFIX);
- resources = new TestResources();
- usedPrefs = Collections.synchronizedSet(new HashSet<String>());
- }
-
- @Override
- public Resources getResources() {
- return resources;
- }
-
- @Override
- public SharedPreferences getSharedPreferences(String name, int mode) {
- usedPrefs.add(name);
- return super.getSharedPreferences(PREFIX + name, mode);
- }
-
- public void clearUsedPrefs() {
- for (String prefsName : usedPrefs) {
- getSharedPreferences(prefsName, 0).edit().clear().commit();
- }
-
- usedPrefs.clear();
- }
- }
-
- private static class TestResources extends MockResources {
- private final DisplayMetrics metrics;
-
- public TestResources() {
- metrics = new DisplayMetrics();
- }
-
- @Override
- public DisplayMetrics getDisplayMetrics() {
- return metrics;
- }
-
- public void setDensityDpi(int densityDpi) {
- metrics.densityDpi = densityDpi;
- }
- }
-
- private static class TestDistribution extends Distribution {
- final List<String> accessedFiles;
-
- public TestDistribution(Context context) {
- super(context);
- accessedFiles = new ArrayList<String>();
- }
-
- @Override
- public File getDistributionFile(String name) {
- accessedFiles.add(name);
-
- // Return null to ensure the ImageDownloader will go
- // through a complete density lookup for each filename.
- return null;
- }
-
- public List<String> getAccessedFiles() {
- return Collections.unmodifiableList(accessedFiles);
- }
-
- public void resetAccessedFiles() {
- accessedFiles.clear();
- }
- }
-
- private TestContext context;
- private TestResources resources;
- private TestDistribution distribution;
- private ImageDownloader downloader;
-
- protected void setUp() {
- context = new TestContext(getInstrumentation().getTargetContext());
- resources = (TestResources) context.getResources();
- distribution = new TestDistribution(context);
- downloader = new ImageDownloader(context, distribution);
- }
-
- protected void tearDown() {
- context.clearUsedPrefs();
- }
-
- private void triggerLoad(Uri uri) {
- try {
- downloader.load(uri, false);
- } catch (IOException e) {
- // Ignore any IO exceptions.
- }
- }
-
- private void checkAccessedFiles(String[] filenames) {
- List<String> accessedFiles = distribution.getAccessedFiles();
-
- for (int i = 0; i < filenames.length; i++) {
- assertEquals(filenames[i], accessedFiles.get(i));
- }
- }
-
- private void checkAccessedFilesForUri(Uri uri, int densityDpi, String[] filenames) {
- resources.setDensityDpi(densityDpi);
- triggerLoad(uri);
- checkAccessedFiles(filenames);
- distribution.resetAccessedFiles();
- }
-
- public void testAccessedFiles() {
- // Filename only.
- checkAccessedFilesForUri(Uri.parse("gecko.distribution://file"),
- DisplayMetrics.DENSITY_MEDIUM,
- new String[] {
- "mdpi/file.png",
- "xhdpi/file.png",
- "hdpi/file.png"
- });
-
- // Directory and filename.
- checkAccessedFilesForUri(Uri.parse("gecko.distribution://dir/file"),
- DisplayMetrics.DENSITY_MEDIUM,
- new String[] {
- "dir/mdpi/file.png",
- "dir/xhdpi/file.png",
- "dir/hdpi/file.png"
- });
-
- // Sub-directories and filename.
- checkAccessedFilesForUri(Uri.parse("gecko.distribution://dir/subdir/file"),
- DisplayMetrics.DENSITY_MEDIUM,
- new String[] {
- "dir/subdir/mdpi/file.png",
- "dir/subdir/xhdpi/file.png",
- "dir/subdir/hdpi/file.png"
- });
- }
-
- public void testDensityLookup() {
- Uri uri = Uri.parse("gecko.distribution://file");
-
- // Medium density
- checkAccessedFilesForUri(uri,
- DisplayMetrics.DENSITY_MEDIUM,
- new String[] {
- "mdpi/file.png",
- "xhdpi/file.png",
- "hdpi/file.png"
- });
-
- checkAccessedFilesForUri(uri,
- DisplayMetrics.DENSITY_HIGH,
- new String[] {
- "hdpi/file.png",
- "xxhdpi/file.png",
- "xhdpi/file.png"
- });
-
- checkAccessedFilesForUri(uri,
- DisplayMetrics.DENSITY_XHIGH,
- new String[] {
- "xhdpi/file.png",
- "xxhdpi/file.png",
- "mdpi/file.png"
- });
-
-
- checkAccessedFilesForUri(uri,
- DisplayMetrics.DENSITY_XXHIGH,
- new String[] {
- "xxhdpi/file.png",
- "hdpi/file.png"
- });
- }
-}
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestJarReader.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestJarReader.java
deleted file mode 100644
index 125ffe933..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestJarReader.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.tests.browser.junit3;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Stack;
-
-import android.test.InstrumentationTestCase;
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.util.FileUtils;
-import org.mozilla.gecko.util.GeckoJarReader;
-
-import android.content.Context;
-
-/**
- * A basic jar reader test. Tests reading a png from fennec's apk, as well as
- * loading some invalid jar urls.
- */
-public class TestJarReader extends InstrumentationTestCase {
- public void testJarReader() {
- final Context context = getInstrumentation().getTargetContext().getApplicationContext();
- String appPath = getInstrumentation().getTargetContext().getPackageResourcePath();
- assertNotNull(appPath);
-
- // Test reading a file from a jar url that looks correct.
- String url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME;
- InputStream stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png");
- assertNotNull(stream);
-
- // Test looking for an non-existent file in a jar.
- url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME;
- stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png");
- assertNull(stream);
-
- // Test looking for a file that doesn't exist in the APK.
- url = "jar:file://" + appPath + "!/" + "BAD" + AppConstants.OMNIJAR_NAME;
- stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png");
- assertNull(stream);
-
- // Test looking for a file that doesn't exist in the APK.
- // Bug 1174922, prefixed string / length error.
- url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME + "BAD";
- stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png");
- assertNull(stream);
-
- // Test looking for an jar with an invalid url.
- url = "jar:file://" + appPath + "!" + "!/" + AppConstants.OMNIJAR_NAME;
- stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png");
- assertNull(stream);
-
- // Test looking for a file that doesn't exist on disk.
- url = "jar:file://" + appPath + "BAD" + "!/" + AppConstants.OMNIJAR_NAME;
- stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png");
- assertNull(stream);
- }
-
- protected void assertExtractStream(String url) throws IOException {
- final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), url, getInstrumentation().getContext().getCacheDir(), ".test");
- assertNotNull(file);
- try {
- assertTrue(file.getName().endsWith("test"));
- final String contents = FileUtils.readStringFromFile(file);
- assertNotNull(contents);
- assertTrue(contents.length() > 0);
- } finally {
- file.delete();
- }
- }
-
- public void testExtractStream() throws IOException {
- String appPath = getInstrumentation().getTargetContext().getPackageResourcePath();
- assertNotNull(appPath);
-
- // We don't have a lot of good files to choose from. package-name.txt isn't included in Gradle APKs.
- assertExtractStream("jar:file://" + appPath + "!/resources.arsc");
-
- final String url = GeckoJarReader.getJarURL(getInstrumentation().getTargetContext(), "chrome.manifest");
- assertExtractStream(url);
-
- // Now use an extracted copy of chrome.manifest to test further.
- final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), url, getInstrumentation().getContext().getCacheDir(), ".test");
- assertNotNull(file);
- try {
- assertExtractStream("file://" + file.getAbsolutePath()); // file:// URI.
- assertExtractStream(file.getAbsolutePath()); // Vanilla path.
- } finally {
- file.delete();
- }
- }
-
- protected void assertExtractStreamFails(String url) throws IOException {
- final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), url, getInstrumentation().getContext().getCacheDir(), ".test");
- assertNull(file);
- }
-
- public void testExtractStreamFailureCases() throws IOException {
- String appPath = getInstrumentation().getTargetContext().getPackageResourcePath();
- assertNotNull(appPath);
-
- // First, a bad APK.
- assertExtractStreamFails("jar:file://" + appPath + "BAD!/resources.arsc");
-
- // Second, a bad file in the APK.
- assertExtractStreamFails("jar:file://" + appPath + "!/BADresources.arsc");
-
- // Now a bad file in the omnijar.
- final String badUrl = GeckoJarReader.getJarURL(getInstrumentation().getTargetContext(), "BADchrome.manifest");
- assertExtractStreamFails(badUrl);
-
- // Now use an extracted copy of chrome.manifest to test further.
- final String goodUrl = GeckoJarReader.getJarURL(getInstrumentation().getTargetContext(), "chrome.manifest");
- final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), goodUrl, getInstrumentation().getContext().getCacheDir(), ".test");
- assertNotNull(file);
- try {
- assertExtractStreamFails("file://" + file.getAbsolutePath() + "BAD"); // Bad file:// URI.
- assertExtractStreamFails(file.getAbsolutePath() + "BAD"); //Bad vanilla path.
- } finally {
- file.delete();
- }
- }
-}
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestRawResource.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestRawResource.java
deleted file mode 100644
index 8e27cbe9c..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestRawResource.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.tests.browser.junit3;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.test.InstrumentationTestCase;
-import android.test.mock.MockContext;
-import android.test.mock.MockResources;
-import org.mozilla.gecko.util.RawResource;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Tests whether RawResource.getAsString() produces the right String
- * result after reading the returned raw resource's InputStream.
- */
-public class TestRawResource extends InstrumentationTestCase {
- private static final int RAW_RESOURCE_ID = 1;
- private static final String RAW_CONTENTS = "RAW";
-
- private static class TestContext extends MockContext {
- private final Resources resources;
-
- public TestContext() {
- resources = new TestResources();
- }
-
- @Override
- public Resources getResources() {
- return resources;
- }
- }
-
- /**
- * Browser instrumentation tests can't have access to test-only
- * resources (bug 994135) yet so we mock the access to resources
- * for now.
- */
- private static class TestResources extends MockResources {
- @Override
- public InputStream openRawResource(int id) {
- if (id == RAW_RESOURCE_ID) {
- return new ByteArrayInputStream(RAW_CONTENTS.getBytes());
- }
-
- return null;
- }
- }
-
- public void testGet() {
- Context context = new TestContext();
- String result;
-
- try {
- result = RawResource.getAsString(context, RAW_RESOURCE_ID);
- } catch (IOException e) {
- result = null;
- }
-
- assertEquals(RAW_CONTENTS, result);
- }
-}
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java
deleted file mode 100644
index c29c369d6..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java
+++ /dev/null
@@ -1,473 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.tests.browser.junit3;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
-import android.test.RenamingDelegatingContext;
-import android.test.mock.MockResources;
-import org.json.JSONArray;
-import org.json.JSONObject;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.GeckoSharedPrefs;
-import org.mozilla.gecko.Locales;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.SuggestedSites;
-import org.mozilla.gecko.distribution.Distribution;
-import org.mozilla.gecko.preferences.GeckoPreferences;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class TestSuggestedSites extends InstrumentationTestCase {
- private static class TestContext extends RenamingDelegatingContext {
- private static final String PREFIX = "TestSuggestedSites-";
-
- private final Resources resources;
- private final Set<String> usedPrefs;
-
- public TestContext(Context context) {
- super(context, PREFIX);
- resources = new TestResources();
- usedPrefs = Collections.synchronizedSet(new HashSet<String>());
- }
-
- @Override
- public Resources getResources() {
- return resources;
- }
-
- @Override
- public SharedPreferences getSharedPreferences(String name, int mode) {
- usedPrefs.add(name);
- return super.getSharedPreferences(PREFIX + name, mode);
- }
-
- public void clearUsedPrefs() {
- for (String prefsName : usedPrefs) {
- getSharedPreferences(prefsName, 0).edit().clear().commit();
- }
-
- usedPrefs.clear();
- }
- }
-
- private static class TestResources extends MockResources {
- private String suggestedSites;
-
- @Override
- public InputStream openRawResource(int id) {
- if (id == R.raw.suggestedsites && suggestedSites != null) {
- return new ByteArrayInputStream(suggestedSites.getBytes());
- }
-
- return null;
- }
-
- public void setSuggestedSitesResource(String suggestedSites) {
- this.suggestedSites = suggestedSites;
- }
- }
-
- private static class TestDistribution extends Distribution {
- private final Map<Locale, File> filesPerLocale;
-
- public TestDistribution(Context context) {
- super(context);
- this.filesPerLocale = new HashMap<Locale, File>();
- }
-
- @Override
- public File getDistributionFile(String name) {
- for (Locale locale : filesPerLocale.keySet()) {
- if (name.startsWith("suggestedsites/locales/" + Locales.getLanguageTag(locale))) {
- return filesPerLocale.get(locale);
- }
- }
-
- return null;
- }
-
- @Override
- public boolean exists() {
- return true;
- }
-
- public void setFileForLocale(Locale locale, File file) {
- filesPerLocale.put(locale, file);
- }
-
- public void start() {
- doInit();
- }
- }
-
- class TestObserver extends ContentObserver {
- private final CountDownLatch changeLatch;
-
- public TestObserver(CountDownLatch changeLatch) {
- super(null);
- this.changeLatch = changeLatch;
- }
-
- @Override
- public void onChange(boolean selfChange) {
- changeLatch.countDown();
- }
- }
-
- private static final int DEFAULT_LIMIT = 6;
-
- private static final String DIST_PREFIX = "dist";
-
- private TestContext context;
- private TestResources resources;
- private List<File> tempFiles;
-
- private String generateSites(int n) {
- return generateSites(n, "");
- }
-
- private String generateSites(int n, String prefix) {
- JSONArray sites = new JSONArray();
-
- try {
- for (int i = 0; i < n; i++) {
- JSONObject site = new JSONObject();
- site.put("url", prefix + "url" + i);
- site.put("title", prefix + "title" + i);
- site.put("imageurl", prefix + "imageUrl" + i);
- site.put("bgcolor", prefix + "bgColor" + i);
-
- sites.put(site);
- }
- } catch (Exception e) {
- return "";
- }
-
- return sites.toString();
- }
-
- private File createDistSuggestedSitesFile(int n) {
- FileOutputStream fos = null;
-
- try {
- File distFile = File.createTempFile("distrosites", ".json",
- context.getCacheDir());
-
- fos = new FileOutputStream(distFile);
- fos.write(generateSites(n, DIST_PREFIX).getBytes());
-
- return distFile;
- } catch (IOException e) {
- fail("Failed to create temp suggested sites file");
- } finally {
- if (fos != null) {
- try {
- fos.close();
- } catch (IOException e) {
- // Ignore.
- }
- }
- }
-
- return null;
- }
-
- private void checkCursorCount(String content, int expectedCount) {
- checkCursorCount(content, expectedCount, DEFAULT_LIMIT);
- }
-
- private void checkCursorCount(String content, int expectedCount, int limit) {
- resources.setSuggestedSitesResource(content);
- Cursor c = new SuggestedSites(context).get(limit);
- assertEquals(expectedCount, c.getCount());
- c.close();
- }
-
- protected void setUp() {
- context = new TestContext(getInstrumentation().getTargetContext());
- resources = (TestResources) context.getResources();
- tempFiles = new ArrayList<File>();
- }
-
- protected void tearDown() {
- context.clearUsedPrefs();
- for (File f : tempFiles) {
- f.delete();
- }
- }
-
- public void testCount() {
- // Empty array = empty cursor
- checkCursorCount(generateSites(0), 0);
-
- // 2 items = cursor with 2 rows
- checkCursorCount(generateSites(2), 2);
-
- // 10 items with lower limit = cursor respects limit
- checkCursorCount(generateSites(10), 3, 3);
- }
-
- public void testEmptyCursor() {
- // Null resource = empty cursor
- checkCursorCount(null, 0);
-
- // Empty string = empty cursor
- checkCursorCount("", 0);
-
- // Invalid json string = empty cursor
- checkCursorCount("{ broken: }", 0);
- }
-
- public void testCursorContent() {
- resources.setSuggestedSitesResource(generateSites(3));
-
- Cursor c = new SuggestedSites(context).get(DEFAULT_LIMIT);
- assertEquals(3, c.getCount());
-
- c.moveToPosition(-1);
- while (c.moveToNext()) {
- int position = c.getPosition();
-
- String url = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL));
- assertEquals("url" + position, url);
-
- String title = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.TITLE));
- assertEquals("title" + position, title);
- }
-
- c.close();
- }
-
- public void testExcludeUrls() {
- resources.setSuggestedSitesResource(generateSites(6));
-
- List<String> excludedUrls = new ArrayList<String>(3);
- excludedUrls.add("url1");
- excludedUrls.add("url3");
- excludedUrls.add("url5");
-
- List<String> includedUrls = new ArrayList<String>(3);
- includedUrls.add("url0");
- includedUrls.add("url2");
- includedUrls.add("url4");
-
- Cursor c = new SuggestedSites(context).get(DEFAULT_LIMIT, excludedUrls);
-
- c.moveToPosition(-1);
- while (c.moveToNext()) {
- String url = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL));
- assertFalse(excludedUrls.contains(url));
- assertTrue(includedUrls.contains(url));
- }
-
- c.close();
- }
-
- public void testHiddenSites() {
- resources.setSuggestedSitesResource(generateSites(6));
-
- List<String> visibleUrls = new ArrayList<String>(3);
- visibleUrls.add("url3");
- visibleUrls.add("url4");
- visibleUrls.add("url5");
-
- List<String> hiddenUrls = new ArrayList<String>(3);
- hiddenUrls.add("url0");
- hiddenUrls.add("url1");
- hiddenUrls.add("url2");
-
- // Add mocked hidden sites to SharedPreferences.
- StringBuilder hiddenUrlBuilder = new StringBuilder();
- for (String s : hiddenUrls) {
- hiddenUrlBuilder.append(" ");
- hiddenUrlBuilder.append(Uri.encode(s));
- }
-
- final String hiddenPref = hiddenUrlBuilder.toString();
- GeckoSharedPrefs.forProfile(context).edit()
- .putString(SuggestedSites.PREF_SUGGESTED_SITES_HIDDEN, hiddenPref)
- .commit();
-
- Cursor c = new SuggestedSites(context).get(DEFAULT_LIMIT);
- assertEquals(Math.min(3, DEFAULT_LIMIT), c.getCount());
-
- c.moveToPosition(-1);
- while (c.moveToNext()) {
- String url = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL));
- assertFalse(hiddenUrls.contains(url));
- assertTrue(visibleUrls.contains(url));
- }
-
- c.close();
- }
-
- public void testImageUrlAndBgColor() {
- final int count = 3;
- resources.setSuggestedSitesResource(generateSites(count));
-
- SuggestedSites suggestedSites = new SuggestedSites(context);
-
- // Suggested sites hasn't been loaded yet.
- for (int i = 0; i < count; i++) {
- String url = "url" + i;
- assertFalse(suggestedSites.contains(url));
- assertNull(suggestedSites.getImageUrlForUrl(url));
- assertNull(suggestedSites.getBackgroundColorForUrl(url));
- }
-
- Cursor c = suggestedSites.get(DEFAULT_LIMIT);
- c.moveToPosition(-1);
-
- // We should have cached results after the get() call.
- while (c.moveToNext()) {
- String url = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL));
- assertTrue(suggestedSites.contains(url));
- assertEquals("imageUrl" + c.getPosition(),
- suggestedSites.getImageUrlForUrl(url));
- assertEquals("bgColor" + c.getPosition(),
- suggestedSites.getBackgroundColorForUrl(url));
- }
- c.close();
-
- // No valid values for unknown URLs.
- assertFalse(suggestedSites.contains("foo"));
- assertNull(suggestedSites.getImageUrlForUrl("foo"));
- assertNull(suggestedSites.getBackgroundColorForUrl("foo"));
- }
-
- public void testLocaleChanges() {
- resources.setSuggestedSitesResource(generateSites(3));
-
- SuggestedSites suggestedSites = new SuggestedSites(context);
-
- // Initial load with predefined locale
- Cursor c = suggestedSites.get(DEFAULT_LIMIT, Locale.UK);
- assertEquals(3, c.getCount());
- c.close();
-
- resources.setSuggestedSitesResource(generateSites(5));
-
- // Second load with same locale should return same results
- // even though the contents of the resource have changed.
- c = suggestedSites.get(DEFAULT_LIMIT, Locale.UK);
- assertEquals(3, c.getCount());
- c.close();
-
- // Changing the locale forces the cached list to be refreshed.
- c = suggestedSites.get(DEFAULT_LIMIT, Locale.US);
- assertEquals(5, c.getCount());
- c.close();
- }
-
- public void testDistribution() {
- final int DIST_COUNT = 2;
- final int DEFAULT_COUNT = 3;
-
- File sitesFile = new File(context.getCacheDir(),
- "suggestedsites-" + SystemClock.uptimeMillis() + ".json");
- tempFiles.add(sitesFile);
- assertFalse(sitesFile.exists());
-
- File distFile = createDistSuggestedSitesFile(DIST_COUNT);
- tempFiles.add(distFile);
- assertTrue(distFile.exists());
-
- final CountDownLatch changeLatch = new CountDownLatch(1);
-
- // Watch for change notifications on suggested sites.
- ContentResolver cr = context.getContentResolver();
- ContentObserver observer = new TestObserver(changeLatch);
- cr.registerContentObserver(BrowserContract.SuggestedSites.CONTENT_URI,
- false, observer);
-
- // Init distribution with the mock file.
- TestDistribution distribution = new TestDistribution(context);
- distribution.setFileForLocale(Locale.getDefault(), distFile);
- distribution.start();
-
- // Init suggested sites with default values.
- resources.setSuggestedSitesResource(generateSites(DEFAULT_COUNT));
- SuggestedSites suggestedSites =
- new SuggestedSites(context, distribution, sitesFile);
-
- // The initial query will not contain the distribution sites
- // yet. This will happen asynchronously once the distribution
- // is installed.
- Cursor c1 = null;
- try {
- c1 = suggestedSites.get(DEFAULT_LIMIT);
- assertEquals(DEFAULT_COUNT, c1.getCount());
- } finally {
- if (c1 != null) {
- c1.close();
- }
- }
-
- try {
- assertTrue(changeLatch.await(5, TimeUnit.SECONDS));
- } catch (InterruptedException ie) {
- fail("No change notification after fetching distribution file");
- }
-
- // Target file should exist after distribution is deployed.
- assertTrue(sitesFile.exists());
- cr.unregisterContentObserver(observer);
-
- Cursor c2 = null;
- try {
- c2 = suggestedSites.get(DEFAULT_LIMIT);
-
- // The next query should contain the distribution contents.
- assertEquals(DIST_COUNT + DEFAULT_COUNT, c2.getCount());
-
- // The first items should be from the distribution
- for (int i = 0; i < DIST_COUNT; i++) {
- c2.moveToPosition(i);
-
- String url = c2.getString(c2.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL));
- assertEquals(DIST_PREFIX + "url" + i, url);
-
- String title = c2.getString(c2.getColumnIndexOrThrow(BrowserContract.SuggestedSites.TITLE));
- assertEquals(DIST_PREFIX + "title" + i, title);
- }
-
- // The remaining items should be the default ones
- for (int i = 0; i < c2.getCount() - DIST_COUNT; i++) {
- c2.moveToPosition(i + DIST_COUNT);
-
- String url = c2.getString(c2.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL));
- assertEquals("url" + i, url);
-
- String title = c2.getString(c2.getColumnIndexOrThrow(BrowserContract.SuggestedSites.TITLE));
- assertEquals("title" + i, title);
- }
- } finally {
- if (c2 != null) {
- c2.close();
- }
- }
- }
-}
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserInstrumentationTestRunner.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserInstrumentationTestRunner.java
deleted file mode 100644
index 36c60d92e..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserInstrumentationTestRunner.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.tests.browser.junit3.harness;
-
-import android.os.Bundle;
-import android.test.AndroidTestRunner;
-import android.test.InstrumentationTestRunner;
-import android.util.Log;
-
-/**
- * A test runner that installs a special test listener.
- * <p>
- * In future, this listener will turn JUnit 3 test events into log messages in
- * the format that Mochitest parsers understand.
- */
-public class BrowserInstrumentationTestRunner extends InstrumentationTestRunner {
- private static final String LOG_TAG = "BInstTestRunner";
-
- @Override
- public void onCreate(Bundle arguments) {
- Log.d(LOG_TAG, "onCreate");
- super.onCreate(arguments);
- }
-
- @Override
- protected AndroidTestRunner getAndroidTestRunner() {
- Log.d(LOG_TAG, "getAndroidTestRunner");
- AndroidTestRunner testRunner = super.getAndroidTestRunner();
- testRunner.addTestListener(new BrowserTestListener());
- return testRunner;
- }
-}
diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserTestListener.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserTestListener.java
deleted file mode 100644
index 026d5065f..000000000
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserTestListener.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.tests.browser.junit3.harness;
-
-import android.util.Log;
-import junit.framework.AssertionFailedError;
-import junit.framework.Test;
-import junit.framework.TestListener;
-
-/**
- * BrowserTestListener turns JUnit 3 test events into log messages in the format
- * that Mochitest parsers understand.
- * <p>
- * The idea is that, on infrastructure, we'll be able to use the same test
- * parsing code for Browser JUnit 3 tests as we do for Robocop tests.
- * <p>
- * In future, that is!
- */
-public class BrowserTestListener implements TestListener {
- public static final String LOG_TAG = "BTestListener";
-
- @Override
- public void startTest(Test test) {
- Log.d(LOG_TAG, "startTest: " + test);
- }
-
- @Override
- public void endTest(Test test) {
- Log.d(LOG_TAG, "endTest: " + test);
- }
-
- @Override
- public void addFailure(Test test, AssertionFailedError t) {
- Log.d(LOG_TAG, "addFailure: " + test);
- }
-
- @Override
- public void addError(Test test, Throwable t) {
- Log.d(LOG_TAG, "addError: " + test);
- }
-}
diff --git a/mobile/android/tests/browser/moz.build b/mobile/android/tests/browser/moz.build
deleted file mode 100644
index ca1214e44..000000000
--- a/mobile/android/tests/browser/moz.build
+++ /dev/null
@@ -1,17 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini']
-
-if not CONFIG['MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE']:
- TEST_DIRS += [
- 'junit3',
- ]
-
-TEST_DIRS += [
- 'robocop/roboextender',
- 'robocop',
-]
diff --git a/mobile/android/tests/browser/robocop/AndroidManifest.xml.in b/mobile/android/tests/browser/robocop/AndroidManifest.xml.in
deleted file mode 100644
index 028799f72..000000000
--- a/mobile/android/tests/browser/robocop/AndroidManifest.xml.in
+++ /dev/null
@@ -1,67 +0,0 @@
-#filter substitution
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.mozilla.roboexample.test"
-#ifdef MOZ_ANDROID_SHARED_ID
- android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
-#endif
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-sdk android:minSdkVersion="@MOZ_ANDROID_MIN_SDK_VERSION@"
-#ifdef MOZ_ANDROID_MAX_SDK_VERSION
- android:maxSdkVersion="@MOZ_ANDROID_MAX_SDK_VERSION@"
-#endif
- android:targetSdkVersion="23"/>
-
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-
- <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
-
- <instrumentation
- android:name="org.mozilla.gecko.FennecInstrumentationTestRunner"
- android:targetPackage="@ANDROID_PACKAGE_NAME@" />
-
- <application
- android:label="@string/app_name"
- android:debuggable="true">
-
- <uses-library android:name="android.test.runner" />
-
- <!-- Fake handlers to ensure that we have some share intents to show in our share handler list -->
- <activity android:name="org.mozilla.gecko.RobocopShare1"
- android:label="Robocop fake activity">
-
- <intent-filter android:label="Fake robocop share handler 1">
- <action android:name="android.intent.action.SEND" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="text/*" />
- <data android:mimeType="image/*" />
- </intent-filter>
-
- </activity>
-
- <activity android:name="org.mozilla.gecko.RobocopShare2"
- android:label="Robocop fake activity 2">
-
- <intent-filter android:label="Fake robocop share handler 2">
- <action android:name="android.intent.action.SEND" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="text/*" />
- <data android:mimeType="image/*" />
- </intent-filter>
-
- </activity>
-
- <activity android:name="org.mozilla.gecko.LaunchFennecWithConfigurationActivity"
- android:label="Robocop Fennec">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
- </application>
-
-</manifest>
diff --git a/mobile/android/tests/browser/robocop/Firefox.jpg b/mobile/android/tests/browser/robocop/Firefox.jpg
deleted file mode 100644
index 6a00b485c..000000000
--- a/mobile/android/tests/browser/robocop/Firefox.jpg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/Makefile.in b/mobile/android/tests/browser/robocop/Makefile.in
deleted file mode 100644
index f553080e7..000000000
--- a/mobile/android/tests/browser/robocop/Makefile.in
+++ /dev/null
@@ -1,67 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-TESTPATH := $(srcdir)/src/org/mozilla/gecko/tests
-
-ANDROID_EXTRA_JARS += \
- $(srcdir)/libs/robotium-solo-5.5.4.jar \
- $(NULL)
-
-_JAVA_HARNESS := \
- Actions.java \
- Assert.java \
- Driver.java \
- Element.java \
- FennecInstrumentationTestRunner.java \
- FennecNativeActions.java \
- FennecMochitestAssert.java \
- FennecTalosAssert.java \
- FennecNativeDriver.java \
- FennecNativeElement.java \
- LaunchFennecWithConfigurationActivity.java \
- RoboCopException.java \
- RobocopShare1.java \
- RobocopShare2.java \
- RobocopUtils.java \
- PaintedSurface.java \
- StructuredLogger.java \
- $(NULL)
-
-java-harness := $(addprefix $(srcdir)/src/org/mozilla/gecko/,$(_JAVA_HARNESS))
-java-tests := \
- $(wildcard $(TESTPATH)/*.java) \
- $(wildcard $(TESTPATH)/components/*.java) \
- $(wildcard $(TESTPATH)/helpers/*.java)
-
-ANDROID_MANIFEST_FILE := $(CURDIR)/AndroidManifest.xml
-
-JAVAFILES += \
- $(java-harness) \
- $(java-tests) \
- $(NULL)
-
-include $(topsrcdir)/config/rules.mk
-
-ifndef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
-tools:: $(ANDROID_APK_NAME).apk
-endif
-
-# The test APK needs to know the contents of the target APK while not
-# being linked against them. This is a best effort to avoid getting
-# out of sync with base's build config.
-jars_dir := $(DEPTH)/mobile/android/base
-stumbler_jars_dir := $(DEPTH)/mobile/android/stumbler
-ANDROID_CLASSPATH_JARS += \
- $(wildcard $(jars_dir)/*.jar) \
- $(wildcard $(stumbler_jars_dir)/*.jar) \
- $(NULL)
-# We don't have transitive dependencies: these are the browser jar
-# dependencies inserted manually.
-ANDROID_CLASSPATH_JARS += \
- $(ANDROID_SUPPORT_V4_AAR_LIB) \
- $(ANDROID_SUPPORT_V4_AAR_INTERNAL_LIB) \
- $(ANDROID_DESIGN_AAR_LIB) \
- $(ANDROID_RECYCLERVIEW_V7_AAR_LIB) \
- $(ANDROID_APPCOMPAT_V7_AAR_LIB) \
- $(NULL)
diff --git a/mobile/android/tests/browser/robocop/README b/mobile/android/tests/browser/robocop/README
deleted file mode 100644
index 35e15865e..000000000
--- a/mobile/android/tests/browser/robocop/README
+++ /dev/null
@@ -1,12 +0,0 @@
-Robocop is a Mozilla project which uses Robotium to test Firefox on Android devices.
-
-Robotium is an open source tool licensed under the Apache 2.0 license and the original
-source can be found here:
-https://github.com/RobotiumTech/robotium
-
-We are including robotium-solo-5.5.4.jar as a binary and are not modifying it in any way
-from the original download found at:
-https://github.com/RobotiumTech/robotium/wiki/Downloads
-
-Firefox for Android developers should read the documentation in
-mobile/android/tests/browser/robocop/README.rst.
diff --git a/mobile/android/tests/browser/robocop/README.rst b/mobile/android/tests/browser/robocop/README.rst
deleted file mode 100644
index 7ace7cdeb..000000000
--- a/mobile/android/tests/browser/robocop/README.rst
+++ /dev/null
@@ -1,61 +0,0 @@
-Robocop Mochitest
-=================
-
-*Robocop Mochitest* is a Mozilla project which uses Robotium to test
- Firefox on Android devices.
-
-*Robocop Mochitest* tests run on Native Android builds marked with an
-'rc' on treeherder. These are Java based tests which run from the mochitest
-harness and generate similar log files. These are designed for
-testing the native UI of Android devices by sending events to the
-front end.
-
-See the documentation at
-https://wiki.mozilla.org/Auto-tools/Projects/Robocop/WritingTests for
-details.
-
-Development cycle
------------------
-
-To deploy the robocop APK to your device and start the robocop test
-suite, use::
-
- mach robocop
-
-To run a specific test case, such as ``testLoad``::
-
- mach robocop testLoad
-
-The Java files in ``mobile/android/tests/browser/robocop`` are dependencies of the
-robocop APK built by ``build/mobile/robocop``. If you modify Java files
-in ``mobile/android/tests/browser/robocop``, you need to rebuild the robocop APK
-with::
-
- mach build build/mobile/robocop
-
-Changes to ``.html``, ``.css``, ``.sjs``, and ``.js`` files in
-``mobile/android/tests/browser/robocop`` do not require rebuilding the robocop
-APK -- these changes are always 'live', since they are served by the
-mochitest HTTP server and downloaded each test run by your device.
-
-``mach package`` does build and sign a robocop APK, but ``mach
-robocop`` does not use it. (This signed APK is used to test
-signed releases on the buildbots).
-
-As always, changes to ``mobile/android/base``, ``mobile/android/chrome``,
-``mobile/android/modules``, etc., require::
-
- mach build mobile/android/base && mach package && mach install
-
-as usual.
-
-Licensing
----------
-
-Robotium is an open source tool licensed under the Apache 2.0 license and the original
-source can be found here:
-https://github.com/RobotiumTech/robotium
-
-We are including robotium-solo-5.5.4.jar as a binary and are not modifying it in any way
-from the original download found at:
-https://github.com/RobotiumTech/robotium/wiki/Downloads
diff --git a/mobile/android/tests/browser/robocop/assets/README b/mobile/android/tests/browser/robocop/assets/README
deleted file mode 100644
index 565ca2a9f..000000000
--- a/mobile/android/tests/browser/robocop/assets/README
+++ /dev/null
@@ -1,4 +0,0 @@
-You can place test assets in this file.
-They can be read as raw InputStreams with the getAsset() method in BaseTest.
-
-(This file is a placeholder to ensure that the assets/ directory exists, as it is referenced in the robocop Makefile.)
diff --git a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v27.db b/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v27.db
deleted file mode 100644
index 02103dde0..000000000
--- a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v27.db
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v28.db b/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v28.db
deleted file mode 100644
index d3f4c2826..000000000
--- a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v28.db
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v29.db b/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v29.db
deleted file mode 100644
index e07281b1a..000000000
--- a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v29.db
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v30.db b/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v30.db
deleted file mode 100644
index 77524cf99..000000000
--- a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v30.db
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v31.db b/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v31.db
deleted file mode 100644
index 597d78dfa..000000000
--- a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v31.db
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v32.db b/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v32.db
deleted file mode 100644
index 63263d6ff..000000000
--- a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v32.db
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v33.db b/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v33.db
deleted file mode 100644
index c5241dae0..000000000
--- a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v33.db
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v34.db b/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v34.db
deleted file mode 100644
index fa7e2b77b..000000000
--- a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v34.db
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v35.db b/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v35.db
deleted file mode 100644
index fa1d9b3f9..000000000
--- a/mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v35.db
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/golem_favicon.ico b/mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/golem_favicon.ico
deleted file mode 100644
index e5f6fd86f..000000000
--- a/mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/golem_favicon.ico
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/microsoft_favicon.ico b/mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/microsoft_favicon.ico
deleted file mode 100644
index bfe873eb2..000000000
--- a/mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/microsoft_favicon.ico
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/nvidia_favicon.ico b/mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/nvidia_favicon.ico
deleted file mode 100644
index 424df8720..000000000
--- a/mobile/android/tests/browser/robocop/assets/ico_decoder_favicons/nvidia_favicon.ico
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/mock-package.zip b/mobile/android/tests/browser/robocop/assets/mock-package.zip
deleted file mode 100644
index c599046cb..000000000
--- a/mobile/android/tests/browser/robocop/assets/mock-package.zip
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/browser.db b/mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/browser.db
deleted file mode 100644
index 684c7c644..000000000
--- a/mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/browser.db
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/readercache/DWUP3U4ERC6TKJVSYXKJLHHEFY.json b/mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/readercache/DWUP3U4ERC6TKJVSYXKJLHHEFY.json
deleted file mode 100644
index 83521462f..000000000
--- a/mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/readercache/DWUP3U4ERC6TKJVSYXKJLHHEFY.json
+++ /dev/null
@@ -1 +0,0 @@
-{"title":"US election 2016: Gloves come off for Clinton and Sanders - BBC News","byline":"Anthony Zurcher\n North America reporter","content":"<div id=\"readability-page-1\" class=\"page\"><div property=\"articleBody\" class=\"story-body__inner\"><figure class=\"media-landscape has-caption full-width lead\">\n <span class=\"image-and-copyright-container\">\n \n <img width=\"976\" height=\"549\" src=\"http://ichef.bbci.co.uk/news/320/cpsprodpb/E387/production/_89074285_89074283.jpg\" alt=\"This combination of file photos shows Democratic presidential hopefuls Bernie Sanders(L)on March 31, 2016 and Hillary Clinton on March 30, 2016,\" class=\"js-image-replace\"/>\n \n \n \n <span class=\"off-screen\">Image copyright</span>\n <span class=\"story-image-copyright\">Getty Images</span>\n \n </span>\n \n <figcaption class=\"media-caption\">\n <span class=\"off-screen\">Image caption</span>\n <span class=\"media-caption__text\">\n The Democratic candidates are engaging in more frequent attacks\n </span>\n </figcaption>\n \n </figure><p class=\"story-body__introduction\">It's crunch time in the Democratic race, and if the past week is any indication, nerves are starting to fray.</p><p>The fratricide within the Republican Party is getting much of the national attention, but the two remaining Democratic candidates - and their supporters - are starting to swing some sharp elbows.</p><p>The Wisconsin primary on Tuesday marks the beginning of the Democratic presidential campaign's endgame. More than half the pledged delegates have already been apportioned, and only a few truly landscape-altering battlegrounds - New York, Pennsylvania, New Jersey and California - remain on the calendar.</p><p>Mr Sanders can claim momentum, with wins in five of the last six contests, but he needs a sizeable victory in Wisconsin if he wants to properly set the stage for the critical coming contests and cut into Mrs Clinton's 263 delegate lead. </p><p>It's enough to set both candidates on edge.</p><p>On Thursday, when confronted by a Greenpeace activist in New York about whether she could address climate change while taking donations from the fossil fuel industry, Mrs Clinton <a class=\"story-body__link-external\" href=\"http://www.politico.com/blogs/2016-dem-primary-live-updates-and-results/2016/03/hillary-clinton-bernie-sanders-campaign-lies-221434\">showed a rare flash of anger</a>.</p><p>\"I am so sick of the Sanders campaign lying about me,\" she said. Her campaign would later assert that the former secretary of state, like Mr Sanders, takes donations from individuals employed in the energy sector but is prohibited from accepting money from corporations.</p><figure class=\"media-landscape has-caption full-width\">\n <span class=\"image-and-copyright-container\">\n \n \n \n \n \n <span class=\"off-screen\">Image copyright</span>\n <span class=\"story-image-copyright\">Reuters</span>\n \n </span>\n \n <figcaption class=\"media-caption\">\n <span class=\"off-screen\">Image caption</span>\n <span class=\"media-caption__text\">\n Mrs Clinton recently lost her cool with a Greenpeace activist\n </span>\n </figcaption>\n \n </figure><p>It was a moment of emotion for a usually carefully controlled candidate - and the Sanders camp quickly responded.</p><p>\"If the Clinton campaign wants to argue that industry lobbyists giving thousands of dollars to her campaign won't affect her decisions if she's elected, that's fine,\" Sanders adviser Jeff Weaver said. \"But to call us liars for pointing out basic facts about the secretary's fundraising is deeply cynical and very disappointing.\"</p><p>It was just one of numerous recent shots between the two campaigns. When Mrs Clinton unveiled manufacturing proposals on Friday, a Sanders spokesperson said the former secretary of state has embraced \"policies that have decimated the manufacturing industry ... and eliminated millions of jobs across the country\".</p><hr class=\"story-body__line\"/><figure class=\"media-with-caption\">\n \n <figcaption class=\"media-with-caption__caption\"><span class=\"off-screen\">Media caption</span>Bernie Sanders supporter: \"We need bold ideas\"</figcaption>\n</figure><p><a class=\"story-body__link\" href=\"http://www.bbc.com/news/world-us-canada-35912640\">Trump's disastrous women voter problem </a>- This voting bloc could doom in chances in the general election</p><p><a class=\"story-body__link\" href=\"http://www.bbc.co.uk/news/blogs-trending-35930999\">#BernieMadeMeWhite: Minority supporters of Sanders speak out</a> - Supporters push back against \"all-white\" narrative</p><p><a class=\"story-body__link\" href=\"http://www.bbc.com/news/election-us-2016-35933156\">Trump, Clinton and the 'None of the Above' era</a> - Rarely have those running for high office been held in such low esteem </p><p><a class=\"story-body__link\" href=\"http://www.bbc.co.uk/news/election/us2016\">Full US election coverage from the BBC</a></p><hr class=\"story-body__line\"/><p>At a campaign event, Mr Sanders offered criticisms of Mrs Clinton's six-figure speeches to Wall Street firms, her foreign policy views and her position on environmental issues, as his supporters heartily booed. </p><p>On Saturday Mrs Clinton noted that she has been a \"proud Democrat my adult life\" - drawing a contrast with Mr Sanders, who is a self identified \"democratic socialist\" who serves in Congress as an independent. </p><p>\"I think that is kind of important if we are selecting someone to be the Democratic nominee of the Democratic Party,\" <a class=\"story-body__link-external\" href=\"http://www.cnn.com/2016/04/02/politics/hillary-clinton-bernie-sanders-democrat-wisconsin/\">Mrs Clinton said</a>.</p><p>\"I think the secretary is getting very nervous,\" Mr Sanders countered on Sunday, noting that polls show him doing better than Mrs Clinton against Republican front-runner Donald Trump. </p><p>\"I think we've got a lot of young people's vote, working-class people's vote,\" Mr Sanders said. \"I think we're on the way to a victory if we can win the Democratic nomination.\"</p><figure class=\"media-landscape has-caption full-width\">\n <span class=\"image-and-copyright-container\">\n \n \n \n \n \n <span class=\"off-screen\">Image copyright</span>\n <span class=\"story-image-copyright\">Reuters</span>\n \n </span>\n \n <figcaption class=\"media-caption\">\n <span class=\"off-screen\">Image caption</span>\n <span class=\"media-caption__text\">\n Mr Sanders has declined to use Mrs Clinton's email flap as a campaign issue\n </span>\n </figcaption>\n \n </figure><p>This tension in the Democrat race is a relatively recent development. Last autumn, Mr Sanders famously said during the first debate that he was \"sick and tired\" of talking about Mrs Clinton's email server imbroglio - passing on a chance to target what could have been a key weakness in his main opponent.</p><p>When Mr Sanders entered the race, he said he wasn't interested in running a negative political campaign. It was a strategic decision that has lead to some recent second-guessing among advisers within the candidate's campaign, as witnessed <a class=\"story-body__link-external\" href=\"http://mobile.nytimes.com/2016/04/04/us/politics/bernie-sanders-hillary-clinton.html\">by a surprisingly pessimistic story in the New York Times</a> on Monday.</p><p>\"The central complication with Bernie is that he never wanted to cross into the zone of personal attacks because it would undercut his brand,\" Sanders adviser Tad Devine told the Times. </p><p>That hasn't stopped acrimony from flaring among the two candidates' supporters, however - even in typically restrained states like Wisconsin.</p><figure class=\"media-landscape has-caption full-width\">\n <span class=\"image-and-copyright-container\">\n \n \n \n \n \n <span class=\"off-screen\">Image copyright</span>\n <span class=\"story-image-copyright\">Reuters</span>\n \n </span>\n \n <figcaption class=\"media-caption\">\n <span class=\"off-screen\">Image caption</span>\n <span class=\"media-caption__text\">\n Sanders supporters have been criticised for being overzealous, particularly online\n </span>\n </figcaption>\n \n </figure><p>Lisa Stubek, a state representative who endorsed Mrs Clinton early in the campaign, says she's caught fire from pro-Sanders constituents in the ultra-liberal state capital of Madison.</p><p>\"Bernie Sanders supporters are pretty relentless, unfortunately, as far as their support and as far as attacking those who support anyone but their candidate,\" she said. \"And that's not true of everyone, but certainly there is a core group of Bernie Sanders supporters here in Madison who do that.\"</p><p>While Ms Stubek says that the campaign has largely been above-the-board, things have taken a turn for the worse.</p><p>\"I think certainly when you have Bernie Sanders out there stretching the truth or out-and-out lying, things do heat up,\" she said. \"I'm glad that Hillary is out there defending her record. More than anything people in our state want the facts.\"</p><p>Another Madison-area Democratic representative, Melissa Sargent, says she decided not to endorse a presidential candidate in part because the noise between the two candidates would drown out her efforts to address other issues and local campaigns.</p><p>\"When I go to doors and I'm stumping for my local candidates, I can talk about the things that I want to talk about and I can hear authentically what folks are saying,\" she said. \"It felt like I wouldn't be able to navigate the path that I am with these other races.\"</p><figure class=\"media-landscape has-caption full-width\">\n <span class=\"image-and-copyright-container\">\n \n \n \n \n \n <span class=\"off-screen\">Image copyright</span>\n <span class=\"story-image-copyright\">Reuters</span>\n \n </span>\n \n <figcaption class=\"media-caption\">\n <span class=\"off-screen\">Image caption</span>\n <span class=\"media-caption__text\">\n Mrs Clinton holds a large lead over Mr Sanders\n </span>\n </figcaption>\n \n </figure><p>Democrats in Wisconsin are quick to note that their challenges are nothing compared to what the Republicans are facing, as their two leading candidates engage in harsh negative attacks and exchange barbs over their wives and martial infidelity.</p><p>Brett Hulsey, a former Wisconsin Democratic state representative who is backing Mr Sanders, called the Republican campaign a \"food fight circus\".</p><p>\"Democrats are still fighting by the <a class=\"story-body__link-external\" href=\"http://www.britannica.com/sports/Marquess-of-Queensberry-rules\">Queensberry Rules</a>,\" he said, drawing a boxing analogy.</p><p>He cautions that while tempers seem to be flaring among Democrats at this point, things will eventually calm down. If Mrs Clinton wins, he plans to support her - and he predicts most Sanders backers will follow suit.</p><p>\"We're in the middle of the fray right now,\" he said. \"I remind everybody to take a few deep breaths and remain calm. I've worked every presidential since 1980 for Jimmy Carter. I've seen this movie before.\"</p><p>At a rally in Madison on Sunday night it seemed an era of good feelings may have returned. Mr Sanders spoke to a crowd of 4,200 for more than an hour and made no mention of his Democratic opponent. Instead, he focused his criticism on Mr Trump and Republican Governor (and former candidate) Scott Walker.</p><p>He also seemed to be broadening his perspective.</p><p>\"This campaign is about more than just electing a president of the United States, although I would very much appreciate your support,\" he said. \"It's about creating a political revolution.\"</p><figure class=\"media-landscape has-caption full-width\">\n <span class=\"image-and-copyright-container\">\n \n \n \n \n \n <span class=\"off-screen\">Image copyright</span>\n <span class=\"story-image-copyright\">Reuters</span>\n \n </span>\n \n <figcaption class=\"media-caption\">\n <span class=\"off-screen\">Image caption</span>\n <span class=\"media-caption__text\">\n Mr Sanders has criticised Mrs Clinton's ties to the fossil fuel industry\n </span>\n </figcaption>\n \n </figure><p>After the event, Jess A Weber - who had travelled to Madison from Illinois to volunteer for the Sanders campaign - said she appreciated that Mr Sanders has tried to run a positive campaign.</p><p>\"He continues to pull focus back to the message and back to our strength in unifying, coming together instead of dividing and bringing anyone down,\" she said.</p><p>On the campaign trail in Janesville on Monday, however, Mr Sanders was back to swiping at his opponent for her past positions on international trade and commerce.</p><p>\"I have voted against and led the opposition to every one of these disastrous trade agreements,\" Mr Sanders said. \"Secretary Clinton has supported virtually every one.\"</p><p>The Democratic race is far from a bare-knuckle fight, but the candidates aren't done trying to draw blood.</p></div></div>","length":10394,"excerpt":"It's crunch time in the Democratic race, and if the past week is any indication, nerves are starting to fray.","url":"http://www.bbc.com/news/election-us-2016-35962179"} \ No newline at end of file
diff --git a/mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/readercache/KWNV7PXD3JFOJBQJVFXI3CQKNE.json b/mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/readercache/KWNV7PXD3JFOJBQJVFXI3CQKNE.json
deleted file mode 100644
index 9b907de00..000000000
--- a/mobile/android/tests/browser/robocop/assets/reading_list_bookmarks_migration/readercache/KWNV7PXD3JFOJBQJVFXI3CQKNE.json
+++ /dev/null
@@ -1 +0,0 @@
-{"title":"Panama Papers: Iceland PM refuses to resign over investments - BBC News","byline":null,"content":"<div id=\"readability-page-1\" class=\"page\"><div property=\"articleBody\" class=\"story-body__inner\"><figure class=\"media-with-caption\">\n \n <figcaption class=\"media-with-caption__caption\"><span class=\"off-screen\">Media caption</span>The Icelandic PM walked out of an interview with the Swedish Public Broadcaster, SVT, after being questioned over offshore company Wintris</figcaption>\n</figure><p class=\"story-body__introduction\">Iceland's prime minister has refused to resign after being accused of hiding millions of dollars in investments behind a secretive offshore company.</p><p>Leaked documents show that Sigmundur Gunnlaugsson and his wife bought offshore company Wintris in 2007.</p><p>He did not declare an interest in the company when entering parliament in 2009. He sold his 50% of Wintris to his wife for $1 (70p), eight months later.</p><p>Opposition parties say they plan to hold a confidence vote in parliament.</p><p>Mr Gunnlaugsson says no rules were broken and his wife did not benefit financially. </p><p>The offshore company was used to invest millions of dollars of inherited money, according to a document signed by Mr Gunnlaugsson's wife, Anna Sigurlaug Palsdottir, in 2015.</p><hr class=\"story-body__line\"/><h2 class=\"story-body__crosshead\">Panama Papers - tax havens of the rich and powerful exposed</h2><ul class=\"story-body__unordered-list\">\n<li class=\"story-body__list-item\">Eleven million documents held by the Panama-based law firm Mossack Fonseca have been passed to German newspaper Sueddeutsche Zeitung, which then shared them with the <a class=\"story-body__link-external\" href=\"https://www.icij.org/\">International Consortium of Investigative Journalists</a>. BBC Panorama is among 107 media organisations - including UK newspaper <a class=\"story-body__link-external\" href=\"http://www.theguardian.com/news/series/panama-papers\">the Guardian</a> - in 76 countries which have been analysing the documents. The BBC doesn't know the identity of the source</li>\n<li class=\"story-body__list-item\">They show how the company has helped clients launder money, dodge sanctions and evade tax</li>\n<li class=\"story-body__list-item\">Mossack Fonseca says it has operated beyond reproach for 40 years and never been accused or charged with criminal wrong-doing</li>\n<li class=\"story-body__list-item\">Tricks of the trade: <a class=\"story-body__link\" href=\"http://www.bbc.co.uk/news/business-35943740\">How assets are hidden and taxes evaded</a>\n</li>\n<li class=\"story-body__list-item\">Panama Papers: <a class=\"story-body__link\" href=\"http://www.bbc.co.uk/news/world-35934836\">Full coverage</a>; follow reaction on Twitter using #PanamaPapers; in the BBC News app, follow the tag \"Panama Papers\"</li>\n<li class=\"story-body__list-item\">\n<a class=\"story-body__link\" href=\"http://www.bbc.co.uk/programmes/b006t14n/episodes/player\">Watch Panorama</a> on the BBC iPlayer (UK viewers only)</li>\n</ul><hr class=\"story-body__line\"/><p>The leaked documents, published on Sunday, show that Mr Gunnlaugsson was granted a general power of attorney over Wintris - which gave him the power to manage the company \"without any limitation\". Ms Palsdottir had a similar power of attorney.</p><p>Court records show that Wintris had significant investments in the bonds of three major Icelandic banks that collapsed during the financial crisis which began in 2008. Wintris is listed as a creditor with millions of dollars in claims in the banks' bankruptcies. </p><p>Mr Gunnlaugsson became prime minister in 2013 and has been involved in negotiations about the banks which could affect the value of the bonds held by Wintris.</p><p>He resisted pressure from foreign creditors - including many UK customers - to repay their deposits in full. Had foreign investors been repaid, it might have adversely affected both the Icelandic banks and the value of the bonds held by Wintris.</p><p>But Mr Gunnlaugsson kept his wife's interest in the outcome a secret.</p><h2 class=\"story-body__crosshead\">'Lost all trust'</h2><p>On Monday, Icelandic opposition parties called on Mr Gunnlaugsson to resign over the alleged conflict of interest and said they planned to table a confidence motion in parliament.</p><p>\"What would be the most natural and the right thing to do is that [he] resign as prime minister,\" Birgitta Jonsdottir, the head of the Pirate Party, told the Reuters news agency. \"There is a great and strong demand for that in society and he has totally lost all his trust and believability.\"</p><figure class=\"media-landscape no-caption full-width\">\n <span class=\"image-and-copyright-container\">\n \n \n \n \n \n <span class=\"off-screen\">Image copyright</span>\n <span class=\"story-image-copyright\">Iceland Monitor/Eva Björk</span>\n \n </span>\n \n </figure><p>Former Prime Minister Johanna Sigurdardottir, who oversaw Iceland's recovery from the financial crisis, meanwhile wrote on Facebook: \"The prime minister should immediately resign.\"</p><p>An online petition demanding Mr Gunnlaugsson's resignation also had some 24,000 signatures - more than 7% of the island nation's population.</p><p>But in an interview with Channel 2 television, the prime minister insisted he had put the interests of the Icelandic people ahead of the interests of the failed banks' claimants.</p><p>\"I have not considered quitting because of this matter nor am I going to quit because of this matter,\" he said.</p><p>\"The government has had good results. Progress has been strong and it is important that the government can finish their work.\"</p><p>A spokesman for the prime minister earlier said that Ms Palsdottir had always declared the assets to the tax authorities and that, under parliamentary rules, Mr Gunnlaugsson did not have to declare an interest in Wintris.</p><p>He said that joint share certificates in Wintris had been issued because the prime minister and his wife had a joint bank account. This was pointed out to them when the documents were reviewed in 2009. </p></div></div>","length":4680,"excerpt":"Iceland's prime minister refuses to resign after being accused of hiding millions of dollars in investments behind a secretive offshore company.","url":"http://www.bbc.com/news/world-europe-35962670"} \ No newline at end of file
diff --git a/mobile/android/tests/browser/robocop/assets/testcheck2-motionevents b/mobile/android/tests/browser/robocop/assets/testcheck2-motionevents
deleted file mode 100644
index a5961e466..000000000
--- a/mobile/android/tests/browser/robocop/assets/testcheck2-motionevents
+++ /dev/null
@@ -1,444 +0,0 @@
-04-24 15:00:54.643 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=398.44662, y[0]=528.4731, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25865746, downTime=25865746, deviceId=6, source=0x1002 }
-04-24 15:00:54.675 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=400.44385, y[0]=527.4739, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25865774, downTime=25865746, deviceId=6, source=0x1002 }
-04-24 15:00:54.683 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=400.44385, y[0]=527.4739, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25865782, downTime=25865746, deviceId=6, source=0x1002 }
-04-24 15:00:54.784 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=396.44937, y[0]=471.51758, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25865889, downTime=25865889, deviceId=6, source=0x1002 }
-04-24 15:00:54.831 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=396.44937, y[0]=471.51758, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25865936, downTime=25865889, deviceId=6, source=0x1002 }
-04-24 15:00:56.026 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=460.36063, y[0]=166.75565, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25867126, downTime=25867126, deviceId=6, source=0x1002 }
-04-24 15:00:56.073 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=460.36063, y[0]=166.75565, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25867173, downTime=25867126, deviceId=6, source=0x1002 }
-04-24 15:00:56.190 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=451.3731, y[0]=205.72522, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25867289, downTime=25867289, deviceId=6, source=0x1002 }
-04-24 15:00:56.245 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=451.3731, y[0]=205.72522, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25867346, downTime=25867289, deviceId=6, source=0x1002 }
-04-24 15:00:57.253 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=406.43552, y[0]=447.53632, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25868355, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.261 I/System.out( 5517): MotionEvent { action=ACTION_POINTER_DOWN(1), id[0]=0, x[0]=406.43552, y[0]=447.53632, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=325.54785, y[1]=612.4075, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25868364, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.284 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=407.43414, y[0]=446.5371, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=325.54785, y[1]=612.4075, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25868374, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.300 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=407.43414, y[0]=446.5371, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=323.55063, y[1]=614.40594, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25868393, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.323 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=409.43137, y[0]=439.54254, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=317.55896, y[1]=622.39966, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868413, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.339 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=412.4272, y[0]=430.54956, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=305.5756, y[1]=636.38873, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868432, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.362 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=415.42303, y[0]=419.55817, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=291.595, y[1]=652.3763, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868451, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.378 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=419.41748, y[0]=407.5675, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=276.6158, y[1]=667.36456, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868471, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.393 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=423.41193, y[0]=393.57843, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=265.63107, y[1]=682.35284, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868490, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.417 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=432.39944, y[0]=373.59406, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=252.64911, y[1]=697.3411, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868509, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.433 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=442.3856, y[0]=354.6089, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=241.66437, y[1]=712.3294, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868529, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.448 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=455.36755, y[0]=331.62686, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=234.67407, y[1]=722.3216, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868548, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.472 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=467.35092, y[0]=310.64325, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=227.68378, y[1]=732.31384, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868567, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.487 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=482.3301, y[0]=289.65964, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=220.69348, y[1]=741.30676, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868586, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.511 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=496.3107, y[0]=265.67838, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=213.7032, y[1]=750.29974, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868606, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.526 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=509.29266, y[0]=243.69556, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=206.7129, y[1]=758.2935, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868625, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.542 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=521.276, y[0]=221.71274, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=201.71983, y[1]=765.288, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868644, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.565 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=533.2594, y[0]=204.72598, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=197.72539, y[1]=772.2826, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868664, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.581 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=541.2483, y[0]=192.73535, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=193.73093, y[1]=778.2779, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868684, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.604 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=545.24274, y[0]=186.74005, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=191.7337, y[1]=781.2756, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25868693, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.620 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=551.23444, y[0]=177.74707, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=187.73926, y[1]=787.2709, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868713, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.643 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=555.2289, y[0]=171.75177, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=185.74203, y[1]=789.26935, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868732, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.659 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=557.2261, y[0]=167.75488, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=183.7448, y[1]=792.26697, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25868752, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.683 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=558.2247, y[0]=165.75644, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=181.74757, y[1]=795.26465, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25868761, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.698 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=560.2219, y[0]=163.758, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=179.75035, y[1]=797.26306, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25868781, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.714 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=560.2219, y[0]=163.758, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=178.75174, y[1]=799.26154, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25868800, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.737 I/System.out( 5517): MotionEvent { action=ACTION_POINTER_UP(0), id[0]=0, x[0]=560.2219, y[0]=163.758, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=178.75174, y[1]=799.26154, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25868828, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:57.745 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=1, x[0]=178.75174, y[0]=799.26154, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25868835, downTime=25868355, deviceId=6, source=0x1002 }
-04-24 15:00:58.362 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=454.36893, y[0]=663.3677, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25869459, downTime=25869459, deviceId=6, source=0x1002 }
-04-24 15:00:58.378 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=452.3717, y[0]=650.3778, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25869469, downTime=25869459, deviceId=6, source=0x1002 }
-04-24 15:00:58.393 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=447.37866, y[0]=588.4262, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25869488, downTime=25869459, deviceId=6, source=0x1002 }
-04-24 15:00:58.417 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=445.38144, y[0]=498.49646, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25869507, downTime=25869459, deviceId=6, source=0x1002 }
-04-24 15:00:58.433 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=449.3759, y[0]=381.58783, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25869526, downTime=25869459, deviceId=6, source=0x1002 }
-04-24 15:00:58.456 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=466.3523, y[0]=241.69711, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25869545, downTime=25869459, deviceId=6, source=0x1002 }
-04-24 15:00:58.472 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=497.3093, y[0]=82.82123, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25869564, downTime=25869459, deviceId=6, source=0x1002 }
-04-24 15:00:58.472 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=497.3093, y[0]=82.82123, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25869573, downTime=25869459, deviceId=6, source=0x1002 }
-04-24 15:00:59.800 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=453.37033, y[0]=646.3809, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25870898, downTime=25870898, deviceId=6, source=0x1002 }
-04-24 15:00:59.815 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=451.3731, y[0]=614.40594, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25870907, downTime=25870898, deviceId=6, source=0x1002 }
-04-24 15:00:59.831 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=454.36893, y[0]=506.49023, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25870926, downTime=25870898, deviceId=6, source=0x1002 }
-04-24 15:00:59.854 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=473.3426, y[0]=344.6167, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25870946, downTime=25870898, deviceId=6, source=0x1002 }
-04-24 15:00:59.870 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=509.29266, y[0]=151.76736, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25870964, downTime=25870898, deviceId=6, source=0x1002 }
-04-24 15:00:59.870 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=509.29266, y[0]=151.76736, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25870973, downTime=25870898, deviceId=6, source=0x1002 }
-04-24 15:01:00.690 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=262.63522, y[0]=677.35675, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25871790, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:00.706 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=272.62137, y[0]=671.36145, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25871799, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:00.729 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=323.55063, y[0]=647.3802, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25871819, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:00.745 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=391.45633, y[0]=626.39655, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25871838, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:00.768 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=460.36063, y[0]=615.40515, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25871857, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:00.784 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=530.26355, y[0]=605.41296, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25871876, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:00.800 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=591.17896, y[0]=601.4161, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25871895, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:00.823 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=650.0971, y[0]=598.4184, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25871914, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:00.839 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=678.0583, y[0]=597.4192, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25871933, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:00.862 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=688.0444, y[0]=595.4208, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25871943, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:00.862 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=688.0444, y[0]=595.4208, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25871952, downTime=25871790, deviceId=6, source=0x1002 }
-04-24 15:01:01.198 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=551.23444, y[0]=146.77127, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25872298, downTime=25872298, deviceId=6, source=0x1002 }
-04-24 15:01:01.214 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=549.2372, y[0]=150.76816, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25872317, downTime=25872298, deviceId=6, source=0x1002 }
-04-24 15:01:01.237 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=546.24133, y[0]=162.75879, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25872327, downTime=25872298, deviceId=6, source=0x1002 }
-04-24 15:01:01.253 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=538.25244, y[0]=222.71194, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25872346, downTime=25872298, deviceId=6, source=0x1002 }
-04-24 15:01:01.276 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=536.2552, y[0]=333.6253, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25872365, downTime=25872298, deviceId=6, source=0x1002 }
-04-24 15:01:01.292 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=543.2455, y[0]=484.5074, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25872384, downTime=25872298, deviceId=6, source=0x1002 }
-04-24 15:01:01.308 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=557.2261, y[0]=640.3856, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25872403, downTime=25872298, deviceId=6, source=0x1002 }
-04-24 15:01:01.331 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=572.20526, y[0]=788.2701, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25872423, downTime=25872298, deviceId=6, source=0x1002 }
-04-24 15:01:01.347 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=584.18866, y[0]=851.22095, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25872432, downTime=25872298, deviceId=6, source=0x1002 }
-04-24 15:01:01.347 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=584.18866, y[0]=851.22095, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25872441, downTime=25872298, deviceId=6, source=0x1002 }
-04-24 15:01:02.151 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=556.2275, y[0]=204.72598, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25873238, downTime=25873238, deviceId=6, source=0x1002 }
-04-24 15:01:02.159 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=552.23303, y[0]=225.7096, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25873248, downTime=25873238, deviceId=6, source=0x1002 }
-04-24 15:01:02.175 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=544.24414, y[0]=316.63855, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873267, downTime=25873238, deviceId=6, source=0x1002 }
-04-24 15:01:02.198 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=548.2386, y[0]=437.54413, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873286, downTime=25873238, deviceId=6, source=0x1002 }
-04-24 15:01:02.214 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=555.2289, y[0]=558.44965, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873305, downTime=25873238, deviceId=6, source=0x1002 }
-04-24 15:01:02.229 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=562.2192, y[0]=659.3708, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873324, downTime=25873238, deviceId=6, source=0x1002 }
-04-24 15:01:02.253 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=570.20807, y[0]=738.30914, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873345, downTime=25873238, deviceId=6, source=0x1002 }
-04-24 15:01:02.268 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=583.19, y[0]=798.26227, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873363, downTime=25873238, deviceId=6, source=0x1002 }
-04-24 15:01:02.276 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=583.19, y[0]=798.26227, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25873372, downTime=25873238, deviceId=6, source=0x1002 }
-04-24 15:01:02.706 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=656.0888, y[0]=237.70023, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25873804, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.722 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=654.09155, y[0]=236.70102, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25873823, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.745 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=650.0971, y[0]=237.70023, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25873842, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.761 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=640.11096, y[0]=242.69632, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25873852, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.776 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=613.14844, y[0]=261.6815, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873871, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.800 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=578.19696, y[0]=293.65652, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873890, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.815 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=540.2497, y[0]=332.62607, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873910, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.839 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=494.31348, y[0]=381.58783, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873929, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.854 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=433.39807, y[0]=446.5371, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873948, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.870 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=367.4896, y[0]=522.4777, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873968, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.893 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=302.57974, y[0]=604.41376, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25873986, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.933 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=244.6602, y[0]=679.35516, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874006, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.933 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=200.72122, y[0]=735.31146, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874025, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.948 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=165.76978, y[0]=783.274, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874044, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.972 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=137.80861, y[0]=813.2506, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874063, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:02.987 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=117.83634, y[0]=838.2311, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874082, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:03.011 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=104.85437, y[0]=853.21936, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874101, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:03.026 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=97.86408, y[0]=862.21234, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874121, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:03.042 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=93.86963, y[0]=867.20844, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874140, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:03.065 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=92.87102, y[0]=869.20685, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25874149, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:03.081 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=91.8724, y[0]=871.2053, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25874169, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:03.104 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=90.87379, y[0]=873.20374, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25874188, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:03.112 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=90.87379, y[0]=873.20374, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25874215, downTime=25873804, deviceId=6, source=0x1002 }
-04-24 15:01:03.448 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=632.1221, y[0]=63.83606, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25874552, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.472 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=629.1262, y[0]=64.83528, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25874572, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.487 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=622.1359, y[0]=70.8306, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25874581, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.511 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=601.16504, y[0]=103.80484, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874600, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.526 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=569.2095, y[0]=163.758, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874619, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.542 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=528.2663, y[0]=241.69711, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874639, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.565 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=491.31763, y[0]=315.63934, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874658, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.581 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=447.37866, y[0]=382.58704, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874677, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.604 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=394.45215, y[0]=458.5277, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874696, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.620 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=344.5215, y[0]=525.4754, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874716, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.643 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=299.58392, y[0]=582.4309, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874735, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.659 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=267.6283, y[0]=632.3919, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874754, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.675 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=244.6602, y[0]=675.35834, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874773, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.698 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=224.68794, y[0]=711.3302, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874792, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.722 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=210.70735, y[0]=743.30524, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874811, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.737 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=194.72955, y[0]=771.2834, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874831, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.753 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=180.74896, y[0]=799.26154, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874850, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.776 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=166.76839, y[0]=829.2381, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874869, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.792 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=153.7864, y[0]=852.22015, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25874888, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.808 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=150.79057, y[0]=860.21387, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25874897, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:03.815 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=150.79057, y[0]=860.21387, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25874906, downTime=25874552, deviceId=6, source=0x1002 }
-04-24 15:01:04.183 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=615.1456, y[0]=187.73926, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25875281, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.198 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=606.15814, y[0]=198.73068, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25875291, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.214 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=570.20807, y[0]=249.69086, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25875310, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.237 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=517.28156, y[0]=324.63232, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25875329, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.253 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=455.36755, y[0]=415.56128, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25875348, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.276 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=394.45215, y[0]=510.48712, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25875367, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.292 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=325.54785, y[0]=599.41766, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25875387, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.308 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=267.6283, y[0]=676.35754, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25875406, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.331 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=217.69765, y[0]=745.30365, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25875425, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.347 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=174.75728, y[0]=807.25525, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25875444, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.370 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=148.79335, y[0]=860.21387, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25875463, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.370 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=148.79335, y[0]=860.21387, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25875472, downTime=25875281, deviceId=6, source=0x1002 }
-04-24 15:01:04.940 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=219.69487, y[0]=771.2834, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876039, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:04.956 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=221.6921, y[0]=767.2865, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876058, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:04.979 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=224.68794, y[0]=762.2904, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876068, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:04.995 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=240.66574, y[0]=740.30756, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876087, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.011 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=268.62692, y[0]=702.3372, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876106, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.034 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=309.57004, y[0]=653.3755, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876125, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.050 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=351.5118, y[0]=605.41296, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876144, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.073 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=395.45078, y[0]=559.44885, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876164, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.089 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=432.39944, y[0]=522.4777, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876183, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.112 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=463.35645, y[0]=495.49884, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876202, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.128 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=488.32178, y[0]=474.5152, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876221, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.143 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=504.2996, y[0]=459.52692, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876241, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.167 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=513.2871, y[0]=453.53162, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876260, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.183 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=518.28015, y[0]=449.53473, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876279, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.198 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=520.2774, y[0]=448.53552, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876289, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.222 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=522.27466, y[0]=446.5371, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876308, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.237 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=524.27185, y[0]=445.53784, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876327, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.315 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=526.2691, y[0]=445.53784, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876413, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.331 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=529.2649, y[0]=447.53632, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876432, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.347 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=533.2594, y[0]=450.53394, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876442, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.370 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=547.2399, y[0]=461.5254, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876461, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.386 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=570.20807, y[0]=479.5113, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876480, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.409 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=599.16785, y[0]=499.49573, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876499, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.425 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=642.1082, y[0]=520.4793, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876518, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.440 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=674.06384, y[0]=534.4684, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876537, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.464 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=694.0361, y[0]=544.4606, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876556, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.479 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=706.0194, y[0]=551.45514, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876575, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.495 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=710.01385, y[0]=554.45276, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876585, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.495 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=710.01385, y[0]=554.45276, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876594, downTime=25876039, deviceId=6, source=0x1002 }
-04-24 15:01:05.839 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=248.65465, y[0]=765.288, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876941, downTime=25876941, deviceId=6, source=0x1002 }
-04-24 15:01:05.862 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=249.65326, y[0]=761.2912, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25876950, downTime=25876941, deviceId=6, source=0x1002 }
-04-24 15:01:05.878 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=264.63245, y[0]=730.31537, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876969, downTime=25876941, deviceId=6, source=0x1002 }
-04-24 15:01:05.893 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=301.58115, y[0]=665.3661, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25876988, downTime=25876941, deviceId=6, source=0x1002 }
-04-24 15:01:05.917 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=352.5104, y[0]=582.4309, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25877008, downTime=25876941, deviceId=6, source=0x1002 }
-04-24 15:01:05.933 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=411.4286, y[0]=483.50818, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25877027, downTime=25876941, deviceId=6, source=0x1002 }
-04-24 15:01:05.948 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=481.33148, y[0]=363.60187, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25877046, downTime=25876941, deviceId=6, source=0x1002 }
-04-24 15:01:05.972 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=547.2399, y[0]=241.69711, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25877065, downTime=25876941, deviceId=6, source=0x1002 }
-04-24 15:01:05.987 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=604.1609, y[0]=149.76892, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25877084, downTime=25876941, deviceId=6, source=0x1002 }
-04-24 15:01:05.995 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=604.1609, y[0]=149.76892, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25877093, downTime=25876941, deviceId=6, source=0x1002 }
-04-24 15:01:06.745 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=592.17755, y[0]=115.79547, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25877844, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.761 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=589.1817, y[0]=116.79468, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25877864, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.776 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=585.18726, y[0]=120.791565, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25877874, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.776 I/System.out( 5517): MotionEvent { action=ACTION_POINTER_DOWN(1), id[0]=0, x[0]=585.18726, y[0]=120.791565, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=350.51318, y[1]=860.21387, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25877874, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.792 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=580.1942, y[0]=127.7861, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=354.50763, y[1]=850.2217, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25877883, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.808 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=573.2039, y[0]=151.76736, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=373.4813, y[1]=810.2529, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25877903, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.831 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=565.21497, y[0]=190.73694, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=396.44937, y[1]=771.2834, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25877921, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.847 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=558.2247, y[0]=227.70804, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=414.4244, y[1]=740.30756, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25877940, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.870 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=550.2358, y[0]=262.68073, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=427.4064, y[1]=714.3279, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25877959, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.886 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=541.2483, y[0]=307.6456, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=437.39252, y[1]=691.3458, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25877978, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.909 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=532.26074, y[0]=366.59955, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=450.37448, y[1]=664.3669, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25877997, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.925 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=523.27325, y[0]=420.55737, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=460.36063, y[1]=644.3825, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25878017, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.948 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=520.2774, y[0]=447.53632, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=465.3537, y[1]=635.3895, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25878036, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.964 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=516.28296, y[0]=461.5254, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=468.34952, y[1]=630.39343, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25878055, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:06.979 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=513.2871, y[0]=468.5199, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=468.34952, y[1]=628.395, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25878074, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:07.003 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=511.2899, y[0]=470.51837, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=468.34952, y[1]=625.39734, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25878083, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:07.003 I/System.out( 5517): MotionEvent { action=ACTION_POINTER_UP(0), id[0]=0, x[0]=511.2899, y[0]=470.51837, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=468.34952, y[1]=623.3989, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25878092, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:07.011 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=1, x[0]=469.34814, y[0]=621.40045, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878101, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:07.011 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=1, x[0]=469.34814, y[0]=621.40045, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25878110, downTime=25877844, deviceId=6, source=0x1002 }
-04-24 15:01:07.667 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=175.7559, y[0]=484.5074, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25878767, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.683 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=188.73787, y[0]=484.5074, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878783, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.706 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=224.68794, y[0]=485.50665, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878802, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.722 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=278.61304, y[0]=486.50586, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878821, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.745 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=336.5326, y[0]=487.50507, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878840, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.761 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=391.45633, y[0]=486.50586, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878859, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.776 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=439.38974, y[0]=484.5074, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878879, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.800 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=478.33566, y[0]=484.5074, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878898, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.815 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=495.31207, y[0]=485.50665, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25878907, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.839 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=538.25244, y[0]=486.50586, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=25878936, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.854 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=559.2233, y[0]=489.50354, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878955, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.878 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=571.20667, y[0]=491.50195, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878974, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.893 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=580.1942, y[0]=494.49963, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25878993, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.909 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=582.1914, y[0]=494.49963, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25879002, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:07.917 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=582.1914, y[0]=494.49963, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25879013, downTime=25878767, deviceId=6, source=0x1002 }
-04-24 15:01:08.136 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=534.258, y[0]=201.72833, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25879233, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:08.151 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=531.26215, y[0]=210.72131, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25879243, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:08.167 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=520.2774, y[0]=254.68695, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25879262, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:08.190 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=509.29266, y[0]=318.637, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25879281, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:08.206 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=500.30515, y[0]=399.5738, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25879300, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:08.229 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=493.31485, y[0]=485.50665, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25879320, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:08.245 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=488.32178, y[0]=568.44183, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25879339, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:08.268 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=484.32733, y[0]=650.3778, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25879358, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:08.284 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=484.32733, y[0]=723.32086, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25879377, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:08.300 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=488.32178, y[0]=756.2951, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25879387, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:08.308 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=488.32178, y[0]=756.2951, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25879396, downTime=25879233, deviceId=6, source=0x1002 }
-04-24 15:01:09.104 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=147.79474, y[0]=671.36145, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25880205, downTime=25880205, deviceId=6, source=0x1002 }
-04-24 15:01:09.128 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=147.79474, y[0]=671.36145, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25880231, downTime=25880205, deviceId=6, source=0x1002 }
-04-24 15:01:09.245 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=163.77254, y[0]=667.36456, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25880346, downTime=25880346, deviceId=6, source=0x1002 }
-04-24 15:01:09.292 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=163.77254, y[0]=667.36456, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25880393, downTime=25880346, deviceId=6, source=0x1002 }
-04-24 15:01:09.722 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=453.37033, y[0]=804.2576, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25880826, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:09.745 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=452.3717, y[0]=796.26385, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25880835, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:09.761 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=447.37866, y[0]=749.30054, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25880855, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:09.784 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=443.3842, y[0]=670.36224, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25880874, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:09.800 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=443.3842, y[0]=577.4348, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25880893, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:09.815 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=445.38144, y[0]=470.51837, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25880912, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:09.839 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=453.37033, y[0]=357.60657, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25880931, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:09.854 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=467.35092, y[0]=235.70178, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25880951, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:09.878 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=490.319, y[0]=99.80797, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25880970, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:09.893 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=500.30515, y[0]=46.849335, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25880979, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:09.893 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=500.30515, y[0]=46.849335, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25880989, downTime=25880826, deviceId=6, source=0x1002 }
-04-24 15:01:11.026 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=562.2192, y[0]=813.2506, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25882131, downTime=25882131, deviceId=6, source=0x1002 }
-04-24 15:01:11.050 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=562.2192, y[0]=801.25995, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25882140, downTime=25882131, deviceId=6, source=0x1002 }
-04-24 15:01:11.065 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=568.2108, y[0]=728.31696, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25882159, downTime=25882131, deviceId=6, source=0x1002 }
-04-24 15:01:11.089 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=580.1942, y[0]=627.3958, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25882178, downTime=25882131, deviceId=6, source=0x1002 }
-04-24 15:01:11.104 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=593.17615, y[0]=516.4824, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25882198, downTime=25882131, deviceId=6, source=0x1002 }
-04-24 15:01:11.120 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=600.16644, y[0]=398.57452, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25882217, downTime=25882131, deviceId=6, source=0x1002 }
-04-24 15:01:11.143 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=608.15533, y[0]=263.67993, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25882236, downTime=25882131, deviceId=6, source=0x1002 }
-04-24 15:01:11.143 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=608.15533, y[0]=263.67993, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25882245, downTime=25882131, deviceId=6, source=0x1002 }
-04-24 15:01:11.956 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=544.24414, y[0]=599.41766, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25883053, downTime=25883053, deviceId=6, source=0x1002 }
-04-24 15:01:11.972 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=480.3329, y[0]=615.40515, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25883071, downTime=25883053, deviceId=6, source=0x1002 }
-04-24 15:01:11.987 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=392.45493, y[0]=650.3778, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25883090, downTime=25883053, deviceId=6, source=0x1002 }
-04-24 15:01:12.011 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=296.58807, y[0]=703.3364, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25883109, downTime=25883053, deviceId=6, source=0x1002 }
-04-24 15:01:12.026 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=227.68378, y[0]=767.2865, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25883128, downTime=25883053, deviceId=6, source=0x1002 }
-04-24 15:01:12.034 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=227.68378, y[0]=767.2865, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25883137, downTime=25883053, deviceId=6, source=0x1002 }
-04-24 15:01:12.597 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=519.2788, y[0]=114.796265, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25883695, downTime=25883695, deviceId=6, source=0x1002 }
-04-24 15:01:12.612 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=516.28296, y[0]=120.791565, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25883704, downTime=25883695, deviceId=6, source=0x1002 }
-04-24 15:01:12.636 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=505.29822, y[0]=150.76816, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25883724, downTime=25883695, deviceId=6, source=0x1002 }
-04-24 15:01:12.651 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=486.32455, y[0]=212.71976, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25883743, downTime=25883695, deviceId=6, source=0x1002 }
-04-24 15:01:12.667 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=471.34537, y[0]=308.6448, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25883762, downTime=25883695, deviceId=6, source=0x1002 }
-04-24 15:01:12.690 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=464.35507, y[0]=424.55426, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25883781, downTime=25883695, deviceId=6, source=0x1002 }
-04-24 15:01:12.706 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=467.35092, y[0]=567.4426, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25883800, downTime=25883695, deviceId=6, source=0x1002 }
-04-24 15:01:12.729 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=481.33148, y[0]=731.3146, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25883819, downTime=25883695, deviceId=6, source=0x1002 }
-04-24 15:01:12.729 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=481.33148, y[0]=731.3146, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25883828, downTime=25883695, deviceId=6, source=0x1002 }
-04-24 15:01:13.956 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=472.34396, y[0]=407.5675, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25885059, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:13.972 I/System.out( 5517): MotionEvent { action=ACTION_POINTER_DOWN(1), id[0]=0, x[0]=472.34396, y[0]=407.5675, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=363.49515, y[1]=698.34033, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885059, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:13.979 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=472.34396, y[0]=405.5691, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=354.50763, y[1]=708.3326, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885078, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:13.995 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=472.34396, y[0]=402.5714, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=334.53537, y[1]=734.31226, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885097, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.018 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=472.34396, y[0]=400.573, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=322.55203, y[1]=749.30054, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885107, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.034 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=472.34396, y[0]=395.5769, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=301.58115, y[1]=779.2771, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885126, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.050 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=476.33844, y[0]=383.58624, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=285.60333, y[1]=804.2576, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885146, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.073 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=482.3301, y[0]=367.59875, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=272.62137, y[1]=823.2428, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885165, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.089 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=490.319, y[0]=351.61124, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=262.63522, y[1]=837.2319, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885185, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.112 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=500.30515, y[0]=334.6245, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=253.64772, y[1]=849.2225, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885204, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.128 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=510.29126, y[0]=317.6378, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=247.65604, y[1]=858.21545, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885223, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.143 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=519.2788, y[0]=304.64792, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=243.66159, y[1]=866.2092, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885243, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.167 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=526.2691, y[0]=294.65573, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=240.66574, y[1]=871.2053, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885262, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.183 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=531.26215, y[0]=286.662, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=237.6699, y[1]=876.2014, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885281, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.206 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=533.2594, y[0]=283.66434, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=235.67268, y[1]=878.1998, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885300, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.222 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=536.2552, y[0]=278.6682, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=233.67546, y[1]=880.19824, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885320, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.245 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=536.2552, y[0]=276.6698, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=232.67685, y[1]=882.1968, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885339, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.261 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=536.2552, y[0]=276.6698, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=232.67685, y[1]=884.1952, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885358, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.276 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=536.2552, y[0]=276.6698, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=232.67685, y[1]=886.1936, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885377, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.300 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=536.2552, y[0]=274.67136, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=232.67685, y[1]=888.192, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885397, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.308 I/System.out( 5517): MotionEvent { action=ACTION_POINTER_UP(0), id[0]=0, x[0]=536.2552, y[0]=274.67136, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=232.67685, y[1]=888.192, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885406, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.323 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=1, x[0]=232.67685, y[0]=890.1904, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25885413, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.323 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=1, x[0]=232.67685, y[0]=890.1904, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25885421, downTime=25885059, deviceId=6, source=0x1002 }
-04-24 15:01:14.511 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=145.7975, y[0]=924.16394, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25885609, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.518 I/System.out( 5517): MotionEvent { action=ACTION_POINTER_DOWN(1), id[0]=0, x[0]=145.7975, y[0]=924.16394, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=562.2192, y[1]=95.81108, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885619, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.534 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=145.7975, y[0]=924.16394, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=559.2233, y[1]=99.80797, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885629, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.558 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=145.7975, y[0]=924.16394, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=544.24414, y[1]=126.786896, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885649, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.573 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=155.78363, y[0]=916.17017, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=519.2788, y[1]=176.74786, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885669, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.597 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=178.75174, y[0]=894.1874, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=491.31763, y[1]=231.70493, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885688, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.612 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=217.69765, y[0]=860.21387, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=465.3537, y[1]=288.66043, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885707, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.628 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=255.64494, y[0]=825.2412, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=444.3828, y[1]=343.6175, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885726, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.651 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=295.58948, y[0]=789.26935, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=427.4064, y[1]=402.5714, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885745, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.667 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=333.53677, y[0]=755.29584, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=417.42026, y[1]=457.5285, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885764, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.706 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=364.49377, y[0]=733.31305, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=413.4258, y[1]=507.48944, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=1, eventTime=25885783, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.706 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=373.4813, y[0]=726.3185, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=412.4272, y[1]=519.4801, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885792, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.722 I/System.out( 5517): MotionEvent { action=ACTION_POINTER_UP(1), id[0]=0, x[0]=385.46463, y[0]=696.3419, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=412.4272, y[1]=519.4801, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=25885801, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.745 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=387.46185, y[0]=695.3427, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25885810, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:14.753 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=387.46185, y[0]=695.3427, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25885819, downTime=25885609, deviceId=6, source=0x1002 }
-04-24 15:01:15.081 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=304.577, y[0]=508.4887, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25886184, downTime=25886184, deviceId=6, source=0x1002 }
-04-24 15:01:15.104 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=308.57144, y[0]=509.4879, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25886194, downTime=25886184, deviceId=6, source=0x1002 }
-04-24 15:01:15.120 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=330.54092, y[0]=518.4809, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886213, downTime=25886184, deviceId=6, source=0x1002 }
-04-24 15:01:15.143 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=367.4896, y[0]=532.47, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886232, downTime=25886184, deviceId=6, source=0x1002 }
-04-24 15:01:15.159 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=418.41888, y[0]=548.45746, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886251, downTime=25886184, deviceId=6, source=0x1002 }
-04-24 15:01:15.175 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=468.34952, y[0]=561.4473, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886271, downTime=25886184, deviceId=6, source=0x1002 }
-04-24 15:01:15.198 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=516.28296, y[0]=575.4364, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886290, downTime=25886184, deviceId=6, source=0x1002 }
-04-24 15:01:15.214 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=557.2261, y[0]=587.427, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886309, downTime=25886184, deviceId=6, source=0x1002 }
-04-24 15:01:15.237 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=589.1817, y[0]=593.4223, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886328, downTime=25886184, deviceId=6, source=0x1002 }
-04-24 15:01:15.237 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=589.1817, y[0]=593.4223, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25886337, downTime=25886184, deviceId=6, source=0x1002 }
-04-24 15:01:15.472 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=428.405, y[0]=394.5777, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25886568, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:15.487 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=424.41055, y[0]=415.56128, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886587, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:15.503 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=420.4161, y[0]=434.54645, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25886597, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:15.526 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=412.4272, y[0]=491.50195, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886616, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:15.542 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=408.43274, y[0]=555.45197, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886635, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:15.565 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=405.4369, y[0]=618.40283, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886654, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:15.581 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=403.43967, y[0]=678.35596, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886674, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:15.597 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=403.43967, y[0]=722.3216, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886693, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:15.620 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=407.43414, y[0]=765.288, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886712, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:15.636 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=415.42303, y[0]=805.25684, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25886731, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:15.636 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=415.42303, y[0]=805.25684, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25886740, downTime=25886568, deviceId=6, source=0x1002 }
-04-24 15:01:16.042 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=635.1179, y[0]=388.58234, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25887144, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.058 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=633.12067, y[0]=387.58313, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25887153, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.081 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=629.1262, y[0]=386.58392, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25887173, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.097 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=617.1429, y[0]=387.58313, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887192, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.120 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=587.1845, y[0]=394.5777, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887211, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.136 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=550.2358, y[0]=409.56598, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887230, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.159 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=508.29404, y[0]=430.54956, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887249, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.175 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=465.3537, y[0]=451.5332, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887269, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.190 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=421.4147, y[0]=472.51678, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887288, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.214 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=376.4771, y[0]=493.50037, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887307, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.229 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=331.53955, y[0]=516.4824, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887326, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.253 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=294.59085, y[0]=536.4668, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887345, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.268 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=267.6283, y[0]=551.45514, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887364, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.292 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=247.65604, y[0]=562.44653, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887384, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.308 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=235.67268, y[0]=568.44183, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887403, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.323 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=230.67961, y[0]=572.4387, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887423, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.347 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=229.681, y[0]=574.43713, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25887432, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.347 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=229.681, y[0]=574.43713, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25887440, downTime=25887144, deviceId=6, source=0x1002 }
-04-24 15:01:16.659 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=400.44385, y[0]=803.25836, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25887758, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.675 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=396.44937, y[0]=802.25916, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25887767, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.698 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=375.47852, y[0]=789.26935, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887787, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.714 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=347.51733, y[0]=767.2865, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887806, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.729 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=313.5645, y[0]=730.31537, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887825, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.753 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=281.6089, y[0]=686.34973, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887844, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.768 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=256.64355, y[0]=643.3833, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887863, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.792 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=237.6699, y[0]=607.4114, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887883, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.808 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=226.68517, y[0]=566.4434, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887902, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.823 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=227.68378, y[0]=518.4809, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887921, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.847 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=248.65465, y[0]=455.53003, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887941, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.862 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=286.60196, y[0]=392.57922, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887960, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.886 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=334.53537, y[0]=338.6214, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887979, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.901 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=381.47018, y[0]=302.6495, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25887998, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.917 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=425.40915, y[0]=279.66745, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888017, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.940 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=465.3537, y[0]=270.67447, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888036, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.956 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=500.30515, y[0]=270.67447, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888055, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.979 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=530.26355, y[0]=280.66666, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888075, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:16.995 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=553.2316, y[0]=300.65106, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888094, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.018 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=562.2192, y[0]=332.62607, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888113, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.034 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=557.2261, y[0]=377.59094, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888132, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.058 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=540.2497, y[0]=431.54877, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888151, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.073 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=513.2871, y[0]=490.50275, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888170, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.089 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=485.32596, y[0]=542.46216, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888190, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.112 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=454.36893, y[0]=587.427, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888209, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.128 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=424.41055, y[0]=617.40356, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888228, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.151 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=393.45355, y[0]=639.3864, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888247, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.167 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=368.48822, y[0]=644.3825, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888266, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.183 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=339.52844, y[0]=635.3895, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888286, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.206 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=308.57144, y[0]=607.4114, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888305, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.222 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=286.60196, y[0]=564.44495, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888324, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.245 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=278.61304, y[0]=510.48712, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888343, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.261 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=277.61444, y[0]=457.5285, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888362, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.284 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=279.61166, y[0]=433.54724, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25888372, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.300 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=286.60196, y[0]=389.5816, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888391, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.315 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=300.58252, y[0]=352.61047, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888410, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.339 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=319.55618, y[0]=327.62997, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888430, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.339 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=319.55618, y[0]=327.62997, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25888439, downTime=25887758, deviceId=6, source=0x1002 }
-04-24 15:01:17.597 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=351.5118, y[0]=866.2092, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25888698, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.620 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=341.52567, y[0]=859.21466, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25888708, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.636 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=312.5659, y[0]=831.2365, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888727, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.659 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=278.61304, y[0]=797.26306, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888747, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.675 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=245.65881, y[0]=761.2912, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888766, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.690 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=217.69765, y[0]=722.3216, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888785, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.714 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=194.72955, y[0]=675.35834, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888805, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.729 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=178.75174, y[0]=617.40356, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888823, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.753 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=171.76144, y[0]=550.4559, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888842, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.768 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=173.75867, y[0]=488.50427, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888862, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.784 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=188.73787, y[0]=422.5558, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888880, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.808 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=210.70735, y[0]=364.6011, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888900, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.823 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=245.65881, y[0]=314.64014, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888919, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.847 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=287.60056, y[0]=277.669, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888938, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.862 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=326.54648, y[0]=251.6893, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888957, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.878 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=368.48822, y[0]=240.6979, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888976, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.901 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=410.42996, y[0]=238.69946, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25888996, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.917 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=456.36618, y[0]=248.69165, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889015, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.933 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=497.3093, y[0]=275.67056, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889034, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.956 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=528.2663, y[0]=320.63544, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889053, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.972 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=546.24133, y[0]=374.59326, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889072, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:17.995 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=546.24133, y[0]=436.54486, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889092, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.011 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=530.26355, y[0]=504.49182, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889111, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.034 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=498.30792, y[0]=576.4356, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889130, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.050 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=454.36893, y[0]=633.3911, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889149, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.065 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=411.4286, y[0]=671.36145, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889168, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.089 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=364.49377, y[0]=695.3427, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889187, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.104 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=325.54785, y[0]=701.338, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889207, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.128 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=288.59918, y[0]=693.34424, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889227, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.143 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=256.64355, y[0]=669.363, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889245, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.167 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=236.6713, y[0]=622.39966, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889264, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.183 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=233.67546, y[0]=561.4473, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889283, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.198 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=237.6699, y[0]=526.4746, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25889293, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.222 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=256.64355, y[0]=454.53082, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889312, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.237 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=280.61026, y[0]=395.5769, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889332, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.261 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=306.57422, y[0]=354.6089, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889351, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.276 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=335.534, y[0]=323.6331, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889370, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.300 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=366.491, y[0]=306.64636, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889389, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.315 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=401.44244, y[0]=301.65027, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889408, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.339 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=439.38974, y[0]=312.6417, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889428, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.354 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=473.3426, y[0]=343.6175, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889447, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.370 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=493.31485, y[0]=382.58704, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889466, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.393 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=496.3107, y[0]=425.55347, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889485, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.409 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=480.3329, y[0]=478.5121, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889504, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.433 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=445.38144, y[0]=528.4731, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889524, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.448 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=398.44662, y[0]=566.4434, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889543, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.464 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=344.5215, y[0]=595.4208, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889562, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.487 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=295.58948, y[0]=611.40826, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889581, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.503 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=251.6505, y[0]=617.40356, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889600, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.526 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=213.7032, y[0]=614.40594, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889619, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.542 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=178.75174, y[0]=596.42, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889639, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.558 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=155.78363, y[0]=570.4403, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889658, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.581 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=143.80028, y[0]=533.4692, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889677, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.597 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=144.79889, y[0]=489.50354, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889696, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.620 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=155.78363, y[0]=438.54333, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889715, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.636 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=168.76561, y[0]=395.5769, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889735, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.651 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=184.74342, y[0]=358.60577, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25889754, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.675 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=192.73232, y[0]=336.62296, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25889763, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:18.675 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=192.73232, y[0]=336.62296, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25889772, downTime=25888698, deviceId=6, source=0x1002 }
-04-24 15:01:19.081 I/System.out( 5517): MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=485.32596, y[0]=768.2857, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25890185, downTime=25890185, deviceId=6, source=0x1002 }
-04-24 15:01:19.104 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=483.32874, y[0]=757.2943, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25890195, downTime=25890185, deviceId=6, source=0x1002 }
-04-24 15:01:19.120 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=477.33704, y[0]=718.32477, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25890214, downTime=25890185, deviceId=6, source=0x1002 }
-04-24 15:01:19.143 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=470.34674, y[0]=659.3708, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25890233, downTime=25890185, deviceId=6, source=0x1002 }
-04-24 15:01:19.159 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=466.3523, y[0]=600.4169, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25890252, downTime=25890185, deviceId=6, source=0x1002 }
-04-24 15:01:19.183 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=464.35507, y[0]=533.4692, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25890272, downTime=25890185, deviceId=6, source=0x1002 }
-04-24 15:01:19.198 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=464.35507, y[0]=461.5254, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25890291, downTime=25890185, deviceId=6, source=0x1002 }
-04-24 15:01:19.222 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=465.3537, y[0]=398.57452, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25890310, downTime=25890185, deviceId=6, source=0x1002 }
-04-24 15:01:19.237 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=466.3523, y[0]=343.6175, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=25890329, downTime=25890185, deviceId=6, source=0x1002 }
-04-24 15:01:19.253 I/System.out( 5517): MotionEvent { action=ACTION_MOVE, id[0]=0, x[0]=464.35507, y[0]=316.63855, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25890339, downTime=25890185, deviceId=6, source=0x1002 }
-04-24 15:01:19.253 I/System.out( 5517): MotionEvent { action=ACTION_UP, id[0]=0, x[0]=464.35507, y[0]=316.63855, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=25890347, downTime=25890185, deviceId=6, source=0x1002 }
diff --git a/mobile/android/tests/browser/robocop/green.swf b/mobile/android/tests/browser/robocop/green.swf
deleted file mode 100644
index e6f6aed14..000000000
--- a/mobile/android/tests/browser/robocop/green.swf
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/javascript_redirect.sjs b/mobile/android/tests/browser/robocop/javascript_redirect.sjs
deleted file mode 100644
index 06e3af09a..000000000
--- a/mobile/android/tests/browser/robocop/javascript_redirect.sjs
+++ /dev/null
@@ -1,8 +0,0 @@
-function handleRequest(request, response)
-{
- let page = "<!DOCTYPE html><html><head><script>window.opener = null; location.replace('" + request.queryString + "')</script></head><body><p>Redirecting...</p></body></html>";
-
- response.setStatusLine("1.0", 200, "OK");
- response.setHeader("Content-Type", "text/html; charset=utf-8", false);
- response.write(page);
-}
diff --git a/mobile/android/tests/browser/robocop/libs/robotium-solo-5.5.4.jar b/mobile/android/tests/browser/robocop/libs/robotium-solo-5.5.4.jar
deleted file mode 100644
index 9236755f4..000000000
--- a/mobile/android/tests/browser/robocop/libs/robotium-solo-5.5.4.jar
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/link_discovery.html b/mobile/android/tests/browser/robocop/link_discovery.html
deleted file mode 100644
index 1679e6545..000000000
--- a/mobile/android/tests/browser/robocop/link_discovery.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE HTML>
-<html>
- <head id="linkparent">
- <title>Autodiscovery Test</title>
- </head>
- <body>
- </body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/moz.build b/mobile/android/tests/browser/robocop/moz.build
deleted file mode 100644
index 023ccf336..000000000
--- a/mobile/android/tests/browser/robocop/moz.build
+++ /dev/null
@@ -1,34 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
-
-ANDROID_APK_NAME = 'robocop-debug'
-ANDROID_APK_PACKAGE = 'org.mozilla.roboexample.test'
-ANDROID_ASSETS_DIRS += ['assets']
-
-TEST_HARNESS_FILES.testing.mochitest += [
- 'robocop.ini',
- 'robocop_autophone.ini',
-]
-TEST_HARNESS_FILES.testing.mochitest.tests.robocop += [
- '*.html',
- '*.jpg',
- '*.mp4',
- '*.ogg',
- '*.sjs',
- '*.swf',
- '*.webm',
- '*.xml',
- 'reader_mode_pages/**', # The ** preserves directory structure.
- 'robocop*.js',
- 'test*.js',
-]
-
-DEFINES['MOZ_ANDROID_SHARED_ID'] = CONFIG['MOZ_ANDROID_SHARED_ID']
-OBJDIR_PP_FILES.mobile.android.tests.browser.robocop += [
- 'AndroidManifest.xml.in',
-]
diff --git a/mobile/android/tests/browser/robocop/reader_mode_pages/basic_article.html b/mobile/android/tests/browser/robocop/reader_mode_pages/basic_article.html
deleted file mode 100644
index f34cbece4..000000000
--- a/mobile/android/tests/browser/robocop/reader_mode_pages/basic_article.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Article title</title>
-<meta name="description" content="This is the article description." />
-</head>
-<body>
-<header>Site header</header>
-<div>
-<h1>Article title</h1>
-<h2 class="author">by Jane Doe</h2>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p>
-<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
-</div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/reader_mode_pages/developer.mozilla.org/en/XULRunner/Build_Instructions.html b/mobile/android/tests/browser/robocop/reader_mode_pages/developer.mozilla.org/en/XULRunner/Build_Instructions.html
deleted file mode 100644
index 14e613008..000000000
--- a/mobile/android/tests/browser/robocop/reader_mode_pages/developer.mozilla.org/en/XULRunner/Build_Instructions.html
+++ /dev/null
@@ -1,373 +0,0 @@
-<!DOCTYPE html>
-<html lang="en-US" dir="ltr" id="developer-mozilla-org" xmlns:fb="http://www.facebook.com/2008/fbml" xmlns:og="http://ogp.me/ns#">
-<head>
- <title>Building XULRunner | MDN</title>
-
- <meta charset="utf-8">
- <meta name="robots" content="index, follow">
- <link rel="home" href="https://developer.mozilla.org/en-US/">
- <link rel="copyright" href="Build_Instructions.html#copyright">
- <link rel="shortcut icon" href="../../media/img/favicon.ico">
-
- <!--[if !IE 6]><!-->
- <link rel="stylesheet" media="screen,projection,tv" href="../../media/css/mdn-min.css%3Fbuild=f424781.css" />
- <link rel="stylesheet" media="screen,projection,tv" href="../../media/css/wiki-min.css%3Fbuild=f424781.css" />
- <!--<![endif]-->
- <!--[if IE]><link rel="stylesheet" type="text/css" media="all" href="//developer.mozilla.org/media/css/mdn-ie.css"><![endif]-->
- <!--[if lte IE 7]><link rel="stylesheet" type="text/css" media="all" href="//developer.mozilla.org/media/css/mdn-ie7.css"><![endif]-->
- <!--[if lte IE 6]><link rel="stylesheet" type="text/css" media="all" href="//developer.mozilla.org/media/css/mdn-ie6.css"><![endif]-->
- <link rel="stylesheet" type="text/css" media="print" href="../../media/css/mdn-print.css">
- <link rel="stylesheet" href="../../../www.mozilla.org/tabzilla/media/css/tabzilla.css">
-
- <link rel="stylesheet" media="print" href="../../media/css/wiki-print-min.css%3Fbuild=f424781.css" />
- <link rel="stylesheet" type="text/css"
- href="../../en-US/docs/Template:CustomCSS%3Fraw=1.css" />
-
- <!--[if IE]>
- <meta http-equiv="imagetoolbar" content="no">
- <meta http-equiv="X-UA-Compatible" content="IE=Edge">
- <script src="//developer.mozilla.org/media/js/html5.js"></script>
- <![endif]-->
-
- <link rel="alternate" type="application/json" href="https://developer.mozilla.org/en-US/docs/XULRunner/Build_Instructions$json" />
- <link rel="canonical" href="Build_Instructions.html" />
-
- <meta property="og:title" content="Building XULRunner"/>
- <meta property="og:type" content="website"/>
- <meta property="og:image" content="https://developer.mozilla.org/media/img/mdn-logo-sm.png"/>
- <meta property="og:site_name" content="Mozilla Developer Network"/>
-
- <meta property="og:description" content="XULRunner is built using basically the same process as Firefox or other applications. Please read and follow the general Build Documentation for instructions on how to get sources and set up build prerequisites."/>
- <meta name="description" content="XULRunner is built using basically the same process as Firefox or other applications. Please read and follow the general Build Documentation for instructions on how to get sources and set up build prerequisites." />
- </head>
-
-<body id="" class="html-ltr document" role="document">
-<!--[if lte IE 8]>
-<noscript><div class="global-notice">
-<p><strong>Warning:</strong> The Mozilla Developer Network website employs emerging web standards that may not be fully supported in some versions of MicroSoft Internet Explorer. You can improve your experience of this website by enabling JavaScript.</p>
-</div></noscript>
-<![endif]-->
- <header id="masthead" class="minor">
- <div class="wrap">
- <ul id="nav-access">
- <li><a href="Build_Instructions.html#language">Select language</a></li>
- <li><a href="Build_Instructions.html#q">Skip to search</a></li>
- <li><a href="Build_Instructions.html#content">Skip to main content</a></li>
- </ul>
-
- <div id="branding">
- <div id="logo"><a href="https://developer.mozilla.org/en-US/"><img src="../../media/img/mdn-logo-sm.png" alt="Mozilla Developer Network" title="Mozilla Developer Network" width="62" height="71"> Mozilla Developer Network</a></div>
- </div>
-
-
- <nav id="nav">
- <ul id="nav-main" role="menubar">
- <li id="nav-main-topics" class="menu" role="menuitem"><a href="Build_Instructions.html#nav-sub-topics" class="toggle" aria-haspopup="true" aria-labelledby="nav-main-topics" title="Explore other parts of MDN">Topics</a>
- <ul id="nav-sub-topics" class="sub-menu" aria-hidden="true">
- <li id="nav-sub-web"><a href="https://developer.mozilla.org/en-US/web">Web</a></li>
- <li id="nav-sub-apps"><a href="https://developer.mozilla.org/en-US/apps">Apps</a></li>
- <li id="nav-sub-mobile"><a href="https://developer.mozilla.org/en-US/mobile">Mobile</a></li>
- <li id="nav-sub-addons"><a href="https://developer.mozilla.org/en-US/addons">Add-ons</a></li>
- <li id="nav-sub-mozilla"><a href="https://developer.mozilla.org/en-US/mozilla">Mozilla</a></li>
- </ul>
- </li>
- <li id="nav-main-docs" class="menu" role="menuitem">
- <a href="https://developer.mozilla.org/en-US/docs" class="docs toggle" aria-haspopup="true" aria-labelledby="nav-main-docs">Docs</a>
- <div id="nav-sub-docs" class="sub-menu" aria-hidden="true">
- <ul>
- <li>
- <ul>
- <li><a href="https://developer.mozilla.org/en-US/docs/HTML">HTML</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/DOM">DOM</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/Using_HTML5_audio_and_video_in_Firefox">Video</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/Using_HTML5_audio_and_video_in_Firefox">Audio</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/SVG">SVG</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/WebGL">WebGL</a></li>
- </ul>
- </li>
- <li>
- <ul>
- <li><a href="https://developer.mozilla.org/en-US/docs/HTML/HTML5">HTML5</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/WebSockets">WebSockets</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/HTML/Using_the_application_cache">Offline Cache</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/DOM/Storage">Local Storage</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/IndexedDB">IndexedDB</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications">File API</a></li>
- </ul>
- </li>
- <li>
- <ul>
- <li><a href="https://developer.mozilla.org/en-US/docs/CSS">CSS</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/CSS/Using_CSS_gradients">Gradients</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/CSS/Using_CSS_transforms">Transforms</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/CSS/Using_CSS_transitions">Transitions</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/CSS/Using_CSS_animations">Animations</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/CSS/Media_queries">Media Queries</a></li>
- </ul>
- </li>
- <li>
- <ul>
- <li><a href="https://developer.mozilla.org/en-US/docs/JavaScript">JavaScript</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/AJAX">AJAX</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/HTML/Canvas">Canvas</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/Using_geolocation">Geolocation</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/DragDrop/Drag_and_Drop">Drag &amp; Drop</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers">Web Workers</a></li>
- </ul>
- </li>
- </ul>
- <p><a href="https://developer.mozilla.org/en-US/docs">More docs&hellip;</a></p>
- </div>
- </li>
- <li id="nav-main-demos" role="menuitem"><a href="https://developer.mozilla.org/en-US/demos/" class="demos">Demos</a></li>
- <li id="nav-main-learning" role="menuitem"><a href="https://developer.mozilla.org/en-US/learn" class="learning">Learning</a></li>
- <li id="nav-main-community" class="menu" role="menuitem"><a href="Build_Instructions.html#nav-sub-community" class="community toggle" aria-haspopup="true" aria-labelledby="nav-main-community">Community</a>
- <ul id="nav-sub-community" class="sub-menu">
- <li><a href="https://developer.mozilla.org/en-US/events">Events</a></li>
- <li><a href="https://developer.mozilla.org/en-US/discussions">Discussions</a></li>
- <li><a href="https://developer.mozilla.org/en-US/promote">Promote</a></li>
- </ul>
- </li>
- </ul>
- </nav>
-
- <ul class="user-state signed-out">
- <li class="user-signin menu">
- <form class="browserid" action="https://developer.mozilla.org/en-US/users/browserid_verify" method="POST"><div style='display:none;'><input type='hidden' id='csrfmiddlewaretoken' name='csrfmiddlewaretoken' value='c92fde167c4768ad483a05412bede68c' /></div>
- <input id="next" name="next" type="hidden" value="/en-US/docs/XULRunner/Build_Instructions"/>
- <input required="required" type="hidden" name="assertion" id="id_assertion" />
- <a href="Build_Instructions.html#" target="_blank" class="browserid-signin toggle" aria-haspopup="true" title="Sign in with Persona">Sign in</a>
- <div class="browserid-info sub-menu" aria-hidden="true">
- <h3>What's this?</h3> <p>MDN has switched to <a href="https://persona.org/" target="_blank" rel="external">Persona</a>, a safe and simple way to sign in with just your e-mail address. <a href="http://identity.mozilla.com/post/12950196039/deploying-browserid-at-mozilla" rel="external">Learn more about why Mozilla is using Persona</a>.</p> <p><strong>Returning members:</strong> sign in with Persona and you'll be connected to your MDN profile (all your information is still here).</p> <p><strong>New members:</strong> sign in with Persona first, then you'll be able to set up your new MDN profile.</p> <p><a href="Build_Instructions.html#" target="_blank" class="browserid-signin" title="Sign in with Persona">Sign in</a></p>
- </div>
- </form>
- </li>
- </ul>
-
- <form id="site-search" method="get" action="http://www.google.com/search"
- data-url="/en-US/search">
- <p>
- <input type="text" role="search" placeholder="Search MDN" id="q" name="q" value="">
- <noscript><button type="submit">Search</button></noscript>
- </p>
- <input type="hidden" name="sitesearch" value="developer.mozilla.org">
- <div id="site-search-gg"></div>
- </form>
-
- <a href="http://www.mozilla.org/" id="tabzilla">mozilla</a>
- </div>
- </header>
-
-
-
-<!-- top toolbar -->
-<section id="nav-toolbar"><div><div class="wrap">
- <!-- right floated navigation -->
- <nav id="tool-menus" role="navigation">
- <ul id="tools">
- <li class="menu">
- <a href="Build_Instructions.html#page-tools" class="toggle">This page</a>
- <ul id="page-tools" class="sub-menu">
- <li class="page-print"> <a href="Build_Instructions.html#" onclick="return window.print();" title="Print page">Print page</a></li>
- <li><a href="https://developer.mozilla.org/en-US/docs/new?parent=15078">New sub-page</a></li>
- </ul>
- </li>
- <li class="menu">
- <a href="Build_Instructions.html#" class="toggle">Languages</a>
- <ul id="translations">
- <li><a rel="internal" href="https://developer.mozilla.org/ja/docs/XULRunner/Build_Instructions" title="Building XULRunner">日本語</a></li>
-
- <li><a href="https://developer.mozilla.org/en-US/docs/XULRunner/Build_Instructions$locales">Add translation</a></li>
- </ul>
- </li>
- </ul>
- </nav>
-
- <!-- left crumb navigation -->
- <nav class="crumbs" role="navigation">
- <ol>
- <li class="crumb"><a href="https://developer.mozilla.org/en-US/docs/en">MDN</a></li>
- <li class="crumb"><a href="https://developer.mozilla.org/en-US/docs/XULRunner">XULRunner</a></li>
- <li class="crumb">Building XULRunner</li>
- </ol>
- </nav>
-
-</div></div></section>
-
-
-
-<section id="content">
- <div class="wrap">
- <div id="content-main" class="full">
- <article class="article" role="main"
- data-current-revision="129041"
- data-refresh-message="Your changes were merged. However, something else has been edited, so this page will be refreshed to reflect the changes."
- data-cancel-edit-message="Abort editing in progress? Your unsaved changes will be discarded.">
- <header id="article-head">
- <div class="title">
- <h1 class="page-title">Building XULRunner</h1>
- </div>
- <ul id="page-buttons">
- <li class="page-history"><a href="https://developer.mozilla.org/en-US/docs/XULRunner/Build_Instructions$history">History</a></li>
- <li class="page-edit"><a href="https://developer.mozilla.org/en-US/docs/XULRunner/Build_Instructions$edit">Edit</a></li>
- </ul>
-
-
- </header>
-
-
-
-
- <div id="wikiArticle" class="page-content boxed">
- <div id="article-nav">
- <div class="page-toc">
- <h2>Table of Contents</h2>
- <ol>
- <code></code><li><ol><li><a href="Build_Instructions.html#CVS_tags_and_XULRunner_versions" rel="internal">CVS tags and XULRunner versions</a><li><a href="Build_Instructions.html#Fetching_Sources_from_Mercurial" rel="internal">Fetching Sources from Mercurial</a></ol></li>
- </ol>
- </div>
- <ul class="page-anchors">
- <li class="anchor-tags">
- <a href="Build_Instructions.html#page-tags">Tags</a>
- </li>
- <li class="anchor-files">
- <span title="This document has no attachments">Files</span>
- </li>
- </ul>
- </div>
- <p> </p>
-<p><a href="https://developer.mozilla.org/en/XULRunner" title="en/XULRunner">XULRunner</a> is built using basically the same process as Firefox or other applications. Please read and follow the general <a href="https://developer.mozilla.org/En/Developer_Guide/Build_Instructions" title="En/Developer_Guide/Build_Instructions">Build Documentation</a> for instructions on how to get sources and set up build prerequisites.</p>
-<p>By default, XULRunner is built with <a href="https://developer.mozilla.org/en/JavaXPCOM" title="en/JavaXPCOM">JavaXPCOM</a> support; the build system must be able to find an appropriate JDK on the system; see the instructions on <a href="https://developer.mozilla.org/En/Developer_Guide/Build_Instructions/Building_JavaXPCOM" title="En/Developer_Guide/Build_Instructions/Building_JavaXPCOM">Building JavaXPCOM</a> for more details. If you do not want to build JavaXPCOM support, specify <code>--disable-javaxpcom</code> in your configuration.</p>
-<p>On Mac, XULRunner requires Mac OS X 10.3 or higher and XCode 1.5 or higher to build properly. The runtime requirement is Mac OS X 10.2.</p>
-<p>A basic minimal <a href="https://developer.mozilla.org/en/Configuring_Build_Options#Using_a_.mozconfig_Configuration_File" title="en/Configuring_Build_Options#Using_a_.mozconfig_Configuration_File">mozconfig</a> which will build a release configuration of XULRunner is:</p>
-<pre class="eval">mk_add_options MOZ_CO_PROJECT=xulrunner
-mk_add_options MOZ_OBJDIR=@topsrcdir@/obj-xulrunner
-
-ac_add_options --enable-application=xulrunner
-#Uncomment the following line if you don't want to build JavaXPCOM:
-#ac_add_options --disable-javaxpcom
-</pre>
-<h3 id="CVS_tags_and_XULRunner_versions">CVS tags and XULRunner versions</h3>
-<p>Older XULRunner releases where tagged in CVS with (for instance XULRUNNER_1_8_0_5_RELEASE ) up to version 1.8.0.5</p>
-<p>The CVS repository does not have specific tags for XULRunner anymore. Instead a XULRunner build is a just special build made from the Firefox/Mozilla tree, using the same tag as a Firefox build. There is a convention where a certain XULRunner version maps to a certain tag in the CVS.</p>
-<p>For instance XULRunner 1.8.1.3, the corresponding tag is CVS is : FIREFOX_2_0_0_3_RELEASE</p>
-<p>To find out how those Firefox tags and XULRunner version maps, check out the file mozilla/config/milestone.txt .</p>
-<p>You can also check the User Agent string in Firefox Help/About menu to get the mapping from a certain binary Firefox version to the corresponding XULRunner version. For instance, in Firefox 2.0.0.9 you will get :</p>
-<pre class="eval">Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9
-</pre>
-<p>Therefore the XULRunner version for this Firefox version is : 1.8.1.9</p>
-<h3 id="Fetching_Sources_from_Mercurial">Fetching Sources from Mercurial</h3>
-<p>As with all other Mozilla products, one would fetch recent sources from Mercurial. For example, to build XULRunner with the top of the tree:</p>
-<pre>hg clone http://hg.mozilla.org/mozilla-central/ src
-cd src
-echo ". \$topsrcdir/xulrunner/config/mozconfig" &gt; .mozconfig
-make -f client.mk build
-</pre>
-<p><span>Interwiki Language Links</span></p>
-<p></p>
- </div>
- <section class="page-meta">
-
- <section id="page-tags">
- <h2>Tags (4)</h2>
- <div id="deki-page-tags">
- <ul class="tags tagit ui-widget ui-widget-content">
- <li class="tagit-choice ui-widget-content ui-state-default">
- <a class="text tagit-label" href="https://developer.mozilla.org/en-US/docs/tag/Developing%20Mozilla">Developing Mozilla</a>
- </li>
- <li class="tagit-choice ui-widget-content ui-state-default">
- <a class="text tagit-label" href="https://developer.mozilla.org/en-US/docs/tag/XUL">XUL</a>
- </li>
- <li class="tagit-choice ui-widget-content ui-state-default">
- <a class="text tagit-label" href="https://developer.mozilla.org/en-US/docs/tag/XULRunner">XULRunner</a>
- </li>
- <li class="tagit-choice ui-widget-content ui-state-default">
- <a class="text tagit-label" href="https://developer.mozilla.org/en-US/docs/tag/Build%20documentation">Build documentation</a>
- </li>
- </ul>
- </div>
- </section>
-
-
- <section id="doc-contributors">
- Contributors to this page: <a href="https://developer.mozilla.org/en-US/profiles/Kray2">Kray2</a>, <a href="https://developer.mozilla.org/en-US/profiles/Taken">Taken</a>, <a href="https://developer.mozilla.org/en-US/profiles/Kozawa">Kozawa</a>, <a href="https://developer.mozilla.org/en-US/profiles/Benjamin%20Smedberg">Benjamin Smedberg</a>, <a href="https://developer.mozilla.org/en-US/profiles/Nickolay">Nickolay</a>, <a href="https://developer.mozilla.org/en-US/profiles/NickolayBot">NickolayBot</a>, <a href="https://developer.mozilla.org/en-US/profiles/Pombredanne">Pombredanne</a>
- <br />
- Last updated by:
- <a href="https://developer.mozilla.org/en-US/profiles/Taken">Taken</a>,
- <time datetime="2009-10-08T15:16:43-07:00">Oct 8, 2009 3:16:43 PM</time>
- </section>
- </section>
- </article>
- <form id="wiki-page-edit" class="editing" method="post" action="https://developer.mozilla.org/en-US/docs/XULRunner/Build_Instructions$edit"><div style='display:none;'><input type='hidden' name='csrfmiddlewaretoken' value='c92fde167c4768ad483a05412bede68c' /></div>
- <input type="hidden" name="form" id="form" value="rev" />
- <input type="hidden" name="content" id="content" value="" />
- </form>
- </div>
- </div>
- </section>
-
-<section id="footbar">
-<div class="wrap">
- <p>
- What do you think of the new MDN? Please <a href="http://mdn.uservoice.com/forums/51389-mdn-website-feedback-http-developer-mozilla-org">share your feedback</a> with us. <a id="dev-mdc-link" href="https://lists.mozilla.org/listinfo/dev-mdc">Join our mailing list</a> to discuss ways to help create great documentation. </p>
-</div>
-</section>
-<footer id="site-info" class="footer" role="contentinfo">
-<div class="wrap">
- <div id="legal">
- <img src="../../media/img/mdn-logo-tiny.png" alt="" width="42" height="48">
- <p id="copyright">&copy; 2005 - 2012 Mozilla Developer Network and individual contributors</p>
- <p>
- Content is available under <a href="https://developer.mozilla.org/en-US/docs/Project:Copyrights">these licenses</a> &bull; <a href="https://developer.mozilla.org/en-US/docs/Project:About">About MDN</a> &bull;
- <a href="http://www.mozilla.org/en-US/privacy">Privacy Policy</a> &bull;
- <a href="https://developer.mozilla.org/discussions">Help</a></p>
- </div>
- <ul class="user-state signed-out">
- <li class="user-signin menu">
- <form class="browserid" action="https://developer.mozilla.org/en-US/users/browserid_verify" method="POST"><div style='display:none;'><input type='hidden' name='csrfmiddlewaretoken' value='c92fde167c4768ad483a05412bede68c' /></div>
- <input id="next" name="next" type="hidden" value="/en-US/docs/XULRunner/Build_Instructions"/>
- <input required="required" type="hidden" name="assertion" id="id_assertion" />
- <a href="Build_Instructions.html#" target="_blank" class="browserid-signin toggle" aria-haspopup="true" title="Sign in with Persona">Sign in</a>
- <div class="browserid-info sub-menu" aria-hidden="true">
- <h3>What's this?</h3> <p>MDN has switched to <a href="https://persona.org/" target="_blank" rel="external">Persona</a>, a safe and simple way to sign in with just your e-mail address. <a href="http://identity.mozilla.com/post/12950196039/deploying-browserid-at-mozilla" rel="external">Learn more about why Mozilla is using Persona</a>.</p> <p><strong>Returning members:</strong> sign in with Persona and you'll be connected to your MDN profile (all your information is still here).</p> <p><strong>New members:</strong> sign in with Persona first, then you'll be able to set up your new MDN profile.</p> <p><a href="Build_Instructions.html#" target="_blank" class="browserid-signin" title="Sign in with Persona">Sign in</a></p>
- </div>
- </form>
- </li>
- </ul>
- <form class="languages go" method="get" action="https://developer.mozilla.org/en-US/docs">
- <label for="language">Other languages:</label>
- <select id="language" class="wiki-l10n" name="next" dir="ltr">
- <option value="/en-US/docs/XULRunner/Build_Instructions" selected>
- English (US)
- </option>
- <option value="/ja/docs/XULRunner/Build_Instructions">
- 日本語
- </option> </select>
- <noscript><button type="submit">Go</button></noscript>
- </form>
- </div>
-</footer>
-
-<script src="../../en-US/jsi18n/build:f424781"></script>
- <script src="../../../www.google.com/jsapi" type="text/javascript"></script>
- <script src="../../../login.persona.org/include.js" type="text/javascript" async></script>
- <script src="../../../www.mozilla.org/tabzilla/media/js/tabzilla.js" async></script>
- <script src="../../media/js/mdn-min.js%3Fbuild=f424781"></script>
- <script src="../../media/js/wiki-min.js%3Fbuild=f424781"></script>
-
-<script type="text/javascript">
-//<![CDATA[
-var _tag=new WebTrends();
-_tag.dcsGetId();
-//]]>>
-</script>
-<script type="text/javascript">
-//<![CDATA[
-_tag.dcsCollect();
-//]]>>
-</script>
-<noscript>
-<div><img alt="DCSIMG" id="DCSIMG" width="1" height="1" src="../../../statse.webtrendslive.com/dcs8yrjuavz5bdaun34r2o8bi_8o8x/njs.gif%3Fdcsuri=%252Fnojavascript&amp;WT.js=No&amp;WT.tv=8.6.2"/></div>
-</noscript>
-</body>
-</html> \ No newline at end of file
diff --git a/mobile/android/tests/browser/robocop/reader_mode_pages/not_an_article.html b/mobile/android/tests/browser/robocop/reader_mode_pages/not_an_article.html
deleted file mode 100644
index 1facae498..000000000
--- a/mobile/android/tests/browser/robocop/reader_mode_pages/not_an_article.html
+++ /dev/null
@@ -1,132 +0,0 @@
-<!DOCTYPE html>
-<html lang="en-US" class="no-js">
-<head>
- <meta charset="utf-8">
- <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
- <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" media="(device-height: 568px)">
- <meta name="apple-mobile-web-app-capable" content="yes" />
- <meta name="apple-mobile-web-app-status-bar-style" content="black" />
-
- <!-- Don't index mobile optimized pages -->
- <meta name="robots" content="noindex" />
-
- <title>Firefox for Android | Mozilla Support</title>
-
- <link rel="icon" type="image/png" sizes="512x512" href="//support.cdn.mozilla.net/static/img/firefox-512.png?v=1">
- <link rel="icon" type="image/png" sizes="256x256" href="//support.cdn.mozilla.net/static/img/firefox-256.png?v=1">
- <link rel="icon" type="image/png" sizes="128x128" href="//support.cdn.mozilla.net/static/img/firefox-128.png?v=1">
- <link rel="icon" type="image/png" sizes="64x64" href="//support.cdn.mozilla.net/static/img/firefox-64.png?v=1">
- <link rel="icon" type="image/png" sizes="32x32" href="//support.cdn.mozilla.net/static/img/firefox-32.png?v=1">
- <link rel="icon" type="image/png" sizes="16x16" href="//support.cdn.mozilla.net/static/img/firefox-16.png?v=1">
-
-
- <link rel="search" type="application/opensearchdescription+xml" title="Mozilla Support" href="/en-US/search/xml"/>
-
- <link rel="stylesheet" media="screen,projection,tv" href="//support.cdn.mozilla.net/static/css/mobile/common-min.css?build=beb7c1e" />
- <link rel="stylesheet" media="screen,projection,tv" href="//support.cdn.mozilla.net/static/css/mobile/products-min.css?build=beb7c1e" />
-
- </head>
-<body class=""
- data-readonly="false"
- data-static-url="//support.cdn.mozilla.net/static/"
- data-orientation="right"
- data-ga-push="[]"
- data-usernames-api="/en-US/users/api/usernames"
->
-
-<nav class="scrollable">
- <div id="search-bar">
- <form id="search" action="/en-US/search">
- <input type="hidden" name="product" value="mobile" />
- <input name="q" placeholder="Search Mozilla Support" required="required" type="search" value="">
- <button class="icon-sprite" type="submit">Search</button>
- </form>
-
- </div>
-
- <a href="/en-US/products">Home</a>
- <a href="/en-US/questions/new">Ask a question</a>
- <a href="/en-US/questions">Support Forum</a>
-
- <header>Navigation</header>
- <a href="/en-US/get-involved">Help other users</a>
- <a href="?&amp;mobile=0">Switch to desktop site</a>
-
- <header>Profile</header>
- <a href="/en-US/users/login">Sign in</a>
-
- <header>Languages</header>
- <a href="/en-US/locales" class="locale-picker">Switch language</a>
- </nav>
-
-<header class="slide-on-exposed">
- <div id="menu-button" class="icon-sprite"></div>
- <h1>
- Firefox for Android
- </h1>
- </header>
-
-
-<div class="wrapper slide-on-exposed">
- <section id="content">
- <ul id="topics">
- <li>
- <a href="/en-US/products/mobile/get-started" class="cf">
- <img src="//support.cdn.mozilla.net/static/img/blank.png" class="topic-sprite topic-get-started" alt="">
- Learn the Basics: get started
- </a>
- </li>
- <li>
- <a href="/en-US/products/mobile/download-and-install" class="cf">
- <img src="//support.cdn.mozilla.net/static/img/blank.png" class="topic-sprite topic-download-and-install" alt="">
- Download, install and migration
- </a>
- </li>
- <li>
- <a href="/en-US/products/mobile/privacy-and-security" class="cf">
- <img src="//support.cdn.mozilla.net/static/img/blank.png" class="topic-sprite topic-privacy-and-security" alt="">
- Privacy and security settings
- </a>
- </li>
- <li>
- <a href="/en-US/products/mobile/customize" class="cf">
- <img src="//support.cdn.mozilla.net/static/img/blank.png" class="topic-sprite topic-customize" alt="">
- Customize controls, options and add-ons
- </a>
- </li>
- <li>
- <a href="/en-US/products/mobile/sync" class="cf">
- <img src="//support.cdn.mozilla.net/static/img/blank.png" class="topic-sprite topic-sync" alt="">
- Firefox Sync settings
- </a>
- </li>
- <li>
- <a href="/en-US/products/mobile/fix-problems" class="cf">
- <img src="//support.cdn.mozilla.net/static/img/blank.png" class="topic-sprite topic-fix-problems" alt="">
- Fix slowness, crashing, error messages and other problems
- </a>
- </li>
- <li>
- <a href="/en-US/kb/get-community-support" class="cf">
- <img src="//support.cdn.mozilla.net/static/img/blank.png" class="topic-sprite topic-get-community-support" alt="">
- Get community support
- </a>
- </li>
- </ul>
-
- </section>
-
- <footer>
- </footer>
-
- <ul id="notifications">
- </ul>
-</div>
-
-
-<script src="//support.cdn.mozilla.net/static/jsi18n/en-us/javascript.js?beb7c1e"></script>
-
-<script src="//support.cdn.mozilla.net/static/js/mobile/common-min.js?build=beb7c1e"></script>
-
-</body>
-</html> \ No newline at end of file
diff --git a/mobile/android/tests/browser/robocop/res/values/strings.xml b/mobile/android/tests/browser/robocop/res/values/strings.xml
deleted file mode 100644
index c1727416b..000000000
--- a/mobile/android/tests/browser/robocop/res/values/strings.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
- - License, v. 2.0. If a copy of the MPL was not distributed with this
- - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<resources>
- <string name="app_name">Roboexample</string>
-
-</resources>
diff --git a/mobile/android/tests/browser/robocop/robocop.ini b/mobile/android/tests/browser/robocop/robocop.ini
deleted file mode 100644
index e9f30478f..000000000
--- a/mobile/android/tests/browser/robocop/robocop.ini
+++ /dev/null
@@ -1,118 +0,0 @@
-[DEFAULT]
-subsuite = robocop
-
-[src/org/mozilla/gecko/tests/testGeckoProfile.java]
-[src/org/mozilla/gecko/tests/testAboutPage.java]
-[src/org/mozilla/gecko/tests/testActivityStreamContextMenu.java]
-[src/org/mozilla/gecko/tests/testAddonManager.java]
-# disabled on 4.3, bug 1144918
-skip-if = android_version == "18"
-[src/org/mozilla/gecko/tests/testAddSearchEngine.java]
-# disabled on 4.3, bug 1120759
-skip-if = android_version == "18"
-[src/org/mozilla/gecko/tests/testAdobeFlash.java]
-# disabled on 4.3, bug 1146420
-skip-if = android_version == "18"
-[src/org/mozilla/gecko/tests/testANRReporter.java]
-[src/org/mozilla/gecko/tests/testAxisLocking.java]
-# [src/org/mozilla/gecko/tests/testBookmark.java] # see bug 915350
-[src/org/mozilla/gecko/tests/testBookmarksPanel.java]
-# disabled on 4.3, bug 987930
-skip-if = android_version == "18"
-[src/org/mozilla/gecko/tests/testBookmarkFolders.java]
-# disabled on 4.3, bug 1144921
-skip-if = android_version == "18"
-[src/org/mozilla/gecko/tests/testBookmarklets.java]
-# [src/org/mozilla/gecko/tests/testBookmarkKeyword.java] # see bug 915350
-[src/org/mozilla/gecko/tests/testBrowserProvider.java]
-[src/org/mozilla/gecko/tests/testBrowserSearchVisibility.java]
-[src/org/mozilla/gecko/tests/testDBUtils.java]
-[src/org/mozilla/gecko/tests/testDistribution.java]
-[src/org/mozilla/gecko/tests/testDoorHanger.java]
-# disabled on 4.3, bug 1144924
-skip-if = android_version == "18"
-[src/org/mozilla/gecko/tests/testFilterOpenTab.java]
-# [src/org/mozilla/gecko/tests/testFindInPage.java] # bug 1128287
-[src/org/mozilla/gecko/tests/testFlingCorrectness.java]
-[src/org/mozilla/gecko/tests/testFormHistory.java]
-[src/org/mozilla/gecko/tests/testGetUserMedia.java]
-# failures across the board, bug 1092202 & bug 1144926
-skip-if = true
-# [src/org/mozilla/gecko/tests/testHistory.java] # see bug 915350
-[src/org/mozilla/gecko/tests/testHomeBanner.java]
-[src/org/mozilla/gecko/tests/testInputUrlBar.java]
-[src/org/mozilla/gecko/tests/testJarReader.java]
-[src/org/mozilla/gecko/tests/testLinkContextMenu.java]
-# [src/org/mozilla/gecko/tests/testHomeListsProvider.java] # see bug 952310
-[src/org/mozilla/gecko/tests/testLoad.java]
-[src/org/mozilla/gecko/tests/testMailToContextMenu.java]
-[src/org/mozilla/gecko/tests/testNewTab.java]
-[src/org/mozilla/gecko/tests/testPanCorrectness.java]
-# [src/org/mozilla/gecko/tests/testPasswordEncrypt.java] # see bug 824067
-[src/org/mozilla/gecko/tests/testPasswordProvider.java]
-# [src/org/mozilla/gecko/tests/testPermissions.java] # see bug 757475
-[src/org/mozilla/gecko/tests/testPictureLinkContextMenu.java]
-[src/org/mozilla/gecko/tests/testPrefsObserver.java]
-[src/org/mozilla/gecko/tests/testPrivateBrowsing.java]
-[src/org/mozilla/gecko/tests/testPromptGridInput.java]
-# bug 1001657
-skip-if = android_version == "18"
-[src/org/mozilla/gecko/tests/testSearchHistoryProvider.java]
-[src/org/mozilla/gecko/tests/testSearchSuggestions.java]
-# disabled on 4.3, bug 1145867
-skip-if = android_version == "18"
-[src/org/mozilla/gecko/tests/testSessionOOMSave.java]
-# disabled on 4.3, bug 1144888
-skip-if = android_version == "18"
-[src/org/mozilla/gecko/tests/testSessionOOMRestore.java]
-# disabled on 4.3, bug 1145879
-skip-if = android_version == "18"
-# [src/org/mozilla/gecko/tests/testShareLink.java] # see bug 915897
-# [src/org/mozilla/gecko/tests/testThumbnails.java] # see bug 813107
-# [src/org/mozilla/gecko/tests/testVkbOverlap.java] # see bug 907274
-
-# Using JavascriptTest
-# (If your test can be written entirely in Javascript, consider writing
-# it as a chrome test instead. See mobile/android/tests/browser/chrome.)
-[src/org/mozilla/gecko/tests/testBrowserDiscovery.java]
-[src/org/mozilla/gecko/tests/testFilePicker.java]
-[src/org/mozilla/gecko/tests/testHistoryService.java]
-[src/org/mozilla/gecko/tests/testOSLocale.java]
-# disabled on 4.3: Bug 1124494
-skip-if = android_version == "18"
-[src/org/mozilla/gecko/tests/testReadingListCache.java]
-[src/org/mozilla/gecko/tests/testRestrictions.java]
-[src/org/mozilla/gecko/tests/testSnackbarAPI.java]
-[src/org/mozilla/gecko/tests/testTrackingProtection.java]
-[src/org/mozilla/gecko/tests/testUITelemetry.java]
-[src/org/mozilla/gecko/tests/testBug1217581.java]
-[src/org/mozilla/gecko/tests/testVideoControls.java]
-# disabled on 4.3, bug 1098532
-skip-if = android_version == "18"
-
-# Using UITest
-#[src/org/mozilla/gecko/tests/testAboutHomePageNavigation.java] # see bug 947550, bug 979038 and bug 977952
-[src/org/mozilla/gecko/tests/testAboutHomeVisibility.java]
-[src/org/mozilla/gecko/tests/testAppMenuPathways.java]
-[src/org/mozilla/gecko/tests/testBackButtonInEditMode.java]
-[src/org/mozilla/gecko/tests/testBrowserDatabaseHelperUpgrades.java]
-[src/org/mozilla/gecko/tests/testEventDispatcher.java]
-[src/org/mozilla/gecko/tests/testGeckoRequest.java]
-[src/org/mozilla/gecko/tests/testInputConnection.java]
-[src/org/mozilla/gecko/tests/testJavascriptBridge.java]
-[src/org/mozilla/gecko/tests/testReaderCacheMigration.java]
-[src/org/mozilla/gecko/tests/testReadingListToBookmarksMigration.java]
-[src/org/mozilla/gecko/tests/testNativeCrypto.java]
-[src/org/mozilla/gecko/tests/testReaderModeTitle.java]
-[src/org/mozilla/gecko/tests/testSessionHistory.java]
-[src/org/mozilla/gecko/tests/testStateWhileLoading.java]
-[src/org/mozilla/gecko/tests/testUnifiedTelemetryClientId.java]
-
-[src/org/mozilla/gecko/tests/testAccessibleCarets.java]
-
-# testStumblerSetting disabled on Android 4.3, bug 1145846
-[src/org/mozilla/gecko/tests/testStumblerSetting.java]
-skip-if = android_version == "18"
-
-[src/org/mozilla/gecko/tests/testLoginsProvider.java]
-[src/org/mozilla/gecko/tests/testICODecoder.java]
diff --git a/mobile/android/tests/browser/robocop/robocop_404.sjs b/mobile/android/tests/browser/robocop/robocop_404.sjs
deleted file mode 100644
index 770639ec8..000000000
--- a/mobile/android/tests/browser/robocop/robocop_404.sjs
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * Used with testThumbnails.
- * On the first visit, the page is green.
- * On subsequent visits, the page is red.
- */
-
-function handleRequest(request, response) {
- let type = request.queryString.match(/^type=(.*)$/)[1];
- let state = "thumbnails." + type;
- let color = "#0f0";
- let status = 200;
-
- if (getState(state)) {
- color = "#f00";
- if (type == "do404")
- status = 404;
- } else {
- setState(state, "1");
- }
-
- response.setStatusLine(request.httpVersion, status, null);
- response.setHeader("Content-Type", "text/html", false);
- response.setHeader("Cache-Control", "no-cache", false);
- response.write('<html>');
- response.write('<head><title>' + type + '</title> <meta charset="utf-8"> </head>');
- response.write('<body style="background-color: ' + color + '"></body>');
- response.write('</html>');
-}
diff --git a/mobile/android/tests/browser/robocop/robocop_adobe_flash.html b/mobile/android/tests/browser/robocop/robocop_adobe_flash.html
deleted file mode 100644
index 98689c5d1..000000000
--- a/mobile/android/tests/browser/robocop/robocop_adobe_flash.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<html style="margin: 0; padding: 0">
-<head>
- <title>Adobe Flash Test</title>
- <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
- <meta charset="utf-8">
-</head>
-<body style="margin: 0; padding: 0">
- <object width="100" height="100"
- classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
- codebase="http://fpdownload.macromedia.com/
- pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0">
- <param name="SRC" value="green.swf">
- <embed src="green.swf" width="100" height="100">
- </embed>
- </object>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_autophone.ini b/mobile/android/tests/browser/robocop/robocop_autophone.ini
deleted file mode 100644
index b8b16e03f..000000000
--- a/mobile/android/tests/browser/robocop/robocop_autophone.ini
+++ /dev/null
@@ -1 +0,0 @@
-[testAdobeFlash]
diff --git a/mobile/android/tests/browser/robocop/robocop_big_link.html b/mobile/android/tests/browser/robocop/robocop_big_link.html
deleted file mode 100644
index f3811d870..000000000
--- a/mobile/android/tests/browser/robocop/robocop_big_link.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<html>
-<head>
- <title>Big Link</title>
- <link rel="shortcut icon" href="data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==" />
- <meta name="viewport" content="initial-scale=1.0"/>
- <meta charset="utf-8">
-</head>
-<body style="margin: 0; padding: 0">
- <div style="text-align: center; margin: 0; padding: 0">
- <a style="font-size: 60px" href="robocop_blank_01.html">Browser Blank Page</a>
- </div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_big_mailto.html b/mobile/android/tests/browser/robocop/robocop_big_mailto.html
deleted file mode 100644
index a4cc77e3b..000000000
--- a/mobile/android/tests/browser/robocop/robocop_big_mailto.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<html>
-<head>
- <title>Big Mailto</title>
- <link rel="shortcut icon" href="data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==" />
- <meta name="viewport" content="initial-scale=1.0"/>
- <meta charset="utf-8">
-</head>
-<body style="margin: 0; padding: 0">
- <div style="text-align: center; margin: 0; padding: 0">
- <a style="font-size: 60px" href="mailto:foo.bar@example.com">Email Foo.Bar</a>
- </div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_blank_01.html b/mobile/android/tests/browser/robocop/robocop_blank_01.html
deleted file mode 100644
index e4f6c9813..000000000
--- a/mobile/android/tests/browser/robocop/robocop_blank_01.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-<meta charset="utf-8">
-<title>Browser Blank Page 01</title>
-<body>
-<p>Browser Blank Page 01</p>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_blank_02.html b/mobile/android/tests/browser/robocop/robocop_blank_02.html
deleted file mode 100644
index 7aaff168b..000000000
--- a/mobile/android/tests/browser/robocop/robocop_blank_02.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<html>
-<meta charset="utf-8">
-<title>Browser Blank Page 02</title>
-<link rel="shortcut icon" href="data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==" />
-<body>
-<p>Browser Blank Page 02</p>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_blank_03.html b/mobile/android/tests/browser/robocop/robocop_blank_03.html
deleted file mode 100644
index 13be8c743..000000000
--- a/mobile/android/tests/browser/robocop/robocop_blank_03.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-<meta charset="utf-8">
-<title>Browser Blank Page 03</title>
-<body>
-<p>Browser Blank Page 03</p>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_blank_04.html b/mobile/android/tests/browser/robocop/robocop_blank_04.html
deleted file mode 100644
index edac1804b..000000000
--- a/mobile/android/tests/browser/robocop/robocop_blank_04.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-<meta charset="utf-8">
-<title>Browser Blank Page 04</title>
-<body>
-<p>Browser Blank Page 04</p>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_blank_05.html b/mobile/android/tests/browser/robocop/robocop_blank_05.html
deleted file mode 100644
index a8cd44cdb..000000000
--- a/mobile/android/tests/browser/robocop/robocop_blank_05.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-<meta charset="utf-8">
-<title>Browser Blank Page 05</title>
-<body>
-<p>Browser Blank Page 05</p>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_boxes.html b/mobile/android/tests/browser/robocop/robocop_boxes.html
deleted file mode 100644
index 82934a064..000000000
--- a/mobile/android/tests/browser/robocop/robocop_boxes.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-DO NOT MODIFY THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
-
-This file is specifically designed to create a page larger than
-any screen fennec could run on (to allow panning in both axes).
-It is filled with 100x100 pixel boxes that are of unique colour,
-so that we can identify exactly what part of the page we are
-rendering at any given time. The colours are specifically chosen
-so that adjacent boxes have a fairly large variation in colour,
-and so that errors due to 565/888 conversion are minimised. This
-is done by dropping the bottom few bits on each color channel,
-so that conversion from 888->565 is pretty much lossless, and any
-variation only comes in from however the drivers do 565->888.
-
-A lot of the tests depend on this behaviour, so ensure that all
-the tests pass (on a variety of screen sizes) when making any
-changes to this file.
- -->
-<html style="margin: 0; padding: 0">
-<head>
- <title>Browser Box test</title>
- <meta name="viewport" content="initial-scale=1.0"/>
- <meta charset="utf-8">
-</head>
-<body style="margin: 0; padding: 0">
-<script type="text/javascript">
-for (var y = 0; y < 2000; y += 100) {
- document.write("<div style='width: 2000px; height: 100px; margin: 0; padding: 0; border: none'>\n");
- for (var x = 0; x < 2000; x += 100) {
- var r = (Math.floor(x / 3) % 256);
- r = r & 0xF8;
- var g = (x + y) % 256;
- g = g & 0xFC;
- var b = (Math.floor(y / 3) % 256);
- b = b & 0xF8;
- document.write("<div style='float: left; width: 100px; height: 100px; margin: 0; padding: 0; border: none; background-color: rgb(" + r + "," + g + "," + b + ")'> </div>\n");
- }
- document.write("</div>\n");
-}
-</script>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_dynamic.sjs b/mobile/android/tests/browser/robocop/robocop_dynamic.sjs
deleted file mode 100644
index 58ff33e9d..000000000
--- a/mobile/android/tests/browser/robocop/robocop_dynamic.sjs
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Dynamically generated page whose title matches the given id.
- */
-
-function handleRequest(request, response) {
- let id = request.queryString.match(/^id=(.*)$/)[1];
- let key = "dynamic." + id;
-
- response.setStatusLine(request.httpVersion, 200, null);
- response.setHeader("Content-Type", "text/html", false);
- response.setHeader("Cache-Control", "no-cache", false);
- response.write('<html>');
- response.write('<head><title>' + id + '</title><meta charset="utf-8"></head>');
- response.write('<body>');
- response.write('<h1>' + id + '</h1>');
- response.write('</body>');
- response.write('</html>');
-}
diff --git a/mobile/android/tests/browser/robocop/robocop_geolocation.html b/mobile/android/tests/browser/robocop/robocop_geolocation.html
deleted file mode 100644
index 1e3cb0afb..000000000
--- a/mobile/android/tests/browser/robocop/robocop_geolocation.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<html>
-<head>
- <title>Geolocation Test Page</title>
- <meta charset="utf-8">
-</head>
-<body>
-<script>
- function clb(position) {
- // Show a green background if permission is granted
- document.body.style.background = "#008000";
- }
- function err(error) {
- // Show a red background if permission is denied
- if (error.code == error.PERMISSION_DENIED)
- document.body.style.background = "#FF0000";
- }
- navigator.geolocation.getCurrentPosition(clb, err, {timeout: 0});
-</script>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_getusermedia.html b/mobile/android/tests/browser/robocop/robocop_getusermedia.html
deleted file mode 100644
index 1ec86d61b..000000000
--- a/mobile/android/tests/browser/robocop/robocop_getusermedia.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!DOCTYPE html>
-<html><head>
- <title>gUM Test Page</title>
- <meta http-equiv="content-type" content="text/html; charset=UTF-8" charset="utf-8">
-</head>
-<body>
- <div id="content"></div>
- <script type="application/javascript">
- var video_status = false;
- var video = document.createElement("video");
- video.setAttribute("width", 640);
- video.setAttribute("height", 480);
-
- var audio_status = false;
- var audio = document.createElement("audio");
- audio.setAttribute("controls", true);
-
- var content = document.getElementById("content");
- document.title = "gUM Test Page";
-
- startAudioVideo();
-
- function startAudioVideo() {
- video_status = true;
- audio_status = true;
- mediaConstraints = {
- video: {
- mozMediaSource: "browser",
- mediaSource: "browser"
- },
- audio: true
- };
- startMedia(mediaConstraints);
- }
-
- function stopMedia() {
- if (video_status) {
- video.srcObject.stop();
- video.srcObject = null;
- content.removeChild(video);
- capturing = false;
- video_status = false;
- }
- if (audio_status) {
- audio.srcObject.stop();
- audio.srcObject = null;
- content.removeChild(audio);
- audio_status = false;
- }
- }
-
- function startMedia(param) {
- try {
- window.navigator.mozGetUserMedia(param, function(stream) {
- if (video_status) {
- content.appendChild(video);
- video.srcObject = stream;
- video.play();
- }
- if (audio_status) {
- content.appendChild(audio);
- audio.srcObject = stream;
- audio.play();
- }
- var audioTracks = stream.getAudioTracks();
- var videoTracks = stream.getVideoTracks();
- document.title = "";
- if (audioTracks.length > 0) {
- document.title += "audio";
- }
- if (videoTracks.length > 0) {
- document.title += "video";
- }
- document.title += " gumtest";
- audio.srcObject.stop();
- video.srcObject.stop();
- }, function(err) {
- document.title = "failed gumtest";
- stopMedia();
- });
- } catch(e) {
- stopMedia();
- }
- }
-</script>
-</body></html>
diff --git a/mobile/android/tests/browser/robocop/robocop_getusermedia2.html b/mobile/android/tests/browser/robocop/robocop_getusermedia2.html
deleted file mode 100644
index a3ffa2966..000000000
--- a/mobile/android/tests/browser/robocop/robocop_getusermedia2.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<!DOCTYPE html>
-<html><head>
- <title>gUM Test Page</title>
- <meta http-equiv="content-type" content="text/html; charset=UTF-8" charset="utf-8">
-</head>
-<body>
- <div id="content"></div>
- <script type="application/javascript">
- var video_status = false;
- var video = document.createElement("video");
- video.setAttribute("width", 640);
- video.setAttribute("height", 480);
-
- var audio_status = false;
- var audio = document.createElement("audio");
- audio.setAttribute("controls", true);
-
- var content = document.getElementById("content");
- document.title = "gUM Test Page";
-
- startAudioVideo();
-
- function startAudioVideo() {
- video_status = true;
- audio_status = true;
- mediaConstraints = {
- video: true,
- audio: true
- };
- startMedia(mediaConstraints);
- }
-
- function stopMedia() {
- if (video_status) {
- video.mozSrcObject.stop();
- video.mozSrcObject = null;
- content.removeChild(video);
- capturing = false;
- video_status = false;
- }
- if (audio_status) {
- audio.mozSrcObject.stop();
- audio.mozSrcObject = null;
- content.removeChild(audio);
- audio_status = false;
- }
- }
-
- function startMedia(param) {
- try {
- window.navigator.mozGetUserMedia(param, function(stream) {
- if (video_status) {
- content.appendChild(video);
- video.mozSrcObject = stream;
- video.play();
- }
- if (audio_status) {
- content.appendChild(audio);
- audio.mozSrcObject = stream;
- audio.play();
- }
- var audioTracks = stream.getAudioTracks();
- var videoTracks = stream.getVideoTracks();
- document.title = "";
- if (audioTracks.length > 0) {
- document.title += "audio";
- }
- if (videoTracks.length > 0) {
- document.title += "video";
- }
- document.title += " gumtest";
- audio.mozSrcObject.stop();
- video.mozSrcObject.stop();
- }, function(err) {
- document.title = "failed gumtest";
- stopMedia();
- });
- } catch(e) {
- stopMedia();
- }
- }
-</script>
-</body></html>
diff --git a/mobile/android/tests/browser/robocop/robocop_head.js b/mobile/android/tests/browser/robocop/robocop_head.js
deleted file mode 100644
index c9e1383f2..000000000
--- a/mobile/android/tests/browser/robocop/robocop_head.js
+++ /dev/null
@@ -1,829 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// The test js is shared between sandboxed (which has no SpecialPowers object)
-// and content mochitests (where the |Components| object is accessible only as
-// SpecialPowers.Components). Expose Components if necessary here to make things
-// work everywhere.
-//
-// Even if the real |Components| doesn't exist, we might shim in a simple JS
-// placebo for compat. An easy way to differentiate this from the real thing
-// is whether the property is read-only or not.
-{
- let c = Object.getOwnPropertyDescriptor(this, 'Components');
- if ((!c.value || c.writable) && typeof SpecialPowers === 'object')
- Components = SpecialPowers.wrap(SpecialPowers.Components);
-}
-
-/*
- * This file contains common code that is loaded before each test file(s).
- * See http://developer.mozilla.org/en/docs/Writing_xpcshell-based_unit_tests
- * for more information.
- */
-
-var _quit = false;
-var _tests_pending = 0;
-var _pendingTimers = [];
-var _cleanupFunctions = [];
-
-function _dump(str) {
- let start = /^TEST-/.test(str) ? "\n" : "";
- dump(start + str);
-}
-
-// Disable automatic network detection, so tests work correctly when
-// not connected to a network.
-{
- let ios = Components.classes["@mozilla.org/network/io-service;1"]
- .getService(Components.interfaces.nsIIOService2);
- ios.manageOfflineStatus = false;
- ios.offline = false;
-}
-
-// Determine if we're running on parent or child
-var runningInParent = true;
-try {
- runningInParent = Components.classes["@mozilla.org/xre/runtime;1"].
- getService(Components.interfaces.nsIXULRuntime).processType
- == Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-}
-catch (e) { }
-
-try {
- if (runningInParent) {
- let prefs = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
-
- // disable necko IPC security checks for xpcshell, as they lack the
- // docshells needed to pass them
- prefs.setBoolPref("network.disable.ipc.security", true);
-
- // Disable IPv6 lookups for 'localhost' on windows.
- if ("@mozilla.org/windows-registry-key;1" in Components.classes) {
- prefs.setCharPref("network.dns.ipv4OnlyDomains", "localhost");
- }
- }
-}
-catch (e) { }
-
-/**
- * Date.now() is not necessarily monotonically increasing (insert sob story
- * about times not being the right tool to use for measuring intervals of time,
- * robarnold can tell all), so be wary of error by erring by at least
- * _timerFuzz ms.
- */
-const _timerFuzz = 15;
-
-function _Timer(func, delay) {
- delay = Number(delay);
- if (delay < 0)
- do_throw("do_timeout() delay must be nonnegative");
-
- if (typeof func !== "function")
- do_throw("string callbacks no longer accepted; use a function!");
-
- this._func = func;
- this._start = Date.now();
- this._delay = delay;
-
- var timer = Components.classes["@mozilla.org/timer;1"]
- .createInstance(Components.interfaces.nsITimer);
- timer.initWithCallback(this, delay + _timerFuzz, timer.TYPE_ONE_SHOT);
-
- // Keep timer alive until it fires
- _pendingTimers.push(timer);
-}
-
-_Timer.prototype = {
- QueryInterface: function(iid) {
- if (iid.equals(Components.interfaces.nsITimerCallback) ||
- iid.equals(Components.interfaces.nsISupports))
- return this;
-
- throw Components.results.NS_ERROR_NO_INTERFACE;
- },
-
- notify: function(timer) {
- _pendingTimers.splice(_pendingTimers.indexOf(timer), 1);
-
- // The current nsITimer implementation can undershoot, but even if it
- // couldn't, paranoia is probably a virtue here given the potential for
- // random orange on tinderboxen.
- var end = Date.now();
- var elapsed = end - this._start;
- if (elapsed >= this._delay) {
- try {
- this._func.call(null);
- } catch (e) {
- do_throw("exception thrown from do_timeout callback: " + e);
- }
- return;
- }
-
- // Timer undershot, retry with a little overshoot to try to avoid more
- // undershoots.
- var newDelay = this._delay - elapsed;
- do_timeout(newDelay, this._func);
- }
-};
-
-function _do_quit() {
- _dump("TEST-INFO | (xpcshell/head.js) | exiting test\n");
-
- _quit = true;
-}
-
-function _dump_exception_stack(stack) {
- stack.split("\n").forEach(function(frame) {
- if (!frame)
- return;
- // frame is of the form "fname(args)@file:line"
- let frame_regexp = new RegExp("(.*)\\(.*\\)@(.*):(\\d*)", "g");
- let parts = frame_regexp.exec(frame);
- if (parts)
- dump("JS frame :: " + parts[2] + " :: " + (parts[1] ? parts[1] : "anonymous")
- + " :: line " + parts[3] + "\n");
- else /* Could be a -e (command line string) style location. */
- dump("JS frame :: " + frame + "\n");
- });
-}
-
-/************** Functions to be used from the tests **************/
-
-/**
- * Prints a message to the output log.
- */
-function do_print(msg) {
- var caller_stack = Components.stack.caller;
- _dump("TEST-INFO | " + caller_stack.filename + " | " + msg + "\n");
-}
-
-/**
- * Calls the given function at least the specified number of milliseconds later.
- * The callback will not undershoot the given time, but it might overshoot --
- * don't expect precision!
- *
- * @param delay : uint
- * the number of milliseconds to delay
- * @param callback : function() : void
- * the function to call
- */
-function do_timeout(delay, func) {
- new _Timer(func, Number(delay));
-}
-
-function do_execute_soon(callback) {
- do_test_pending();
- var tm = Components.classes["@mozilla.org/thread-manager;1"]
- .getService(Components.interfaces.nsIThreadManager);
-
- tm.mainThread.dispatch({
- run: function() {
- try {
- callback();
- } catch (e) {
- // do_check failures are already logged and set _quit to true and throw
- // NS_ERROR_ABORT. If both of those are true it is likely this exception
- // has already been logged so there is no need to log it again. It's
- // possible that this will mask an NS_ERROR_ABORT that happens after a
- // do_check failure though.
- if (!_quit || e != Components.results.NS_ERROR_ABORT) {
- _dump("TEST-UNEXPECTED-FAIL | (xpcshell/head.js) | " + e);
- if (e.stack) {
- dump(" - See following stack:\n");
- _dump_exception_stack(e.stack);
- }
- else {
- dump("\n");
- }
- _do_quit();
- }
- }
- finally {
- do_test_finished();
- }
- }
- }, Components.interfaces.nsIThread.DISPATCH_NORMAL);
-}
-
-function do_throw(text, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- _dump("TEST-UNEXPECTED-FAIL | " + stack.filename + " | " + text +
- " - See following stack:\n");
- var frame = Components.stack;
- while (frame != null) {
- _dump(frame + "\n");
- frame = frame.caller;
- }
-
- _do_quit();
- throw Components.results.NS_ERROR_ABORT;
-}
-
-function do_throw_todo(text, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- _dump("TEST-UNEXPECTED-PASS | " + stack.filename + " | " + text +
- " - See following stack:\n");
- var frame = Components.stack;
- while (frame != null) {
- _dump(frame + "\n");
- frame = frame.caller;
- }
-
- _do_quit();
- throw Components.results.NS_ERROR_ABORT;
-}
-
-function do_report_unexpected_exception(ex, text) {
- var caller_stack = Components.stack.caller;
- text = text ? text + " - " : "";
-
- _dump("TEST-UNEXPECTED-FAIL | " + caller_stack.filename + " | " + text +
- "Unexpected exception " + ex + ", see following stack:\n" + ex.stack +
- "\n");
-
- _do_quit();
- throw Components.results.NS_ERROR_ABORT;
-}
-
-function do_note_exception(ex, text) {
- var caller_stack = Components.stack.caller;
- text = text ? text + " - " : "";
-
- _dump("TEST-INFO | " + caller_stack.filename + " | " + text +
- "Swallowed exception " + ex + ", see following stack:\n" + ex.stack +
- "\n");
-}
-
-function _do_check_neq(left, right, stack, todo) {
- if (!stack)
- stack = Components.stack.caller;
-
- var text = left + " != " + right;
- if (left == right) {
- if (!todo) {
- do_throw(text, stack);
- } else {
- _dump("TEST-KNOWN-FAIL | " + stack.filename + " | [" + stack.name +
- " : " + stack.lineNumber + "] " + text +"\n");
- }
- } else {
- if (!todo) {
- _dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
- stack.lineNumber + "] " + text + "\n");
- } else {
- do_throw_todo(text, stack);
- }
- }
-}
-
-function do_check_neq(left, right, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- _do_check_neq(left, right, stack, false);
-}
-
-function todo_check_neq(left, right, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- _do_check_neq(left, right, stack, true);
-}
-
-function do_report_result(passed, text, stack, todo) {
- if (passed) {
- if (todo) {
- do_throw_todo(text, stack);
- } else {
- _dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
- stack.lineNumber + "] " + text + "\n");
- }
- } else {
- if (todo) {
- _dump("TEST-KNOWN-FAIL | " + stack.filename + " | [" + stack.name +
- " : " + stack.lineNumber + "] " + text +"\n");
- } else {
- do_throw(text, stack);
- }
- }
-}
-
-/**
- * Checks for a true condition, with a success message.
- */
-function ok(condition, msg) {
- do_report_result(condition, msg, Components.stack.caller, false);
-}
-
-/**
- * Checks for a condition equality, with a success message.
- */
-function is(left, right, msg) {
- do_report_result(left === right, "[ " + left + " === " + right + " ] " + msg,
- Components.stack.caller, false);
-}
-
-function _do_check_eq(left, right, stack, todo) {
- if (!stack)
- stack = Components.stack.caller;
-
- var text = left + " == " + right;
- do_report_result(left == right, text, stack, todo);
-}
-
-function do_check_eq(left, right, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- _do_check_eq(left, right, stack, false);
-}
-
-function todo_check_eq(left, right, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- _do_check_eq(left, right, stack, true);
-}
-
-function do_check_true(condition, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- do_check_eq(condition, true, stack);
-}
-
-function todo_check_true(condition, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- todo_check_eq(condition, true, stack);
-}
-
-function do_check_false(condition, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- do_check_eq(condition, false, stack);
-}
-
-function todo_check_false(condition, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- todo_check_eq(condition, false, stack);
-}
-
-function do_check_null(condition, stack=Components.stack.caller) {
- do_check_eq(condition, null, stack);
-}
-
-function todo_check_null(condition, stack=Components.stack.caller) {
- todo_check_eq(condition, null, stack);
-}
-
-/**
- * Check that |value| matches |pattern|.
- *
- * A |value| matches a pattern |pattern| if any one of the following is true:
- *
- * - |value| and |pattern| are both objects; |pattern|'s enumerable
- * properties' values are valid patterns; and for each enumerable
- * property |p| of |pattern|, plus 'length' if present at all, |value|
- * has a property |p| whose value matches |pattern.p|. Note that if |j|
- * has other properties not present in |p|, |j| may still match |p|.
- *
- * - |value| and |pattern| are equal string, numeric, or boolean literals
- *
- * - |pattern| is |undefined| (this is a wildcard pattern)
- *
- * - typeof |pattern| == "function", and |pattern(value)| is true.
- *
- * For example:
- *
- * do_check_matches({x:1}, {x:1}) // pass
- * do_check_matches({x:1}, {}) // fail: all pattern props required
- * do_check_matches({x:1}, {x:2}) // fail: values must match
- * do_check_matches({x:1}, {x:1, y:2}) // pass: extra props tolerated
- *
- * // Property order is irrelevant.
- * do_check_matches({x:"foo", y:"bar"}, {y:"bar", x:"foo"}) // pass
- *
- * do_check_matches({x:undefined}, {x:1}) // pass: 'undefined' is wildcard
- * do_check_matches({x:undefined}, {x:2})
- * do_check_matches({x:undefined}, {y:2}) // fail: 'x' must still be there
- *
- * // Patterns nest.
- * do_check_matches({a:1, b:{c:2,d:undefined}}, {a:1, b:{c:2,d:3}})
- *
- * // 'length' property counts, even if non-enumerable.
- * do_check_matches([3,4,5], [3,4,5]) // pass
- * do_check_matches([3,4,5], [3,5,5]) // fail; value doesn't match
- * do_check_matches([3,4,5], [3,4,5,6]) // fail; length doesn't match
- *
- * // functions in patterns get applied.
- * do_check_matches({foo:v => v.length == 2}, {foo:"hi"}) // pass
- * do_check_matches({foo:v => v.length == 2}, {bar:"hi"}) // fail
- * do_check_matches({foo:v => v.length == 2}, {foo:"hello"}) // fail
- *
- * // We don't check constructors, prototypes, or classes. However, if
- * // pattern has a 'length' property, we require values to match that as
- * // well, even if 'length' is non-enumerable in the pattern. So arrays
- * // are useful as patterns.
- * do_check_matches({0:0, 1:1, length:2}, [0,1]) // pass
- * do_check_matches({0:1}, [1,2]) // pass
- * do_check_matches([0], {0:0, length:1}) // pass
- *
- * Notes:
- *
- * The 'length' hack gives us reasonably intuitive handling of arrays.
- *
- * This is not a tight pattern-matcher; it's only good for checking data
- * from well-behaved sources. For example:
- * - By default, we don't mind values having extra properties.
- * - We don't check for proxies or getters.
- * - We don't check the prototype chain.
- * However, if you know the values are, say, JSON, which is pretty
- * well-behaved, and if you want to tolerate additional properties
- * appearing on the JSON for backward-compatibility, then do_check_matches
- * is ideal. If you do want to be more careful, you can use function
- * patterns to implement more stringent checks.
- */
-function do_check_matches(pattern, value, stack=Components.stack.caller, todo=false) {
- var matcher = pattern_matcher(pattern);
- var text = "VALUE: " + uneval(value) + "\nPATTERN: " + uneval(pattern) + "\n";
- var diagnosis = []
- if (matcher(value, diagnosis)) {
- do_report_result(true, "value matches pattern:\n" + text, stack, todo);
- } else {
- text = ("value doesn't match pattern:\n" +
- text +
- "DIAGNOSIS: " +
- format_pattern_match_failure(diagnosis[0]) + "\n");
- do_report_result(false, text, stack, todo);
- }
-}
-
-function todo_check_matches(pattern, value, stack=Components.stack.caller) {
- do_check_matches(pattern, value, stack, true);
-}
-
-// Return a pattern-matching function of one argument, |value|, that
-// returns true if |value| matches |pattern|.
-//
-// If the pattern doesn't match, and the pattern-matching function was
-// passed its optional |diagnosis| argument, the pattern-matching function
-// sets |diagnosis|'s '0' property to a JSON-ish description of the portion
-// of the pattern that didn't match, which can be formatted legibly by
-// format_pattern_match_failure.
-function pattern_matcher(pattern) {
- function explain(diagnosis, reason) {
- if (diagnosis) {
- diagnosis[0] = reason;
- }
- return false;
- }
- if (typeof pattern == "function") {
- return pattern;
- } else if (typeof pattern == "object" && pattern) {
- var matchers = [];
- for (let p in pattern) {
- matchers.push([p, pattern_matcher(pattern[p])]);
- }
- // Kludge: include 'length', if not enumerable. (If it is enumerable,
- // we picked it up in the array comprehension, above.
- ld = Object.getOwnPropertyDescriptor(pattern, 'length');
- if (ld && !ld.enumerable) {
- matchers.push(['length', pattern_matcher(pattern.length)])
- }
- return function (value, diagnosis) {
- if (!(value && typeof value == "object")) {
- return explain(diagnosis, "value not object");
- }
- for (let [p, m] of matchers) {
- var element_diagnosis = [];
- if (!(p in value && m(value[p], element_diagnosis))) {
- return explain(diagnosis, { property:p,
- diagnosis:element_diagnosis[0] });
- }
- }
- return true;
- };
- } else if (pattern === undefined) {
- return function(value) { return true; };
- } else {
- return function (value, diagnosis) {
- if (value !== pattern) {
- return explain(diagnosis, "pattern " + uneval(pattern) + " not === to value " + uneval(value));
- }
- return true;
- };
- }
-}
-
-// Format an explanation for a pattern match failure, as stored in the
-// second argument to a matching function.
-function format_pattern_match_failure(diagnosis, indent="") {
- var a;
- if (!diagnosis) {
- a = "Matcher did not explain reason for mismatch.";
- } else if (typeof diagnosis == "string") {
- a = diagnosis;
- } else if (diagnosis.property) {
- a = "Property " + uneval(diagnosis.property) + " of object didn't match:\n";
- a += format_pattern_match_failure(diagnosis.diagnosis, indent + " ");
- }
- return indent + a;
-}
-
-function do_test_pending() {
- ++_tests_pending;
-
- _dump("TEST-INFO | (xpcshell/head.js) | test " + _tests_pending +
- " pending\n");
-}
-
-function do_test_finished() {
- _dump("TEST-INFO | (xpcshell/head.js) | test " + _tests_pending +
- " finished\n");
-
- if (--_tests_pending == 0) {
- _do_execute_cleanup();
- _do_quit();
- }
-}
-
-function do_get_file(path, allowNonexistent) {
- try {
- let lf = Components.classes["@mozilla.org/file/directory_service;1"]
- .getService(Components.interfaces.nsIProperties)
- .get("CurWorkD", Components.interfaces.nsILocalFile);
-
- let bits = path.split("/");
- for (let i = 0; i < bits.length; i++) {
- if (bits[i]) {
- if (bits[i] == "..")
- lf = lf.parent;
- else
- lf.append(bits[i]);
- }
- }
-
- if (!allowNonexistent && !lf.exists()) {
- // Not using do_throw(): caller will continue.
- var stack = Components.stack.caller;
- _dump("TEST-UNEXPECTED-FAIL | " + stack.filename + " | [" +
- stack.name + " : " + stack.lineNumber + "] " + lf.path +
- " does not exist\n");
- }
-
- return lf;
- }
- catch (ex) {
- do_throw(ex.toString(), Components.stack.caller);
- }
-
- return null;
-}
-
-// do_get_cwd() isn't exactly self-explanatory, so provide a helper
-function do_get_cwd() {
- return do_get_file("");
-}
-
-function do_load_manifest(path) {
- var lf = do_get_file(path);
- const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar;
- do_check_true(Components.manager instanceof nsIComponentRegistrar);
- Components.manager.autoRegister(lf);
-}
-
-/**
- * Registers a function that will run when the test harness is done running all
- * tests.
- *
- * @param aFunction
- * The function to be called when the test harness has finished running.
- */
-function do_register_cleanup(func) {
- _dump("TEST-INFO | " + _TEST_FILE + " | " +
- (_gRunningTest ? _gRunningTest.name + " " : "") +
- "registering cleanup function.");
-
- _cleanupFunctions.push(func);
-}
-
-/**
- * Execute a function when the test harness is done running all tests.
- */
-function _do_execute_cleanup() {
- let func;
- while ((func = _cleanupFunctions.pop())) {
- _dump("TEST-INFO | " + _TEST_FILE + " | executing cleanup function.");
- func();
- }
-}
-
-/**
- * Add a test function to the list of tests that are to be run asynchronously.
- *
- * Each test function must call run_next_test() when it's done. Test files
- * should call run_next_test() in their run_test function to execute all
- * async tests.
- *
- * @return the test function that was passed in.
- */
-var _gTests = [];
-function add_test(func) {
- _gTests.push([false, func]);
- return func;
-}
-
-// We lazy import Task.jsm so we don't incur a run-time penalty for all tests.
-var _Task;
-
-/**
- * Add a test function which is a Task function.
- *
- * Task functions are functions fed into Task.jsm's Task.spawn(). They are
- * generators that emit promises.
- *
- * If an exception is thrown, a do_check_* comparison fails, or if a rejected
- * promise is yielded, the test function aborts immediately and the test is
- * reported as a failure.
- *
- * Unlike add_test(), there is no need to call run_next_test(). The next test
- * will run automatically as soon the task function is exhausted. To trigger
- * premature (but successful) termination of the function, simply return or
- * throw a Task.Result instance.
- *
- * Example usage:
- *
- * add_task(function test() {
- * let result = yield Promise.resolve(true);
- *
- * do_check_true(result);
- *
- * let secondary = yield someFunctionThatReturnsAPromise(result);
- * do_check_eq(secondary, "expected value");
- * });
- *
- * add_task(function test_early_return() {
- * let result = yield somethingThatReturnsAPromise();
- *
- * if (!result) {
- * // Test is ended immediately, with success.
- * return;
- * }
- *
- * do_check_eq(result, "foo");
- * });
- */
-function add_task(func) {
- if (!_Task) {
- let ns = {};
- _Task = Components.utils.import("resource://gre/modules/Task.jsm", ns).Task;
- }
-
- _gTests.push([true, func]);
-}
-
-/**
- * Runs the next test function from the list of async tests.
- */
-var _gRunningTest = null;
-var _gTestIndex = 0; // The index of the currently running test.
-function run_next_test()
-{
- function _run_next_test()
- {
- if (_gTestIndex < _gTests.length) {
- do_test_pending();
- let _isTask;
- [_isTask, _gRunningTest] = _gTests[_gTestIndex++];
- _dump("TEST-INFO | " + _TEST_FILE + " | Starting " + _gRunningTest.name);
-
- if (_isTask) {
- _Task.spawn(_gRunningTest)
- .then(run_next_test, do_report_unexpected_exception);
- } else {
- // Exceptions do not kill asynchronous tests, so they'll time out.
- try {
- _gRunningTest();
- } catch (e) {
- do_throw(e);
- }
- }
- }
- }
-
- // For sane stacks during failures, we execute this code soon, but not now.
- // We do this now, before we call do_test_finished(), to ensure the pending
- // counter (_tests_pending) never reaches 0 while we still have tests to run
- // (do_execute_soon bumps that counter).
- do_execute_soon(_run_next_test);
-
- if (_gRunningTest !== null) {
- // Close the previous test do_test_pending call.
- do_test_finished();
- }
-}
-
-/**
- * End of code adapted from xpcshell head.js
- */
-
-
-/**
- * JavaBridge facilitates communication between Java and JS. See
- * JavascriptBridge.java for the corresponding JavascriptBridge and docs.
- */
-
-function JavaBridge(obj) {
-
- this._EVENT_TYPE = "Robocop:JS";
- this._target = obj;
- // The number of replies needed to answer all outstanding sync calls.
- this._repliesNeeded = 0;
- this._Services.obs.addObserver(this, this._EVENT_TYPE, false);
-
- this._sendMessage("notify-loaded", []);
-};
-
-JavaBridge.prototype = {
-
- _Services: Components.utils.import(
- "resource://gre/modules/Services.jsm", {}).Services,
-
- _sendMessageToJava: Components.utils.import(
- "resource://gre/modules/Messaging.jsm", {}).Messaging.sendRequest,
-
- _sendMessage: function (innerType, args) {
- this._sendMessageToJava({
- type: this._EVENT_TYPE,
- innerType: innerType,
- method: args[0],
- args: Array.prototype.slice.call(args, 1),
- });
- },
-
- observe: function(subject, topic, data) {
- let message = JSON.parse(data);
- if (message.innerType === "sync-reply") {
- // Reply to our Javascript-to-Java sync call
- this._repliesNeeded--;
- return;
- }
- // Call the corresponding method on the target
- try {
- this._target[message.method].apply(this._target, message.args);
- } catch (e) {
- do_report_unexpected_exception(e, "Failed to call " + message.method);
- }
- if (message.innerType === "sync-call") {
- // Reply for sync message
- this._sendMessage("sync-reply", [message.method]);
- }
- },
-
- /**
- * Synchronously call a method in Java,
- * given the method name followed by a list of arguments.
- */
- syncCall: function (methodName /*, ... */) {
- this._sendMessage("sync-call", arguments);
- let thread = this._Services.tm.currentThread;
- let initialReplies = this._repliesNeeded;
- // Need one more reply to answer the current sync call.
- this._repliesNeeded++;
- // Wait for the reply to arrive. Normally we would not want to
- // spin the event loop, but here we're in a test and our API
- // specifies a synchronous call, so we spin the loop to wait for
- // the call to finish.
- while (this._repliesNeeded > initialReplies) {
- thread.processNextEvent(true);
- }
- },
-
- /**
- * Asynchronously call a method in Java,
- * given the method name followed by a list of arguments.
- */
- asyncCall: function (methodName /*, ... */) {
- this._sendMessage("async-call", arguments);
- },
-
- /**
- * Disconnect with Java.
- */
- disconnect: function () {
- this._Services.obs.removeObserver(this, this._EVENT_TYPE);
- },
-};
diff --git a/mobile/android/tests/browser/robocop/robocop_input.html b/mobile/android/tests/browser/robocop/robocop_input.html
deleted file mode 100644
index 50ddd6e9a..000000000
--- a/mobile/android/tests/browser/robocop/robocop_input.html
+++ /dev/null
@@ -1,165 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Robocop Input</title>
- </head>
- <body>
- <p>Input: <input id="input" type="text"></p>
- <p>Text area: <textarea id="text-area"></textarea></p>
- <p>Content editable: <div id="content-editable" contentEditable="true"></div></p>
- <p>Design mode: <iframe id="design-mode" src="data:text/html;charset=utf-8,<html><body></body></html>"></iframe></p>
- <p>Resetting input: <input id="resetting-input" type="text"></p>
- <p>Hiding input: <input id="hiding-input" type="text"></p>
- <script type="application/javascript;version=1.8" src="robocop_head.js"></script>
- <script type="application/javascript;version=1.8">
- let input = document.getElementById("input");
- let textArea = document.getElementById("text-area");
- let contentEditable = document.getElementById("content-editable");
-
- let designMode = document.getElementById("design-mode");
- try {
- designMode.contentDocument.designMode = "on";
- } catch (e) {
- // Setting designMode above sometimes fails, so try again later.
- setTimeout(function() { designMode.contentDocument.designMode = "on" }, 0);
- }
-
- // Spatial navigation interferes with design-mode key event tests.
- SpecialPowers.setBoolPref("snav.enabled", false);
-
- // An input that resets the editor on every input by resetting the value property.
- let resetting_input = document.getElementById("resetting-input");
- resetting_input.addEventListener('input', function() {
- this.value = this.value;
- });
-
- // An input that hides on input.
- let hiding_input = document.getElementById("hiding-input");
- hiding_input.addEventListener('keydown', function(e) {
- if (e.key === "!") { // '!' key event as sent by testInputConnection.java.
- this.value = "";
- this.style.display = "none";
- }
- });
-
- let getEditor, setValue, setSelection;
-
- let test = {
- focus_input: function(val) {
- getEditor = function() {
- return SpecialPowers.wrap(input).QueryInterface(
- SpecialPowers.Ci.nsIDOMNSEditableElement).editor;
- };
- setValue = function(val) {
- input.value = val;
- };
- setSelection = function(pos) {
- input.setSelectionRange(pos, pos);
- };
- setValue(val);
- input.focus();
- },
-
- focus_text_area: function(val) {
- getEditor = function() {
- return SpecialPowers.wrap(textArea).QueryInterface(
- SpecialPowers.Ci.nsIDOMNSEditableElement).editor;
- };
- setValue = function(val) {
- textArea.value = val;
- };
- setSelection = function(pos) {
- textArea.setSelectionRange(pos, pos);
- };
- setValue(val);
- textArea.focus();
- },
-
- focus_content_editable: function(val) {
- getEditor = function() {
- return SpecialPowers.wrap(window).QueryInterface(
- SpecialPowers.Ci.nsIInterfaceRequestor).getInterface(
- SpecialPowers.Ci.nsIWebNavigation).QueryInterface(
- SpecialPowers.Ci.nsIDocShell).editor;
- };
- setValue = function(val) {
- contentEditable.innerHTML = val;
- };
- setSelection = function(pos) {
- window.getSelection().collapse(contentEditable.firstChild, pos);
- };
- setValue(val);
- contentEditable.focus();
- },
-
- focus_design_mode: function(val) {
- getEditor = function() {
- return SpecialPowers.wrap(designMode.contentWindow).QueryInterface(
- SpecialPowers.Ci.nsIInterfaceRequestor).getInterface(
- SpecialPowers.Ci.nsIWebNavigation).QueryInterface(
- SpecialPowers.Ci.nsIDocShell).editor;
- };
- setValue = function(val) {
- designMode.contentDocument.body.innerHTML = val;
- };
- setSelection = function(pos) {
- designMode.contentWindow.getSelection().collapse(
- designMode.contentDocument.body.firstChild, pos);
- };
- setValue(val);
- designMode.contentWindow.focus();
- designMode.contentDocument.body.focus();
- },
-
- test_reflush_changes: function() {
- let inputIme = getEditor().QueryInterface(SpecialPowers.Ci.nsIEditorIMESupport);
- do_check_true(inputIme.composing);
-
- // Ending the composition then setting the input value triggers the bug.
- inputIme.forceCompositionEnd();
- setValue("good"); // Value that testInputConnection.java expects.
- setSelection(4);
- },
-
- test_set_selection: function() {
- let inputIme = getEditor().QueryInterface(SpecialPowers.Ci.nsIEditorIMESupport);
- do_check_true(inputIme.composing);
-
- // Ending the composition then setting the selection triggers the bug.
- inputIme.forceCompositionEnd();
- setSelection(3); // Offsets that testInputConnection.java expects.
- },
-
- test_bug1123514: function() {
- document.activeElement.addEventListener('input', function test_bug1123514_listener() {
- this.removeEventListener('input', test_bug1123514_listener);
-
- // Only works on input and textarea.
- if (this.value === 'b') {
- this.value = 'abc';
- }
- });
- },
-
- focus_resetting_input: function(val) {
- resetting_input.value = val;
- resetting_input.focus();
- },
-
- focus_hiding_input: function(val) {
- hiding_input.value = val;
- hiding_input.style.display = "";
- hiding_input.focus();
- },
-
- finish_test: function() {
- java.disconnect();
- },
- };
-
- var java = new JavaBridge(test);
- </script>
- </body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_javascript.html b/mobile/android/tests/browser/robocop/robocop_javascript.html
deleted file mode 100644
index 8719f5c6d..000000000
--- a/mobile/android/tests/browser/robocop/robocop_javascript.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<head>
-<meta charset="UTF-8">
-<title>Mochitest Robotium Javascript Test Harness</title>
-<link rel="author" title="nalexander" href="mailto:nalexander@mozilla.com">
-<script type="application/javascript;version=1.8" src="robocop_testharness.js"></script>
-<script>
-var param = /[&?]path=([^&]+)/.exec(location.search);
-if (param) {
- // We encode so that absolute URLs can be provided. Since the
- // encoding of a relative filename is just the filename, no special
- // processing is needed for the most common case.
- var src = decodeURIComponent(param[1]);
- document.title = src;
-
- // Provided by robocop_testharness.js.
- testOneFile(src);
-}
-</script>
-</head>
diff --git a/mobile/android/tests/browser/robocop/robocop_link_to_slow_loading.html b/mobile/android/tests/browser/robocop/robocop_link_to_slow_loading.html
deleted file mode 100644
index 45e487c2a..000000000
--- a/mobile/android/tests/browser/robocop/robocop_link_to_slow_loading.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<html>
-<head>
- <title>Link</title>
- <meta name="viewport" content="initial-scale=1.0"/>
- <meta charset="utf-8">
-</head>
-<body style="margin: 0; padding: 0">
-<div style="text-align: center; margin: 0; padding: 0">
- <a style="font-size: 60px" href="robocop_slow_loading.html">Slow Loading Page</a>
-</div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_login_01.html b/mobile/android/tests/browser/robocop/robocop_login_01.html
deleted file mode 100644
index 19c7dd1f2..000000000
--- a/mobile/android/tests/browser/robocop/robocop_login_01.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<html>
-<script>
-function login(){
-document.login.username.value="Test1";
-document.login.password.value="Test2";
-document.getElementById('submit').click();
-}
-</script>
-<head>
- <title>Robocop Login</title>
- <meta charset="utf-8">
-</head>
-<body onload="login()">
- <h2>User Login </h2>
- <form name="login" method="post" action="robocop_blank_01.html">
- Username: <input type="text" name="username" id="username"><br>
- Password: <input type="password" name="password" id="password"><br>
- <input type="submit" id="submit" name="submit" value="Login!">
- </form>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_login_02.html b/mobile/android/tests/browser/robocop/robocop_login_02.html
deleted file mode 100644
index 55d7f9308..000000000
--- a/mobile/android/tests/browser/robocop/robocop_login_02.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<html>
-<script>
-function login(){
-document.login.username.value="Test2";
-document.login.password.value="Test2";
-document.getElementById('submit').click();
-}
-</script>
-<head>
- <title>Robocop Login</title>
- <meta charset="utf-8">
-</head>
-<body onload="login()">
- <h2>User Login </h2>
- <form name="login" method="post" action="robocop_blank_02.html">
- Username: <input type="text" name="username" id="username"><br>
- Password: <input type="password" name="password" id="password"><br>
- <input type="submit" id="submit" name="submit" value="Login!">
- </form>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_offline_storage.html b/mobile/android/tests/browser/robocop/robocop_offline_storage.html
deleted file mode 100644
index 50878d764..000000000
--- a/mobile/android/tests/browser/robocop/robocop_offline_storage.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<html manifest="robocop_offline">
-<head>
- <title>Robocop offline storage</title>
- <meta charset="utf-8">
-</head>
-<body>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_picture_link.html b/mobile/android/tests/browser/robocop/robocop_picture_link.html
deleted file mode 100644
index a56af54c0..000000000
--- a/mobile/android/tests/browser/robocop/robocop_picture_link.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<html>
-<head>
- <title>Picture Link</title>
- <link rel="shortcut icon" href="data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==" />
- <meta name="viewport" content="initial-scale=1.0"/>
- <meta charset="utf-8">
-</head>
-<body style="margin: 0; padding: 0">
- <div style="text-align: center; margin: 0; padding: 0">
- <a style="font-size: 60px" href="robocop_blank_02.html"><img src="Firefox.jpg"></img></a>
- </div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_popup.html b/mobile/android/tests/browser/robocop/robocop_popup.html
deleted file mode 100644
index 4b7db35c7..000000000
--- a/mobile/android/tests/browser/robocop/robocop_popup.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!doctype html>
-<html>
- <head>
- <meta charset="UTF-8">
- <title>Page creating a popup</title>
- </head>
- <body>
- <script type="text/javascript">
- window.open("data:text/plain;charset=utf-8,a", "a");
- </script>
- </body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_search.html b/mobile/android/tests/browser/robocop/robocop_search.html
deleted file mode 100644
index 581193c9d..000000000
--- a/mobile/android/tests/browser/robocop/robocop_search.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<html>
- <header>
- <title> Robocop Search Engine </title>
- </header>
- <body>
- <form method="get" action="http://www.google.com/search">
- <input type="text" name="q" style="width:300px; height:500px;" maxlength="255" value="" />
- <input type="submit" value="Google Search" />
- </form>
- </body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_slow_loading.html b/mobile/android/tests/browser/robocop/robocop_slow_loading.html
deleted file mode 100644
index 8c87f5aac..000000000
--- a/mobile/android/tests/browser/robocop/robocop_slow_loading.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<html>
-<head>
- <title>Slow Loading</title>
- <meta name="viewport" content="initial-scale=1.0"/>
- <meta charset="utf-8">
- <script type="text/javascript">
-
- // Busy wait (There's no sleep function in JavaScript)
- var waitForMilliseconds = 10000;
- var start = new Date();
- var now = null;
- do {
- now = new Date();
- } while (now - start < waitForMilliseconds);
-
- </script>
-</head>
-<body style="margin: 0; padding: 0">
-<div style="text-align: center; margin: 0; padding: 0">
- <h1>This page is loading very slow.</h1>
-</div>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/robocop_suggestions.sjs b/mobile/android/tests/browser/robocop/robocop_suggestions.sjs
deleted file mode 100644
index 2621288d9..000000000
--- a/mobile/android/tests/browser/robocop/robocop_suggestions.sjs
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Used with testSearchSuggestions.
- * Returns a set of pre-defined suggestions for given prefixes.
- */
-
-function handleRequest(request, response) {
- let query = request.queryString.match(/^query=(.*)$/)[1];
- query = decodeURIComponent(query).replace(/\+/g, " ");
-
- let suggestMap = {
- "f": ["facebook", "fandango", "frys", "forever 21", "fafsa"],
- "fo": ["forever 21", "food network", "fox news", "foothill college", "fox"],
- "foo": ["food network", "foothill college", "foot locker", "footloose", "foo fighters"],
- "foo ": ["foo fighters", "foo bar", "foo bat", "foo bay"],
- "foo b": ["foo bar", "foo bat", "foo bay"],
- "foo ba": ["foo bar", "foo bat", "foo bay"],
- "foo bar": ["foo bar"]
- };
-
- let suggestions = suggestMap[query];
- if (!suggestions)
- suggestions = [];
- suggestions = [query, suggestions];
-
- /*
- * Sample result:
- * ["foo",["food network","foothill college","foot locker",...]]
- */
- response.setHeader("Content-Type", "text/json", false);
- response.setHeader("Cache-Control", "no-cache", false);
- response.write(JSON.stringify(suggestions));
-}
diff --git a/mobile/android/tests/browser/robocop/robocop_testharness.js b/mobile/android/tests/browser/robocop/robocop_testharness.js
deleted file mode 100644
index acc711b8b..000000000
--- a/mobile/android/tests/browser/robocop/robocop_testharness.js
+++ /dev/null
@@ -1,74 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-function sendMessageToJava(message) {
- SpecialPowers.Services.androidBridge.handleGeckoMessage(message);
-}
-
-function _evalURI(uri, sandbox) {
- // We explicitly allow Cross-Origin requests, since it is useful for
- // testing, but we allow relative URLs by maintaining our baseURI.
- let req = SpecialPowers.Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
- .createInstance();
-
- let baseURI = SpecialPowers.Services.io
- .newURI(window.document.baseURI, window.document.characterSet, null);
- let theURI = SpecialPowers.Services.io
- .newURI(uri, window.document.characterSet, baseURI);
-
- // We append a random slug to avoid caching: see
- // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache.
- req.open('GET', theURI.spec + ((/\?/).test(theURI.spec) ? "&slug=" : "?slug=") + (new Date()).getTime(), false);
- req.setRequestHeader('Cache-Control', 'no-cache');
- req.setRequestHeader('Pragma', 'no-cache');
- req.send();
-
- return SpecialPowers.Cu.evalInSandbox(req.responseText, sandbox, "1.8", uri, 1);
-}
-
-/**
- * Execute the Javascript file at `uri` in a testing sandbox populated
- * with the Javascript test harness.
- *
- * `uri` should be a String, relative (to window.document.baseURI) or
- * absolute.
- *
- * The Javascript test harness sends all output to Java via
- * Robocop:JS messages.
- */
-function testOneFile(uri) {
- let HEAD_JS = "robocop_head.js";
-
- // System principal. This is dangerous, but this is test code that
- // should only run on developer and build farm machines, and the
- // test harness needs access to a lot of the Components API,
- // including Components.stack. Wrapping Components.stack in
- // SpecialPowers magic obfuscates stack traces wonderfully,
- // defeating much of the point of the test harness.
- let principal = SpecialPowers.Cc["@mozilla.org/systemprincipal;1"]
- .createInstance(SpecialPowers.Ci.nsIPrincipal);
-
- let testScope = SpecialPowers.Cu.Sandbox(principal);
-
- // Populate test environment with test harness prerequisites.
- testScope.Components = SpecialPowers.Components;
- testScope._TEST_FILE = uri;
-
- // Output from head.js is fed, line by line, to this function. We
- // send any such output back to the Java Robocop harness.
- testScope.dump = function (str) {
- let message = { type: "Robocop:JS",
- innerType: "progress",
- message: str,
- };
- sendMessageToJava(message);
- };
-
- // Populate test environment with test harness. The symbols defined
- // above must be present before executing the test harness.
- _evalURI(HEAD_JS, testScope);
-
- return _evalURI(uri, testScope);
-}
diff --git a/mobile/android/tests/browser/robocop/robocop_text_page.html b/mobile/android/tests/browser/robocop/robocop_text_page.html
deleted file mode 100644
index db30144dd..000000000
--- a/mobile/android/tests/browser/robocop/robocop_text_page.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<html>
-<head>
-<title> Robocop Text Page </title>
-<meta name="viewport" content="initial-scale=1.0"/>
-<meta charset="utf-8">
-</head>
-<body>
-<p>Text taken from Wikipedia.org</p>
-<p> <b>Will be searching for this string:</b> Robocop 1 </p>
-<p>Mozilla is a free software community best known for producing the Firefox web browser. The Mozilla community uses, develops, spreads and supports Mozilla products and works to advance the goals of the Open Web described in the Mozilla Manifesto.[1] The community is supported institutionally by the Mozilla Foundation and its tax-paying subsidiary, the Mozilla Corporation.[2] </p>
-<div style='float: left; width: 100%; height: 500px; margin: 0; padding: 0; border: none'> </div>
-<p> <b>Will be searching for this string:</b> Robocop 2 </p>
-<p>In addition to the Firefox browser, Mozilla also produces Firefox Mobile, the Firefox OS mobile operating system, the bug tracking system Bugzilla and a number of other projects.</p>
-<div style='float: left; width: 200%; height: 500px; margin: 0; padding: 0; border: none'> </div>
-<p> <b>Will be searching for this string:</b> Robocop 3 </p>
-<p>On February 23, 1998, Netscape Communications Corporation created a project called Mozilla (after the original code name of the Netscape Navigator browser which — according to Pascal Finette — is a mashup of "Mosaic Killer") to co-ordinate the development of the Mozilla Application Suite, the open source version of Netscape's internet software, Netscape Communicator.[3][4] Jamie Zawinski says he came up with the name "Mozilla" at a Netscape staff meeting.[5][6] A small group of Netscape employees were tasked with coordination of the new community.<p>
-<div style='float: left; width: 100%; height: 500px; margin: 0; padding: 0; border: none'> </div>
-<p> <b>Will be searching for this string:</b> Robocop </p>
-<p>Originally, Mozilla aimed to be a technology provider for companies, such as Netscape, who would commercialize their open source code.[7] When AOL (Netscape's parent company) drastically scaled back its involvement with Mozilla in July 2003, the Mozilla Foundation was launched as the legal steward of the project.[8] Soon after, Mozilla deprecated the Mozilla Suite in favor of creating independent applications for each function, primarily the Firefox web browser and the Thunderbird email client, and moved to supply them direct to the public.[9]<p>
-<div style='float: left; width: 100%; height: 200px; margin: 0; padding: 0; border: none'> </div>
-<p> <b>Will be searching for this string:</b> Robocop </p>
-<p>Recently, Mozilla's activities have expanded to include Firefox on mobile platforms (primarily Android),[10] a mobile OS called Firefox OS,[11] a web-based identity system called Mozilla Persona and a marketplace for HTML5 applications.[12]</p>
-<div style='float: left; width: 100%; height: 200px; margin: 0; padding: 0; border: none'> </div>
-<p> <b>Will be searching for this string:</b> Robocop </p>
-<p>In a report released in November of 2012, Mozilla reported that their total revenue for 2011 was $163 million, which was up 33% from $123 million in 2010. Mozilla noted that roughly 85% of their revenue comes from their contract with Google. [13]</p>
-</body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/roboextender/Makefile.in b/mobile/android/tests/browser/robocop/roboextender/Makefile.in
deleted file mode 100644
index 07d7992ac..000000000
--- a/mobile/android/tests/browser/robocop/roboextender/Makefile.in
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-TEST_EXTENSIONS_DIR = $(DEPTH)/_tests/testing/mochitest/extensions
-
-tools::
- -cp $(DEPTH)/mobile/android/tests/javaaddons/javaaddons-test.apk $(TEST_EXTENSIONS_DIR)/roboextender@mozilla.org/base
diff --git a/mobile/android/tests/browser/robocop/roboextender/base/robocop_home_banner.html b/mobile/android/tests/browser/robocop/roboextender/base/robocop_home_banner.html
deleted file mode 100644
index 9a9456604..000000000
--- a/mobile/android/tests/browser/robocop/roboextender/base/robocop_home_banner.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<html>
- <head>
- <title>HomeBanner test page</title>
- <meta name="viewport" content="initial-scale=1.0"/>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
- <script type="application/javascript">
-Components.utils.import("resource://gre/modules/Messaging.jsm");
-Components.utils.import("resource://gre/modules/Services.jsm");
-Components.utils.import("resource://gre/modules/Home.jsm");
-
-const TEXT = "The quick brown fox jumps over the lazy dog.";
-
-function start() {
- var test = location.hash.substring(1);
- window[test]();
-}
-
-var messageId;
-
-function addMessage() {
- messageId = Home.banner.add({
- text: TEXT,
- onshown: function() {
- Messaging.sendRequest({ type: "TestHomeBanner:MessageShown" });
- },
- ondismiss: function() {
- Messaging.sendRequest({ type: "TestHomeBanner:MessageDismissed" });
- }
- });
- Messaging.sendRequest({ type: "TestHomeBanner:MessageAdded" });
-}
-
- </script>
- </head>
- <body onload="start();">
- </body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/roboextender/base/robocop_prompt_gridinput.html b/mobile/android/tests/browser/robocop/roboextender/base/robocop_prompt_gridinput.html
deleted file mode 100644
index 733683c16..000000000
--- a/mobile/android/tests/browser/robocop/roboextender/base/robocop_prompt_gridinput.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<html>
- <head>
- <title>IconGrid test page</title>
- <meta name="viewport" content="initial-scale=1.0"/>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
- <script type="application/javascript">
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-Components.utils.import("resource://gre/modules/Services.jsm");
-Components.utils.import("resource://gre/modules/Prompt.jsm");
-
-function start() {
- var test = location.hash.substring(1);
- window[test]();
-}
-
-function test1() {
- var p = new Prompt({
- title: "Prompt 1",
- buttons: [
- "OK"
- ],
- }).addIconGrid({
- items: [
- { iconUri: "drawable://alert_camera", name: "Icon 1", selected: true },
- { iconUri: "drawable://alert_download", name: "Icon 2" },
- { iconUri: "drawable://icon", name: "Icon 3" },
- { iconUri: "drawable://icon", name: "Icon 4" },
- { iconUri: "drawable://icon", name: "Icon 5" },
- { iconUri: "drawable://icon", name: "Icon 6" },
- { iconUri: "drawable://icon", name: "Icon 7" },
- { iconUri: "drawable://icon", name: "Icon 8" },
- { iconUri: "drawable://icon", name: "Icon 9" },
- { iconUri: "drawable://icon", name: "Icon 10" },
- { iconUri: "drawable://icon", name: "Icon 11" },
- ]
- });
- p.show(function(data) {
- sendResult(data.icongrid0 == 10, "Got result " + data.icongrid0);
- });
-}
-
-function sendResult(pass, message) {
- setTimeout(function() {
- alert((pass ? "PASS " : "FAIL ") + message);
- }, 1000);
-}
- </script>
- </head>
- <body onload="start();">
- </body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/roboextender/bootstrap.js b/mobile/android/tests/browser/robocop/roboextender/bootstrap.js
deleted file mode 100644
index e903aa3f6..000000000
--- a/mobile/android/tests/browser/robocop/roboextender/bootstrap.js
+++ /dev/null
@@ -1,65 +0,0 @@
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-function loadIntoWindow(window) {}
-function unloadFromWindow(window) {}
-
-function _sendMessageToJava (aMsg) {
- return Services.androidBridge.handleGeckoMessage(aMsg);
-};
-
-/*
- bootstrap.js API
-*/
-var windowListener = {
- onOpenWindow: function(aWindow) {
- // Wait for the window to finish loading
- let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
- domWindow.addEventListener("load", function() {
- domWindow.removeEventListener("load", arguments.callee, false);
- if (domWindow) {
- domWindow.addEventListener("scroll", function(e) {
- let message = {
- type: 'robocop:scroll',
- y: XPCNativeWrapper.unwrap(e.target).documentElement.scrollTop,
- height: XPCNativeWrapper.unwrap(e.target).documentElement.scrollHeight,
- cheight: XPCNativeWrapper.unwrap(e.target).documentElement.clientHeight,
- };
- _sendMessageToJava(message);
- });
- }
- }, false);
- },
- onCloseWindow: function(aWindow) { },
- onWindowTitleChange: function(aWindow, aTitle) { }
-};
-
-function startup(aData, aReason) {
- let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
-
- // Load into any new windows
- wm.addListener(windowListener);
- Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
- dump("Robocop:Quit received -- requesting quit");
- let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
- appStartup.quit(Ci.nsIAppStartup.eForceQuit);
- }, "Robocop:Quit", false);
-}
-
-function shutdown(aData, aReason) {
- // When the application is shutting down we normally don't have to clean up any UI changes
- if (aReason == APP_SHUTDOWN) return;
-
- let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
-
- // Stop watching for new windows
- wm.removeListener(windowListener);
-}
-
-function install(aData, aReason) { }
-function uninstall(aData, aReason) { }
-
diff --git a/mobile/android/tests/browser/robocop/roboextender/chrome.manifest b/mobile/android/tests/browser/robocop/roboextender/chrome.manifest
deleted file mode 100644
index 7467f91a6..000000000
--- a/mobile/android/tests/browser/robocop/roboextender/chrome.manifest
+++ /dev/null
@@ -1 +0,0 @@
-content roboextender base/ \ No newline at end of file
diff --git a/mobile/android/tests/browser/robocop/roboextender/install.rdf b/mobile/android/tests/browser/robocop/roboextender/install.rdf
deleted file mode 100644
index cbf66e884..000000000
--- a/mobile/android/tests/browser/robocop/roboextender/install.rdf
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0"?>
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
- <Description about="urn:mozilla:install-manifest">
- <em:id>roboextender@mozilla.org</em:id>
- <em:type>2</em:type>
- <em:name>Robocop Extender</em:name>
- <em:version>1.0</em:version>
- <em:bootstrap>true</em:bootstrap>
- <em:creator>Joel Maher</em:creator>
- <em:targetApplication>
- <Description>
- <em:id>toolkit@mozilla.org</em:id>
- <em:minVersion>10.0</em:minVersion>
- <em:maxVersion>*</em:maxVersion>
- </Description>
- </em:targetApplication>
- </Description>
-</RDF>
-
diff --git a/mobile/android/tests/browser/robocop/roboextender/moz.build b/mobile/android/tests/browser/robocop/roboextender/moz.build
deleted file mode 100644
index e2388a2b8..000000000
--- a/mobile/android/tests/browser/robocop/roboextender/moz.build
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-TEST_HARNESS_FILES.testing.mochitest.extensions['roboextender@mozilla.org'] += [
- 'base/**',
- 'bootstrap.js',
- 'chrome.manifest',
- 'install.rdf',
-]
diff --git a/mobile/android/tests/browser/robocop/simple_redirect.sjs b/mobile/android/tests/browser/robocop/simple_redirect.sjs
deleted file mode 100644
index b6249cadf..000000000
--- a/mobile/android/tests/browser/robocop/simple_redirect.sjs
+++ /dev/null
@@ -1,5 +0,0 @@
-function handleRequest(request, response)
-{
- response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
- response.setHeader("Location", request.queryString, false);
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Actions.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Actions.java
deleted file mode 100644
index 05e6bfa52..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Actions.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-import android.database.Cursor;
-
-public interface Actions {
-
- /** Special keys supported by sendSpecialKey() */
- public enum SpecialKey {
- DOWN,
- UP,
- LEFT,
- RIGHT,
- ENTER,
- MENU,
- DELETE,
- }
-
- public interface EventExpecter {
- /** Blocks until the event has been received. Subsequent calls will return immediately. */
- public void blockForEvent();
- public void blockForEvent(long millis, boolean failOnTimeout);
-
- /** Blocks until the event has been received and returns data associated with the event. */
- public String blockForEventData();
-
- /**
- * Blocks until the event has been received, or until the timeout has been exceeded.
- * Returns the data associated with the event, if applicable.
- */
- public String blockForEventDataWithTimeout(long millis);
-
- /** Polls to see if the event has been received. Once this returns true, subsequent calls will also return true. */
- public boolean eventReceived();
-
- /** Stop listening for events. */
- public void unregisterListener();
- }
-
- public interface RepeatedEventExpecter extends EventExpecter {
- /** Blocks until at least one event has been received, and no events have been received in the last <code>millis</code> milliseconds. */
- public void blockUntilClear(long millis);
- }
-
- /**
- * Sends an event to Gecko.
- *
- * @param geckoEvent The geckoEvent JSONObject's type
- */
- void sendGeckoEvent(String geckoEvent, String data);
-
- public interface PrefWaiter {
- boolean isFinished();
- void waitForFinish();
- void waitForFinish(long timeoutMillis, boolean failOnTimeout);
- }
-
- public abstract static class PrefHandlerBase implements PrefsHelper.PrefHandler {
- /* package */ Assert asserter;
-
- @Override // PrefsHelper.PrefHandler
- public void prefValue(String pref, boolean value) {
- asserter.ok(false, "Unexpected pref callback", "");
- }
-
- @Override // PrefsHelper.PrefHandler
- public void prefValue(String pref, int value) {
- asserter.ok(false, "Unexpected pref callback", "");
- }
-
- @Override // PrefsHelper.PrefHandler
- public void prefValue(String pref, String value) {
- asserter.ok(false, "Unexpected pref callback", "");
- }
-
- @Override // PrefsHelper.PrefHandler
- public void finish() {
- }
- }
-
- PrefWaiter getPrefs(String[] prefNames, PrefHandlerBase handler);
- void setPref(String pref, Object value, boolean flush);
- PrefWaiter addPrefsObserver(String[] prefNames, PrefHandlerBase handler);
- void removePrefsObserver(PrefWaiter handler);
-
- /**
- * Listens for a gecko event to be sent from the Gecko instance.
- * The returned object can be used to test if the event has been
- * received. Note that only one event is listened for.
- *
- * @param geckoEvent The geckoEvent JSONObject's type
- */
- RepeatedEventExpecter expectGeckoEvent(String geckoEvent);
-
- /**
- * Listens for a paint event. Note that calling expectPaint() will
- * invalidate the event expecters returned from any previous calls
- * to expectPaint(); calling any methods on those invalidated objects
- * will result in undefined behaviour.
- */
- RepeatedEventExpecter expectPaint();
-
- /**
- * Send a string to the application
- *
- * @param keysToSend The string to send
- */
- void sendKeys(String keysToSend);
-
- /**
- * Send a special keycode to the element
- *
- * @param key The special key to send
- */
- void sendSpecialKey(SpecialKey key);
- void sendKeyCode(int keyCode);
-
- void drag(int startingX, int endingX, int startingY, int endingY);
-
- /**
- * Run a sql query on the specified database
- */
- public Cursor querySql(String dbPath, String sql);
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Assert.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Assert.java
deleted file mode 100644
index aa76dcf2b..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Assert.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-public interface Assert {
- void dumpLog(String message);
- void dumpLog(String message, Throwable t);
- void setLogFile(String filename);
- void setTestName(String testName);
- void endTest();
-
- void ok(boolean condition, String name, String diag);
- void is(Object actual, Object expected, String name);
- void isnot(Object actual, Object notExpected, String name);
- void todo(boolean condition, String name, String diag);
- void todo_is(Object actual, Object expected, String name);
- void todo_isnot(Object actual, Object notExpected, String name);
- void info(String name, String message);
-
- // robocop-specific asserts
- void ispixel(int actual, int r, int g, int b, String name);
- void isnotpixel(int actual, int r, int g, int b, String name);
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Driver.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Driver.java
deleted file mode 100644
index 4c8373c5b..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Driver.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import android.app.Activity;
-
-public interface Driver {
- /**
- * Find the first Element using the given method.
- *
- * @param activity The activity the element belongs to
- * @param id The resource id of the element
- * @return The first matching element on the current context, or null if not found.
- */
- Element findElement(Activity activity, int id);
-
- /**
- * Sets up scroll handling so that data is received from the extension.
- */
- void setupScrollHandling();
-
- int getPageHeight();
- int getScrollHeight();
- int getHeight();
- int getGeckoTop();
- int getGeckoLeft();
- int getGeckoWidth();
- int getGeckoHeight();
-
- void startFrameRecording();
- int stopFrameRecording();
-
- void startCheckerboardRecording();
- float stopCheckerboardRecording();
-
- /**
- * Get a copy of the painted content region.
- * @return A 2-D array of pixels (indexed by y, then x). The pixels
- * are in ARGB-8888 format.
- */
- PaintedSurface getPaintedSurface();
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Element.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Element.java
deleted file mode 100644
index 97610ff32..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/Element.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-/**
- * Element provides access to a specific UI view (android.view.View).
- * See also Driver.findElement().
- */
-public interface Element {
-
- /** Click on the element's view. Returns true on success. */
- boolean click();
-
- /** Returns true if the element is currently displayed */
- boolean isDisplayed();
-
- /**
- * Returns the text currently displayed on the element, or null
- * if the text cannot be retrieved.
- */
- String getText();
-
- /** Returns the view ID */
- Integer getId();
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecInstrumentationTestRunner.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecInstrumentationTestRunner.java
deleted file mode 100644
index 6bcb4e102..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecInstrumentationTestRunner.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.PowerManager;
-import android.test.InstrumentationTestRunner;
-import android.util.Log;
-
-import static android.os.PowerManager.ACQUIRE_CAUSES_WAKEUP;
-import static android.os.PowerManager.FULL_WAKE_LOCK;
-import static android.os.PowerManager.ON_AFTER_RELEASE;
-
-public class FennecInstrumentationTestRunner extends InstrumentationTestRunner {
- private static Bundle sArguments;
- private PowerManager.WakeLock wakeLock;
- private KeyguardManager.KeyguardLock keyguardLock;
-
- @Override
- public void onCreate(Bundle arguments) {
- sArguments = arguments;
- if (sArguments == null) {
- Log.e("Robocop", "FennecInstrumentationTestRunner.onCreate got null bundle");
- }
- super.onCreate(arguments);
- }
-
- // unfortunately we have to make this static because test classes that don't extend
- // from ActivityInstrumentationTestCase2 can't get a reference to this class.
- public static Bundle getFennecArguments() {
- if (sArguments == null) {
- Log.e("Robocop", "FennecInstrumentationTestCase.getFennecArguments returns null bundle");
- }
- return sArguments;
- }
-
- @Override
- public void onStart() {
- final Context context = getContext(); // The Robocop package itself has DISABLE_KEYGUARD and WAKE_LOCK.
- if (context != null) {
- try {
- String name = FennecInstrumentationTestRunner.class.getSimpleName();
- // Unlock the device so that the tests can input keystrokes.
- final KeyguardManager keyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
- // Deprecated in favour of window flags, which aren't appropriate here.
- keyguardLock = keyguard.newKeyguardLock(name);
- keyguardLock.disableKeyguard();
-
- // Wake up the screen.
- final PowerManager power = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- wakeLock = power.newWakeLock(FULL_WAKE_LOCK | ACQUIRE_CAUSES_WAKEUP | ON_AFTER_RELEASE, name);
- wakeLock.acquire();
- } catch (SecurityException e) {
- Log.w("GeckoInstTestRunner", "Got SecurityException: not disabling keyguard and not taking wakelock.");
- }
- } else {
- Log.w("GeckoInstTestRunner", "Application target context is null: not disabling keyguard and not taking wakelock.");
- }
-
- super.onStart();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (wakeLock != null) {
- wakeLock.release();
- }
- if (keyguardLock != null) {
- // Deprecated in favour of window flags, which aren't appropriate here.
- keyguardLock.reenableKeyguard();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecMochitestAssert.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecMochitestAssert.java
deleted file mode 100644
index cb7c3c464..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecMochitestAssert.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.Writer;
-
-import android.os.SystemClock;
-
-public class FennecMochitestAssert implements Assert {
- // Internal state variables to make logging match up with existing mochitests
- private int mPassed = 0;
- private int mFailed = 0;
- private int mTodo = 0;
-
- // Used to write the first line of the test file
- private boolean mLogStarted = false;
-
- // Used to write the test-start/test-end log lines
- private String mLogTestName = "";
-
- // Measure the time it takes to run test case
- private long mStartTime = 0;
-
- // Structured logger
- private StructuredLogger mLogger;
-
- /** Write information to a logfile and logcat */
- public void dumpLog(String message) {
- mLogger.info(message);
- }
-
- public void dumpLog(String message, Throwable t) {
- Writer sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- t.printStackTrace(pw);
- mLogger.error(message + " - " + sw.toString());
- }
-
- /** Write information to a logfile and logcat */
- static class DumpLogCallback implements StructuredLogger.LoggerCallback {
- public void call(String output) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.INFO, output);
- }
- }
-
-
- public FennecMochitestAssert() {
- mLogger = new StructuredLogger("robocop", new DumpLogCallback());
- }
-
- /** Set the filename used for dumpLog. */
- public void setLogFile(String filename) {
- FennecNativeDriver.setLogFile(filename);
-
- String message;
- if (!mLogStarted) {
- mLogger.info("SimpleTest START");
- mLogStarted = true;
- }
-
- if (mLogTestName != "") {
- long diff = SystemClock.uptimeMillis() - mStartTime;
- mLogger.testEnd(mLogTestName, "OK", "finished in " + diff + "ms");
- }
- }
-
- public void setTestName(String testName) {
- String[] nameParts = testName.split("\\.");
- mLogTestName = nameParts[nameParts.length - 1];
- mStartTime = SystemClock.uptimeMillis();
-
- mLogger.testStart(mLogTestName);
- }
-
- class testInfo {
- public boolean mResult;
- public String mName;
- public String mDiag;
- public boolean mTodo;
- public boolean mInfo;
- public testInfo(boolean r, String n, String d, boolean t, boolean i) {
- mResult = r;
- mName = n;
- mDiag = d;
- mTodo = t;
- mInfo = i;
- }
-
- }
-
- /** Used to log a subtest's result.
- * test represents the subtest (an assertion).
- * passStatus and passExpected are the actual status and the expected status if the assertion is true.
- * failStatus and failExpected are the actual status and the expected status otherwise.
- */
- private void _logMochitestResult(testInfo test, String passStatus, String passExpected, String failStatus, String failExpected) {
- boolean isError = true;
- if (test.mResult || test.mTodo) {
- isError = false;
- }
- if (test.mResult)
- {
- mLogger.testStatus(mLogTestName, test.mName, passStatus, passExpected, test.mDiag);
- } else {
- mLogger.testStatus(mLogTestName, test.mName, failStatus, failExpected, test.mDiag);
- }
-
- if (test.mInfo) {
- // do not count TEST-INFO messages
- } else if (test.mTodo) {
- mTodo++;
- } else if (isError) {
- mFailed++;
- } else {
- mPassed++;
- }
- if (isError) {
- String message = "TEST-UNEXPECTED-" + failStatus + " | " + mLogTestName + " | "
- + test.mName + " - " + test.mDiag;
- junit.framework.Assert.fail(message);
- }
- }
-
- public void endTest() {
- String message;
-
- if (mLogTestName != "") {
- long diff = SystemClock.uptimeMillis() - mStartTime;
- mLogger.testEnd(mLogTestName, "OK", "finished in " + diff + "ms");
- }
-
- mLogger.info("TEST-START | Shutdown");
- mLogger.info("Passed: " + Integer.toString(mPassed));
- mLogger.info("Failed: " + Integer.toString(mFailed));
- mLogger.info("Todo: " + Integer.toString(mTodo));
- mLogger.info("SimpleTest FINISHED");
- }
-
- public void ok(boolean condition, String name, String diag) {
- testInfo test = new testInfo(condition, name, diag, false, false);
- _logMochitestResult(test, "PASS", "PASS", "FAIL", "PASS");
- }
-
- public void is(Object actual, Object expected, String name) {
- boolean pass = checkObjectsEqual(actual, expected);
- ok(pass, name, getEqualString(actual, expected, pass));
- }
-
- public void isnot(Object actual, Object notExpected, String name) {
- boolean pass = checkObjectsNotEqual(actual, notExpected);
- ok(pass, name, getNotEqualString(actual, notExpected, pass));
- }
-
- public void ispixel(int actual, int r, int g, int b, String name) {
- int aAlpha = ((actual >> 24) & 0xFF);
- int aR = ((actual >> 16) & 0xFF);
- int aG = ((actual >> 8) & 0xFF);
- int aB = (actual & 0xFF);
- boolean pass = checkPixel(actual, r, g, b);
- ok(pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (pass ? " " : " not") + " close enough to expected rgb(" + r + "," + g + "," + b + ")");
- }
-
- public void isnotpixel(int actual, int r, int g, int b, String name) {
- int aAlpha = ((actual >> 24) & 0xFF);
- int aR = ((actual >> 16) & 0xFF);
- int aG = ((actual >> 8) & 0xFF);
- int aB = (actual & 0xFF);
- boolean pass = checkPixel(actual, r, g, b);
- ok(!pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (!pass ? " is" : " is not") + " different enough from rgb(" + r + "," + g + "," + b + ")");
- }
-
- private boolean checkPixel(int actual, int r, int g, int b) {
- // When we read GL pixels the GPU has already processed them and they
- // are usually off by a little bit. For example a CSS-color pixel of color #64FFF5
- // was turned into #63FFF7 when it came out of glReadPixels. So in order to compare
- // against the expected value, we use a little fuzz factor. For the alpha we just
- // make sure it is always 0xFF. There is also bug 691354 which crops up every so
- // often just to make our lives difficult. However the individual color components
- // should never be off by more than 8.
- int aAlpha = ((actual >> 24) & 0xFF);
- int aR = ((actual >> 16) & 0xFF);
- int aG = ((actual >> 8) & 0xFF);
- int aB = (actual & 0xFF);
- boolean pass = (aAlpha == 0xFF) /* alpha */
- && (Math.abs(aR - r) <= 8) /* red */
- && (Math.abs(aG - g) <= 8) /* green */
- && (Math.abs(aB - b) <= 8); /* blue */
- if (pass) {
- return true;
- } else {
- return false;
- }
- }
-
- public void todo(boolean condition, String name, String diag) {
- testInfo test = new testInfo(condition, name, diag, true, false);
- _logMochitestResult(test, "PASS", "FAIL", "FAIL", "FAIL");
- }
-
- public void todo_is(Object actual, Object expected, String name) {
- boolean pass = checkObjectsEqual(actual, expected);
- todo(pass, name, getEqualString(actual, expected, pass));
- }
-
- public void todo_isnot(Object actual, Object notExpected, String name) {
- boolean pass = checkObjectsNotEqual(actual, notExpected);
- todo(pass, name, getNotEqualString(actual, notExpected, pass));
- }
-
- private boolean checkObjectsEqual(Object a, Object b) {
- if (a == null || b == null) {
- if (a == null && b == null) {
- return true;
- }
- return false;
- } else {
- return a.equals(b);
- }
- }
-
- private String getEqualString(Object a, Object b, boolean pass) {
- if (pass) {
- return a + " should equal " + b;
- }
- return "got " + a + ", expected " + b;
- }
-
- private boolean checkObjectsNotEqual(Object a, Object b) {
- if (a == null || b == null) {
- if ((a == null && b != null) || (a != null && b == null)) {
- return true;
- } else {
- return false;
- }
- } else {
- return !a.equals(b);
- }
- }
-
- private String getNotEqualString(Object a, Object b, boolean pass) {
- if(pass) {
- return a + " should not equal " + b;
- }
- return "didn't expect " + a + ", but got it";
- }
-
- public void info(String name, String message) {
- mLogger.info(name + " | " + message);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeActions.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeActions.java
deleted file mode 100644
index 7faccdf43..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeActions.java
+++ /dev/null
@@ -1,482 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import java.util.ArrayList;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-import org.json.JSONObject;
-import org.mozilla.gecko.FennecNativeDriver.LogLevel;
-import org.mozilla.gecko.gfx.LayerView;
-import org.mozilla.gecko.gfx.LayerView.DrawListener;
-import org.mozilla.gecko.mozglue.GeckoLoader;
-import org.mozilla.gecko.sqlite.SQLiteBridge;
-import org.mozilla.gecko.util.GeckoEventListener;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.database.Cursor;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.view.KeyEvent;
-
-import com.robotium.solo.Solo;
-
-public class FennecNativeActions implements Actions {
- private static final String LOGTAG = "FennecNativeActions";
-
- private Solo mSolo;
- private Instrumentation mInstr;
- private Assert mAsserter;
-
- public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation, Assert asserter) {
- mSolo = robocop;
- mInstr = instrumentation;
- mAsserter = asserter;
-
- GeckoLoader.loadSQLiteLibs(activity, activity.getApplication().getPackageResourcePath());
- }
-
- class GeckoEventExpecter implements RepeatedEventExpecter {
- private static final int MAX_WAIT_MS = 180000;
-
- private volatile boolean mIsRegistered;
-
- private final String mGeckoEvent;
- private final GeckoEventListener mListener;
-
- private volatile boolean mEventEverReceived;
- private String mEventData;
- private BlockingQueue<String> mEventDataQueue;
-
- GeckoEventExpecter(final String geckoEvent) {
- if (TextUtils.isEmpty(geckoEvent)) {
- throw new IllegalArgumentException("geckoEvent must not be empty");
- }
-
- mGeckoEvent = geckoEvent;
- mEventDataQueue = new LinkedBlockingQueue<String>();
-
- final GeckoEventExpecter expecter = this;
- mListener = new GeckoEventListener() {
- @Override
- public void handleMessage(final String event, final JSONObject message) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
- "handleMessage called for: " + event + "; expecting: " + mGeckoEvent);
- mAsserter.is(event, mGeckoEvent, "Given message occurred for registered event: " + message);
-
- expecter.notifyOfEvent(message);
- }
- };
-
- EventDispatcher.getInstance().registerGeckoThreadListener(mListener, mGeckoEvent);
- mIsRegistered = true;
- }
-
- public void blockForEvent() {
- blockForEvent(MAX_WAIT_MS, true);
- }
-
- public void blockForEvent(long millis, boolean failOnTimeout) {
- if (!mIsRegistered) {
- throw new IllegalStateException("listener not registered");
- }
-
- try {
- mEventData = mEventDataQueue.poll(millis, TimeUnit.MILLISECONDS);
- } catch (InterruptedException ie) {
- FennecNativeDriver.log(LogLevel.ERROR, ie);
- }
- if (mEventData == null) {
- if (failOnTimeout) {
- FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
- mAsserter.ok(false, "GeckoEventExpecter",
- "blockForEvent timeout: "+mGeckoEvent);
- } else {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
- "blockForEvent timeout: "+mGeckoEvent);
- }
- } else {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
- "unblocked on expecter for " + mGeckoEvent);
- }
- }
-
- public void blockUntilClear(long millis) {
- if (!mIsRegistered) {
- throw new IllegalStateException("listener not registered");
- }
- if (millis <= 0) {
- throw new IllegalArgumentException("millis must be > 0");
- }
-
- // wait for at least one event
- try {
- mEventData = mEventDataQueue.poll(MAX_WAIT_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException ie) {
- FennecNativeDriver.log(LogLevel.ERROR, ie);
- }
- if (mEventData == null) {
- FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
- mAsserter.ok(false, "GeckoEventExpecter", "blockUntilClear timeout");
- return;
- }
- // now wait for a period of millis where we don't get an event
- while (true) {
- try {
- mEventData = mEventDataQueue.poll(millis, TimeUnit.MILLISECONDS);
- } catch (InterruptedException ie) {
- FennecNativeDriver.log(LogLevel.INFO, ie);
- }
- if (mEventData == null) {
- // success
- break;
- }
- }
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
- "unblocked on expecter for " + mGeckoEvent);
- }
-
- public String blockForEventData() {
- blockForEvent();
- return mEventData;
- }
-
- public String blockForEventDataWithTimeout(long millis) {
- blockForEvent(millis, false);
- return mEventData;
- }
-
- public void unregisterListener() {
- if (!mIsRegistered) {
- throw new IllegalStateException("listener not registered");
- }
-
- FennecNativeDriver.log(LogLevel.INFO,
- "EventExpecter: no longer listening for " + mGeckoEvent);
-
- EventDispatcher.getInstance().unregisterGeckoThreadListener(mListener, mGeckoEvent);
- mIsRegistered = false;
- }
-
- public boolean eventReceived() {
- return mEventEverReceived;
- }
-
- void notifyOfEvent(final JSONObject message) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
- "received event " + mGeckoEvent);
-
- mEventEverReceived = true;
-
- try {
- mEventDataQueue.put(message.toString());
- } catch (InterruptedException e) {
- FennecNativeDriver.log(LogLevel.ERROR,
- "EventExpecter dropped event: " + message.toString(), e);
- }
- }
- }
-
- public RepeatedEventExpecter expectGeckoEvent(final String geckoEvent) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG, "waiting for " + geckoEvent);
- return new GeckoEventExpecter(geckoEvent);
- }
-
- public void sendGeckoEvent(final String geckoEvent, final String data) {
- GeckoAppShell.notifyObservers(geckoEvent, data);
- }
-
- public static final class PrefProxy implements PrefsHelper.PrefHandler, PrefWaiter {
- public static final int MAX_WAIT_MS = 180000;
-
- /* package */ final PrefHandlerBase target;
- private final String[] expectedPrefs;
- private final ArrayList<String> seenPrefs = new ArrayList<>();
- private boolean finished = false;
-
- /* package */ PrefProxy(PrefHandlerBase target, String[] expectedPrefs, Assert asserter) {
- this.target = target;
- this.expectedPrefs = expectedPrefs;
- target.asserter = asserter;
- }
-
- @Override // PrefsHelper.PrefHandler
- public void prefValue(String pref, boolean value) {
- target.prefValue(pref, value);
- seenPrefs.add(pref);
- }
-
- @Override // PrefsHelper.PrefHandler
- public void prefValue(String pref, int value) {
- target.prefValue(pref, value);
- seenPrefs.add(pref);
- }
-
- @Override // PrefsHelper.PrefHandler
- public void prefValue(String pref, String value) {
- target.prefValue(pref, value);
- seenPrefs.add(pref);
- }
-
- @Override // PrefsHelper.PrefHandler
- public synchronized void finish() {
- target.finish();
-
- for (String pref : expectedPrefs) {
- target.asserter.ok(seenPrefs.remove(pref), "Checking pref was seen", pref);
- }
- target.asserter.ok(seenPrefs.isEmpty(), "Checking unexpected prefs",
- TextUtils.join(", ", seenPrefs));
-
- finished = true;
- this.notifyAll();
- }
-
- @Override // PrefWaiter
- public synchronized boolean isFinished() {
- return finished;
- }
-
- @Override // PrefWaiter
- public void waitForFinish() {
- waitForFinish(MAX_WAIT_MS, /* failOnTimeout */ true);
- }
-
- @Override // PrefWaiter
- public synchronized void waitForFinish(long timeoutMillis, boolean failOnTimeout) {
- final long startTime = System.nanoTime();
- while (!finished) {
- if (System.nanoTime() - startTime
- >= timeoutMillis * 1e6 /* ns per ms */) {
- final String prefsLog = "expected " +
- TextUtils.join(", ", expectedPrefs) + "; got " +
- TextUtils.join(", ", seenPrefs.toArray()) + ".";
- if (failOnTimeout) {
- FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
- target.asserter.ok(false, "Timeout waiting for pref", prefsLog);
- } else {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
- "Pref timeout (" + prefsLog + ")");
- }
- break;
- }
- try {
- this.wait(1000); // Wait for 1 second at a time.
- } catch (final InterruptedException e) {
- // Attempt waiting again.
- }
- }
- finished = false;
- }
- }
-
- @Override // Actions
- public PrefWaiter getPrefs(String[] prefNames, PrefHandlerBase handler) {
- final PrefProxy proxy = new PrefProxy(handler, prefNames, mAsserter);
- PrefsHelper.getPrefs(prefNames, proxy);
- return proxy;
- }
-
- @Override // Actions
- public void setPref(String pref, Object value, boolean flush) {
- PrefsHelper.setPref(pref, value, flush);
- }
-
- @Override // Actions
- public PrefWaiter addPrefsObserver(String[] prefNames, PrefHandlerBase handler) {
- final PrefProxy proxy = new PrefProxy(handler, prefNames, mAsserter);
- PrefsHelper.addObserver(prefNames, proxy);
- return proxy;
- }
-
- @Override // Actions
- public void removePrefsObserver(PrefWaiter proxy) {
- PrefsHelper.removeObserver((PrefProxy) proxy);
- }
-
- class PaintExpecter implements RepeatedEventExpecter {
- private static final int MAX_WAIT_MS = 90000;
-
- private boolean mPaintDone;
- private boolean mListening;
-
- private final LayerView mLayerView;
- private final DrawListener mDrawListener;
-
- PaintExpecter() {
- final PaintExpecter expecter = this;
- mLayerView = GeckoAppShell.getLayerView();
- mDrawListener = new DrawListener() {
- @Override
- public void drawFinished() {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
- "Received drawFinished notification");
- expecter.notifyOfEvent();
- }
- };
- mLayerView.addDrawListener(mDrawListener);
- mListening = true;
- }
-
- private synchronized void notifyOfEvent() {
- mPaintDone = true;
- this.notifyAll();
- }
-
- public synchronized void blockForEvent(long millis, boolean failOnTimeout) {
- if (!mListening) {
- throw new IllegalStateException("draw listener not registered");
- }
- long startTime = SystemClock.uptimeMillis();
- long endTime = 0;
- while (!mPaintDone) {
- try {
- this.wait(millis);
- } catch (InterruptedException ie) {
- FennecNativeDriver.log(LogLevel.ERROR, ie);
- break;
- }
- endTime = SystemClock.uptimeMillis();
- if (!mPaintDone && (endTime - startTime >= millis)) {
- if (failOnTimeout) {
- FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
- mAsserter.ok(false, "PaintExpecter", "blockForEvent timeout");
- }
- return;
- }
- }
- }
-
- public synchronized void blockForEvent() {
- blockForEvent(MAX_WAIT_MS, true);
- }
-
- public synchronized String blockForEventData() {
- blockForEvent();
- return null;
- }
-
- public synchronized String blockForEventDataWithTimeout(long millis) {
- blockForEvent(millis, false);
- return null;
- }
-
- public synchronized boolean eventReceived() {
- return mPaintDone;
- }
-
- public synchronized void blockUntilClear(long millis) {
- if (!mListening) {
- throw new IllegalStateException("draw listener not registered");
- }
- if (millis <= 0) {
- throw new IllegalArgumentException("millis must be > 0");
- }
- // wait for at least one event
- long startTime = SystemClock.uptimeMillis();
- long endTime = 0;
- while (!mPaintDone) {
- try {
- this.wait(MAX_WAIT_MS);
- } catch (InterruptedException ie) {
- FennecNativeDriver.log(LogLevel.ERROR, ie);
- break;
- }
- endTime = SystemClock.uptimeMillis();
- if (!mPaintDone && (endTime - startTime >= MAX_WAIT_MS)) {
- FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
- mAsserter.ok(false, "PaintExpecter", "blockUtilClear timeout");
- return;
- }
- }
- // now wait for a period of millis where we don't get an event
- startTime = SystemClock.uptimeMillis();
- while (true) {
- try {
- this.wait(millis);
- } catch (InterruptedException ie) {
- FennecNativeDriver.log(LogLevel.ERROR, ie);
- break;
- }
- endTime = SystemClock.uptimeMillis();
- if (endTime - startTime >= millis) {
- // success
- break;
- }
-
- // we got a notify() before we could wait long enough, so we need to start over
- // Note, moving the goal post might have us race against a "drawFinished" flood
- startTime = endTime;
- }
- }
-
- public synchronized void unregisterListener() {
- if (!mListening) {
- throw new IllegalStateException("listener not registered");
- }
-
- FennecNativeDriver.log(LogLevel.INFO,
- "PaintExpecter: no longer listening for events");
- mLayerView.removeDrawListener(mDrawListener);
- mListening = false;
- }
- }
-
- public RepeatedEventExpecter expectPaint() {
- return new PaintExpecter();
- }
-
- public void sendSpecialKey(SpecialKey button) {
- switch(button) {
- case DOWN:
- sendKeyCode(Solo.DOWN);
- break;
- case UP:
- sendKeyCode(Solo.UP);
- break;
- case LEFT:
- sendKeyCode(Solo.LEFT);
- break;
- case RIGHT:
- sendKeyCode(Solo.RIGHT);
- break;
- case ENTER:
- sendKeyCode(Solo.ENTER);
- break;
- case MENU:
- sendKeyCode(Solo.MENU);
- break;
- case DELETE:
- sendKeyCode(Solo.DELETE);
- break;
- default:
- mAsserter.ok(false, "sendSpecialKey", "Unknown SpecialKey " + button);
- break;
- }
- }
-
- public void sendKeyCode(int keyCode) {
- if (keyCode <= 0 || keyCode > KeyEvent.getMaxKeyCode()) {
- mAsserter.ok(false, "sendKeyCode", "Unknown keyCode " + keyCode);
- }
- mSolo.sendKey(keyCode);
- }
-
- @Override
- public void sendKeys(String input) {
- mInstr.sendStringSync(input);
- }
-
- public void drag(int startingX, int endingX, int startingY, int endingY) {
- mSolo.drag(startingX, endingX, startingY, endingY, 10);
- }
-
- public Cursor querySql(final String dbPath, final String sql) {
- return new SQLiteBridge(dbPath).rawQuery(sql, null);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeDriver.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeDriver.java
deleted file mode 100644
index 3931b7e20..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeDriver.java
+++ /dev/null
@@ -1,392 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.IntBuffer;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.gecko.gfx.LayerView;
-import org.mozilla.gecko.gfx.PanningPerfAPI;
-import org.mozilla.gecko.util.GeckoEventListener;
-
-import android.app.Activity;
-import android.util.Log;
-import android.view.View;
-
-import com.robotium.solo.Solo;
-
-public class FennecNativeDriver implements Driver {
- private static final int FRAME_TIME_THRESHOLD = 25; // allow 25ms per frame (40fps)
-
- private final Activity mActivity;
- private final Solo mSolo;
- private final String mRootPath;
-
- private static String mLogFile;
- private static LogLevel mLogLevel = LogLevel.INFO;
-
- public enum LogLevel {
- DEBUG(1),
- INFO(2),
- WARN(3),
- ERROR(4);
-
- private final int mValue;
- LogLevel(int value) {
- mValue = value;
- }
- public boolean isEnabled(LogLevel configuredLevel) {
- return mValue >= configuredLevel.getValue();
- }
- private int getValue() {
- return mValue;
- }
- }
-
- public FennecNativeDriver(Activity activity, Solo robocop, String rootPath) {
- mActivity = activity;
- mSolo = robocop;
- mRootPath = rootPath;
- }
-
- //Information on the location of the Gecko Frame.
- private boolean mGeckoInfo = false;
- private int mGeckoTop = 100;
- private int mGeckoLeft = 0;
- private int mGeckoHeight= 700;
- private int mGeckoWidth = 1024;
-
- private void getGeckoInfo() {
- View geckoLayout = mActivity.findViewById(R.id.gecko_layout);
- if (geckoLayout != null) {
- int[] pos = new int[2];
- geckoLayout.getLocationOnScreen(pos);
- mGeckoTop = pos[1];
- mGeckoLeft = pos[0];
- mGeckoWidth = geckoLayout.getWidth();
- mGeckoHeight = geckoLayout.getHeight();
- mGeckoInfo = true;
- } else {
- throw new RoboCopException("Unable to find view gecko_layout");
- }
- }
-
- @Override
- public int getGeckoTop() {
- if (!mGeckoInfo) {
- getGeckoInfo();
- }
- return mGeckoTop;
- }
-
- @Override
- public int getGeckoLeft() {
- if (!mGeckoInfo) {
- getGeckoInfo();
- }
- return mGeckoLeft;
- }
-
- @Override
- public int getGeckoHeight() {
- if (!mGeckoInfo) {
- getGeckoInfo();
- }
- return mGeckoHeight;
- }
-
- @Override
- public int getGeckoWidth() {
- if (!mGeckoInfo) {
- getGeckoInfo();
- }
- return mGeckoWidth;
- }
-
- /** Find the element with given id.
- *
- * @return An Element representing the view, or null if the view is not found.
- */
- @Override
- public Element findElement(Activity activity, int id) {
- return new FennecNativeElement(id, activity);
- }
-
- @Override
- public void startFrameRecording() {
- PanningPerfAPI.startFrameTimeRecording();
- }
-
- @Override
- public int stopFrameRecording() {
- final List<Long> frames = PanningPerfAPI.stopFrameTimeRecording();
- int badness = 0;
- for (int i = 1; i < frames.size(); i++) {
- long frameTime = frames.get(i) - frames.get(i - 1);
- int delay = (int)(frameTime - FRAME_TIME_THRESHOLD);
- // for each frame we miss, add the square of the delay. This
- // makes large delays much worse than small delays.
- if (delay > 0) {
- badness += delay * delay;
- }
- }
-
- // Don't do any averaging of the numbers because really we want to
- // know how bad the jank was at its worst
- return badness;
- }
-
- @Override
- public void startCheckerboardRecording() {
- PanningPerfAPI.startCheckerboardRecording();
- }
-
- @Override
- public float stopCheckerboardRecording() {
- final List<Float> checkerboard = PanningPerfAPI.stopCheckerboardRecording();
- float total = 0;
- for (float val : checkerboard) {
- total += val;
- }
- return total * 100.0f;
- }
-
- private LayerView getSurfaceView() {
- final LayerView layerView = mSolo.getView(LayerView.class, 0);
-
- if (layerView == null) {
- log(LogLevel.WARN, "getSurfaceView could not find LayerView");
- for (final View v : mSolo.getViews()) {
- log(LogLevel.WARN, " View: " + v);
- }
- }
- return layerView;
- }
-
- @Override
- public PaintedSurface getPaintedSurface() {
- final LayerView view = getSurfaceView();
- if (view == null) {
- return null;
- }
-
- final IntBuffer pixelBuffer = view.getPixels();
-
- // now we need to (1) flip the image, because GL likes to do things up-side-down,
- // and (2) rearrange the bits from AGBR-8888 to ARGB-8888.
- int w = view.getWidth();
- int h = view.getHeight();
- pixelBuffer.position(0);
- String mapFile = mRootPath + "/pixels.map";
-
- FileOutputStream fos = null;
- BufferedOutputStream bos = null;
- DataOutputStream dos = null;
- try {
- fos = new FileOutputStream(mapFile);
- bos = new BufferedOutputStream(fos);
- dos = new DataOutputStream(bos);
-
- for (int y = h - 1; y >= 0; y--) {
- for (int x = 0; x < w; x++) {
- int agbr = pixelBuffer.get();
- dos.writeInt((agbr & 0xFF00FF00) | ((agbr >> 16) & 0x000000FF) | ((agbr << 16) & 0x00FF0000));
- }
- }
- } catch (IOException e) {
- throw new RoboCopException("exception with pixel writer on file: " + mapFile);
- } finally {
- try {
- if (dos != null) {
- dos.flush();
- dos.close();
- }
- // closing dos automatically closes bos
- if (fos != null) {
- fos.flush();
- fos.close();
- }
- } catch (IOException e) {
- log(LogLevel.ERROR, e);
- throw new RoboCopException("exception closing pixel writer on file: " + mapFile);
- }
- }
- return new PaintedSurface(mapFile, w, h);
- }
-
- public int mHeight=0;
- public int mScrollHeight=0;
- public int mPageHeight=10;
-
- @Override
- public int getScrollHeight() {
- return mScrollHeight;
- }
- @Override
- public int getPageHeight() {
- return mPageHeight;
- }
- @Override
- public int getHeight() {
- return mHeight;
- }
-
- @Override
- public void setupScrollHandling() {
- GeckoApp.getEventDispatcher().registerGeckoThreadListener(new GeckoEventListener() {
- @Override
- public void handleMessage(final String event, final JSONObject message) {
- try {
- mScrollHeight = message.getInt("y");
- mHeight = message.getInt("cheight");
- // We don't want a height of 0. That means it's a bad response.
- if (mHeight > 0) {
- mPageHeight = message.getInt("height");
- }
- } catch (JSONException e) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.WARN,
- "WARNING: ScrollReceived, but message does not contain " +
- "expected fields: " + e);
- }
- }
- }, "robocop:scroll");
- }
-
- /**
- * Takes a filename, loads the file, and returns a string version of the entire file.
- */
- public static String getFile(String filename)
- {
- StringBuilder text = new StringBuilder();
-
- BufferedReader br = null;
- try {
- br = new BufferedReader(new FileReader(filename));
- String line;
-
- while ((line = br.readLine()) != null) {
- text.append(line);
- text.append('\n');
- }
- } catch (IOException e) {
- log(LogLevel.ERROR, e);
- } finally {
- try {
- if (br != null) {
- br.close();
- }
- } catch (IOException e) {
- }
- }
- return text.toString();
- }
-
- /**
- * Takes a string of "key=value" pairs split by \n and creates a hash table.
- */
- public static Map<String, String> convertTextToTable(String data)
- {
- HashMap<String, String> retVal = new HashMap<String, String>();
-
- String[] lines = data.split("\n");
- for (int i = 0; i < lines.length; i++) {
- String[] parts = lines[i].split("=", 2);
- retVal.put(parts[0].trim(), parts[1].trim());
- }
- return retVal;
- }
-
- public static void logAllStackTraces(LogLevel level) {
- StringBuffer sb = new StringBuffer();
- sb.append("Dumping ALL the threads!\n");
- Map<Thread, StackTraceElement[]> allStacks = Thread.getAllStackTraces();
- for (Thread t : allStacks.keySet()) {
- sb.append(t.toString()).append('\n');
- for (StackTraceElement ste : allStacks.get(t)) {
- sb.append(ste.toString()).append('\n');
- }
- sb.append('\n');
- }
- log(level, sb.toString());
- }
-
- /**
- * Set the filename used for logging. If the file already exists, delete it
- * as a safe-guard against accidentally appending to an old log file.
- */
- public static void setLogFile(String filename) {
- mLogFile = filename;
- File file = new File(mLogFile);
- if (file.exists()) {
- file.delete();
- }
- }
-
- public static void setLogLevel(LogLevel level) {
- mLogLevel = level;
- }
-
- public static void log(LogLevel level, String message) {
- log(level, message, null);
- }
-
- public static void log(LogLevel level, Throwable t) {
- log(level, null, t);
- }
-
- public static void log(LogLevel level, String message, Throwable t) {
- if (mLogFile == null) {
- throw new RuntimeException("No log file specified!");
- }
-
- if (level.isEnabled(mLogLevel)) {
- PrintWriter pw = null;
- try {
- pw = new PrintWriter(new FileWriter(mLogFile, true));
- if (message != null) {
- pw.println(message);
- }
- if (t != null) {
- t.printStackTrace(pw);
- }
- } catch (IOException ioe) {
- Log.e("Robocop", "exception with file writer on: " + mLogFile);
- } finally {
- if (pw != null) {
- pw.close();
- }
- }
-
- // PrintWriter doesn't throw IOE but sets an error flag instead,
- // so check for that
- if (pw != null && pw.checkError()) {
- Log.e("Robocop", "exception with file writer on: " + mLogFile);
- }
- }
-
- if (level == LogLevel.INFO) {
- Log.i("Robocop", message, t);
- } else if (level == LogLevel.DEBUG) {
- Log.d("Robocop", message, t);
- } else if (level == LogLevel.WARN) {
- Log.w("Robocop", message, t);
- } else if (level == LogLevel.ERROR) {
- Log.e("Robocop", message, t);
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeElement.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeElement.java
deleted file mode 100644
index 2a24344fd..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecNativeElement.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import android.app.Activity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.EditText;
-import android.widget.TextSwitcher;
-import android.widget.TextView;
-
-public class FennecNativeElement implements Element {
- private final Activity mActivity;
- private final Integer mId;
- private final String mName;
-
- public FennecNativeElement(Integer id, Activity activity) {
- mId = id;
- mActivity = activity;
- mName = activity.getResources().getResourceName(id);
- }
-
- @Override
- public Integer getId() {
- return mId;
- }
-
- private boolean mClickSuccess;
-
- @Override
- public boolean click() {
- mClickSuccess = false;
- RobocopUtils.runOnUiThreadSync(mActivity,
- new Runnable() {
- @Override
- public void run() {
- View view = mActivity.findViewById(mId);
- if (view != null) {
- if (view.performClick()) {
- mClickSuccess = true;
- } else {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.WARN,
- "Robocop called click on an element with no listener " + mId + " " + mName);
- }
- } else {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR,
- "click: unable to find view " + mId + " " + mName);
- }
- }
- });
- return mClickSuccess;
- }
-
- private Object mText;
-
- @Override
- public String getText() {
- mText = null;
- RobocopUtils.runOnUiThreadSync(mActivity,
- new Runnable() {
- @Override
- public void run() {
- View v = mActivity.findViewById(mId);
- if (v instanceof EditText) {
- EditText et = (EditText)v;
- mText = et.getEditableText();
- } else if (v instanceof TextSwitcher) {
- TextSwitcher ts = (TextSwitcher)v;
- mText = ((TextView)ts.getCurrentView()).getText();
- } else if (v instanceof ViewGroup) {
- ViewGroup vg = (ViewGroup)v;
- for (int i = 0; i < vg.getChildCount(); i++) {
- if (vg.getChildAt(i) instanceof TextView) {
- mText = ((TextView)vg.getChildAt(i)).getText();
- }
- }
- } else if (v instanceof TextView) {
- mText = ((TextView)v).getText();
- } else if (v == null) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR,
- "getText: unable to find view " + mId + " " + mName);
- } else {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR,
- "getText: unhandled type for view " + mId + " " + mName);
- }
- } // end of run() method definition
- } // end of anonymous Runnable object instantiation
- );
- if (mText == null) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.WARN,
- "getText: Text is null for view " + mId + " " + mName);
- return null;
- }
- return mText.toString();
- }
-
- private boolean mDisplayed;
-
- @Override
- public boolean isDisplayed() {
- mDisplayed = false;
- RobocopUtils.runOnUiThreadSync(mActivity,
- new Runnable() {
- @Override
- public void run() {
- View view = mActivity.findViewById(mId);
- if (view != null) {
- mDisplayed = true;
- }
- }
- });
- return mDisplayed;
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecTalosAssert.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecTalosAssert.java
deleted file mode 100644
index 862f66777..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/FennecTalosAssert.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-
-public class FennecTalosAssert implements Assert {
-
- public FennecTalosAssert() { }
-
- /**
- * Write information to a logfile and logcat
- */
- public void dumpLog(String message) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.INFO, message);
- }
-
- /** Write information to a logfile and logcat */
- public void dumpLog(String message, Throwable t) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.INFO, message, t);
- }
-
- /**
- * Set the filename used for dumpLog.
- */
- public void setLogFile(String filename) {
- FennecNativeDriver.setLogFile(filename);
- }
-
- public void setTestName(String testName) { }
-
- public void endTest() { }
-
- public void ok(boolean condition, String name, String diag) {
- if (!condition) {
- dumpLog("__FAIL" + name + ": " + diag + "__FAIL");
- }
- }
-
- public void is(Object actual, Object expected, String name) {
- boolean pass = (actual == null ? expected == null : actual.equals(expected));
- ok(pass, name, "got " + actual + ", expected " + expected);
- }
-
- public void isnot(Object actual, Object notExpected, String name) {
- boolean fail = (actual == null ? notExpected == null : actual.equals(notExpected));
- ok(!fail, name, "got " + actual + ", expected not " + notExpected);
- }
-
- public void ispixel(int actual, int r, int g, int b, String name) {
- throw new UnsupportedOperationException();
- }
-
- public void isnotpixel(int actual, int r, int g, int b, String name) {
- throw new UnsupportedOperationException();
- }
-
- public void todo(boolean condition, String name, String diag) {
- throw new UnsupportedOperationException();
- }
-
- public void todo_is(Object actual, Object expected, String name) {
- throw new UnsupportedOperationException();
- }
-
- public void todo_isnot(Object actual, Object notExpected, String name) {
- throw new UnsupportedOperationException();
- }
-
- public void info(String name, String message) {
- dumpLog(name + ": " + message);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/LaunchFennecWithConfigurationActivity.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/LaunchFennecWithConfigurationActivity.java
deleted file mode 100644
index 208b2c7bd..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/LaunchFennecWithConfigurationActivity.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import java.util.Map;
-
-import org.mozilla.gecko.tests.BaseRobocopTest;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-/**
- * An Activity that extracts Robocop settings from robotium.config, launches
- * Fennec with the Robocop testing parameters, and finishes itself.
- * <p>
- * This is intended to be used by local testers using |mach robocop --serve|.
- */
-public class LaunchFennecWithConfigurationActivity extends Activity {
- @Override
- public void onCreate(Bundle arguments) {
- super.onCreate(arguments);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- final String configFile = FennecNativeDriver.getFile(BaseRobocopTest.DEFAULT_ROOT_PATH + "/robotium.config");
- final Map<String, String> config = FennecNativeDriver.convertTextToTable(configFile);
- final Intent intent = BaseRobocopTest.createActivityIntent(config);
-
- intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
-
- this.finish();
- this.startActivity(intent);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/PaintedSurface.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/PaintedSurface.java
deleted file mode 100644
index 17d77b758..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/PaintedSurface.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-
-import android.graphics.Bitmap;
-import android.util.Base64;
-import android.util.Base64OutputStream;
-
-public class PaintedSurface {
- private String mFileName;
- private int mWidth;
- private int mHeight;
- private FileInputStream mPixelFile;
- private MappedByteBuffer mPixelBuffer;
-
- public PaintedSurface(String filename, int width, int height) {
- mFileName = filename;
- mWidth = width;
- mHeight = height;
-
- try {
- File f = new File(filename);
- int pixelSize = (int)f.length();
-
- mPixelFile = new FileInputStream(filename);
- mPixelBuffer = mPixelFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, pixelSize);
- } catch (java.io.FileNotFoundException e) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR, e);
- } catch (java.io.IOException e) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR, e);
- }
- }
-
- public final int getWidth() {
- return mWidth;
- }
-
- public final int getHeight() {
- return mHeight;
- }
-
- private int pixelAtIndex(int index) {
- int b1 = mPixelBuffer.get(index) & 0xFF;
- int b2 = mPixelBuffer.get(index + 1) & 0xFF;
- int b3 = mPixelBuffer.get(index + 2) & 0xFF;
- int b4 = mPixelBuffer.get(index + 3) & 0xFF;
- int value = (b1 << 24) + (b2 << 16) + (b3 << 8) + (b4 << 0);
- return value;
- }
-
- public final int getPixelAt(int x, int y) {
- if (mPixelBuffer == null) {
- throw new RoboCopException("Trying to access PaintedSurface with no active PixelBuffer");
- }
-
- if (x >= mWidth || x < 0) {
- throw new RoboCopException("Trying to access PaintedSurface with invalid x value");
- }
-
- if (y >= mHeight || y < 0) {
- throw new RoboCopException("Trying to access PaintedSurface with invalid y value");
- }
-
- // The rows are reversed so row 0 is at the end and we start with the last row.
- // This is why we do mHeight-y;
- int index = (x + ((mHeight - y - 1) * mWidth)) * 4;
- return pixelAtIndex(index);
- }
-
- public final String asDataUri() {
- try {
- Bitmap bm = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
- for (int y = 0; y < mHeight; y++) {
- for (int x = 0; x < mWidth; x++) {
- int index = (x + ((mHeight - y - 1) * mWidth)) * 4;
- bm.setPixel(x, y, pixelAtIndex(index));
- }
- }
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- out.write("data:image/png;base64,".getBytes());
- Base64OutputStream b64 = new Base64OutputStream(out, Base64.NO_WRAP);
- bm.compress(Bitmap.CompressFormat.PNG, 100, b64);
- return new String(out.toByteArray());
- } catch (Exception e) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR, e);
- throw new RoboCopException("Unable to convert surface to a PNG data:uri");
- }
- }
-
- public void close() {
- try {
- mPixelFile.close();
- } catch (Exception e) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG, e);
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RoboCopException.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RoboCopException.java
deleted file mode 100644
index 420df818d..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RoboCopException.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-public class RoboCopException extends RuntimeException {
-
- public RoboCopException() {
- super();
- }
-
- public RoboCopException(String message) {
- super(message);
- }
-
- public RoboCopException(Throwable cause) {
- super(cause);
- }
-
- public RoboCopException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopShare1.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopShare1.java
deleted file mode 100644
index 80ab3396c..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopShare1.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-
-public class RobocopShare1 extends FragmentActivity {
- private static Bundle sArguments;
-
- @Override
- public void onCreate(Bundle arguments) {
- super.onCreate(arguments);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopShare2.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopShare2.java
deleted file mode 100644
index 4874dffb7..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopShare2.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-
-public class RobocopShare2 extends FragmentActivity {
- private static Bundle sArguments;
-
- @Override
- public void onCreate(Bundle arguments) {
- super.onCreate(arguments);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopUtils.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopUtils.java
deleted file mode 100644
index 7a33abfa6..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/RobocopUtils.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import android.app.Activity;
-
-public final class RobocopUtils {
- private static final int MAX_WAIT_MS = 20000;
-
- private RobocopUtils() {}
-
- public static void runOnUiThreadSync(Activity activity, final Runnable runnable) {
- final AtomicBoolean sentinel = new AtomicBoolean(false);
-
- // On the UI thread, run the Runnable, then set sentinel to true and wake this thread.
- activity.runOnUiThread(
- new Runnable() {
- @Override
- public void run() {
- runnable.run();
-
- synchronized (sentinel) {
- sentinel.set(true);
- sentinel.notifyAll();
- }
- }
- }
- );
-
-
- // Suspend this thread, until the other thread completes its work or until a timeout is
- // reached.
- long startTimestamp = System.currentTimeMillis();
-
- synchronized (sentinel) {
- while (!sentinel.get()) {
- try {
- sentinel.wait(MAX_WAIT_MS);
- } catch (InterruptedException e) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR, e);
- }
-
- // Abort if we woke up due to timeout (instead of spuriously).
- if (System.currentTimeMillis() - startTimestamp >= MAX_WAIT_MS) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR,
- "time-out waiting for UI thread");
- FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
-
- return;
- }
- }
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/StructuredLogger.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/StructuredLogger.java
deleted file mode 100644
index 87d5a3c25..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/StructuredLogger.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko;
-
-import java.util.HashSet;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.json.JSONObject;
-
-// This implements the structured logging API described here: http://mozbase.readthedocs.org/en/latest/mozlog_structured.html
-public class StructuredLogger {
- private final static HashSet<String> validTestStatus = new HashSet<String>(Arrays.asList("PASS", "FAIL", "TIMEOUT", "NOTRUN", "ASSERT"));
- private final static HashSet<String> validTestEnd = new HashSet<String>(Arrays.asList("PASS", "FAIL", "OK", "ERROR", "TIMEOUT",
- "CRASH", "ASSERT", "SKIP"));
-
- private String mName;
- private String mComponent;
- private LoggerCallback mCallback;
-
- static public interface LoggerCallback {
- public void call(String output);
- }
-
- /* A default logger callback that prints the JSON output to stdout.
- * This is not to be used in robocop as we write to a log file. */
- static class StandardLoggerCallback implements LoggerCallback {
- public void call(String output) {
- System.out.println(output);
- }
- }
-
- public StructuredLogger(String name, String component, LoggerCallback callback) {
- mName = name;
- mComponent = component;
- mCallback = callback;
- }
-
- public StructuredLogger(String name, String component) {
- this(name, component, new StandardLoggerCallback());
- }
-
- public StructuredLogger(String name, LoggerCallback callback) {
- this(name, null, callback);
- }
-
- public StructuredLogger(String name) {
- this(name, null, new StandardLoggerCallback());
- }
-
- public void suiteStart(List<String> tests, Map<String, Object> runInfo) {
- HashMap<String, Object> data = new HashMap<String, Object>();
- data.put("tests", tests);
- if (runInfo != null) {
- data.put("run_info", runInfo);
- }
- this.logData("suite_start", data);
- }
-
- public void suiteStart(List<String> tests) {
- this.suiteStart(tests, null);
- }
-
- public void suiteEnd() {
- this.logData("suite_end");
- }
-
- public void testStart(String test) {
- HashMap<String, Object> data = new HashMap<String, Object>();
- data.put("test", test);
- this.logData("test_start", data);
- }
-
- public void testStatus(String test, String subtest, String status, String expected, String message) {
- status = status.toUpperCase();
- if (!StructuredLogger.validTestStatus.contains(status)) {
- throw new IllegalArgumentException("Unrecognized status: " + status);
- }
-
- HashMap<String, Object> data = new HashMap<String, Object>();
- data.put("test", test);
- data.put("subtest", subtest);
- data.put("status", status);
-
- if (message != null) {
- data.put("message", message);
- }
- if (!expected.equals(status)) {
- data.put("expected", expected);
- }
-
- this.logData("test_status", data);
- }
-
- public void testStatus(String test, String subtest, String status, String message) {
- this.testStatus(test, subtest, status, "PASS", message);
- }
-
- public void testEnd(String test, String status, String expected, String message, Map<String, Object> extra) {
- status = status.toUpperCase();
- if (!StructuredLogger.validTestEnd.contains(status)) {
- throw new IllegalArgumentException("Unrecognized status: " + status);
- }
-
- HashMap<String, Object> data = new HashMap<String, Object>();
- data.put("test", test);
- data.put("status", status);
-
- if (message != null) {
- data.put("message", message);
- }
- if (extra != null) {
- data.put("extra", extra);
- }
- if (!expected.equals(status) && !status.equals("SKIP")) {
- data.put("expected", expected);
- }
-
- this.logData("test_end", data);
- }
-
- public void testEnd(String test, String status, String expected, String message) {
- this.testEnd(test, status, expected, message, null);
- }
-
- public void testEnd(String test, String status, String message) {
- this.testEnd(test, status, "OK", message, null);
- }
-
-
- public void debug(String message) {
- this.log("debug", message);
- }
-
- public void info(String message) {
- this.log("info", message);
- }
-
- public void warning(String message) {
- this.log("warning", message);
- }
-
- public void error(String message) {
- this.log("error", message);
- }
-
- public void critical(String message) {
- this.log("critical", message);
- }
-
- private void log(String level, String message) {
- HashMap<String, Object> data = new HashMap<String, Object>();
- data.put("message", message);
- data.put("level", level);
- this.logData("log", data);
- }
-
- private HashMap<String, Object> makeLogData(String action, Map<String, Object> data) {
- HashMap<String, Object> allData = new HashMap<String, Object>();
- allData.put("action", action);
- allData.put("time", System.currentTimeMillis());
- allData.put("thread", JSONObject.NULL);
- allData.put("pid", JSONObject.NULL);
- allData.put("source", mName);
- if (mComponent != null) {
- allData.put("component", mComponent);
- }
-
- allData.putAll(data);
-
- return allData;
- }
-
- private void logData(String action, Map<String, Object> data) {
- HashMap<String, Object> logData = this.makeLogData(action, data);
- JSONObject jsonObject = new JSONObject(logData);
- mCallback.call(jsonObject.toString());
- }
-
- private void logData(String action) {
- this.logData(action, new HashMap<String, Object>());
- }
-
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/AboutHomeTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/AboutHomeTest.java
deleted file mode 100644
index cadb5df93..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/AboutHomeTest.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.util.ArrayList;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.home.HomePager;
-
-import android.support.v4.view.ViewPager;
-import android.support.v7.widget.RecyclerView;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.TabWidget;
-import android.widget.TextView;
-
-import com.robotium.solo.Condition;
-
-/**
- * This class is an extension of BaseTest that helps with interaction with about:home
- * This class contains methods that access the different tabs from about:home, methods that get information like history and bookmarks from the database, edit and remove bookmarks and history items
- * The purpose of this class is to collect all the logically connected methods that deal with about:home
- * To use any of these methods in your test make sure it extends AboutHomeTest instead of BaseTest
- */
-abstract class AboutHomeTest extends PixelTest {
- protected enum AboutHomeTabs {
- RECENT_TABS,
- HISTORY,
- TOP_SITES,
- BOOKMARKS,
- };
-
- private final ArrayList<String> aboutHomeTabs = new ArrayList<String>() {{
- add("TOP_SITES");
- add("BOOKMARKS");
- }};
-
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- if (aboutHomeTabs.size() < 4) {
- // Update it for tablets vs. phones.
- if (mDevice.type.equals("phone")) {
- aboutHomeTabs.add(0, AboutHomeTabs.HISTORY.toString());
- aboutHomeTabs.add(0, AboutHomeTabs.RECENT_TABS.toString());
- } else {
- aboutHomeTabs.add(AboutHomeTabs.HISTORY.toString());
- aboutHomeTabs.add(AboutHomeTabs.RECENT_TABS.toString());
- }
- }
- }
-
- /**
- * FIXME: Write new versions of these methods and update their consumers to use the new about:home pages.
- */
- protected ListView getHistoryList(String waitText, int expectedChildCount) {
- return null;
- }
- protected ListView getHistoryList(String waitText) {
- return null;
- }
-
- // Returns true if the bookmark is displayed in the bookmarks tab, false otherwise - does not check in folders
- protected void isBookmarkDisplayed(final String url) {
- boolean isCorrect = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- View bookmark = getDisplayedBookmark(url);
- return bookmark != null;
- }
- }, MAX_WAIT_MS);
-
- mAsserter.ok(isCorrect, "Checking that " + url + " displayed as a bookmark", url + " displayed");
- }
-
- // Loads a bookmark by tapping on the bookmark view in the Bookmarks tab
- protected void loadBookmark(String url) {
- View bookmark = getDisplayedBookmark(url);
- if (bookmark != null) {
- Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
- mSolo.clickOnView(bookmark);
- contentEventExpecter.blockForEvent();
- contentEventExpecter.unregisterListener();
- } else {
- mAsserter.ok(false, url + " is not one of the displayed bookmarks", "Please make sure the url provided is bookmarked");
- }
- }
-
- // Opens the bookmark context menu by long-tapping on it
- protected void openBookmarkContextMenu(String url) {
- View bookmark = getDisplayedBookmark(url);
- if (bookmark != null) {
- mSolo.waitForView(bookmark);
- mSolo.clickLongOnView(bookmark, LONG_PRESS_TIME);
- mSolo.waitForDialogToOpen();
- } else {
- mAsserter.ok(false, url + " is not one of the displayed bookmarks", "Please make sure the url provided is bookmarked");
- }
- }
-
- // @return the View associated with bookmark for the provided url or null if the link is not bookmarked
- protected View getDisplayedBookmark(String url) {
- openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
- mSolo.hideSoftKeyboard();
- getInstrumentation().waitForIdleSync();
- ListView bookmarksTabList = findListViewWithTag(HomePager.LIST_TAG_BOOKMARKS);
- waitForNonEmptyListToLoad(bookmarksTabList);
- ListAdapter adapter = bookmarksTabList.getAdapter();
- if (adapter != null) {
- for (int i = 0; i < adapter.getCount(); i++ ) {
- // I am unable to click the view taken with getView for some reason so getting the child at i
- bookmarksTabList.smoothScrollToPosition(i);
- View bookmarkView = bookmarksTabList.getChildAt(i);
- if (bookmarkView instanceof android.widget.LinearLayout) {
- ViewGroup bookmarkItemView = (ViewGroup) bookmarkView;
- for (int j = 0 ; j < bookmarkItemView.getChildCount(); j++) {
- View bookmarkContent = bookmarkItemView.getChildAt(j);
- if (bookmarkContent instanceof android.widget.LinearLayout) {
- ViewGroup bookmarkItemLayout = (ViewGroup) bookmarkContent;
- for (int k = 0 ; k < bookmarkItemLayout.getChildCount(); k++) {
- // Both the title and url are represented as text views so we can cast the view without any issues
- TextView bookmarkTextContent = (TextView)bookmarkItemLayout.getChildAt(k);
- if (url.equals(bookmarkTextContent.getText().toString())) {
- return bookmarkView;
- }
- }
- }
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Waits for the given ListView to have a non-empty adapter and be populated
- * with a minimum number of items.
- *
- * This method will return false if the given ListView or its adapter is null,
- * or if the ListView does not have the minimum number of items.
- */
- protected boolean waitForListToLoad(final ListView listView, final int minSize) {
- Condition listWaitCondition = new Condition() {
- @Override
- public boolean isSatisfied() {
- if (listView == null) {
- return false;
- }
-
- final ListAdapter adapter = listView.getAdapter();
- if (adapter == null) {
- return false;
- }
-
- return (listView.getCount() - listView.getHeaderViewsCount() >= minSize);
- }
- };
- return waitForCondition(listWaitCondition, MAX_WAIT_MS);
- }
-
- protected boolean waitForNonEmptyListToLoad(final ListView listView) {
- return waitForListToLoad(listView, 1);
- }
-
- /**
- * Get an active ListView with the specified tag .
- *
- * This method uses the predefined tags in HomePager.
- */
- protected final ListView findListViewWithTag(String tag) {
- for (ListView listView : mSolo.getCurrentViews(ListView.class)) {
- final String listTag = (String) listView.getTag();
- if (TextUtils.isEmpty(listTag)) {
- continue;
- }
-
- if (TextUtils.equals(listTag, tag)) {
- return listView;
- }
- }
-
- return null;
- }
-
- // A wait in order for the about:home tab to be rendered after drag/tab selection
- private void waitForAboutHomeTab(final int tabIndex) {
- boolean correctTab = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- ViewPager pager = mSolo.getView(ViewPager.class, 0);
- return (pager.getCurrentItem() == tabIndex);
- }
- }, MAX_WAIT_MS);
- mAsserter.ok(correctTab, "Checking that the correct tab is displayed", "The " + aboutHomeTabs.get(tabIndex) + " tab is displayed");
- }
-
- private void clickAboutHomeTab(AboutHomeTabs tab) {
- mSolo.clickOnText(tab.toString().replace("_", " "));
- }
-
- /**
- * Swipes to an about:home tab.
- * @param swipeVector swipeVector Value and direction to swipe (go left for negative, right for positive).
- */
- private void swipeAboutHome(int swipeVector) {
- // Increase swipe width, which will especially impact tablets.
- int swipeWidth = mDriver.getGeckoWidth() - 1;
- int swipeHeight = mDriver.getGeckoHeight() / 2;
-
- if (swipeVector >= 0) {
- // Emulate swipe motion from right to left.
- for (int i = 0; i < swipeVector; i++) {
- mActions.drag(swipeWidth, 0, swipeHeight, swipeHeight);
- mSolo.sleep(100);
- }
- } else {
- // Emulate swipe motion from left to right.
- for (int i = 0; i > swipeVector; i--) {
- mActions.drag(0, swipeWidth, swipeHeight, swipeHeight);
- mSolo.sleep(100);
- }
- }
- }
-
- /**
- * This method can be used to open the different tabs of about:home.
- */
- protected void openAboutHomeTab(AboutHomeTabs tab) {
- focusUrlBar();
- ViewPager pager = mSolo.getView(ViewPager.class, 0);
- final int currentTabIndex = pager.getCurrentItem();
- int tabOffset;
-
- // Handle tablets by just clicking the visible tab title.
- if (mDevice.type.equals("tablet")) {
- clickAboutHomeTab(tab);
- return;
- }
-
- // Handle phones (non-tablets).
- tabOffset = aboutHomeTabs.indexOf(tab.toString()) - currentTabIndex;
- swipeAboutHome(tabOffset);
- waitForAboutHomeTab(aboutHomeTabs.indexOf(tab.toString()));
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseRobocopTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseRobocopTest.java
deleted file mode 100644
index 3033524e8..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseRobocopTest.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.os.PowerManager;
-import android.test.ActivityInstrumentationTestCase2;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.robotium.solo.Solo;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.Assert;
-import org.mozilla.gecko.BrowserApp;
-import org.mozilla.gecko.Driver;
-import org.mozilla.gecko.FennecInstrumentationTestRunner;
-import org.mozilla.gecko.FennecMochitestAssert;
-import org.mozilla.gecko.FennecNativeActions;
-import org.mozilla.gecko.FennecNativeDriver;
-import org.mozilla.gecko.FennecTalosAssert;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.updater.UpdateServiceHelper;
-
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.Map;
-
-@SuppressWarnings("unchecked")
-public abstract class BaseRobocopTest extends ActivityInstrumentationTestCase2<Activity> {
- public static final String LOGTAG = "BaseTest";
-
- public enum Type {
- MOCHITEST,
- TALOS
- }
-
- public static final String DEFAULT_ROOT_PATH = "/mnt/sdcard/tests";
-
- // How long to wait for a Robocop:Quit message to actually kill Fennec.
- private static final int ROBOCOP_QUIT_WAIT_MS = 180000;
-
- /**
- * The Java Class instance that launches the browser.
- * <p>
- * This should always agree with {@link AppConstants#MOZ_ANDROID_BROWSER_INTENT_CLASS}.
- */
- public static final Class<? extends Activity> BROWSER_INTENT_CLASS;
-
- // Use reflection here so we don't have to preprocess this file.
- static {
- Class<? extends Activity> cl;
- try {
- cl = (Class<? extends Activity>) Class.forName(AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
- } catch (ClassNotFoundException e) {
- // Oh well.
- cl = Activity.class;
- }
- BROWSER_INTENT_CLASS = cl;
- }
-
- protected Assert mAsserter;
- protected String mLogFile;
-
- protected String mBaseHostnameUrl;
- protected String mBaseIpUrl;
-
- protected Map<String, String> mConfig;
- protected String mRootPath;
-
- protected Solo mSolo;
- protected Driver mDriver;
- protected Actions mActions;
-
- protected String mProfile;
-
- protected StringHelper mStringHelper;
-
- /**
- * The browser is started at the beginning of this test. A single test is a
- * class inheriting from <code>BaseRobocopTest</code> that contains test
- * methods.
- * <p>
- * If a test should not start the browser at the beginning of a test,
- * specify a different activity class to the one-argument constructor. To do
- * as little as possible, specify <code>Activity.class</code>.
- */
- public BaseRobocopTest() {
- this((Class<Activity>) BROWSER_INTENT_CLASS);
- }
-
- /**
- * Start the given activity class at the beginning of this test.
- * <p>
- * <b>You should use the no-argument constructor in almost all cases.</b>
- *
- * @param activityClass to start before this test.
- */
- protected BaseRobocopTest(Class<Activity> activityClass) {
- super(activityClass);
- }
-
- /**
- * Returns the test type: mochitest or talos.
- * <p>
- * By default tests are mochitests, but a test can override this method in
- * order to change its type. Most Robocop tests are mochitests.
- */
- protected Type getTestType() {
- return Type.MOCHITEST;
- }
-
- // Member function to allow specialization.
- protected Intent createActivityIntent() {
- return BaseRobocopTest.createActivityIntent(mConfig);
- }
-
- // Static function to allow re-use.
- public static Intent createActivityIntent(Map<String, String> config) {
- final Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.putExtra("args", "-no-remote -profile " + config.get("profile"));
- // Don't show the first run experience.
- intent.putExtra(BrowserApp.EXTRA_SKIP_STARTPANE, true);
-
- final String envString = config.get("envvars");
- if (!TextUtils.isEmpty(envString)) {
- final String[] envStrings = envString.split(",");
-
- for (int iter = 0; iter < envStrings.length; iter++) {
- intent.putExtra("env" + iter, envStrings[iter]);
- }
- }
-
- return intent;
- }
-
- @Override
- protected void setUp() throws Exception {
- // Disable the updater.
- UpdateServiceHelper.setEnabled(false);
-
- // Load config file from root path (set up by Python script).
- mRootPath = FennecInstrumentationTestRunner.getFennecArguments().getString("deviceroot");
- if (mRootPath == null) {
- Log.w("Robocop", "Did not find deviceroot in arguments; falling back to: " + DEFAULT_ROOT_PATH);
- mRootPath = DEFAULT_ROOT_PATH;
- }
- String configFile = FennecNativeDriver.getFile(mRootPath + "/robotium.config");
- mConfig = FennecNativeDriver.convertTextToTable(configFile);
- mLogFile = mConfig.get("logfile");
- mProfile = mConfig.get("profile");
- mBaseHostnameUrl = mConfig.get("host").replaceAll("(/$)", "");
- mBaseIpUrl = mConfig.get("rawhost").replaceAll("(/$)", "");
-
- // Initialize the asserter.
- if (getTestType() == Type.TALOS) {
- mAsserter = new FennecTalosAssert();
- } else {
- mAsserter = new FennecMochitestAssert();
- }
- mAsserter.setLogFile(mLogFile);
- mAsserter.setTestName(getClass().getName());
-
- // Start the activity.
- final Intent intent = createActivityIntent();
- setActivityIntent(intent);
-
- // Set up Robotium.solo and Driver objects
- Activity tempActivity = getActivity();
-
- StringHelper.initialize(tempActivity.getResources());
- mStringHelper = StringHelper.get();
-
- mSolo = new Solo(getInstrumentation(), tempActivity);
- mDriver = new FennecNativeDriver(tempActivity, mSolo, mRootPath);
- mActions = new FennecNativeActions(tempActivity, mSolo, getInstrumentation(), mAsserter);
- }
-
- @Override
- protected void runTest() throws Throwable {
- try {
- super.runTest();
- } catch (Throwable t) {
- // save screenshot -- written to /mnt/sdcard/Robotium-Screenshots
- // as <filename>.jpg
- mSolo.takeScreenshot("robocop-screenshot-"+getClass().getName());
- if (mAsserter != null) {
- mAsserter.dumpLog("Exception caught during test!", t);
- mAsserter.ok(false, "Exception caught", t.toString());
- }
- // re-throw to continue bail-out
- throw t;
- }
- }
-
- @Override
- public void tearDown() throws Exception {
- try {
- mAsserter.endTest();
-
- // By default, we don't quit Fennec on finish, and we don't finish
- // all opened activities. Not quiting Fennec entirely is intended to
- // make life better for local testers, who might want to alter a
- // test that is under development rather than Fennec itself. Not
- // finishing activities is intended to allow local testers to
- // manually inspect an activity's state after a test
- // run. runtestsremote.py sets this to "1". Testers running via an
- // IDE will not have this set at all.
- final String quitAndFinish = FennecInstrumentationTestRunner.getFennecArguments()
- .getString("quit_and_finish"); // null means not specified.
- if ("1".equals(quitAndFinish)) {
- // Request the browser force quit and wait for it to take effect.
- Log.i(LOGTAG, "Requesting force quit.");
- mActions.sendGeckoEvent("Robocop:Quit", null);
- mSolo.sleep(ROBOCOP_QUIT_WAIT_MS);
-
- // If still running, finish activities as recommended by Robotium.
- Log.i(LOGTAG, "Finishing all opened activities.");
- mSolo.finishOpenedActivities();
- } else {
- // This has the effect of keeping the activity-under-test
- // around; if we don't set it to null, it is killed, either by
- // finishOpenedActivities above or super.tearDown below.
- Log.i(LOGTAG, "Not requesting force quit and trying to keep started activity alive.");
- setActivity(null);
- }
- } catch (Throwable e) {
- e.printStackTrace();
- }
- super.tearDown();
- }
-
- /**
- * Function to early abort if we can't reach the given HTTP server. Provides local testers
- * with diagnostic information. Not currently available for TALOS tests, which are rarely run
- * locally in any case.
- */
- public void throwIfHttpGetFails() {
- if (getTestType() == Type.TALOS) {
- return;
- }
-
- // rawURL to test fetching from. This should be a raw (IP) URL, not an alias
- // (like mochi.test). We can't (easily) test fetching from the aliases, since
- // those are managed by Fennec's proxy settings.
- final String rawUrl = ((String) mConfig.get("rawhost")).replaceAll("(/$)", "");
-
- HttpURLConnection urlConnection = null;
-
- try {
- urlConnection = (HttpURLConnection) new URL(rawUrl).openConnection();
-
- final int statusCode = urlConnection.getResponseCode();
- if (200 != statusCode) {
- throw new IllegalStateException("Status code: " + statusCode);
- }
- } catch (Exception e) {
- mAsserter.ok(false, "Robocop tests on your device need network/wifi access to reach: [" + rawUrl + "].", e.toString());
- } finally {
- if (urlConnection != null) {
- urlConnection.disconnect();
- }
- }
- }
-
- /**
- * Ensure that the screen on the test device is powered on during tests.
- */
- public void throwIfScreenNotOn() {
- final PowerManager pm = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
- mAsserter.ok(pm.isScreenOn(),
- "Robocop tests need the test device screen to be powered on.", "");
- }
-
- protected GeckoProfile getTestProfile() {
- if (mProfile.startsWith("/")) {
- return GeckoProfile.get(getActivity(), /* profileName */ null, mProfile);
- }
-
- return GeckoProfile.get(getActivity(), mProfile);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseTest.java
deleted file mode 100644
index a8dfedc4e..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseTest.java
+++ /dev/null
@@ -1,976 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Element;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.GeckoThread;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.RobocopUtils;
-import org.mozilla.gecko.Tab;
-import org.mozilla.gecko.Tabs;
-
-import android.content.ContentValues;
-import android.content.res.AssetManager;
-import android.database.Cursor;
-import android.os.Build;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-import android.support.v7.widget.RecyclerView;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-
-import com.robotium.solo.Condition;
-import com.robotium.solo.Timeout;
-
-/**
- * A convenient base class suitable for most Robocop tests.
- */
-@SuppressWarnings("unchecked")
-abstract class BaseTest extends BaseRobocopTest {
- private static final int VERIFY_URL_TIMEOUT = 2000;
- private static final int MAX_WAIT_ENABLED_TEXT_MS = 15000;
- private static final int MAX_WAIT_HOME_PAGER_HIDDEN_MS = 15000;
- private static final int MAX_WAIT_VERIFY_PAGE_TITLE_MS = 15000;
- public static final int MAX_WAIT_MS = 4500;
- public static final int LONG_PRESS_TIME = 6000;
- private static final int GECKO_READY_WAIT_MS = 180000;
-
- protected static final String URL_HTTP_PREFIX = "http://";
-
- public Device mDevice;
- protected DatabaseHelper mDatabaseHelper;
- protected int mScreenMidWidth;
- protected int mScreenMidHeight;
- private final HashSet<Integer> mKnownTabIDs = new HashSet<Integer>();
-
- protected void blockForDelayedStartup() {
- try {
- Actions.EventExpecter delayedStartupExpector = mActions.expectGeckoEvent("Gecko:DelayedStartup");
- delayedStartupExpector.blockForEvent(GECKO_READY_WAIT_MS, true);
- delayedStartupExpector.unregisterListener();
- } catch (Exception e) {
- mAsserter.dumpLog("Exception in blockForDelayedStartup", e);
- }
- }
-
- protected void blockForGeckoReady() {
- try {
- Actions.EventExpecter geckoReadyExpector = mActions.expectGeckoEvent("Gecko:Ready");
- if (!GeckoThread.isRunning()) {
- geckoReadyExpector.blockForEvent(GECKO_READY_WAIT_MS, true);
- }
- geckoReadyExpector.unregisterListener();
- } catch (Exception e) {
- mAsserter.dumpLog("Exception in blockForGeckoReady", e);
- }
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- mDevice = new Device();
- mDatabaseHelper = new DatabaseHelper(getActivity(), mAsserter);
-
- // Ensure Robocop tests have access to network, and are run with Display powered on.
- throwIfHttpGetFails();
- throwIfScreenNotOn();
- }
-
- protected void initializeProfile() {
- final GeckoProfile profile = getTestProfile();
-
- // In Robocop tests, we typically don't get initialized correctly, because
- // GeckoProfile doesn't create the profile directory.
- profile.enqueueInitialization(profile.getDir());
- }
-
- /**
- * Click on the URL bar to focus it and enter editing mode.
- */
- protected final void focusUrlBar() {
- // Click on the browser toolbar to enter editing mode
- mSolo.waitForView(R.id.browser_toolbar);
- final View toolbarView = mSolo.getView(R.id.browser_toolbar);
- mSolo.clickOnView(toolbarView);
-
- // Wait for highlighed text to gain focus
- boolean success = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- mSolo.waitForView(R.id.url_edit_text);
- EditText urlEditText = (EditText) mSolo.getView(R.id.url_edit_text);
- if (urlEditText.isInputMethodTarget()) {
- return true;
- }
- return false;
- }
- }, MAX_WAIT_ENABLED_TEXT_MS);
-
- mAsserter.ok(success, "waiting for urlbar text to gain focus", "urlbar text gained focus");
- }
-
- protected final void enterUrl(String url) {
- focusUrlBar();
-
- final EditText urlEditView = (EditText) mSolo.getView(R.id.url_edit_text);
-
- // Send the keys for the URL we want to enter
- mSolo.clearEditText(urlEditView);
- mSolo.typeText(urlEditView, url);
-
- // Get the URL text from the URL bar EditText view
- final String urlBarText = urlEditView.getText().toString();
- mAsserter.is(url, urlBarText, "URL typed properly");
- }
-
- protected final Fragment getBrowserSearch() {
- final FragmentManager fm = ((FragmentActivity) getActivity()).getSupportFragmentManager();
- return fm.findFragmentByTag("browser_search");
- }
-
- protected final void hitEnterAndWait() {
- Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
- mActions.sendSpecialKey(Actions.SpecialKey.ENTER);
- // wait for screen to load
- contentEventExpecter.blockForEvent();
- contentEventExpecter.unregisterListener();
- }
-
- /**
- * Load <code>url</code> by sending key strokes to the URL bar UI.
- *
- * This method waits synchronously for the <code>DOMContentLoaded</code>
- * message from Gecko before returning.
- *
- * Unless you need to test text entry in the url bar, consider using loadUrl
- * instead -- it loads pages more directly and quickly.
- */
- protected final void inputAndLoadUrl(String url) {
- enterUrl(url);
- hitEnterAndWait();
- }
-
- /**
- * Load <code>url</code> using the internal
- * <code>org.mozilla.gecko.Tabs</code> API.
- *
- * This method does not wait for any confirmation from Gecko before
- * returning -- consider using verifyUrlBarTitle or a similar approach
- * to wait for the page to load, or at least use loadUrlAndWait.
- */
- protected final void loadUrl(final String url) {
- try {
- Tabs.getInstance().loadUrl(url);
- } catch (Exception e) {
- mAsserter.dumpLog("Exception in loadUrl", e);
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Load <code>url</code> using the internal
- * <code>org.mozilla.gecko.Tabs</code> API and wait for DOMContentLoaded.
- */
- protected final void loadUrlAndWait(final String url) {
- Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
- loadUrl(url);
- contentEventExpecter.blockForEvent();
- contentEventExpecter.unregisterListener();
- }
-
- protected final void closeTab(int tabId) {
- Tabs tabs = Tabs.getInstance();
- Tab tab = tabs.getTab(tabId);
- tabs.closeTab(tab);
- }
-
- public final void verifyUrl(String url) {
- final EditText urlEditText = (EditText) mSolo.getView(R.id.url_edit_text);
- String urlBarText = null;
- if (urlEditText != null) {
- // wait for a short time for the expected text, in case there is a delay
- // in updating the view
- waitForCondition(new VerifyTextViewText(urlEditText, url), VERIFY_URL_TIMEOUT);
- urlBarText = urlEditText.getText().toString();
-
- }
- mAsserter.is(urlBarText, url, "Browser toolbar URL stayed the same");
- }
-
- class VerifyTextViewText implements Condition {
- private final TextView mTextView;
- private final String mExpected;
- public VerifyTextViewText(TextView textView, String expected) {
- mTextView = textView;
- mExpected = expected;
- }
-
- @Override
- public boolean isSatisfied() {
- String textValue = mTextView.getText().toString();
- return mExpected.equals(textValue);
- }
- }
-
- class VerifyContentDescription implements Condition {
- private final View view;
- private final String expected;
-
- public VerifyContentDescription(View view, String expected) {
- this.view = view;
- this.expected = expected;
- }
-
- @Override
- public boolean isSatisfied() {
- final CharSequence actual = view.getContentDescription();
- return TextUtils.equals(actual, expected);
- }
- }
-
- protected final String getAbsoluteUrl(String url) {
- return mBaseHostnameUrl + "/" + url.replaceAll("(^/)", "");
- }
-
- protected final String getAbsoluteRawUrl(String url) {
- return mBaseIpUrl + "/" + url.replaceAll("(^/)", "");
- }
-
- /*
- * Wrapper method for mSolo.waitForCondition with additional logging.
- */
- protected final boolean waitForCondition(Condition condition, int timeout) {
- boolean result = mSolo.waitForCondition(condition, timeout);
- if (!result) {
- // Log timeout failure for diagnostic purposes only; a failed wait may
- // be normal and does not necessarily warrant a test assertion/failure.
- mAsserter.dumpLog("waitForCondition timeout after " + timeout + " ms.");
- }
- return result;
- }
-
- public void SqliteCompare(String dbName, String sqlCommand, ContentValues[] cvs) {
- File profile = new File(mProfile);
- String dbPath = new File(profile, dbName).getPath();
-
- Cursor c = mActions.querySql(dbPath, sqlCommand);
- SqliteCompare(c, cvs);
- }
-
- public void SqliteCompare(Cursor c, ContentValues[] cvs) {
- mAsserter.is(c.getCount(), cvs.length, "List is correct length");
- if (c.moveToFirst()) {
- do {
- boolean found = false;
- for (int i = 0; !found && i < cvs.length; i++) {
- if (CursorMatches(c, cvs[i])) {
- found = true;
- }
- }
- mAsserter.is(found, true, "Password was found");
- } while (c.moveToNext());
- }
- }
-
- public boolean CursorMatches(Cursor c, ContentValues cv) {
- for (int i = 0; i < c.getColumnCount(); i++) {
- String column = c.getColumnName(i);
- if (cv.containsKey(column)) {
- mAsserter.info("Comparing", "Column values for: " + column);
- Object value = cv.get(column);
- if (value == null) {
- if (!c.isNull(i)) {
- return false;
- }
- } else {
- if (c.isNull(i) || !value.toString().equals(c.getString(i))) {
- return false;
- }
- }
- }
- }
- return true;
- }
-
- public InputStream getAsset(String filename) throws IOException {
- AssetManager assets = getInstrumentation().getContext().getAssets();
- return assets.open(filename);
- }
-
- public boolean waitForText(final String text) {
- // false is the default value for finding only
- // visible views in `Solo.waitForText(String)`.
- return waitForText(text, false);
- }
-
- public boolean waitForText(final String text, final boolean onlyVisibleViews) {
- // We use the default robotium values from
- // `Waiter.waitForText(String)` for unspecified arguments.
- final boolean rc =
- mSolo.waitForText(text, 0, Timeout.getLargeTimeout(), true, onlyVisibleViews);
- if (!rc) {
- // log out failed wait for diagnostic purposes only;
- // waitForText failures are sometimes expected/normal
- mAsserter.dumpLog("waitForText timeout on "+text);
- }
- return rc;
- }
-
- // waitForText usually scrolls down in a view when text is not visible.
- // For PreferenceScreens and dialogs, Solo.waitForText scrolling does not
- // work, so we use this hack to do the same thing.
- protected boolean waitForPreferencesText(String txt) {
- boolean foundText = waitForText(txt);
- if (!foundText) {
- if ((mScreenMidWidth == 0) || (mScreenMidHeight == 0)) {
- mScreenMidWidth = mDriver.getGeckoWidth()/2;
- mScreenMidHeight = mDriver.getGeckoHeight()/2;
- }
-
- // If we don't see the item, scroll down once in case it's off-screen.
- // Hacky way to scroll down. solo.scroll* does not work in dialogs.
- MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop());
- meh.dragSync(mScreenMidWidth, mScreenMidHeight+100, mScreenMidWidth, mScreenMidHeight-100);
-
- foundText = mSolo.waitForText(txt);
- }
- return foundText;
- }
-
- /**
- * Wait for <text> to be visible and also be enabled/clickable.
- */
- public boolean waitForEnabledText(String text) {
- final String testText = text;
- boolean rc = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- // Solo.getText() could be used here, except that it sometimes
- // hits an assertion when the requested text is not found.
- ArrayList<View> views = mSolo.getCurrentViews();
- for (View view : views) {
- if (view instanceof TextView) {
- TextView tv = (TextView)view;
- String viewText = tv.getText().toString();
- if (tv.isEnabled() && viewText != null && viewText.matches(testText)) {
- return true;
- }
- }
- }
- return false;
- }
- }, MAX_WAIT_ENABLED_TEXT_MS);
- if (!rc) {
- // log out failed wait for diagnostic purposes only;
- // failures are sometimes expected/normal
- mAsserter.dumpLog("waitForEnabledText timeout on "+text);
- }
- return rc;
- }
-
-
- /**
- * Select <item> from Menu > "Settings" > <section>.
- */
- public void selectSettingsItem(String section, String item) {
- String[] itemPath = { "Settings", section, item };
- selectMenuItemByPath(itemPath);
- }
-
- /**
- * Traverses the items in listItems in order in the menu.
- */
- public void selectMenuItemByPath(String[] listItems) {
- int listLength = listItems.length;
- if (listLength > 0) {
- selectMenuItem(listItems[0]);
- }
- if (listLength > 1) {
- for (int i = 1; i < listLength; i++) {
- String itemName = "^" + listItems[i] + "$";
- mAsserter.ok(waitForPreferencesText(itemName), "Waiting for and scrolling once to find item " + itemName, itemName + " found");
- mAsserter.ok(waitForEnabledText(itemName), "Waiting for enabled text " + itemName, itemName + " option is present and enabled");
- mSolo.clickOnText(itemName);
- }
- }
- }
-
- public final void selectMenuItem(String menuItemName) {
- // build the item name ready to be used
- String itemName = "^" + menuItemName + "$";
- final View menuView = mSolo.getView(R.id.menu);
- mAsserter.isnot(menuView, null, "Menu view is not null");
- mSolo.clickOnView(menuView, true);
- mAsserter.ok(waitForEnabledText(itemName), "Waiting for menu item " + itemName, itemName + " is present and enabled");
- mSolo.clickOnText(itemName);
- }
-
- public final void verifyHomePagerHidden() {
- final View homePagerContainer = mSolo.getView(R.id.home_screen_container);
-
- boolean rc = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return homePagerContainer.getVisibility() != View.VISIBLE;
- }
- }, MAX_WAIT_HOME_PAGER_HIDDEN_MS);
-
- if (!rc) {
- mAsserter.ok(rc, "Verify HomePager is hidden", "HomePager is hidden");
- }
- }
-
- public final void verifyUrlBarTitle(String url) {
- mAsserter.isnot(url, null, "The url argument is not null");
-
- final String expected;
- if (mStringHelper.ABOUT_HOME_URL.equals(url)) {
- expected = mStringHelper.ABOUT_HOME_TITLE;
- } else if (url.startsWith(URL_HTTP_PREFIX)) {
- expected = url.substring(URL_HTTP_PREFIX.length());
- } else {
- expected = url;
- }
-
- final TextView urlBarTitle = (TextView) mSolo.getView(R.id.url_bar_title);
- String pageTitle = null;
- if (urlBarTitle != null) {
- // Wait for the title to make sure it has been displayed in case the view
- // does not update fast enough
- waitForCondition(new VerifyTextViewText(urlBarTitle, expected), MAX_WAIT_VERIFY_PAGE_TITLE_MS);
- pageTitle = urlBarTitle.getText().toString();
- }
- mAsserter.is(pageTitle, expected, "Page title is correct");
- }
-
- public final void verifyUrlInContentDescription(String url) {
- mAsserter.isnot(url, null, "The url argument is not null");
-
- final String expected;
- if (mStringHelper.ABOUT_HOME_URL.equals(url)) {
- expected = mStringHelper.ABOUT_HOME_TITLE;
- } else if (url.startsWith(URL_HTTP_PREFIX)) {
- expected = url.substring(URL_HTTP_PREFIX.length());
- } else {
- expected = url;
- }
-
- final View urlDisplayLayout = mSolo.getView(R.id.display_layout);
- assertNotNull("ToolbarDisplayLayout is not null", urlDisplayLayout);
-
- String actualUrl = null;
-
- // Wait for the title to make sure it has been displayed in case the view
- // does not update fast enough
- waitForCondition(new VerifyContentDescription(urlDisplayLayout, expected), MAX_WAIT_VERIFY_PAGE_TITLE_MS);
- if (urlDisplayLayout.getContentDescription() != null) {
- actualUrl = urlDisplayLayout.getContentDescription().toString();
- }
-
- mAsserter.is(actualUrl, expected, "Url is correct");
- }
-
- public final void verifyTabCount(int expectedTabCount) {
- Element tabCount = mDriver.findElement(getActivity(), R.id.tabs_counter);
- String tabCountText = tabCount.getText();
- int tabCountInt = Integer.parseInt(tabCountText);
- mAsserter.is(tabCountInt, expectedTabCount, "The correct number of tabs are opened");
- }
-
- public void verifyPinned(final boolean isPinned, final String gridItemTitle) {
- boolean viewFound = waitForText(gridItemTitle);
- mAsserter.ok(viewFound, "Found top site title: " + gridItemTitle, null);
-
- boolean success = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- // We set the left compound drawable (index 0) to the pin icon.
- final TextView gridItemTextView = mSolo.getText(gridItemTitle);
- return isPinned == (gridItemTextView.getCompoundDrawables()[0] != null);
- }
- }, MAX_WAIT_MS);
- mAsserter.ok(success, "Top site item was pinned: " + isPinned, null);
- }
-
- public void pinTopSite(String gridItemTitle) {
- verifyPinned(false, gridItemTitle);
- mSolo.clickLongOnText(gridItemTitle);
- boolean dialogOpened = mSolo.waitForDialogToOpen();
- mAsserter.ok(dialogOpened, "Pin site dialog opened: " + gridItemTitle, null);
- boolean pinSiteFound = waitForText(mStringHelper.CONTEXT_MENU_PIN_SITE);
- mAsserter.ok(pinSiteFound, "Found pin site menu item", null);
- mSolo.clickOnText(mStringHelper.CONTEXT_MENU_PIN_SITE);
- verifyPinned(true, gridItemTitle);
- }
-
- public void unpinTopSite(String gridItemTitle) {
- verifyPinned(true, gridItemTitle);
- mSolo.clickLongOnText(gridItemTitle);
- boolean dialogOpened = mSolo.waitForDialogToOpen();
- mAsserter.ok(dialogOpened, "Pin site dialog opened: " + gridItemTitle, null);
- boolean unpinSiteFound = waitForText(mStringHelper.CONTEXT_MENU_UNPIN_SITE);
- mAsserter.ok(unpinSiteFound, "Found unpin site menu item", null);
- mSolo.clickOnText(mStringHelper.CONTEXT_MENU_UNPIN_SITE);
- verifyPinned(false, gridItemTitle);
- }
-
- // Used to perform clicks on pop-up buttons without having to close the virtual keyboard
- public void clickOnButton(String label) {
- final Button button = mSolo.getButton(label);
- try {
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- button.performClick();
- }
- });
- } catch (Throwable throwable) {
- mAsserter.ok(false, "Unable to click the button","Was unable to click button ");
- }
- }
-
- private void waitForAnimationsToFinish() {
- // Ideally we'd actually wait for animations to finish but since we have
- // no good way of doing that, we just wait an arbitrary unit of time.
- mSolo.sleep(3500);
- }
-
- public void addTab() {
- mSolo.clickOnView(mSolo.getView(R.id.tabs));
- waitForAnimationsToFinish();
-
- // wait for addTab to appear (this is usually immediate)
- boolean success = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- View addTabView = mSolo.getView(R.id.add_tab);
- if (addTabView == null) {
- return false;
- }
- return true;
- }
- }, MAX_WAIT_MS);
- mAsserter.ok(success, "waiting for add tab view", "add tab view available");
- final Actions.RepeatedEventExpecter pageShowExpecter = mActions.expectGeckoEvent("Content:PageShow");
- mSolo.clickOnView(mSolo.getView(R.id.add_tab));
- waitForAnimationsToFinish();
-
- // Wait until we get a PageShow event for a new tab ID
- for(;;) {
- try {
- JSONObject data = new JSONObject(pageShowExpecter.blockForEventData());
- int tabID = data.getInt("tabID");
- if (tabID == 0) {
- mAsserter.dumpLog("addTab ignoring PageShow for tab 0");
- continue;
- }
- if (!mKnownTabIDs.contains(tabID)) {
- mKnownTabIDs.add(tabID);
- break;
- }
- } catch(JSONException e) {
- mAsserter.ok(false, "Exception in addTab", getStackTraceString(e));
- }
- }
- pageShowExpecter.unregisterListener();
- }
-
- public void addTab(String url) {
- addTab();
-
- // Adding a new tab opens about:home, so now we just need to load the url in it.
- loadUrlAndWait(url);
- }
-
- public void closeAddedTabs() {
- for(int tabID : mKnownTabIDs) {
- closeTab(tabID);
- }
- }
-
- // A temporary tabs list/grid holder while the list and grid views are being transitioned to
- // RecyclerViews (bug 1116415 and bug 1310081).
- private static class TabsView {
- private AdapterView<ListAdapter> gridView;
- private RecyclerView listView;
-
- public TabsView(View view) {
- if (view instanceof RecyclerView) {
- listView = (RecyclerView) view;
- } else {
- gridView = (AdapterView<ListAdapter>) view;
- }
- }
-
- public void bringPositionIntoView(int index) {
- if (gridView != null) {
- gridView.setSelection(index);
- } else {
- listView.scrollToPosition(index);
- }
- }
-
- public View getViewAtIndex(int index) {
- if (gridView != null) {
- return gridView.getChildAt(index - gridView.getFirstVisiblePosition());
- } else {
- final RecyclerView.ViewHolder itemViewHolder = listView.findViewHolderForLayoutPosition(index);
- return itemViewHolder == null ? null : itemViewHolder.itemView;
- }
- }
-
- public void post(Runnable runnable) {
- if (gridView != null) {
- gridView.post(runnable);
- } else {
- listView.post(runnable);
- }
- }
- }
- /**
- * Gets the AdapterView of the tabs list.
- *
- * @return List view in the tabs panel
- */
- private final TabsView getTabsLayout() {
- Element tabs = mDriver.findElement(getActivity(), R.id.tabs);
- tabs.click();
- return new TabsView(getActivity().findViewById(R.id.normal_tabs));
- }
-
- /**
- * Gets the view in the tabs panel at the specified index.
- *
- * @return View at index
- */
- private View getTabViewAt(final int index) {
- final View[] childView = { null };
-
- final TabsView view = getTabsLayout();
-
- runOnUiThreadSync(new Runnable() {
- @Override
- public void run() {
- view.bringPositionIntoView(index);
-
- // The selection isn't updated synchronously; posting a
- // runnable to the view's queue guarantees we'll run after the
- // layout pass.
- view.post(new Runnable() {
- @Override
- public void run() {
- // Index is relative to all views in the list.
- childView[0] = view.getViewAtIndex(index);
- }
- });
- }
- });
-
- boolean result = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return childView[0] != null;
- }
- }, MAX_WAIT_MS);
-
- mAsserter.ok(result, "list item at index " + index + " exists", null);
-
- return childView[0];
- }
-
- /**
- * Selects the tab at the specified index.
- *
- * @param index Index of tab to select
- */
- public void selectTabAt(final int index) {
- mSolo.clickOnView(getTabViewAt(index));
- }
-
- public final void runOnUiThreadSync(Runnable runnable) {
- RobocopUtils.runOnUiThreadSync(getActivity(), runnable);
- }
-
- /* Tap the "star" (bookmark) button to bookmark or un-bookmark the current page */
- public void toggleBookmark() {
- mActions.sendSpecialKey(Actions.SpecialKey.MENU);
- waitForText("Settings");
-
- // On ICS+ phones, there is no button labeled "Bookmarks"
- // instead we have to just dig through every button on the screen
- ArrayList<View> images = mSolo.getCurrentViews();
- for (int i = 0; i < images.size(); i++) {
- final View view = images.get(i);
- boolean found = false;
- found = "Bookmark".equals(view.getContentDescription());
-
- // on older android versions, try looking at the button's text
- if (!found) {
- if (view instanceof TextView) {
- found = "Bookmark".equals(((TextView)view).getText());
- }
- }
-
- if (found) {
- int[] xy = new int[2];
- view.getLocationOnScreen(xy);
-
- final int viewWidth = view.getWidth();
- final int viewHeight = view.getHeight();
- final float x = xy[0] + (viewWidth / 2.0f);
- float y = xy[1] + (viewHeight / 2.0f);
-
- mSolo.clickOnScreen(x, y);
- }
- }
- }
-
- class Device {
- public final String version; // 2.x or 3.x or 4.x
- public String type; // "tablet" or "phone"
- public final int width;
- public final int height;
- public final float density;
-
- public Device() {
- // Determine device version
- int sdk = Build.VERSION.SDK_INT;
- if (sdk < Build.VERSION_CODES.HONEYCOMB) {
- version = "2.x";
- } else {
- if (sdk > Build.VERSION_CODES.HONEYCOMB_MR2) {
- version = "4.x";
- } else {
- version = "3.x";
- }
- }
- // Determine with and height
- DisplayMetrics dm = new DisplayMetrics();
- getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
- height = dm.heightPixels;
- width = dm.widthPixels;
- density = dm.density;
- // Determine device type
- type = "phone";
- try {
- if (GeckoAppShell.isTablet()) {
- type = "tablet";
- }
- } catch (Exception e) {
- mAsserter.dumpLog("Exception in detectDevice", e);
- }
- }
- }
-
- class Navigation {
- private final String devType;
- private final String osVersion;
-
- public Navigation(Device mDevice) {
- devType = mDevice.type;
- osVersion = mDevice.version;
- }
-
- public void back() {
- Actions.EventExpecter pageShowExpecter = mActions.expectGeckoEvent("Content:PageShow");
-
- if (devType.equals("tablet")) {
- Element backBtn = mDriver.findElement(getActivity(), R.id.back);
- backBtn.click();
- } else {
- mSolo.goBack();
- }
-
- pageShowExpecter.blockForEvent();
- pageShowExpecter.unregisterListener();
- }
-
- public void forward() {
- Actions.EventExpecter pageShowExpecter = mActions.expectGeckoEvent("Content:PageShow");
-
- if (devType.equals("tablet")) {
- mSolo.waitForView(R.id.forward);
- mSolo.clickOnView(mSolo.getView(R.id.forward));
- } else {
- mActions.sendSpecialKey(Actions.SpecialKey.MENU);
- waitForText("^New Tab$");
- if (!osVersion.equals("2.x")) {
- mSolo.waitForView(R.id.forward);
- mSolo.clickOnView(mSolo.getView(R.id.forward));
- } else {
- mSolo.clickOnText("^Forward$");
- }
- ensureMenuClosed();
- }
-
- pageShowExpecter.blockForEvent();
- pageShowExpecter.unregisterListener();
- }
-
- // DEPRECATED!
- // Use BaseTest.toggleBookmark() in new code.
- public void bookmark() {
- mActions.sendSpecialKey(Actions.SpecialKey.MENU);
- waitForText("^New Tab$");
- if (mSolo.searchText("^Bookmark$")) {
- // This is the Android 2.x so the button has text
- mSolo.clickOnText("^Bookmark$");
- } else {
- Element bookmarkBtn = mDriver.findElement(getActivity(), R.id.bookmark);
- if (bookmarkBtn != null) {
- // We are on Android 4.x so the button is an image button
- bookmarkBtn.click();
- }
- }
- ensureMenuClosed();
- }
-
- // On some devices, the menu may not be dismissed after clicking on an
- // item. Close it here.
- private void ensureMenuClosed() {
- if (mSolo.searchText("^New Tab$")) {
- mSolo.goBack();
- }
- }
- }
-
- /**
- * Gets the string representation of a stack trace.
- *
- * @param t Throwable to get stack trace for
- * @return Stack trace as a string
- */
- public static String getStackTraceString(Throwable t) {
- StringWriter sw = new StringWriter();
- t.printStackTrace(new PrintWriter(sw));
- return sw.toString();
- }
-
- /**
- * Condition class that waits for a view, and allows callers access it when done.
- */
- private class DescriptionCondition<T extends View> implements Condition {
- public T mView;
- private final String mDescr;
- private final Class<T> mCls;
-
- public DescriptionCondition(Class<T> cls, String descr) {
- mDescr = descr;
- mCls = cls;
- }
-
- @Override
- public boolean isSatisfied() {
- mView = findViewWithContentDescription(mCls, mDescr);
- return (mView != null);
- }
- }
-
- /**
- * Wait for a view with the specified description .
- */
- public <T extends View> T waitForViewWithDescription(Class<T> cls, String description) {
- DescriptionCondition<T> c = new DescriptionCondition<T>(cls, description);
- waitForCondition(c, MAX_WAIT_ENABLED_TEXT_MS);
- return c.mView;
- }
-
- /**
- * Get an active view with the specified description .
- */
- public <T extends View> T findViewWithContentDescription(Class<T> cls, String description) {
- for (T view : mSolo.getCurrentViews(cls)) {
- final String descr = (String) view.getContentDescription();
- if (TextUtils.isEmpty(descr)) {
- continue;
- }
-
- if (TextUtils.equals(description, descr)) {
- return view;
- }
- }
-
- return null;
- }
-
- /**
- * Abstract class for running small test cases within a BaseTest.
- */
- abstract class TestCase implements Runnable {
- /**
- * Implement tests here. setUp and tearDown for the test case
- * should be handled by the parent test. This is so we can avoid the
- * overhead of starting Gecko and creating profiles.
- */
- protected abstract void test() throws Exception;
-
- @Override
- public void run() {
- try {
- test();
- } catch (Exception e) {
- mAsserter.ok(false,
- "Test " + this.getClass().getName() + " threw exception: " + e,
- "");
- }
- }
- }
-
- /**
- * Set the preference and wait for it to change before proceeding with the test.
- */
- public void setPreferenceAndWaitForChange(final String name, final Object value) {
- blockForGeckoReady();
- mActions.setPref(name, value, /* flush */ false);
-
- // Wait for confirmation of the pref change before proceeding with the test.
- mActions.getPrefs(new String[] { name }, new Actions.PrefHandlerBase() {
-
- @Override // Actions.PrefHandlerBase
- public void prefValue(String pref, boolean changedValue) {
- mAsserter.is(pref, name, "Expecting correct pref name");
- mAsserter.ok(value instanceof Boolean, "Expecting boolean pref", "");
- mAsserter.is(changedValue, value, "Expecting matching pref value");
- }
-
- @Override // Actions.PrefHandlerBase
- public void prefValue(String pref, int changedValue) {
- mAsserter.is(pref, name, "Expecting correct pref name");
- mAsserter.ok(value instanceof Integer, "Expecting int pref", "");
- mAsserter.is(changedValue, value, "Expecting matching pref value");
- }
-
- @Override // Actions.PrefHandlerBase
- public void prefValue(String pref, String changedValue) {
- mAsserter.is(pref, name, "Expecting correct pref name");
- mAsserter.ok(value instanceof CharSequence, "Expecting string pref", "");
- mAsserter.is(changedValue, value, "Expecting matching pref value");
- }
-
- }).waitForFinish();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/ContentContextMenuTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/ContentContextMenuTest.java
deleted file mode 100644
index 5a1d09f8c..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/ContentContextMenuTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.util.Clipboard;
-import org.mozilla.gecko.Element;
-import org.mozilla.gecko.R;
-
-import android.util.DisplayMetrics;
-
-import com.robotium.solo.Condition;
-
-/**
- * This class covers interactions with the context menu opened from web content
- */
-abstract class ContentContextMenuTest extends PixelTest {
- private static final int MAX_TEST_TIMEOUT = 30000; // 30 seconds (worst case)
-
- // This method opens the context menu of any web content. It assumes that the page is already loaded
- protected void openWebContentContextMenu(String waitText) {
- DisplayMetrics dm = new DisplayMetrics();
- getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
-
- // The web content we are trying to open the context menu for should be positioned at the top of the page, at least 60px high and aligned to the middle
- float top = mDriver.getGeckoTop() + 30 * dm.density;
- float left = mDriver.getGeckoLeft() + mDriver.getGeckoWidth() / 2;
-
- mAsserter.dumpLog("long-clicking at "+left+", "+top);
- mSolo.clickLongOnScreen(left, top);
- waitForText(waitText);
- }
-
- protected void verifyContextMenuItems(String[] items) {
- // Test that the menu items are displayed
- if (!mSolo.searchText(items[0])) {
- openWebContentContextMenu(items[0]); // Open the context menu if it is not already
- }
-
- for (String option:items) {
- mAsserter.ok(mSolo.searchText(option), "Checking that the option: " + option + " is available", "The option is available");
- }
- }
-
- protected void openTabFromContextMenu(String contextMenuOption, int expectedTabCount) {
- if (!mSolo.searchText(contextMenuOption)) {
- openWebContentContextMenu(contextMenuOption); // Open the context menu if it is not already
- }
- Actions.EventExpecter tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
- mSolo.clickOnText(contextMenuOption);
- tabEventExpecter.blockForEvent();
- tabEventExpecter.unregisterListener();
- verifyTabCount(expectedTabCount);
- }
-
- protected void verifyTabs(String[] items) {
- if (!mSolo.searchText(items[0])) {
- openWebContentContextMenu(items[0]);
- }
-
- for (String option:items) {
- mAsserter.ok(mSolo.searchText(option), "Checking that the option: " + option + " is available", "The option is available");
- }
- }
-
- protected void switchTabs(String tab) {
- if (!mSolo.searchText(tab)) {
- openWebContentContextMenu(tab);
- }
- mSolo.clickOnText(tab);
- }
-
-
- protected void verifyCopyOption(String copyOption, final String copiedText) {
- if (!mSolo.searchText(copyOption)) {
- openWebContentContextMenu(copyOption); // Open the context menu if it is not already
- }
- mSolo.clickOnText(copyOption);
- boolean correctText = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- final String clipboardText = Clipboard.getText();
- mAsserter.dumpLog("Clipboard text = " + clipboardText + " , expected text = " + copiedText);
- return clipboardText.contains(copiedText);
- }
- }, MAX_TEST_TIMEOUT);
- mAsserter.ok(correctText, "Checking if the text is correctly copied", "The text was correctly copied");
- }
-
-
-
- protected void verifyShareOption(String shareOption, String pageTitle) {
- waitForText(pageTitle); // Even if this fails, it won't assert
- if (!mSolo.searchText(shareOption)) {
- openWebContentContextMenu(shareOption); // Open the context menu if it is not already
- }
- mSolo.clickOnText(shareOption);
- mAsserter.ok(waitForText(shareOption), "Checking that the share pop-up is displayed", "The pop-up has been displayed");
-
- // Close the Share Link option menu and wait for the page to be focused again
- mSolo.goBack();
- waitForText(pageTitle);
- }
-
- protected void verifyViewImageOption(String viewImageOption, final String imageUrl, String pageTitle) {
- if (!mSolo.searchText(viewImageOption)) {
- openWebContentContextMenu(viewImageOption);
- }
- mSolo.clickOnText(viewImageOption);
-
- boolean viewedImage = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- final Element urlBarElement = mDriver.findElement(getActivity(), R.id.url_edit_text);
- final String loadedUrl = urlBarElement.getText();
- return loadedUrl.contentEquals(imageUrl);
- }
- }, MAX_TEST_TIMEOUT);
- mAsserter.ok(viewedImage, "Checking if the image is correctly viewed", "The image was correctly viewed");
-
- mSolo.goBack();
- waitForText(pageTitle);
- }
-
- protected void verifyBookmarkLinkOption(String bookmarkOption, String link) {
- if (!mSolo.searchText(bookmarkOption)) {
- openWebContentContextMenu(bookmarkOption); // Open the context menu if it is not already
- }
- mSolo.clickOnText(bookmarkOption);
- mAsserter.ok(waitForText("Bookmark added"), "Waiting for the Bookmark added toaster notification", "The notification has been displayed");
- mAsserter.ok(mDatabaseHelper.isBookmark(link), "Checking if the link has been added as a bookmark", "The link has been bookmarked");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/ContentProviderTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/ContentProviderTest.java
deleted file mode 100644
index 5496c97d2..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/ContentProviderTest.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.concurrent.Callable;
-
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserProvider;
-
-import android.content.ContentProvider;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.OperationApplicationException;
-import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.res.AssetManager;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Build;
-import android.test.IsolatedContext;
-import android.test.RenamingDelegatingContext;
-import android.test.mock.MockContentResolver;
-import android.test.mock.MockContext;
-
-/*
- * ContentProviderTest provides the infrastructure to run content provider
- * tests in an controlled/isolated environment, guaranteeing that your tests
- * will not affect or be affected by any UI-related code. This is basically
- * a heavily adapted port of Android's ProviderTestCase2 to work on Mozilla's
- * infrastructure.
- *
- * For some tests, we need to have access to UI parts, or at least launch
- * the activity so the assets with test data become available, which requires
- * that we derive this test from BaseTest and consequently pull in some more
- * UI code than we'd ideally want. Furthermore, we need to pass the
- * Activity and not the instrumentation Context for the UI part to find some
- * of its required resources.
- * Similarly, we need to pass the Activity instead of the Instrumentation
- * Context down to some of our users (still wrapped in the Delegating Provider)
- * because they will stop working correctly if we do not. A typical problem
- * is that databases used in the ContentProvider will be attempted to be
- * opened twice.
- */
-abstract class ContentProviderTest extends BaseTest {
- protected ContentProvider mProvider;
- protected ChangeRecordingMockContentResolver mResolver;
- protected ArrayList<Runnable> mTests;
- protected String mDatabaseName;
- protected String mProviderAuthority;
- protected IsolatedContext mProviderContext;
-
- private class ContentProviderMockContext extends MockContext {
- @Override
- public Resources getResources() {
- // We will fail to find some resources if we don't point
- // at the original activity.
- return ((Context)getActivity()).getResources();
- }
-
- @Override
- public String getPackageName() {
- return getInstrumentation().getContext().getPackageName();
- }
-
- @Override
- public String getPackageResourcePath() {
- return getInstrumentation().getContext().getPackageResourcePath();
- }
-
- @Override
- public File getDir(String name, int mode) {
- return getInstrumentation().getContext().getDir(this.getClass().getSimpleName() + "_" + name, mode);
- }
-
- @Override
- public Context getApplicationContext() {
- return this;
- }
-
- @Override
- public SharedPreferences getSharedPreferences(String name, int mode) {
- return getInstrumentation().getContext().getSharedPreferences(name, mode);
- }
-
- @Override
- public ApplicationInfo getApplicationInfo() {
- return getInstrumentation().getContext().getApplicationInfo();
- }
- }
-
- protected class DelegatingTestContentProvider extends ContentProvider {
- ContentProvider mTargetProvider;
-
- public DelegatingTestContentProvider(ContentProvider targetProvider) {
- super();
- mTargetProvider = targetProvider;
- }
-
- private Uri appendTestParam(Uri uri) {
- try {
- return appendUriParam(uri, BrowserContract.PARAM_IS_TEST, "1");
- } catch (Exception e) {}
-
- return null;
- }
-
- @Override
- public boolean onCreate() {
- return mTargetProvider.onCreate();
- }
-
- @Override
- public String getType(Uri uri) {
- return mTargetProvider.getType(uri);
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return mTargetProvider.delete(appendTestParam(uri), selection, selectionArgs);
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return mTargetProvider.insert(appendTestParam(uri), values);
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
- return mTargetProvider.update(appendTestParam(uri), values,
- selection, selectionArgs);
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- return mTargetProvider.query(appendTestParam(uri), projection, selection,
- selectionArgs, sortOrder);
- }
-
- @Override
- public ContentProviderResult[] applyBatch (ArrayList<ContentProviderOperation> operations)
- throws OperationApplicationException {
- return mTargetProvider.applyBatch(operations);
- }
-
- @Override
- public int bulkInsert(Uri uri, ContentValues[] values) {
- return mTargetProvider.bulkInsert(appendTestParam(uri), values);
- }
-
- public ContentProvider getTargetProvider() {
- return mTargetProvider;
- }
- }
-
- /*
- * A MockContentResolver that records each URI that is supplied to
- * notifyChange. Warning: the list of changed URIs is not
- * synchronized.
- */
- protected class ChangeRecordingMockContentResolver extends MockContentResolver {
- public final LinkedList<Uri> notifyChangeList = new LinkedList<Uri>();
-
- @Override
- public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
- notifyChangeList.addLast(uri);
-
- super.notifyChange(uri, observer, syncToNetwork);
- }
- }
-
- /**
- * Factory function that makes new ContentProvider instances.
- * <p>
- * We want a fresh provider each test, so this should be invoked in
- * <code>setUp</code> before each individual test.
- */
- protected static Callable<ContentProvider> sBrowserProviderCallable = new Callable<ContentProvider>() {
- @Override
- public ContentProvider call() {
- return new BrowserProvider();
- }
- };
-
- private void setUpContentProvider(ContentProvider targetProvider) throws Exception {
- mResolver = new ChangeRecordingMockContentResolver();
-
- final String filenamePrefix = this.getClass().getSimpleName() + ".";
- RenamingDelegatingContext targetContextWrapper =
- new RenamingDelegatingContext(
- new ContentProviderMockContext(),
- (Context)getActivity(),
- filenamePrefix);
-
- mProviderContext = new IsolatedContext(mResolver, targetContextWrapper);
-
- targetProvider.attachInfo(mProviderContext, null);
-
- mProvider = new DelegatingTestContentProvider(targetProvider);
- mProvider.attachInfo(mProviderContext, null);
-
- mResolver.addProvider(mProviderAuthority, mProvider);
- }
-
- public static Uri appendUriParam(Uri uri, String param, String value) {
- return uri.buildUpon().appendQueryParameter(param, value).build();
- }
-
- public void setTestName(String testName) {
- mAsserter.setTestName(this.getClass().getName() + " - " + testName);
- }
-
- @Override
- public void setUp() throws Exception {
- throw new UnsupportedOperationException("You should call setUp(authority, databaseName) instead");
- }
-
- public void setUp(Callable<ContentProvider> contentProviderFactory, String authority, String databaseName) throws Exception {
- super.setUp();
-
- mTests = new ArrayList<Runnable>();
- mDatabaseName = databaseName;
-
- mProviderAuthority = authority;
-
- setUpContentProvider(contentProviderFactory.call());
- }
-
- @Override
- public void tearDown() throws Exception {
- if (Build.VERSION.SDK_INT >= 11) {
- mProvider.shutdown();
- }
-
- if (mDatabaseName != null) {
- mProviderContext.deleteDatabase(mDatabaseName);
- }
-
- super.tearDown();
- }
-
- public AssetManager getAssetManager() {
- return getInstrumentation().getContext().getAssets();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/DatabaseHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/DatabaseHelper.java
deleted file mode 100644
index c87dc2432..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/DatabaseHelper.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.util.ArrayList;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.Assert;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.db.BrowserDB;
-
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.database.Cursor;
-import android.net.Uri;
-
-class DatabaseHelper {
- protected enum BrowserDataType {BOOKMARKS, HISTORY};
- private final Activity mActivity;
- private final Assert mAsserter;
-
- public DatabaseHelper(Activity activity, Assert asserter) {
- mActivity = activity;
- mAsserter = asserter;
- }
- /**
- * This method can be used to check if an URL is present in the bookmarks database
- */
- protected boolean isBookmark(String url) {
- final ContentResolver resolver = mActivity.getContentResolver();
- return getProfileDB().isBookmark(resolver, url);
- }
-
- protected Uri buildUri(BrowserDataType dataType) {
- Uri uri = null;
- if (dataType == BrowserDataType.BOOKMARKS || dataType == BrowserDataType.HISTORY) {
- uri = Uri.parse("content://" + AppConstants.ANDROID_PACKAGE_NAME + ".db.browser/" + dataType.toString().toLowerCase());
- } else {
- mAsserter.ok(false, "The wrong data type has been provided = " + dataType.toString(), "Please provide the correct data type");
- }
- uri = uri.buildUpon().appendQueryParameter("profile", GeckoProfile.DEFAULT_PROFILE)
- .appendQueryParameter("sync", "true").build();
- return uri;
- }
-
- /**
- * Adds a bookmark.
- */
- protected void addMobileBookmark(String title, String url) {
- final ContentResolver resolver = mActivity.getContentResolver();
- getProfileDB().addBookmark(resolver, title, url);
- mAsserter.ok(true, "Inserting a new bookmark", "Inserting the bookmark with the title = " + title + " and the url = " + url);
- }
-
- /**
- * Updates the title and keyword of a bookmark with the given URL.
- *
- * Warning: This method assumes that there's only one bookmark with the given URL.
- */
- protected void updateBookmark(String url, String title, String keyword) {
- final ContentResolver resolver = mActivity.getContentResolver();
- // Get the id for the bookmark with the given URL.
- Cursor c = null;
- try {
- c = getProfileDB().getBookmarkForUrl(resolver, url);
- if (!c.moveToFirst()) {
- mAsserter.ok(false, "Getting bookmark with url", "Couldn't find bookmark with url = " + url);
- return;
- }
-
- int id = c.getInt(c.getColumnIndexOrThrow("_id"));
- getProfileDB().updateBookmark(resolver, id, url, title, keyword);
-
- mAsserter.ok(true, "Updating bookmark", "Updating bookmark with url = " + url);
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
-
- protected void deleteBookmark(String url) {
- final ContentResolver resolver = mActivity.getContentResolver();
- getProfileDB().removeBookmarksWithURL(resolver, url);
- }
-
- protected void deleteHistoryItem(String url) {
- final ContentResolver resolver = mActivity.getContentResolver();
- getProfileDB().removeHistoryEntry(resolver, url);
- }
-
- // About the same implementation as getFolderIdFromGuid from LocalBrowserDB because it is declared private and we can't use reflections to access it
- protected long getFolderIdFromGuid(String guid) {
- final ContentResolver resolver = mActivity.getContentResolver();
- long folderId = -1L;
- final Uri bookmarksUri = buildUri(BrowserDataType.BOOKMARKS);
-
- Cursor c = null;
- try {
- c = resolver.query(bookmarksUri,
- new String[] { "_id" },
- "guid = ?",
- new String[] { guid },
- null);
- if (c.moveToFirst()) {
- folderId = c.getLong(c.getColumnIndexOrThrow("_id"));
- }
-
- if (folderId == -1) {
- mAsserter.ok(false, "Trying to get the folder id" ,"We did not get the correct folder id");
- }
- } finally {
- if (c != null) {
- c.close();
- }
- }
- return folderId;
- }
-
- /**
- * Returns all of the bookmarks or history entries in a database.
- *
- * @return an ArrayList of the urls in the Firefox for Android Bookmarks or History databases.
- */
- protected ArrayList<String> getBrowserDBUrls(BrowserDataType dataType) {
- final ArrayList<String> browserData = new ArrayList<String>();
- final ContentResolver resolver = mActivity.getContentResolver();
-
- Cursor cursor = null;
- final BrowserDB db = getProfileDB();
- if (dataType == BrowserDataType.HISTORY) {
- cursor = db.getAllVisitedHistory(resolver);
- } else if (dataType == BrowserDataType.BOOKMARKS) {
- cursor = db.getBookmarksInFolder(resolver, getFolderIdFromGuid("mobile"));
- }
-
- if (cursor == null) {
- mAsserter.ok(false, "We could not retrieve any data from the database", "The cursor was null");
- return browserData;
- }
-
- try {
- if (!cursor.moveToFirst()) {
- // Nothing here, but that's OK -- maybe there are zero results. The calling test will fail.
- return browserData;
- }
-
- do {
- // The URL field may be null for folders in the structure of the Bookmarks table for Firefox. Eliminate those.
- if (cursor.getString(cursor.getColumnIndex("url")) != null) {
- browserData.add(cursor.getString(cursor.getColumnIndex("url")));
- }
- } while (cursor.moveToNext());
-
- return browserData;
- } finally {
- cursor.close();
- }
- }
-
- protected BrowserDB getProfileDB() {
- return BrowserDB.from(mActivity);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/JavascriptBridgeTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/JavascriptBridgeTest.java
deleted file mode 100644
index a71f8fd49..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/JavascriptBridgeTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.*;
-
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-import org.mozilla.gecko.tests.helpers.JavascriptBridge;
-import org.mozilla.gecko.tests.helpers.NavigationHelper;
-
-/**
- * Extended to write tests using JavascriptBridge, which allows Java and JS to communicate back-and-forth.
- * If you don't need back-and-forth communication, consider {@link JavascriptTest}.
- *
- * To write a test:
- * * Extend this class
- * * Add your javascript file to the base robocop directory (see where `testJavascriptBridge.js` is located)
- * * In the main test method, call {@link #blockForReadyAndLoadJS(String)} with your javascript file name
- * (don't include the path) or if you're loading a non-harness url, be sure to call {@link GeckoHelper#blockForReady()}
- * * You can access js calls via the {@link #getJS()} method
- * - Read {@link JavascriptBridge} javadoc for more information about using the API.
- */
-public class JavascriptBridgeTest extends UITest {
-
- private static final long WAIT_GET_FROM_JS_MILLIS = 20000;
-
- private JavascriptBridge js;
-
- // Feel free to implement additional return types.
- private boolean isAsyncValueSet;
- private String asyncValueStr;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- js = new JavascriptBridge(this);
- }
-
- @Override
- public void tearDown() throws Exception {
- js.disconnect();
- super.tearDown();
- }
-
- public JavascriptBridge getJS() {
- return js;
- }
-
- protected void blockForReadyAndLoadJS(final String jsFilename) {
- NavigationHelper.enterAndLoadUrl(mStringHelper.getHarnessUrlForJavascript(jsFilename));
- }
-
- /**
- * Used to retrieve values from js when it's required to call async methods (e.g. promises).
- * This method will block until the value is retrieved else timeout.
- *
- * This method is not thread-safe.
- *
- * Ideally, we could just have Javascript call Java when the callback completes but Java won't
- * listen for messages unless we call into JS again (bug 1253467).
- *
- * To use this method:
- * * Call this method with a name argument, henceforth known as `varName`. Note that it will be capitalized
- * in all function names.
- * * Create a js function, `"getAsync" + varName` (e.g. if `varName == "clientId`, the function is
- * `getAsyncClientId`) of no args. This function should call the async get method and assign a global variable to
- * the return value.
- * * Create a js function, `"pollGetAsync" + varName` (e.g. `pollGetAsyncClientId`) of no args. It should call
- * `java.asyncCall('blockingFromJsResponseString', ...` with two args: a boolean if the async value has been set yet
- * and a String with the global return value (`null` or `undefined` are acceptable if the value has not been set).
- */
- public String getBlockingFromJsString(final String varName) {
- isAsyncValueSet = false;
- final String fnSuffix = capitalize(varName);
- getJS().syncCall("getAsync" + fnSuffix); // Initiate async callback
-
- final long timeoutMillis = System.currentTimeMillis() + WAIT_GET_FROM_JS_MILLIS;
- do {
- // Avoid sleeping! The async callback may have already completed so
- // we test for completion here, rather than in the loop predicate.
- getJS().syncCall("pollGetAsync" + fnSuffix);
- if (isAsyncValueSet) {
- break;
- }
-
- if (System.currentTimeMillis() > timeoutMillis) {
- fFail("Retrieving " + varName + " from JS has timed out");
- }
- try {
- Thread.sleep(500, 0); // Give time for JS to complete its operation. (emulator one core?)
- } catch (final InterruptedException e) { }
- } while (true);
-
- return asyncValueStr;
- }
-
- public void blockingFromJsResponseString(final boolean isValueSet, final String value) {
- this.isAsyncValueSet = isValueSet;
- this.asyncValueStr = value;
- }
-
- private String capitalize(final String str) {
- return str.substring(0, 1).toUpperCase() + str.substring(1);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/JavascriptTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/JavascriptTest.java
deleted file mode 100644
index 52893510d..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/JavascriptTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.json.JSONObject;
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.tests.helpers.JavascriptBridge;
-import org.mozilla.gecko.tests.helpers.JavascriptMessageParser;
-
-import android.util.Log;
-
-/**
- * Extended to test stand-alone Javascript in automation. If you're looking to test JS interactions
- * with Java, see {@link JavascriptBridgeTest}.
- *
- * There are also other tests that run stand-alone javascript but are more difficult for the mobile
- * team to run (e.g. xpcshell).
- */
-public class JavascriptTest extends BaseTest {
- private static final String LOGTAG = "JavascriptTest";
- private static final String EVENT_TYPE = JavascriptBridge.EVENT_TYPE;
-
- // Calculate these once, at initialization. isLoggable is too expensive to
- // have in-line in each log call.
- private static final boolean logDebug = Log.isLoggable(LOGTAG, Log.DEBUG);
- private static final boolean logVerbose = Log.isLoggable(LOGTAG, Log.VERBOSE);
-
- private final String javascriptUrl;
-
- public JavascriptTest(String javascriptUrl) {
- super();
- this.javascriptUrl = javascriptUrl;
- }
-
- public void testJavascript() throws Exception {
- blockForGeckoReady();
-
- doTestJavascript();
- }
-
- protected void doTestJavascript() throws Exception {
- // We want to be waiting for Robocop messages before the page is loaded
- // because the test harness runs each test in the suite (and possibly
- // completes testing) before the page load event is fired.
- final Actions.EventExpecter expecter = mActions.expectGeckoEvent(EVENT_TYPE);
- mAsserter.dumpLog("Registered listener for " + EVENT_TYPE);
-
- final String url = getAbsoluteUrl(mStringHelper.getHarnessUrlForJavascript(javascriptUrl));
- mAsserter.dumpLog("Loading JavaScript test from " + url);
- loadUrl(url);
-
- final JavascriptMessageParser testMessageParser =
- new JavascriptMessageParser(mAsserter, false);
- try {
- while (!testMessageParser.isTestFinished()) {
- if (logVerbose) {
- Log.v(LOGTAG, "Waiting for " + EVENT_TYPE);
- }
- String data = expecter.blockForEventData();
- if (logVerbose) {
- Log.v(LOGTAG, "Got event with data '" + data + "'");
- }
-
- JSONObject o = new JSONObject(data);
- String innerType = o.getString("innerType");
- if (!"progress".equals(innerType)) {
- throw new Exception("Unexpected event innerType " + innerType);
- }
-
- String message = o.getString("message");
- if (message == null) {
- throw new Exception("Progress message must not be null");
- }
- testMessageParser.logMessage(message);
- }
-
- if (logDebug) {
- Log.d(LOGTAG, "Got test finished message");
- }
- } finally {
- expecter.unregisterListener();
- mAsserter.dumpLog("Unregistered listener for " + EVENT_TYPE);
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/MotionEventHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/MotionEventHelper.java
deleted file mode 100644
index 5b8254e99..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/MotionEventHelper.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.gfx.LayerView;
-import org.mozilla.gecko.PrefsHelper;
-
-import android.app.Instrumentation;
-import android.os.SystemClock;
-import android.util.Log;
-import android.view.MotionEvent;
-
-class MotionEventHelper {
- private static final String LOGTAG = "RobocopMotionEventHelper";
-
- private static final long DRAG_EVENTS_PER_SECOND = 20; // 20 move events per second when doing a drag
-
- private final Instrumentation mInstrumentation;
- private final int mSurfaceOffsetX;
- private final int mSurfaceOffsetY;
- private final LayerView layerView;
- private boolean mApzEnabled;
- private float mTouchStartTolerance;
- private final int mDpi;
-
- public MotionEventHelper(Instrumentation inst, int surfaceOffsetX, int surfaceOffsetY) {
- mInstrumentation = inst;
- mSurfaceOffsetX = surfaceOffsetX;
- mSurfaceOffsetY = surfaceOffsetY;
- layerView = GeckoAppShell.getLayerView();
- mApzEnabled = false;
- mTouchStartTolerance = 0.0f;
- mDpi = GeckoAppShell.getDpi();
- Log.i(LOGTAG, "Initialized using offset (" + mSurfaceOffsetX + "," + mSurfaceOffsetY + ")");
- PrefsHelper.getPref("layers.async-pan-zoom.enabled", new PrefsHelper.PrefHandlerBase() {
- @Override public void prefValue(String pref, boolean value) {
- mApzEnabled = value;
- }
- });
- PrefsHelper.getPref("apz.touch_start_tolerance", new PrefsHelper.PrefHandlerBase() {
- @Override public void prefValue(String pref, String value) {
- mTouchStartTolerance = Float.parseFloat(value);
- }
- });
- }
-
- public long down(float x, float y) {
- Log.d(LOGTAG, "Triggering down at (" + x + "," + y + ")");
- long downTime = SystemClock.uptimeMillis();
- MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, mSurfaceOffsetX + x, mSurfaceOffsetY + y, 0);
- try {
- mInstrumentation.sendPointerSync(event);
- } finally {
- event.recycle();
- event = null;
- }
- return downTime;
- }
-
- public long move(long downTime, float x, float y) {
- return move(downTime, SystemClock.uptimeMillis(), x, y);
- }
-
- public long move(long downTime, long moveTime, float x, float y) {
- Log.d(LOGTAG, "Triggering move to (" + x + "," + y + ")");
- MotionEvent event = MotionEvent.obtain(downTime, moveTime, MotionEvent.ACTION_MOVE, mSurfaceOffsetX + x, mSurfaceOffsetY + y, 0);
- try {
- mInstrumentation.sendPointerSync(event);
- } finally {
- event.recycle();
- event = null;
- }
- return downTime;
- }
-
- public long up(long downTime, float x, float y) {
- return up(downTime, SystemClock.uptimeMillis(), x, y);
- }
-
- public long up(long downTime, long upTime, float x, float y) {
- Log.d(LOGTAG, "Triggering up at (" + x + "," + y + ")");
- MotionEvent event = MotionEvent.obtain(downTime, upTime, MotionEvent.ACTION_UP, mSurfaceOffsetX + x, mSurfaceOffsetY + y, 0);
- try {
- mInstrumentation.sendPointerSync(event);
- } finally {
- event.recycle();
- event = null;
- }
- return -1L;
- }
-
- private long movePastTouchStartTolerance(float startX, float startY, float endX, float endY) {
- long downTime = 0;
- float eventDx = (endX - startX);
- float eventDy = (endY - startY);
- if (mApzEnabled && (mTouchStartTolerance > 0.0f) && (eventDx != 0 || eventDy !=0)) {
- final float dragLength = (float)Math.sqrt((eventDx * eventDx) + (eventDy * eventDy));
- final float extraDragLength = (float)Math.ceil(mTouchStartTolerance * mDpi);
- final float extraDx = (eventDx / dragLength) * extraDragLength * (eventDx > 0.0f ? -1.0f : 1.0f);
- final float extraDy = (eventDy / dragLength) * extraDragLength * (eventDy > 0.0f ? -1.0f : 1.0f);
- downTime = down(startX + extraDx, startY + extraDy);
- downTime = move(downTime, startX + extraDx, startY + extraDy);
- try {
- Thread.sleep(1000L / DRAG_EVENTS_PER_SECOND);
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- } else {
- downTime = down(startX, startY);
- }
- return downTime;
- }
-
- public Thread dragAsync(final float startX, final float startY, final float endX, final float endY, final long durationMillis) {
- Thread t = new Thread() {
- @Override
- public void run() {
- layerView.setIsLongpressEnabled(false);
-
- int numEvents = (int)(durationMillis * DRAG_EVENTS_PER_SECOND / 1000);
- float eventDx = (endX - startX) / numEvents;
- float eventDy = (endY - startY) / numEvents;
- long downTime = movePastTouchStartTolerance(startX, startY, endX, endY);
- for (int i = 0; i < numEvents - 1; i++) {
- downTime = move(downTime, startX + (eventDx * i), startY + (eventDy * i));
- try {
- Thread.sleep(1000L / DRAG_EVENTS_PER_SECOND);
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- }
- // sleep a bit before sending the last move so that the calculated
- // fling velocity is low and we don't end up doing a fling afterwards.
- try {
- Thread.sleep(1000L);
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- // do the last one using endX/endY directly to avoid rounding errors
- downTime = move(downTime, endX, endY);
- downTime = up(downTime, endX, endY);
-
- layerView.setIsLongpressEnabled(true);
- }
- };
- t.start();
- return t;
- }
-
- public void dragSync(float startX, float startY, float endX, float endY, long durationMillis) {
- try {
- dragAsync(startX, startY, endX, endY, durationMillis).join();
- mInstrumentation.waitForIdleSync();
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- }
-
- public void dragSync(float startX, float startY, float endX, float endY) {
- dragSync(startX, startY, endX, endY, 1000);
- }
-
- public Thread flingAsync(final float startX, final float startY, final float endX, final float endY, final float velocity) {
- // note that the first move after the touch-down is used to get over the panning threshold, and
- // is basically cancelled out. this means we need to generate (at least) two move events, with
- // the last move event hitting the target velocity. to do this we just slice the total distance
- // in half, assuming the first half will get us over the panning threshold and the second half
- // will trigger the fling.
- final float dx = (endX - startX) / 2;
- final float dy = (endY - startY) / 2;
- float distance = (float) Math.sqrt((dx * dx) + (dy * dy));
- final long time = (long)(distance / velocity);
- if (time <= 0) {
- throw new IllegalArgumentException( "Fling parameters require too small a time period" );
- }
- Thread t = new Thread() {
- @Override
- public void run() {
- long downTime = down(startX, startY);
- downTime = move(downTime, downTime + time, startX + dx, startY + dy);
- downTime = move(downTime, downTime + time + time, endX, endY);
- downTime = up(downTime, downTime + time + time + time, endX, endY);
- }
- };
- t.start();
- return t;
- }
-
- public void flingSync(float startX, float startY, float endX, float endY, float velocity) {
- try {
- flingAsync(startX, startY, endX, endY, velocity).join();
- mInstrumentation.waitForIdleSync();
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- }
-
- public void tap(float x, float y) {
- long downTime = down(x, y);
- downTime = up(downTime, x, y);
- }
-
- public void doubleTap(float x, float y) {
- tap(x, y);
- tap(x, y);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/MotionEventReplayer.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/MotionEventReplayer.java
deleted file mode 100644
index 508c6b197..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/MotionEventReplayer.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import android.app.Instrumentation;
-import android.os.Build;
-import android.os.SystemClock;
-import android.util.Log;
-import android.view.MotionEvent;
-
-class MotionEventReplayer {
- private static final String LOGTAG = "RobocopMotionEventReplayer";
-
- // the inner dimensions of the window on which the motion event capture was taken from
- private static final int CAPTURE_WINDOW_WIDTH = 720;
- private static final int CAPTURE_WINDOW_HEIGHT = 1038;
-
- private final Instrumentation mInstrumentation;
- private final int mSurfaceOffsetX;
- private final int mSurfaceOffsetY;
- private final int mSurfaceWidth;
- private final int mSurfaceHeight;
- private final Map<String, Integer> mActionTypes;
- private Method mObtainNanoMethod;
-
- public MotionEventReplayer(Instrumentation inst, int surfaceOffsetX, int surfaceOffsetY, int surfaceWidth, int surfaceHeight) {
- mInstrumentation = inst;
- mSurfaceOffsetX = surfaceOffsetX;
- mSurfaceOffsetY = surfaceOffsetY;
- mSurfaceWidth = surfaceWidth;
- mSurfaceHeight = surfaceHeight;
- Log.i(LOGTAG, "Initialized using offset (" + mSurfaceOffsetX + "," + mSurfaceOffsetY + ")");
-
- mActionTypes = new HashMap<String, Integer>();
- mActionTypes.put("ACTION_CANCEL", MotionEvent.ACTION_CANCEL);
- mActionTypes.put("ACTION_DOWN", MotionEvent.ACTION_DOWN);
- mActionTypes.put("ACTION_MOVE", MotionEvent.ACTION_MOVE);
- mActionTypes.put("ACTION_POINTER_DOWN", MotionEvent.ACTION_POINTER_DOWN);
- mActionTypes.put("ACTION_POINTER_UP", MotionEvent.ACTION_POINTER_UP);
- mActionTypes.put("ACTION_UP", MotionEvent.ACTION_UP);
- }
-
- private int parseAction(String action) {
- int index = 0;
-
- // ACTION_POINTER_DOWN and ACTION_POINTER_UP might be followed by
- // pointer index in parentheses, like ACTION_POINTER_UP(1)
- int beginParen = action.indexOf("(");
- if (beginParen >= 0) {
- int endParen = action.indexOf(")", beginParen + 1);
- index = Integer.parseInt(action.substring(beginParen + 1, endParen));
- action = action.substring(0, beginParen);
- }
-
- return mActionTypes.get(action) | (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
- }
-
- private int parseInt(String value) {
- if (value == null) {
- return 0;
- }
- if (value.startsWith("0x")) {
- return Integer.parseInt(value.substring(2), 16);
- }
- return Integer.parseInt(value);
- }
-
- private float scaleX(float value) {
- return value * mSurfaceWidth / CAPTURE_WINDOW_WIDTH;
- }
-
- private float scaleY(float value) {
- return value * mSurfaceHeight / CAPTURE_WINDOW_HEIGHT;
- }
-
- public void replayEvents(InputStream eventDescriptions)
- throws IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
- {
- // As an example, a line in the input stream might look like:
- //
- // MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=424.41055, y[0]=825.2412,
- // toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0,
- // edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=21972329,
- // downTime=21972329, deviceId=6, source=0x1002 }
- //
- // These can be generated by printing out event.toString() in LayerView's
- // onTouchEvent function on a phone running Ice Cream Sandwich. Different
- // Android versions have different serializations of the motion event, and this
- // code could probably be modified to parse other serializations if needed.
- Pattern p = Pattern.compile("MotionEvent \\{ (.*?) \\}");
- Map<String, String> eventProperties = new HashMap<String, String>();
-
- boolean firstEvent = true;
- long timeDelta = 0L;
- long lastEventTime = 0L;
-
- BufferedReader br = new BufferedReader(new InputStreamReader(eventDescriptions));
- try {
- for (String eventStr = br.readLine(); eventStr != null; eventStr = br.readLine()) {
- Matcher m = p.matcher(eventStr);
- if (! m.find()) {
- // this line doesn't have any MotionEvent data, skip it
- continue;
- }
-
- // extract the key-value pairs from the description and store them
- // in the eventProperties table
- StringTokenizer keyValues = new StringTokenizer(m.group(1), ",");
- while (keyValues.hasMoreTokens()) {
- String keyValue = keyValues.nextToken();
- String key = keyValue.substring(0, keyValue.indexOf('=')).trim();
- String value = keyValue.substring(keyValue.indexOf('=') + 1).trim();
- eventProperties.put(key, value);
- }
-
- // set up the values we need to build the MotionEvent
- long downTime = Long.parseLong(eventProperties.get("downTime"));
- long eventTime = Long.parseLong(eventProperties.get("eventTime"));
- int action = parseAction(eventProperties.get("action"));
- float pressure = 1.0f;
- float size = 1.0f;
- int metaState = parseInt(eventProperties.get("metaState"));
- float xPrecision = 1.0f;
- float yPrecision = 1.0f;
- int deviceId = 0;
- int edgeFlags = parseInt(eventProperties.get("edgeFlags"));
- int source = parseInt(eventProperties.get("source"));
- int flags = parseInt(eventProperties.get("flags"));
-
- int pointerCount = parseInt(eventProperties.get("pointerCount"));
- int[] pointerIds = new int[pointerCount];
- Object pointerData;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
- MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointerCount];
- for (int i = 0; i < pointerCount; i++) {
- pointerIds[i] = Integer.parseInt(eventProperties.get("id[" + i + "]"));
- pointerCoords[i] = new MotionEvent.PointerCoords();
- pointerCoords[i].x = mSurfaceOffsetX + scaleX(Float.parseFloat(eventProperties.get("x[" + i + "]")));
- pointerCoords[i].y = mSurfaceOffsetY + scaleY(Float.parseFloat(eventProperties.get("y[" + i + "]")));
- }
- pointerData = pointerCoords;
- } else {
- // pre-gingerbread we have to use a hidden API to create the motion event, and we have
- // to create a flattened list of floats rather than an array of PointerCoords
- final int NUM_SAMPLE_DATA = 4; // MotionEvent.NUM_SAMPLE_DATA
- final int SAMPLE_X = 0; // MotionEvent.SAMPLE_X
- final int SAMPLE_Y = 1; // MotionEvent.SAMPLE_Y
- float[] sampleData = new float[pointerCount * NUM_SAMPLE_DATA];
- for (int i = 0; i < pointerCount; i++) {
- pointerIds[i] = Integer.parseInt(eventProperties.get("id[" + i + "]"));
- sampleData[(i * NUM_SAMPLE_DATA) + SAMPLE_X] =
- mSurfaceOffsetX + scaleX(Float.parseFloat(eventProperties.get("x[" + i + "]")));
- sampleData[(i * NUM_SAMPLE_DATA) + SAMPLE_Y] =
- mSurfaceOffsetY + scaleY(Float.parseFloat(eventProperties.get("y[" + i + "]")));
- }
- pointerData = sampleData;
- }
-
- // we want to adjust the timestamps on all the generated events so that they line up with
- // the time that this function is executing on-device.
- long now = SystemClock.uptimeMillis();
- if (firstEvent) {
- timeDelta = now - eventTime;
- firstEvent = false;
- }
- downTime += timeDelta;
- eventTime += timeDelta;
-
- // we also generate the events in "real-time" (i.e. have delays between events that
- // correspond to the delays in the event timestamps).
- if (now < eventTime) {
- try {
- Thread.sleep(eventTime - now);
- } catch (InterruptedException ie) {
- }
- }
-
- // and finally we dispatch the event
- MotionEvent event;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
- event = MotionEvent.obtain(downTime, eventTime, action, pointerCount,
- pointerIds, (MotionEvent.PointerCoords[])pointerData, metaState,
- xPrecision, yPrecision, deviceId, edgeFlags, source, flags);
- } else {
- // pre-gingerbread we have to use a hidden API to accomplish this
- if (mObtainNanoMethod == null) {
- mObtainNanoMethod = MotionEvent.class.getMethod("obtainNano", long.class,
- long.class, long.class, int.class, int.class, pointerIds.getClass(),
- pointerData.getClass(), int.class, float.class, float.class,
- int.class, int.class);
- }
- event = (MotionEvent)mObtainNanoMethod.invoke(null, downTime, eventTime,
- eventTime * 1000000, action, pointerCount, pointerIds, (float[])pointerData,
- metaState, xPrecision, yPrecision, deviceId, edgeFlags);
- }
- try {
- Log.v(LOGTAG, "Injecting " + event.toString());
- mInstrumentation.sendPointerSync(event);
- } finally {
- event.recycle();
- event = null;
- }
-
- eventProperties.clear();
- }
- } finally {
- br.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/PixelTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/PixelTest.java
deleted file mode 100644
index a33ecf241..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/PixelTest.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.PaintedSurface;
-
-abstract class PixelTest extends BaseTest {
- private static final long PAINT_CLEAR_DELAY = 10000; // milliseconds
-
- protected final PaintedSurface loadAndGetPainted(String url) {
- Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
- loadUrlAndWait(url);
- verifyHomePagerHidden();
- paintExpecter.blockUntilClear(PAINT_CLEAR_DELAY);
- paintExpecter.unregisterListener();
- PaintedSurface p = mDriver.getPaintedSurface();
- if (p == null) {
- mAsserter.ok(p != null, "checking that painted surface loaded",
- "painted surface loaded");
- }
- return p;
- }
-
- protected final void loadAndPaint(String url) {
- PaintedSurface painted = loadAndGetPainted(url);
- painted.close();
- }
-
- protected final PaintedSurface reloadAndGetPainted() {
- Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
-
- mActions.sendSpecialKey(Actions.SpecialKey.MENU);
- waitForText(mStringHelper.RELOAD_LABEL);
- mSolo.clickOnText(mStringHelper.RELOAD_LABEL);
-
- paintExpecter.blockUntilClear(PAINT_CLEAR_DELAY);
- paintExpecter.unregisterListener();
- PaintedSurface p = mDriver.getPaintedSurface();
- if (p == null) {
- mAsserter.ok(p != null, "checking that painted surface loaded",
- "painted surface loaded");
- }
- return p;
- }
-
- protected final void reloadAndPaint() {
- PaintedSurface painted = reloadAndGetPainted();
- painted.close();
- }
-
- protected final PaintedSurface waitForPaint(Actions.RepeatedEventExpecter expecter) {
- expecter.blockUntilClear(PAINT_CLEAR_DELAY);
- PaintedSurface p = mDriver.getPaintedSurface();
- if (p == null) {
- mAsserter.ok(p != null, "checking that painted surface loaded",
- "painted surface loaded");
- }
- return p;
- }
-
- protected final PaintedSurface waitWithNoPaint(Actions.RepeatedEventExpecter expecter) {
- try {
- Thread.sleep(PAINT_CLEAR_DELAY);
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- mAsserter.is(expecter.eventReceived(), false, "Checking gecko didn't draw unnecessarily");
- PaintedSurface p = mDriver.getPaintedSurface();
- if (p == null) {
- mAsserter.ok(p != null, "checking that painted surface loaded",
- "painted surface loaded");
- }
- return p;
- }
-
- // this matches the algorithm in robocop_boxes.html
- protected final int[] getBoxColorAt(int x, int y) {
- int r = ((int)Math.floor(x / 3) % 256);
- r = r & 0xF8;
- int g = (x + y) % 256;
- g = g & 0xFC;
- int b = ((int)Math.floor(y / 3) % 256);
- b = b & 0xF8;
- return new int[] { r, g, b };
- }
-
- /**
- * Checks the top-left corner of the visible area of the page is at (x,y) of robocop_boxes.html.
- */
- protected final void checkScrollWithBoxes(PaintedSurface painted, int x, int y) {
- int[] color = getBoxColorAt(x, y);
- mAsserter.ispixel(painted.getPixelAt(0, 0), color[0], color[1], color[2], "Pixel at 0, 0");
- color = getBoxColorAt(x + 100, y);
- mAsserter.ispixel(painted.getPixelAt(100, 0), color[0], color[1], color[2], "Pixel at 100, 0");
- color = getBoxColorAt(x, y + 100);
- mAsserter.ispixel(painted.getPixelAt(0, 100), color[0], color[1], color[2], "Pixel at 0, 100");
- color = getBoxColorAt(x + 100, y + 100);
- mAsserter.ispixel(painted.getPixelAt(100, 100), color[0], color[1], color[2], "Pixel at 100, 100");
- }
-
- /**
- * Loads the robocop_boxes.html file and verifies that we are positioned at (0,0) on it.
- * @param url URL of the robocop_boxes.html file.
- * @return The painted surface after rendering the file.
- */
- protected final void loadAndVerifyBoxes(String url) {
- PaintedSurface painted = loadAndGetPainted(url);
- try {
- checkScrollWithBoxes(painted, 0, 0);
- } finally {
- painted.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/SelectionHandlerTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/SelectionHandlerTest.java
deleted file mode 100644
index eb808b542..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/SelectionHandlerTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-import org.mozilla.gecko.tests.helpers.NavigationHelper;
-
-import android.util.Log;
-
-import org.json.JSONObject;
-
-/**
- * A base test class for selection handler tests.
- */
-abstract class SelectionHandlerTest extends UITest {
- private static final String geckoEventString = "Robocop:testSelectionHandler";
- private final String url;
-
- public SelectionHandlerTest(String url) {
- this.url = url;
- }
-
- public void testSelection() {
- GeckoHelper.blockForReady();
-
- Actions.EventExpecter robocopTestExpecter = getActions().expectGeckoEvent(geckoEventString);
- NavigationHelper.enterAndLoadUrl(url);
- mToolbar.assertTitle(url);
-
- while (!test(robocopTestExpecter)) {
- // do nothing
- }
-
- robocopTestExpecter.unregisterListener();
- }
-
- protected boolean test(Actions.EventExpecter expecter) {
- final JSONObject eventData;
- try {
- eventData = new JSONObject(expecter.blockForEventData());
- } catch(Exception ex) {
- // Log and ignore
- getAsserter().ok(false, "JS Test", "Error decoding data " + ex);
- return false;
- }
-
- if (eventData.has("result")) {
- getAsserter().ok(eventData.optBoolean("result"), "JS Test", eventData.optString("msg"));
- } else if (eventData.has("todo")) {
- getAsserter().todo(eventData.optBoolean("todo"), "JS TODO", eventData.optString("msg"));
- }
-
- EventDispatcher.sendResponse(eventData, new JSONObject());
- return eventData.optBoolean("done", false);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/SessionTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/SessionTest.java
deleted file mode 100644
index e07a9750c..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/SessionTest.java
+++ /dev/null
@@ -1,407 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Assert;
-import org.mozilla.gecko.FennecMochitestAssert;
-
-public abstract class SessionTest extends BaseTest {
- protected Navigation mNavigation;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- mNavigation = new Navigation(mDevice);
- }
-
- /**
- * A generic session object representing a collection of items that has a
- * selected index.
- */
- protected abstract class SessionObject<T> {
- private final int mIndex;
- private final T[] mItems;
-
- public SessionObject(int index, T... items) {
- mIndex = index;
- mItems = items;
- }
-
- public int getIndex() {
- return mIndex;
- }
-
- public T[] getItems() {
- return mItems;
- }
- }
-
- protected class PageInfo {
- private final String url;
- private final String title;
-
- public PageInfo(String key) {
- if (key.startsWith("about:")) {
- url = key;
- } else {
- url = getPage(key);
- }
- title = key;
- }
- }
-
- protected class SessionTab extends SessionObject<PageInfo> {
- public SessionTab(int index, PageInfo... items) {
- super(index, items);
- }
- }
-
- protected class Session extends SessionObject<SessionTab> {
- public Session(int index, SessionTab... items) {
- super(index, items);
- }
- }
-
- /**
- * Walker for visiting items in a browser-like navigation order.
- */
- protected abstract class NavigationWalker<T> {
- private final T[] mItems;
- private final int mIndex;
-
- public NavigationWalker(SessionObject<T> obj) {
- mItems = obj.getItems();
- mIndex = obj.getIndex();
- }
-
- /**
- * Walks over the list of items, calling the onItem() callback for each.
- *
- * The selected item is the first item visited. Each item after the
- * selected item is then visited in ascending index order. Finally, the
- * list is iterated in reverse, and each item before the selected item
- * is visited in descending index order.
- */
- public void walk() {
- onItem(mItems[mIndex], mIndex);
- for (int i = mIndex + 1; i < mItems.length; i++) {
- goForward();
- onItem(mItems[i], i);
- }
- if (mIndex > 0) {
- for (int i = mItems.length - 2; i >= 0; i--) {
- goBack();
- if (i < mIndex) {
- onItem(mItems[i], i);
- }
- }
- }
- }
-
- /**
- * Callback when an item is visited during a walk.
- *
- * Only one callback is executed per item.
- */
- public abstract void onItem(T item, int currentIndex);
-
- /**
- * Callback executed for each back step of the walk.
- */
- public void goBack() {}
-
- /**
- * Callback executed for each forward step of the walk.
- */
- public void goForward() {}
- }
-
- /**
- * Loads a set of tabs in the browser specified by the given session.
- *
- * @param session Session to load
- */
- protected void loadSessionTabs(Session session) {
- // Verify initial about:home tab
- verifyTabCount(1);
- verifyUrl(mStringHelper.ABOUT_HOME_URL);
-
- SessionTab[] tabs = session.getItems();
- for (int i = 0; i < tabs.length; i++) {
- final SessionTab tab = tabs[i];
- final PageInfo[] pages = tab.getItems();
-
- // New tabs always start with about:home, so make sure about:home
- // is always the first entry.
- mAsserter.is(pages[0].url, mStringHelper.ABOUT_HOME_URL, "first page in tab is " +
- mStringHelper.ABOUT_HOME_URL);
-
- // If this is the first tab, the tab already exists, so no need to
- // create a new one. Otherwise, create a new tab if we're loading
- // the first the first page in the set.
- if (i > 0) {
- addTab();
- }
-
- for (int j = 1; j < pages.length; j++) {
- Actions.EventExpecter pageShowExpecter = mActions.expectGeckoEvent("Content:PageShow");
-
- loadUrl(pages[j].url);
-
- pageShowExpecter.blockForEvent();
- pageShowExpecter.unregisterListener();
- }
-
- final int index = tab.getIndex();
- for (int j = pages.length - 1; j > index; j--) {
- mNavigation.back();
- }
- }
-
- selectTabAt(session.getIndex());
- }
-
- /**
- * Verifies that the set of open tabs matches the given session.
- *
- * @param session Session to verify
- */
- protected void verifySessionTabs(Session session) {
- verifyTabCount(session.getItems().length);
-
- (new NavigationWalker<SessionTab>(session) {
- boolean mFirstTabVisited;
-
- @Override
- public void onItem(SessionTab tab, int currentIndex) {
- // The first tab to check should already be selected at startup
- if (mFirstTabVisited) {
- selectTabAt(currentIndex);
- } else {
- mFirstTabVisited = true;
- }
-
- (new NavigationWalker<PageInfo>(tab) {
- @Override
- public void onItem(PageInfo page, int currentIndex) {
- final String text;
- if (mStringHelper.ABOUT_HOME_URL.equals(page.url)) {
- text = mStringHelper.TITLE_PLACE_HOLDER;
- } else if (page.url.startsWith(URL_HTTP_PREFIX)) {
- text = page.url.substring(URL_HTTP_PREFIX.length());
- } else {
- text = page.url;
- }
- waitForText(text);
-
- verifyUrlBarTitle(page.url);
- }
-
- @Override
- public void goBack() {
- mNavigation.back();
- }
-
- @Override
- public void goForward() {
- mNavigation.forward();
- }
- }).walk();
- }
- }).walk();
- }
-
- /**
- * Gets session restore JSON corresponding to the open session.
- *
- * The JSON format follows the format used in Gecko for session restore and
- * should be interchangeable with the Gecko's generated sessionstore.js.
- *
- * @param session Session to serialize
- * @return JSON string of session
- */
- protected String buildSessionJSON(Session session) {
- final SessionTab[] sessionTabs = session.getItems();
- String sessionString = null;
-
- try {
- final JSONArray tabs = new JSONArray();
-
- for (int i = 0; i < sessionTabs.length; i++) {
- final JSONObject tab = new JSONObject();
- final JSONArray entries = new JSONArray();
- final SessionTab sessionTab = sessionTabs[i];
- final PageInfo[] pages = sessionTab.getItems();
-
- for (int j = 0; j < pages.length; j++) {
- final PageInfo page = pages[j];
- final JSONObject entry = new JSONObject();
- entry.put("url", page.url);
- entry.put("title", page.title);
- entries.put(entry);
- }
-
- tab.put("entries", entries);
- tab.put("index", sessionTab.getIndex() + 1);
- tabs.put(tab);
- }
-
- JSONObject window = new JSONObject();
- window.put("tabs", tabs);
- window.put("selected", session.getIndex() + 1);
- sessionString = new JSONObject().put("windows", new JSONArray().put(window)).toString();
- } catch (JSONException e) {
- mAsserter.ok(false, "JSON exception", getStackTraceString(e));
- }
-
- return sessionString;
- }
-
- /**
- * @see SessionTest#verifySessionJSON(Session, String, Assert)
- */
- protected void verifySessionJSON(Session session, String sessionString) {
- verifySessionJSON(session, sessionString, mAsserter);
- }
-
- /**
- * Verifies a session JSON string against the given session.
- *
- * @param session Session to verify against
- * @param sessionString JSON string to verify
- * @param asserter Assert class to use during verification
- */
- protected void verifySessionJSON(Session session, String sessionString, Assert asserter) {
- final SessionTab[] sessionTabs = session.getItems();
-
- try {
- final JSONObject window = new JSONObject(sessionString).getJSONArray("windows").getJSONObject(0);
- final JSONArray tabs = window.getJSONArray("tabs");
- final int optSelected = window.optInt("selected", -1);
-
- asserter.is(optSelected, session.getIndex() + 1, "selected tab matches");
-
- for (int i = 0; i < tabs.length(); i++) {
- final JSONObject tab = tabs.getJSONObject(i);
- final int index = tab.getInt("index");
- final JSONArray entries = tab.getJSONArray("entries");
- final SessionTab sessionTab = sessionTabs[i];
- final PageInfo[] pages = sessionTab.getItems();
-
- asserter.is(index, sessionTab.getIndex() + 1, "selected page index matches");
-
- for (int j = 0; j < entries.length(); j++) {
- final JSONObject entry = entries.getJSONObject(j);
- final String url = entry.getString("url");
- final String title = entry.optString("title");
- final PageInfo page = pages[j];
-
- asserter.is(url, page.url, "URL in JSON matches session URL");
- if (!page.url.startsWith("about:")) {
- asserter.is(title, page.title, "title in JSON matches session title");
- }
- }
- }
- } catch (JSONException e) {
- asserter.ok(false, "JSON exception", getStackTraceString(e));
- }
- }
-
- /**
- * Exception thrown by NonFatalAsserter for assertion failures.
- */
- public static class AssertException extends RuntimeException {
- public AssertException(String msg) {
- super(msg);
- }
- }
-
- /**
- * Asserter that throws an AssertException on failure instead of aborting
- * the test.
- *
- * This can be used in methods called via waitForCondition() where an assertion
- * might not immediately succeed.
- */
- public class NonFatalAsserter extends FennecMochitestAssert {
- @Override
- public void ok(boolean condition, String name, String diag) {
- if (!condition) {
- String details = (diag == null ? "" : " | " + diag);
- throw new AssertException("Assertion failed: " + name + details);
- }
- mAsserter.ok(condition, name, diag);
- }
- }
-
- /**
- * Gets a URL for a dynamically-generated page.
- *
- * The page will have a URL unique to the given ID, and the page's title
- * will match the given ID.
- *
- * @param id ID used to generate page URL
- * @return URL of the page
- */
- protected String getPage(String id) {
- return getAbsoluteUrl("/robocop/robocop_dynamic.sjs?id=" + id);
- }
-
- protected String readProfileFile(String filename) {
- try {
- return readFile(new File(mProfile, filename));
- } catch (IOException e) {
- mAsserter.ok(false, "Error reading" + filename, getStackTraceString(e));
- }
- return null;
- }
-
- protected void writeProfileFile(String filename, String data) {
- try {
- writeFile(new File(mProfile, filename), data);
- } catch (IOException e) {
- mAsserter.ok(false, "Error writing to " + filename, getStackTraceString(e));
- }
- }
-
- private String readFile(File target) throws IOException {
- if (!target.exists()) {
- return null;
- }
-
- FileReader fr = new FileReader(target);
- try {
- StringBuffer sb = new StringBuffer();
- char[] buf = new char[8192];
- int read = fr.read(buf);
- while (read >= 0) {
- sb.append(buf, 0, read);
- read = fr.read(buf);
- }
- return sb.toString();
- } finally {
- fr.close();
- }
- }
-
- private void writeFile(File target, String data) throws IOException {
- FileWriter writer = new FileWriter(target);
- try {
- writer.write(data);
- } finally {
- writer.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/StringHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/StringHelper.java
deleted file mode 100644
index 6f5db560d..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/StringHelper.java
+++ /dev/null
@@ -1,401 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.content.res.Resources;
-
-import org.mozilla.gecko.R;
-
-public class StringHelper {
- private static StringHelper instance;
-
- // This needs to be accessed statically, before an instance of StringHelper can be created.
- public static String STATIC_ABOUT_HOME_URL = "about:home";
-
- public final String OK;
- public final String CANCEL;
- public final String CLEAR;
-
- // Note: DEFAULT_BOOKMARKS_TITLES.length == DEFAULT_BOOKMARKS_URLS.length
- public final String[] DEFAULT_BOOKMARKS_TITLES;
- public final String[] DEFAULT_BOOKMARKS_URLS;
- public final int DEFAULT_BOOKMARKS_COUNT;
-
- // About pages
- public final String ABOUT_BLANK_URL = "about:blank";
- public final String ABOUT_FIREFOX_URL;
- public final String ABOUT_HOME_URL = "about:home";
- public final String ABOUT_ADDONS_URL = "about:addons";
- public final String ABOUT_SCHEME = "about:";
-
- // About pages' titles
- public final String ABOUT_HOME_TITLE = "";
-
- // Context Menu item strings
- public final String CONTEXT_MENU_BOOKMARK_LINK = "Bookmark Link";
- public final String CONTEXT_MENU_OPEN_LINK_IN_NEW_TAB = "Open Link in New Tab";
- public final String CONTEXT_MENU_OPEN_IN_NEW_TAB;
- public final String CONTEXT_MENU_OPEN_LINK_IN_PRIVATE_TAB = "Open Link in Private Tab";
- public final String CONTEXT_MENU_OPEN_IN_PRIVATE_TAB;
- public final String CONTEXT_MENU_COPY_LINK = "Copy Link";
- public final String CONTEXT_MENU_SHARE_LINK = "Share Link";
- public final String CONTEXT_MENU_EDIT;
- public final String CONTEXT_MENU_SHARE;
- public final String CONTEXT_MENU_REMOVE;
- public final String CONTEXT_MENU_COPY_ADDRESS;
- public final String CONTEXT_MENU_EDIT_SITE_SETTINGS;
- public final String CONTEXT_MENU_SITE_SETTINGS_SAVE_PASSWORD = "Save Password";
- public final String CONTEXT_MENU_ADD_TO_HOME_SCREEN;
- public final String CONTEXT_MENU_PIN_SITE;
- public final String CONTEXT_MENU_UNPIN_SITE;
-
- // Context Menu menu items
- public final String[] CONTEXT_MENU_ITEMS_IN_PRIVATE_TAB;
-
- public final String[] CONTEXT_MENU_ITEMS_IN_NORMAL_TAB;
-
- public final String[] BOOKMARK_CONTEXT_MENU_ITEMS;
-
- public final String[] CONTEXT_MENU_ITEMS_IN_URL_BAR;
-
- public final String TITLE_PLACE_HOLDER;
-
- // Robocop page urls
- // Note: please use getAbsoluteUrl(String url) on each robocop url to get the correct url
- public final String ROBOCOP_BIG_LINK_URL = "/robocop/robocop_big_link.html";
- public final String ROBOCOP_BIG_MAILTO_URL = "/robocop/robocop_big_mailto.html";
- public final String ROBOCOP_BLANK_PAGE_01_URL = "/robocop/robocop_blank_01.html";
- public final String ROBOCOP_BLANK_PAGE_02_URL = "/robocop/robocop_blank_02.html";
- public final String ROBOCOP_BLANK_PAGE_03_URL = "/robocop/robocop_blank_03.html";
- public final String ROBOCOP_BLANK_PAGE_04_URL = "/robocop/robocop_blank_04.html";
- public final String ROBOCOP_BLANK_PAGE_05_URL = "/robocop/robocop_blank_05.html";
- public final String ROBOCOP_BOXES_URL = "/robocop/robocop_boxes.html";
- public final String ROBOCOP_GEOLOCATION_URL = "/robocop/robocop_geolocation.html";
- public final String ROBOCOP_LOGIN_01_URL= "/robocop/robocop_login_01.html";
- public final String ROBOCOP_LOGIN_02_URL= "/robocop/robocop_login_02.html";
- public final String ROBOCOP_POPUP_URL = "/robocop/robocop_popup.html";
- public final String ROBOCOP_OFFLINE_STORAGE_URL = "/robocop/robocop_offline_storage.html";
- public final String ROBOCOP_PICTURE_LINK_URL = "/robocop/robocop_picture_link.html";
- public final String ROBOCOP_SEARCH_URL = "/robocop/robocop_search.html";
- public final String ROBOCOP_TEXT_PAGE_URL = "/robocop/robocop_text_page.html";
- public final String ROBOCOP_ADOBE_FLASH_URL = "/robocop/robocop_adobe_flash.html";
- public final String ROBOCOP_INPUT_URL = "/robocop/robocop_input.html";
- public final String ROBOCOP_READER_MODE_BASIC_ARTICLE = "/robocop/reader_mode_pages/basic_article.html";
- public final String ROBOCOP_LINK_TO_SLOW_LOADING = "/robocop/robocop_link_to_slow_loading.html";
-
- private final String ROBOCOP_JS_HARNESS_URL = "/robocop/robocop_javascript.html";
-
- // Robocop page images
- public final String ROBOCOP_PICTURE_URL = "/robocop/Firefox.jpg";
-
- // Robocop page titles
- public final String ROBOCOP_BIG_LINK_TITLE = "Big Link";
- public final String ROBOCOP_BIG_MAILTO_TITLE = "Big Mailto";
- public final String ROBOCOP_BLANK_PAGE_01_TITLE = "Browser Blank Page 01";
- public final String ROBOCOP_BLANK_PAGE_02_TITLE = "Browser Blank Page 02";
- public final String ROBOCOP_GEOLOCATION_TITLE = "Geolocation Test Page";
- public final String ROBOCOP_PICTURE_LINK_TITLE = "Picture Link";
- public final String ROBOCOP_SEARCH_TITLE = "Robocop Search Engine";
-
- // Distribution tile labels
- public final String DISTRIBUTION1_LABEL = "Distribution 1";
- public final String DISTRIBUTION2_LABEL = "Distribution 2";
-
- // Settings menu strings
- public final String PRIVACY_SECTION_LABEL;
- public final String MOZILLA_SECTION_LABEL;
-
- // Mozilla
- public final String BRAND_NAME = "(Fennec|Nightly|Firefox Aurora|Firefox Beta|Firefox)";
- public final String ABOUT_LABEL = "About " + BRAND_NAME ;
- public final String LOCATION_SERVICES_LABEL = "Mozilla Location Service";
-
- // Labels for the about:home tabs
- public final String HISTORY_LABEL;
- public final String TOP_SITES_LABEL;
- public final String BOOKMARKS_LABEL;
- public final String TODAY_LABEL;
-
- // Desktop default bookmarks folders
- public final String BOOKMARKS_UP_TO;
- public final String BOOKMARKS_ROOT_LABEL;
- public final String DESKTOP_FOLDER_LABEL;
- public final String TOOLBAR_FOLDER_LABEL;
- public final String BOOKMARKS_MENU_FOLDER_LABEL;
- public final String UNSORTED_FOLDER_LABEL;
-
- // Menu items - some of the items are found only on android 2.3 and lower and some only on android 3.0+
- public final String NEW_TAB_LABEL;
- public final String NEW_PRIVATE_TAB_LABEL;
- public final String SHARE_LABEL;
- public final String FIND_IN_PAGE_LABEL;
- public final String DESKTOP_SITE_LABEL;
- public final String PDF_LABEL;
- public final String DOWNLOADS_LABEL;
- public final String ADDONS_LABEL;
- public final String LOGINS_LABEL;
- public final String SETTINGS_LABEL;
- public final String GUEST_MODE_LABEL;
- public final String TAB_QUEUE_LABEL;
- public final String TAB_QUEUE_SUMMARY;
-
- // Android 3.0+
- public final String TOOLS_LABEL;
- public final String PAGE_LABEL;
-
- // Android 2.3 and lower only
- public final String MORE_LABEL = "More";
- public final String RELOAD_LABEL;
- public final String FORWARD_LABEL;
- public final String BOOKMARK_LABEL;
-
- // Bookmark Toast Notification
- public final String BOOKMARK_ADDED_LABEL;
- public final String BOOKMARK_REMOVED_LABEL;
- public final String BOOKMARK_UPDATED_LABEL;
- public final String BOOKMARK_OPTIONS_LABEL;
-
- // Edit Bookmark screen
- public final String EDIT_BOOKMARK;
-
- // Strings used in doorhanger messages and buttons
- public final String GEO_MESSAGE = "Share your location with";
- public final String GEO_ALLOW;
- public final String GEO_DENY = "Don't share";
-
- public final String OFFLINE_MESSAGE = "to store data on your device for offline use";
- public final String OFFLINE_ALLOW = "Allow";
- public final String OFFLINE_DENY = "Don't allow";
-
- public final String LOGIN_MESSAGE = "Would you like " + BRAND_NAME + " to remember this login?";
- public final String LOGIN_ALLOW = "Remember";
- public final String LOGIN_DENY = "Never";
-
- public final String POPUP_MESSAGE = "prevented this site from opening";
- public final String POPUP_ALLOW;
- public final String POPUP_DENY = "Don't show";
-
- // Strings used as content description, e.g. for ImageButtons
- public final String CONTENT_DESCRIPTION_READER_MODE_BUTTON = "Enter Reader View";
-
- // Home Panel Settings
- public final String CUSTOMIZE_HOME;
- public final String ENABLED;
- public final String HISTORY;
- public final String PANELS;
-
- // Search Settings
- public final String SEARCH_TITLE;
- public final String SEARCH_SUGGESTIONS;
- public final String SEARCH_INSTALLED;
-
- // Advanced Settings
- public final String ADVANCED;
- public final String DONT_SHOW_MENU;
- public final String SHOW_MENU;
- public final String DISABLED;
- public final String TAP_TO_PLAY;
- public final String HIDE_TITLE_BAR;
-
- // Update Settings
- public final String AUTOMATIC_UPDATES;
- public final String OVER_WIFI_OPTION;
- public final String DOWNLOAD_UPDATES_AUTO;
- public final String ALWAYS;
- public final String NEVER;
-
- // Restore Tabs Settings
- public final String DONT_RESTORE_TABS;
- public final String ALWAYS_RESTORE_TABS;
- public final String DONT_RESTORE_QUIT;
-
- private StringHelper(final Resources res) {
-
- OK = res.getString(R.string.button_ok);
- CANCEL = res.getString(R.string.button_cancel);
- CLEAR = res.getString(R.string.button_clear);
-
- // Note: DEFAULT_BOOKMARKS_TITLES.length == DEFAULT_BOOKMARKS_URLS.length
- DEFAULT_BOOKMARKS_TITLES = new String[] {
- res.getString(R.string.bookmarkdefaults_title_aboutfirefox),
- res.getString(R.string.bookmarkdefaults_title_support),
- res.getString(R.string.bookmarkdefaults_title_addons)
- };
- DEFAULT_BOOKMARKS_URLS = new String[] {
- res.getString(R.string.bookmarkdefaults_url_aboutfirefox),
- res.getString(R.string.bookmarkdefaults_url_support),
- res.getString(R.string.bookmarkdefaults_url_addons)
- };
- DEFAULT_BOOKMARKS_COUNT = DEFAULT_BOOKMARKS_TITLES.length;
-
- // About pages
- ABOUT_FIREFOX_URL = res.getString(R.string.bookmarkdefaults_url_aboutfirefox);
-
- // Context Menu item strings
- CONTEXT_MENU_OPEN_IN_NEW_TAB = res.getString(R.string.contextmenu_open_new_tab);
- CONTEXT_MENU_OPEN_IN_PRIVATE_TAB = res.getString(R.string.contextmenu_open_private_tab);
- CONTEXT_MENU_EDIT = res.getString(R.string.contextmenu_top_sites_edit);
- CONTEXT_MENU_SHARE = res.getString(R.string.contextmenu_share);
- CONTEXT_MENU_REMOVE = res.getString(R.string.contextmenu_remove);
- CONTEXT_MENU_COPY_ADDRESS = res.getString(R.string.contextmenu_copyurl);
- CONTEXT_MENU_EDIT_SITE_SETTINGS = res.getString(R.string.contextmenu_site_settings);
- CONTEXT_MENU_ADD_TO_HOME_SCREEN = res.getString(R.string.contextmenu_add_to_launcher);
- CONTEXT_MENU_PIN_SITE = res.getString(R.string.contextmenu_top_sites_pin);
- CONTEXT_MENU_UNPIN_SITE = res.getString(R.string.contextmenu_top_sites_unpin);
-
- // Context Menu menu items
- CONTEXT_MENU_ITEMS_IN_PRIVATE_TAB = new String[] {
- CONTEXT_MENU_OPEN_LINK_IN_PRIVATE_TAB,
- CONTEXT_MENU_COPY_LINK,
- CONTEXT_MENU_SHARE_LINK,
- CONTEXT_MENU_BOOKMARK_LINK
- };
-
- CONTEXT_MENU_ITEMS_IN_NORMAL_TAB = new String[] {
- CONTEXT_MENU_OPEN_LINK_IN_NEW_TAB,
- CONTEXT_MENU_OPEN_LINK_IN_PRIVATE_TAB,
- CONTEXT_MENU_COPY_LINK,
- CONTEXT_MENU_SHARE_LINK,
- CONTEXT_MENU_BOOKMARK_LINK
- };
-
- BOOKMARK_CONTEXT_MENU_ITEMS = new String[] {
- CONTEXT_MENU_OPEN_IN_NEW_TAB,
- CONTEXT_MENU_OPEN_IN_PRIVATE_TAB,
- CONTEXT_MENU_COPY_ADDRESS,
- CONTEXT_MENU_SHARE,
- CONTEXT_MENU_EDIT,
- CONTEXT_MENU_REMOVE,
- CONTEXT_MENU_ADD_TO_HOME_SCREEN
- };
-
- CONTEXT_MENU_ITEMS_IN_URL_BAR = new String[] {
- CONTEXT_MENU_SHARE,
- CONTEXT_MENU_COPY_ADDRESS,
- CONTEXT_MENU_EDIT_SITE_SETTINGS,
- CONTEXT_MENU_ADD_TO_HOME_SCREEN
- };
-
- TITLE_PLACE_HOLDER = res.getString(R.string.url_bar_default_text);
-
- // Settings menu strings
- PRIVACY_SECTION_LABEL = res.getString(R.string.pref_category_privacy_short);
- MOZILLA_SECTION_LABEL = res.getString(R.string.pref_category_vendor);
-
- // Labels for the about:home tabs
- HISTORY_LABEL = res.getString(R.string.home_history_title);
- TOP_SITES_LABEL = res.getString(R.string.home_top_sites_title);
- BOOKMARKS_LABEL = res.getString(R.string.bookmarks_title);
- TODAY_LABEL = res.getString(R.string.history_today_section);
-
- BOOKMARKS_UP_TO = res.getString(R.string.home_move_back_to_filter);
- BOOKMARKS_ROOT_LABEL = res.getString(R.string.bookmarks_title);
- DESKTOP_FOLDER_LABEL = res.getString(R.string.bookmarks_folder_desktop);
- TOOLBAR_FOLDER_LABEL = res.getString(R.string.bookmarks_folder_toolbar);
- BOOKMARKS_MENU_FOLDER_LABEL = res.getString(R.string.bookmarks_folder_menu);
- UNSORTED_FOLDER_LABEL = res.getString(R.string.bookmarks_folder_unfiled);
-
- // Menu items - some of the items are found only on android 2.3 and lower and some only on android 3.0+
- NEW_TAB_LABEL = res.getString(R.string.new_tab);
- NEW_PRIVATE_TAB_LABEL = res.getString(R.string.new_private_tab);
- SHARE_LABEL = res.getString(R.string.share);
- FIND_IN_PAGE_LABEL = res.getString(R.string.find_in_page);
- DESKTOP_SITE_LABEL = res.getString(R.string.desktop_mode);
- PDF_LABEL = res.getString(R.string.save_as_pdf);
- DOWNLOADS_LABEL = res.getString(R.string.downloads);
- ADDONS_LABEL = res.getString(R.string.addons);
- LOGINS_LABEL = res.getString(R.string.logins);
- SETTINGS_LABEL = res.getString(R.string.settings);
- GUEST_MODE_LABEL = res.getString(R.string.new_guest_session);
- TAB_QUEUE_LABEL = res.getString(R.string.pref_tab_queue_title);
- TAB_QUEUE_SUMMARY = res.getString(R.string.pref_tab_queue_summary);
-
- // Android 3.0+
- TOOLS_LABEL = res.getString(R.string.tools);
- PAGE_LABEL = res.getString(R.string.page);
-
- // Android 2.3 and lower only
- RELOAD_LABEL = res.getString(R.string.reload);
- FORWARD_LABEL = res.getString(R.string.forward);
- BOOKMARK_LABEL = res.getString(R.string.bookmark);
-
- // Bookmark Toast Notification
- BOOKMARK_ADDED_LABEL = res.getString(R.string.bookmark_added);
- BOOKMARK_REMOVED_LABEL = res.getString(R.string.bookmark_removed);
- BOOKMARK_UPDATED_LABEL = res.getString(R.string.bookmark_updated);
- BOOKMARK_OPTIONS_LABEL = res.getString(R.string.bookmark_options);
-
- // Edit Bookmark screen
- EDIT_BOOKMARK = res.getString(R.string.bookmark_edit_title);
-
- // Strings used in doorhanger messages and buttons
- GEO_ALLOW = res.getString(R.string.share);
-
- POPUP_ALLOW = res.getString(R.string.pref_panels_show);
-
- // Home Settings
- PANELS = res.getString(R.string.pref_category_home_panels);
- CUSTOMIZE_HOME = res.getString(R.string.pref_category_home);
- ENABLED = res.getString(R.string.pref_home_updates_enabled);
- HISTORY = res.getString(R.string.home_history_title);
-
- // Search Settings
- SEARCH_TITLE = res.getString(R.string.search);
- SEARCH_SUGGESTIONS = res.getString(R.string.pref_search_suggestions);
- SEARCH_INSTALLED = res.getString(R.string.pref_category_installed_search_engines);
-
- // Advanced Settings
- ADVANCED = res.getString(R.string.pref_category_advanced);
- DONT_SHOW_MENU = res.getString(R.string.pref_char_encoding_off);
- SHOW_MENU = res.getString(R.string.pref_char_encoding_on);
- DISABLED = res.getString(R.string.pref_plugins_disabled );
- TAP_TO_PLAY = res.getString(R.string.pref_plugins_tap_to_play);
- HIDE_TITLE_BAR = res.getString(R.string.pref_scroll_title_bar_summary );
-
- // Update Settings
- AUTOMATIC_UPDATES = res.getString(R.string.pref_home_updates);
- OVER_WIFI_OPTION = res.getString(R.string.pref_update_autodownload_wifi);
- DOWNLOAD_UPDATES_AUTO = res.getString(R.string.pref_update_autodownload);
- ALWAYS = res.getString(R.string.pref_update_autodownload_enabled);
- NEVER = res.getString(R.string.pref_update_autodownload_disabled);
-
- // Restore Tabs Settings
- DONT_RESTORE_TABS = res.getString(R.string.pref_restore_quit);
- ALWAYS_RESTORE_TABS = res.getString(R.string.pref_restore_always);
- DONT_RESTORE_QUIT = res.getString(R.string.pref_restore_quit);
- }
-
- public static void initialize(Resources res) {
- if (instance != null) {
- throw new IllegalStateException(StringHelper.class.getSimpleName() + " already Initialized");
- }
- instance = new StringHelper(res);
- }
-
- public static StringHelper get() {
- if (instance == null) {
- throw new IllegalStateException(StringHelper.class.getSimpleName() + " instance is not yet initialized. Use StringHelper.initialize(Resources) first.");
- }
- return instance;
- }
-
- /**
- * Build a URL for loading a Javascript file in the Robocop Javascript
- * harness.
- * <p>
- * We append a random slug to avoid caching: see
- * <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache">https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache</a>.
- *
- * @param javascriptUrl to load.
- * @return URL with harness wrapper.
- */
- public String getHarnessUrlForJavascript(String javascriptUrl) {
- // We include a slug to make sure we never cache the harness.
- return ROBOCOP_JS_HARNESS_URL +
- "?slug=" + System.currentTimeMillis() +
- "&path=" + javascriptUrl;
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/UITest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/UITest.java
deleted file mode 100644
index da952b5cb..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/UITest.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Assert;
-import org.mozilla.gecko.Driver;
-import org.mozilla.gecko.tests.components.AboutHomeComponent;
-import org.mozilla.gecko.tests.components.AppMenuComponent;
-import org.mozilla.gecko.tests.components.BaseComponent;
-import org.mozilla.gecko.tests.components.GeckoViewComponent;
-import org.mozilla.gecko.tests.components.TabStripComponent;
-import org.mozilla.gecko.tests.components.ToolbarComponent;
-import org.mozilla.gecko.tests.helpers.HelperInitializer;
-
-import com.robotium.solo.Solo;
-
-/**
- * A base test class for Robocop (UI-centric) tests. This and the related classes attempt to
- * provide a framework to improve upon the issues discovered with the previous BaseTest
- * implementation by providing simple test authorship and framework extension, consistency,
- * and reliability.
- *
- * For documentation on writing tests and extending the framework, see
- * https://wiki.mozilla.org/Mobile/Fennec/Android/UITest
- */
-abstract class UITest extends BaseRobocopTest
- implements UITestContext {
-
- private static final String JUNIT_FAILURE_MSG = "A JUnit method was called. Make sure " +
- "you are using AssertionHelper to make assertions. Try `fAssert*(...);`";
-
- protected AboutHomeComponent mAboutHome;
- protected AppMenuComponent mAppMenu;
- protected GeckoViewComponent mGeckoView;
- protected TabStripComponent mTabStrip;
- protected ToolbarComponent mToolbar;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- // Helpers depend on components so initialize them first.
- initComponents();
- initHelpers();
-
- // Ensure Robocop tests have access to network, and are run with Display powered on.
- throwIfHttpGetFails();
- throwIfScreenNotOn();
- }
-
- private void initComponents() {
- mAboutHome = new AboutHomeComponent(this);
- mAppMenu = new AppMenuComponent(this);
- mGeckoView = new GeckoViewComponent(this);
- mTabStrip = new TabStripComponent(this);
- mToolbar = new ToolbarComponent(this);
- }
-
- private void initHelpers() {
- HelperInitializer.init(this);
- }
-
- @Override
- public Solo getSolo() {
- return mSolo;
- }
-
- @Override
- public Assert getAsserter() {
- return mAsserter;
- }
-
- @Override
- public Driver getDriver() {
- return mDriver;
- }
-
- @Override
- public Actions getActions() {
- return mActions;
- }
-
- @Override
- public StringHelper getStringHelper() {
- return mStringHelper;
- }
-
- @Override
- public void dumpLog(final String logtag, final String message) {
- mAsserter.dumpLog(logtag + ": " + message);
- }
-
- @Override
- public void dumpLog(final String logtag, final String message, final Throwable t) {
- mAsserter.dumpLog(logtag + ": " + message, t);
- }
-
- @Override
- public BaseComponent getComponent(final ComponentType type) {
- switch (type) {
- case ABOUTHOME:
- return mAboutHome;
-
- case APPMENU:
- return mAppMenu;
-
- case GECKOVIEW:
- return mGeckoView;
-
- case TOOLBAR:
- return mToolbar;
-
- default:
- fail("Unknown component type, " + type + ".");
- return null; // Should not reach this statement but required by javac.
- }
- }
-
- /**
- * Returns the test type. By default this returns MOCHITEST, but tests can override this
- * method in order to change the type of the test.
- */
- @Override
- protected Type getTestType() {
- return Type.MOCHITEST;
- }
-
- @Override
- public String getAbsoluteHostnameUrl(final String url) {
- return getAbsoluteUrl(mBaseHostnameUrl, url);
- }
-
- @Override
- public String getAbsoluteIpUrl(final String url) {
- return getAbsoluteUrl(mBaseIpUrl, url);
- }
-
- private String getAbsoluteUrl(final String baseUrl, final String url) {
- return baseUrl + "/" + url.replaceAll("(^/)", "");
- }
-
- /**
- * Throws an Exception. Called from overridden JUnit methods to ensure JUnit assertions
- * are not accidentally used over AssertionHelper assertions (the latter of which contains
- * additional logging facilities for use in our test harnesses).
- */
- private static void junit() {
- throw new UnsupportedOperationException(JUNIT_FAILURE_MSG);
- }
-
- // Note: inexplicably, javac does not think we're overriding these methods,
- // so we can't use the @Override annotation.
- public static void assertEquals(short e, short a) { junit(); }
- public static void assertEquals(String m, int e, int a) { junit(); }
- public static void assertEquals(String m, short e, short a) { junit(); }
- public static void assertEquals(char e, char a) { junit(); }
- public static void assertEquals(String m, String e, String a) { junit(); }
- public static void assertEquals(int e, int a) { junit(); }
- public static void assertEquals(String m, double e, double a, double delta) { junit(); }
- public static void assertEquals(String m, long e, long a) { junit(); }
- public static void assertEquals(byte e, byte a) { junit(); }
- public static void assertEquals(Object e, Object a) { junit(); }
- public static void assertEquals(boolean e, boolean a) { junit(); }
- public static void assertEquals(String m, float e, float a, float delta) { junit(); }
- public static void assertEquals(String m, boolean e, boolean a) { junit(); }
- public static void assertEquals(String e, String a) { junit(); }
- public static void assertEquals(float e, float a, float delta) { junit(); }
- public static void assertEquals(String m, byte e, byte a) { junit(); }
- public static void assertEquals(double e, double a, double delta) { junit(); }
- public static void assertEquals(String m, char e, char a) { junit(); }
- public static void assertEquals(String m, Object e, Object a) { junit(); }
- public static void assertEquals(long e, long a) { junit(); }
-
- public static void assertFalse(String m, boolean c) { junit(); }
- public static void assertFalse(boolean c) { junit(); }
-
- public static void assertNotNull(String m, Object o) { junit(); }
- public static void assertNotNull(Object o) { junit(); }
-
- public static void assertNotSame(Object e, Object a) { junit(); }
- public static void assertNotSame(String m, Object e, Object a) { junit(); }
-
- public static void assertNull(Object o) { junit(); }
- public static void assertNull(String m, Object o) { junit(); }
-
- public static void assertSame(Object e, Object a) { junit(); }
- public static void assertSame(String m, Object e, Object a) { junit(); }
-
- public static void assertTrue(String m, boolean c) { junit(); }
- public static void assertTrue(boolean c) { junit(); }
-
- public static void fail(String m) { junit(); }
- public static void fail() { junit(); }
-
- public static void failNotEquals(String m, Object e, Object a) { junit(); }
- public static void failNotSame(String m, Object e, Object a) { junit(); }
- public static void failSame(String m) { junit(); }
-
- public static String format(String m, Object e, Object a) { junit(); return null; }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/UITestContext.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/UITestContext.java
deleted file mode 100644
index c825a20a4..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/UITestContext.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Assert;
-import org.mozilla.gecko.Driver;
-import org.mozilla.gecko.tests.components.BaseComponent;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-
-import com.robotium.solo.Solo;
-
-/**
- * Interface to the global information about a UITest environment.
- */
-public interface UITestContext {
-
- public static enum ComponentType {
- ABOUTHOME,
- APPMENU,
- GECKOVIEW,
- TOOLBAR
- }
-
- public Activity getActivity();
- public Solo getSolo();
- public Assert getAsserter();
- public Driver getDriver();
- public Actions getActions();
- public Instrumentation getInstrumentation();
- public StringHelper getStringHelper();
-
- public void dumpLog(final String logtag, final String message);
- public void dumpLog(final String logtag, final String message, final Throwable t);
-
- /**
- * Returns the absolute version of the given URL using the host's hostname.
- */
- public String getAbsoluteHostnameUrl(final String url);
-
- /**
- * Returns the absolute version of the given URL using the host's IP address.
- */
- public String getAbsoluteIpUrl(final String url);
-
- public BaseComponent getComponent(final ComponentType type);
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/AboutHomeComponent.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/AboutHomeComponent.java
deleted file mode 100644
index b12e0d23e..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/AboutHomeComponent.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.components;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.mozilla.gecko.AboutPages;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.Tabs;
-import org.mozilla.gecko.home.HomeConfig.PanelType;
-import org.mozilla.gecko.tests.UITestContext;
-import org.mozilla.gecko.tests.helpers.WaitHelper;
-
-import android.os.Build;
-import android.support.v4.view.ViewPager;
-import android.view.View;
-import android.widget.TextView;
-
-import com.robotium.solo.Condition;
-import com.robotium.solo.Solo;
-
-/**
- * A class representing any interactions that take place on the Awesomescreen.
- */
-public class AboutHomeComponent extends BaseComponent {
- private static final String LOGTAG = AboutHomeComponent.class.getSimpleName();
-
- private static final List<PanelType> PANEL_ORDERING = Arrays.asList(
- PanelType.TOP_SITES,
- PanelType.BOOKMARKS,
- PanelType.COMBINED_HISTORY
- );
-
- // The percentage of the panel to swipe between 0 and 1. This value was set through
- // testing: 0.55f was tested on try and fails on armv6 devices.
- private static final float SWIPE_PERCENTAGE = 0.70f;
-
- public AboutHomeComponent(final UITestContext testContext) {
- super(testContext);
- }
-
- private View getHomePagerContainer() {
- return mSolo.getView(R.id.home_screen_container);
- }
-
- private ViewPager getHomePagerView() {
- return (ViewPager) mSolo.getView(R.id.home_pager);
- }
-
- private View getHomeBannerView() {
- if (mSolo.waitForView(R.id.home_banner)) {
- return mSolo.getView(R.id.home_banner);
- }
- return null;
- }
-
- public AboutHomeComponent assertCurrentPanel(final PanelType expectedPanel) {
- assertVisible();
-
- final int expectedPanelIndex = PANEL_ORDERING.indexOf(expectedPanel);
- fAssertEquals("The current HomePager panel is " + expectedPanel,
- expectedPanelIndex, getHomePagerView().getCurrentItem());
- return this;
- }
-
- public AboutHomeComponent assertNotVisible() {
- fAssertTrue("The HomePager is not visible",
- getHomePagerContainer().getVisibility() != View.VISIBLE ||
- getHomePagerView().getVisibility() != View.VISIBLE);
- return this;
- }
-
- public AboutHomeComponent assertVisible() {
- fAssertTrue("The HomePager is visible",
- getHomePagerContainer().getVisibility() == View.VISIBLE &&
- getHomePagerView().getVisibility() == View.VISIBLE);
- return this;
- }
-
- public AboutHomeComponent assertBannerNotVisible() {
- View banner = getHomeBannerView();
- if (Build.VERSION.SDK_INT >= 11) {
- fAssertTrue("The HomeBanner is not visible",
- getHomePagerContainer().getVisibility() != View.VISIBLE ||
- banner == null ||
- banner.getVisibility() != View.VISIBLE ||
- banner.getTranslationY() == banner.getHeight());
- } else {
- // getTranslationY is not available before api 11.
- // This check is a little less specific.
- fAssertTrue("The HomeBanner is not visible",
- getHomePagerContainer().getVisibility() != View.VISIBLE ||
- banner == null ||
- banner.isShown() == false);
- }
- return this;
- }
-
- public AboutHomeComponent assertBannerVisible() {
- fAssertTrue("The HomeBanner is visible",
- getHomePagerContainer().getVisibility() == View.VISIBLE &&
- getHomeBannerView().getVisibility() == View.VISIBLE);
- return this;
- }
-
- public AboutHomeComponent assertBannerText(String text) {
- assertBannerVisible();
-
- final TextView textView = (TextView) getHomeBannerView().findViewById(R.id.text);
- fAssertEquals("The correct HomeBanner text is shown",
- text, textView.getText().toString());
- return this;
- }
-
- public AboutHomeComponent clickOnBanner() {
- assertBannerVisible();
-
- mTestContext.dumpLog(LOGTAG, "Clicking on HomeBanner.");
- mSolo.clickOnView(getHomeBannerView());
- return this;
- }
-
- public AboutHomeComponent dismissBanner() {
- assertBannerVisible();
-
- mTestContext.dumpLog(LOGTAG, "Clicking on HomeBanner close button.");
- mSolo.clickOnView(getHomeBannerView().findViewById(R.id.close));
- return this;
- }
-
- public AboutHomeComponent swipeToPanelOnRight() {
- mTestContext.dumpLog(LOGTAG, "Swiping to the panel on the right.");
- swipeToPanel(Solo.RIGHT);
- return this;
- }
-
- public AboutHomeComponent swipeToPanelOnLeft() {
- mTestContext.dumpLog(LOGTAG, "Swiping to the panel on the left.");
- swipeToPanel(Solo.LEFT);
- return this;
- }
-
- private void swipeToPanel(final int panelDirection) {
- fAssertTrue("Swiping in a valid direction",
- panelDirection == Solo.LEFT || panelDirection == Solo.RIGHT);
- assertVisible();
-
- final int panelIndex = getHomePagerView().getCurrentItem();
-
- mSolo.scrollViewToSide(getHomePagerView(), panelDirection, SWIPE_PERCENTAGE);
-
- // The panel on the left is a lower index and vice versa.
- final int unboundedPanelIndex = panelIndex + (panelDirection == Solo.LEFT ? -1 : 1);
- final int maxPanelIndex = PANEL_ORDERING.size() - 1;
- final int expectedPanelIndex = Math.min(Math.max(0, unboundedPanelIndex), maxPanelIndex);
-
- waitForPanelIndex(expectedPanelIndex);
- }
-
- private void waitForPanelIndex(final int expectedIndex) {
- final String panelName = PANEL_ORDERING.get(expectedIndex).name();
-
- WaitHelper.waitFor("HomePager " + panelName + " panel", new Condition() {
- @Override
- public boolean isSatisfied() {
- return (getHomePagerView().getCurrentItem() == expectedIndex);
- }
- });
- }
-
- /**
- * Navigate directly to a built-in panel by its panel type.
- * <p>
- * If the panel type is not part of the active Home Panel configuration, the
- * default about:home panel is displayed. If the panel type is not a
- * built-in panel, an IllegalArgumentException is thrown.
- *
- * @param panelType to navigate to.
- * @return self, for chaining.
- */
- public AboutHomeComponent navigateToBuiltinPanelType(PanelType panelType) throws IllegalArgumentException {
- Tabs.getInstance().loadUrl(AboutPages.getURLForBuiltinPanelType(panelType));
- final int expectedPanelIndex = PANEL_ORDERING.indexOf(panelType);
- waitForPanelIndex(expectedPanelIndex);
- return this;
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/AppMenuComponent.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/AppMenuComponent.java
deleted file mode 100644
index 278cc7564..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/AppMenuComponent.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.components;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertFalse;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.menu.MenuItemActionBar;
-import org.mozilla.gecko.menu.MenuItemDefault;
-import org.mozilla.gecko.tests.UITestContext;
-import org.mozilla.gecko.tests.helpers.DeviceHelper;
-import org.mozilla.gecko.tests.helpers.RobotiumHelper;
-import org.mozilla.gecko.tests.helpers.WaitHelper;
-
-import android.text.TextUtils;
-import android.view.View;
-import android.widget.TextView;
-import android.widget.RelativeLayout;
-
-import com.robotium.solo.Condition;
-import com.robotium.solo.RobotiumUtils;
-import com.robotium.solo.Solo;
-
-/**
- * A class representing any interactions that take place on the app menu.
- */
-public class AppMenuComponent extends BaseComponent {
- private static final int MAX_WAITTIME_FOR_MENU_UPDATE_IN_MS = 7500;
-
- public enum MenuItem {
- FORWARD(R.string.forward),
- NEW_TAB(R.string.new_tab),
- PAGE(R.string.page),
- RELOAD(R.string.reload);
-
- private final int resourceID;
- private String stringResource;
-
- MenuItem(final int resourceID) {
- this.resourceID = resourceID;
- }
-
- public String getString(final Solo solo) {
- if (stringResource == null) {
- stringResource = solo.getString(resourceID);
- }
-
- return stringResource;
- }
- };
-
- public enum PageMenuItem {
- SAVE_AS_PDF(R.string.save_as_pdf);
-
- private static final MenuItem PARENT_MENU = MenuItem.PAGE;
-
- private final int resourceID;
- private String stringResource;
-
- PageMenuItem(final int resourceID) {
- this.resourceID = resourceID;
- }
-
- public String getString(final Solo solo) {
- if (stringResource == null) {
- stringResource = solo.getString(resourceID);
- }
-
- return stringResource;
- }
- };
-
- public AppMenuComponent(final UITestContext testContext) {
- super(testContext);
- }
-
- public void assertMenuIsOpen() {
- fAssertTrue("Menu is open", isMenuOpen());
- }
-
- public void assertMenuIsNotOpen() {
- fAssertFalse("Menu is not open", isMenuOpen());
- }
-
- public void assertMenuItemIsDisabledAndVisible(PageMenuItem pageMenuItem) {
- openAppMenu();
-
- // Non-legacy devices have hierarchical menu, check for parent menu item "page".
- final View parentMenuItemView = findAppMenuItemView(MenuItem.PAGE.getString(mSolo));
- if (parentMenuItemView.isEnabled()) {
- fAssertTrue("The parent 'page' menu item is enabled", parentMenuItemView.isEnabled());
- fAssertEquals("The parent 'page' menu item is visible", View.VISIBLE,
- parentMenuItemView.getVisibility());
-
- // Parent menu "page" is enabled, open page menu and check for menu item represented by pageMenuItem.
- pressMenuItem(MenuItem.PAGE.getString(mSolo));
-
- final View pageMenuItemView = findAppMenuItemView(pageMenuItem.getString(mSolo));
- fAssertNotNull("The page menu item is not null", pageMenuItemView);
- fAssertFalse("The page menu item is not enabled", pageMenuItemView.isEnabled());
- fAssertEquals("The page menu item is visible", View.VISIBLE, pageMenuItemView.getVisibility());
- } else {
- fAssertFalse("The parent 'page' menu item is not enabled", parentMenuItemView.isEnabled());
- fAssertEquals("The parent 'page' menu item is visible", View.VISIBLE, parentMenuItemView.getVisibility());
- }
- // Close the App Menu.
- mSolo.goBack();
- }
-
- private View getOverflowMenuButtonView() {
- return mSolo.getView(R.id.menu);
- }
-
- /**
- * Try to find a MenuItemActionBar/MenuItemDefault with the given text set as contentDescription / text.
- *
- * When using legacy menus, make sure the menu has been opened to the appropriate level
- * (i.e. base menu or "More" menu) to ensure the appropriate menu views are in memory.
- * TODO: ^ Maybe we just need to have opened the "More" menu and the current one doesn't matter.
- *
- * This method is dependent on not having two views with equivalent contentDescription / text.
- */
- private View findAppMenuItemView(final String text) {
- return WaitHelper.waitFor(String.format("menu item view '%s'", text), new Callable<View>() {
- @Override
- public View call() throws Exception {
- final List<View> views = mSolo.getViews();
-
- final List<MenuItemActionBar> menuItemActionBarList = RobotiumUtils.filterViews(MenuItemActionBar.class, views);
- for (MenuItemActionBar menuItem : menuItemActionBarList) {
- if (TextUtils.equals(menuItem.getContentDescription(), text)) {
- return menuItem;
- }
- }
-
- final List<MenuItemDefault> menuItemDefaultList = RobotiumUtils.filterViews(MenuItemDefault.class, views);
- for (MenuItemDefault menuItem : menuItemDefaultList) {
- if (TextUtils.equals(menuItem.getText(), text)) {
- return menuItem;
- }
- }
-
- // On Android 2.3, menu items may be instances of
- // com.android.internal.view.menu.ListMenuItemView, each with a child
- // android.widget.RelativeLayout which in turn has a child
- // TextView with the appropriate text.
- final List<TextView> textViewList = RobotiumUtils.filterViews(TextView.class, views);
- for (TextView textView : textViewList) {
- if (TextUtils.equals(textView.getText(), text)) {
- View relativeLayout = (View) textView.getParent();
- if (relativeLayout instanceof RelativeLayout) {
- View listMenuItemView = (View)relativeLayout.getParent();
- return listMenuItemView;
- }
- }
- }
- return null;
- }
- }, MAX_WAITTIME_FOR_MENU_UPDATE_IN_MS);
- }
-
- /**
- * Helper function to let Robotium locate and click menu item from legacy Android menu (devices with Android 2.x).
- *
- * Robotium will also try to open the menu if there are no open dialog.
- *
- * @param menuItemTitle, The title of menu item to open.
- */
- private void pressLegacyMenuItem(final String menuItemTitle) {
- mSolo.clickOnMenuItem(menuItemTitle, true);
- }
-
- private void pressMenuItem(final String menuItemTitle) {
- // Wait for the menu item view to be enabled. This improves reliability on Android 2.3.
- WaitHelper.waitFor(String.format("menu item %s to be enabled", menuItemTitle), new Condition() {
- @Override
- public boolean isSatisfied() {
- View v = findAppMenuItemView(menuItemTitle);
- return (v != null) && v.isEnabled();
- }
- });
-
- final View menuItemView = findAppMenuItemView(menuItemTitle);
- fAssertTrue("Menu is open", isMenuOpen(menuItemView));
-
- fAssertTrue(String.format("The menu item %s is enabled", menuItemTitle), menuItemView.isEnabled());
- fAssertEquals(String.format("The menu item %s is visible", menuItemTitle), View.VISIBLE,
- menuItemView.getVisibility());
-
- mSolo.clickOnView(menuItemView);
- }
-
- private void pressSubMenuItem(final String parentMenuItemTitle, final String childMenuItemTitle) {
- openAppMenu();
-
- pressMenuItem(parentMenuItemTitle);
-
- // Child menu item is not pressed yet, Click on it.
- pressMenuItem(childMenuItemTitle);
- }
-
- public void pressMenuItem(MenuItem menuItem) {
- openAppMenu();
- pressMenuItem(menuItem.getString(mSolo));
- }
-
- public void pressMenuItem(final PageMenuItem pageMenuItem) {
- pressSubMenuItem(PageMenuItem.PARENT_MENU.getString(mSolo), pageMenuItem.getString(mSolo));
- }
-
- private void openAppMenu() {
- assertMenuIsNotOpen();
-
- // This is a hack needed for tablets where the OverflowMenuButton is always in the GONE state,
- // so we press the menu key instead.
- if (DeviceHelper.isTablet()) {
- mSolo.sendKey(Solo.MENU);
- } else {
- pressOverflowMenuButton();
- }
-
- waitForMenuOpen();
- }
-
- private void pressOverflowMenuButton() {
- final View overflowMenuButton = getOverflowMenuButtonView();
-
- fAssertTrue("The overflow menu button is enabled", overflowMenuButton.isEnabled());
- fAssertEquals("The overflow menu button is visible", View.VISIBLE, overflowMenuButton.getVisibility());
-
- mSolo.clickOnView(overflowMenuButton, true);
- }
-
- /**
- * Determines whether the app menu is open by searching for items in the menu.
- *
- * @return true if app menu is open.
- */
- private boolean isMenuOpen() {
- // We choose these options because New Tab is near the top of the menu and Page is near the middle/bottom.
- // Intermittently, the menu doesn't scroll to top so we can't just use the first item in the list.
- return isMenuOpen(MenuItem.NEW_TAB.getString(mSolo)) || isMenuOpen(MenuItem.PAGE.getString(mSolo));
- }
-
- /**
- * Determines whether the app menu is open by searching for the text in menuItemTitle.
- *
- * @param menuItemTitle, The contentDescription of menu item to search.
- *
- * @return true if app menu is open.
- */
- private boolean isMenuOpen(String menuItemTitle) {
- final View menuItemView = findAppMenuItemView(menuItemTitle);
- return isMenuOpen(menuItemView) ? true : RobotiumHelper.searchExactText(menuItemTitle, true);
- }
-
- /**
- * If a ListMenuItemView with menuItemTitle is visible then the app menu is open .
- *
- * @param menuItemView, must be a ListMenuItemView with menuItemTitle.
- * You must use findAppMenuItemView(menuItemTitle) to obtain it.
- *
- * @return true if app menu is open.
- */
- private boolean isMenuOpen(View menuItemView) {
- return (menuItemView != null) && (menuItemView.getVisibility() == View.VISIBLE);
- }
-
- public void waitForMenuOpen() {
- WaitHelper.waitFor("menu to open", new Condition() {
- @Override
- public boolean isSatisfied() {
- return isMenuOpen();
- }
- });
- }
-
- public void waitForMenuClose() {
- WaitHelper.waitFor("menu to close", new Condition() {
- @Override
- public boolean isSatisfied() {
- return !isMenuOpen();
- }
- });
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/BaseComponent.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/BaseComponent.java
deleted file mode 100644
index eadaaa173..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/BaseComponent.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.components;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.tests.StringHelper;
-import org.mozilla.gecko.tests.UITestContext;
-
-import android.app.Activity;
-
-import com.robotium.solo.Solo;
-
-/**
- * A base class for constructing components - an abstraction over small bits of Firefox
- * functionality. For example, the Toolbar or the about:home screen could be considered a
- * component. Components should not need to know about each others existences and should be
- * combined via helpers. Helpers can also handle a series of actions taken on one component
- * (e.g. clicking the toolbar, entering a url, and waiting for page load).
- */
-public abstract class BaseComponent {
- protected final UITestContext mTestContext;
- protected final Activity mActivity;
- protected final Solo mSolo;
- protected final Actions mActions;
- protected final StringHelper mStringHelper;
-
- public BaseComponent(final UITestContext testContext) {
- mTestContext = testContext;
- mActivity = mTestContext.getActivity();
- mSolo = mTestContext.getSolo();
- mActions = mTestContext.getActions();
- mStringHelper = mTestContext.getStringHelper();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/GeckoViewComponent.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/GeckoViewComponent.java
deleted file mode 100644
index 3beab3169..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/GeckoViewComponent.java
+++ /dev/null
@@ -1,343 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.components;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotSame;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertSame;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
-
-import org.mozilla.gecko.GeckoThread;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.tests.UITestContext;
-import org.mozilla.gecko.tests.helpers.FrameworkHelper;
-import org.mozilla.gecko.tests.helpers.WaitHelper;
-
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.MessageQueue;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodManager;
-
-import com.robotium.solo.Condition;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-/**
- * A class representing any interactions that take place on GeckoView.
- */
-public class GeckoViewComponent extends BaseComponent {
-
- public final TextInput mTextInput;
-
- public GeckoViewComponent(final UITestContext testContext) {
- super(testContext);
- mTextInput = new TextInput();
- }
-
- /**
- * Returns the GeckoView.
- */
- private View getView() {
- // Solo.getView asserts returning a valid View
- return mSolo.getView(R.id.layer_view);
- }
-
- private void setContext(final Context newContext) {
- final View geckoView = getView();
- // Switch to a no-InputMethodManager context to avoid interference
- mTestContext.getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- FrameworkHelper.setViewContext(geckoView, newContext);
- }
- });
- }
-
- public static abstract class InputConnectionTest {
- protected Handler inputConnectionHandler;
-
- /**
- * Processes pending events on the input connection thread before returning.
- * Must be called on the input connection thread during a test.
- */
- protected void processInputConnectionEvents() {
- fAssertSame("Should be called on input connection thread",
- Looper.myLooper(), inputConnectionHandler.getLooper());
-
- // Adapted from GeckoThread.pumpMessageLoop.
- MessageQueue queue = Looper.myQueue();
- queue.addIdleHandler(new MessageQueue.IdleHandler() {
- @Override
- public boolean queueIdle() {
- final Message msg = Message.obtain(inputConnectionHandler);
- msg.obj = inputConnectionHandler;
- inputConnectionHandler.sendMessageAtFrontOfQueue(msg);
- return false; // Remove this idle handler.
- }
- });
-
- final Method getNextMessage;
- try {
- getNextMessage = queue.getClass().getDeclaredMethod("next");
- } catch (final NoSuchMethodException e) {
- throw new UnsupportedOperationException(e);
- }
- getNextMessage.setAccessible(true);
-
- while (true) {
- final Message msg;
- try {
- msg = (Message) getNextMessage.invoke(queue);
- } catch (final IllegalAccessException | InvocationTargetException e) {
- throw new UnsupportedOperationException(e);
- }
- if (msg.obj == inputConnectionHandler &&
- msg.getTarget() == inputConnectionHandler) {
- // Our idle signal
- break;
- } else if (msg.getTarget() == null) {
- Looper.myLooper().quit();
- break;
- }
- msg.getTarget().dispatchMessage(msg);
- }
- }
-
- /**
- * Processes pending events on the Gecko thread before returning.
- * Must be called on the input connection thread during a test.
- */
- protected void processGeckoEvents() {
- fAssertSame("Should be called on input connection thread",
- Looper.myLooper(), inputConnectionHandler.getLooper());
-
- GeckoThread.waitOnGecko();
- }
-
- private static ExtractedText getExtractedText(final InputConnection ic) {
- final ExtractedTextRequest req = new ExtractedTextRequest();
- return ic.getExtractedText(req, 0);
- }
-
- protected String getText(final InputConnection ic) {
- return getExtractedText(ic).text.toString();
- }
-
- private static void assertText(final String message,
- final String expected,
- final String actual) {
- // In an HTML editor, Gecko may insert an additional element that show up as a
- // return character at the end. Deal with that here.
- int end = actual.length();
- if (end > 0 && actual.charAt(end - 1) == '\n') {
- end--;
- }
- fAssertEquals(message, expected, actual.substring(0, end));
- }
-
- protected void assertText(final String message,
- final InputConnection ic,
- final String text) {
- processGeckoEvents();
- processInputConnectionEvents();
-
- assertText(message, text, getText(ic));
- }
-
- protected void assertSelection(final String message,
- final InputConnection ic,
- final int start,
- final int end) {
- processGeckoEvents();
- processInputConnectionEvents();
-
- final ExtractedText extract = getExtractedText(ic);
- fAssertEquals(message, start, extract.selectionStart);
- fAssertEquals(message, end, extract.selectionEnd);
- }
-
- protected void assertSelectionAt(final String message,
- final InputConnection ic,
- final int value) {
- assertSelection(message, ic, value, value);
- }
-
- protected void assertTextAndSelection(final String message,
- final InputConnection ic,
- final String text,
- final int start,
- final int end) {
- processGeckoEvents();
- processInputConnectionEvents();
-
- final ExtractedText extract = getExtractedText(ic);
- assertText(message, text, extract.text.toString());
- fAssertEquals(message, start, extract.selectionStart);
- fAssertEquals(message, end, extract.selectionEnd);
- }
-
- protected void assertTextAndSelectionAt(final String message,
- final InputConnection ic,
- final String text,
- final int selection) {
- assertTextAndSelection(message, ic, text, selection, selection);
- }
-
- public abstract void test(InputConnection ic, EditorInfo info);
- }
-
- public class TextInput {
- private TextInput() {
- }
-
- private InputMethodManager getInputMethodManager() {
- final InputMethodManager imm = (InputMethodManager)
- mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
- fAssertNotNull("Must have an InputMethodManager", imm);
- return imm;
- }
-
- /**
- * Returns whether text input is being directed to the GeckoView.
- */
- private boolean isActive() {
- return getInputMethodManager().isActive(getView());
- }
-
- public TextInput assertActive() {
- fAssertTrue("Current view should be the active input view", isActive());
- return this;
- }
-
- public TextInput waitForActive() {
- WaitHelper.waitFor("current view to become the active input view", new Condition() {
- @Override
- public boolean isSatisfied() {
- return isActive();
- }
- });
- return this;
- }
-
- /**
- * Returns whether an InputConnection is available.
- * An InputConnection is available when text input is being directed to the
- * GeckoView, and a text field (input, textarea, contentEditable, etc.) is
- * currently focused inside the GeckoView.
- */
- private boolean hasInputConnection() {
- final InputMethodManager imm = getInputMethodManager();
- return imm.isActive(getView()) && imm.isAcceptingText();
- }
-
- public TextInput assertInputConnection() {
- fAssertTrue("Current view should have an active InputConnection", hasInputConnection());
- return this;
- }
-
- public TextInput waitForInputConnection() {
- WaitHelper.waitFor("current view to have an active InputConnection", new Condition() {
- @Override
- public boolean isSatisfied() {
- return hasInputConnection();
- }
- });
- return this;
- }
-
- /**
- * Starts an InputConnectionTest. An InputConnectionTest must run on the
- * InputConnection thread which may or may not be the main UI thread. Also,
- * during an InputConnectionTest, the system InputMethodManager service must
- * be temporarily disabled to prevent the system IME from interfering with our
- * tests. We disable the service by override the GeckoView's context with one
- * that returns a null InputMethodManager service.
- *
- * @param test Test to run
- */
- public TextInput testInputConnection(final InputConnectionTest test) {
-
- fAssertNotNull("Test must not be null", test);
- assertInputConnection();
-
- // GeckoInputConnection can run on another thread than the main thread,
- // so we need to be testing it on that same thread it's running on
- final View geckoView = getView();
- final Handler inputConnectionHandler = geckoView.getHandler();
- final Context oldGeckoViewContext = FrameworkHelper.getViewContext(geckoView);
-
- setContext(new ContextWrapper(oldGeckoViewContext) {
- @Override
- public Object getSystemService(String name) {
- if (Context.INPUT_METHOD_SERVICE.equals(name)) {
- return null;
- }
- return super.getSystemService(name);
- }
- });
-
- (new InputConnectionTestRunner(test, inputConnectionHandler)).launch();
-
- setContext(oldGeckoViewContext);
- return this;
- }
-
- private class InputConnectionTestRunner implements Runnable {
- private final InputConnectionTest mTest;
- private boolean mDone;
-
- public InputConnectionTestRunner(final InputConnectionTest test,
- final Handler handler) {
- test.inputConnectionHandler = handler;
- mTest = test;
- }
-
- public synchronized void launch() {
- // Below, we are blocking the instrumentation thread to wait on the
- // InputConnection thread. Therefore, the InputConnection thread must not be
- // the same as the instrumentation thread to avoid a deadlock. This should
- // always be the case and we perform a sanity check to make sure.
- fAssertNotSame("InputConnection should not be running on instrumentation thread",
- Looper.myLooper(), mTest.inputConnectionHandler.getLooper());
-
- mDone = false;
- mTest.inputConnectionHandler.post(this);
- do {
- try {
- wait();
- } catch (InterruptedException e) {
- // Ignore interrupts
- }
- } while (!mDone);
- }
-
- @Override
- public void run() {
- final EditorInfo info = new EditorInfo();
- final InputConnection ic = getView().onCreateInputConnection(info);
- fAssertNotNull("Must have an InputConnection", ic);
- // Restore the IC to a clean state
- ic.clearMetaKeyStates(-1);
- ic.finishComposingText();
- mTest.test(ic, info);
- synchronized (this) {
- // Test finished; return from launch().
- mDone = true;
- notify();
- }
- }
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/TabStripComponent.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/TabStripComponent.java
deleted file mode 100644
index e8a90b351..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/TabStripComponent.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.mozilla.gecko.tests.components;
-
-import android.view.View;
-
-import com.robotium.solo.Condition;
-
-import org.mozilla.gecko.tests.UITestContext;
-import org.mozilla.gecko.tests.helpers.DeviceHelper;
-import org.mozilla.gecko.tests.helpers.WaitHelper;
-import org.mozilla.gecko.widget.TwoWayView;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.*;
-
-/**
- * A class representing any interactions that take place on the tablet tab strip.
- */
-public class TabStripComponent extends BaseComponent {
- // Using a text id because the layout and therefore the id might be stripped from the (non-tablet) build
- private static final String TAB_STRIP_ID = "tab_strip";
-
- public TabStripComponent(final UITestContext testContext) {
- super(testContext);
- }
-
- public void switchToTab(int index) {
- // The tab strip is only available on tablets
- DeviceHelper.assertIsTablet();
-
- View tabView = waitForTabView(index);
- fAssertNotNull(String.format("Tab at index %d is not null", index), tabView);
-
- mSolo.clickOnView(tabView);
- }
-
- private View waitForTabView(final int index) {
- final TwoWayView tabStrip = getTabStripView();
- final View[] tabView = new View[1];
-
- WaitHelper.waitFor(String.format("Tab at index %d to be visible", index), new Condition() {
- @Override
- public boolean isSatisfied() {
- return (tabView[0] = tabStrip.getChildAt(index)) != null;
- }
- });
-
- return tabView[0];
- }
-
- private TwoWayView getTabStripView() {
- TwoWayView tabStrip = (TwoWayView) mSolo.getView("tab_strip");
-
- fAssertNotNull("Tab strip is not null", tabStrip);
-
- return tabStrip;
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/ToolbarComponent.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/ToolbarComponent.java
deleted file mode 100644
index 25101a395..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/ToolbarComponent.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.components;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertFalse;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.tests.UITestContext;
-import org.mozilla.gecko.tests.helpers.DeviceHelper;
-import org.mozilla.gecko.tests.helpers.NavigationHelper;
-import org.mozilla.gecko.tests.helpers.WaitHelper;
-import org.mozilla.gecko.toolbar.PageActionLayout;
-
-import android.view.View;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.TextView;
-
-import com.robotium.solo.Condition;
-import com.robotium.solo.Solo;
-
-/**
- * A class representing any interactions that take place on the Toolbar.
- */
-public class ToolbarComponent extends BaseComponent {
-
- private static final String URL_HTTP_PREFIX = "http://";
-
- // We are waiting up to 30 seconds instead of the default waiting time because reader mode
- // parsing can take quite some time on slower devices (Bug 1142699)
- private static final int READER_MODE_WAIT_MS = 30000;
-
- public ToolbarComponent(final UITestContext testContext) {
- super(testContext);
- }
-
- public ToolbarComponent assertIsEditing() {
- fAssertTrue("The toolbar is in the editing state", isEditing());
- return this;
- }
-
- public ToolbarComponent assertIsNotEditing() {
- fAssertFalse("The toolbar is not in the editing state", isEditing());
- return this;
- }
-
- public ToolbarComponent assertTitle(final String url) {
- fAssertNotNull("The url argument is not null", url);
-
- final String expected;
- final String absoluteURL = NavigationHelper.adjustUrl(url);
-
- if (mStringHelper.ABOUT_HOME_URL.equals(absoluteURL)) {
- expected = mStringHelper.ABOUT_HOME_TITLE;
- } else if (absoluteURL.startsWith(URL_HTTP_PREFIX)) {
- expected = absoluteURL.substring(URL_HTTP_PREFIX.length());
- } else {
- expected = absoluteURL;
- }
-
- // Since we only display a shortened "base domain" (See bug 1236431) we use the content
- // description to obtain the full URL.
- fAssertEquals("The Toolbar title is " + expected, expected, getUrlFromContentDescription());
- return this;
- }
-
- public ToolbarComponent assertUrl(final String expected) {
- assertIsEditing();
- fAssertEquals("The Toolbar url is " + expected, expected, getUrlEditText().getText());
- return this;
- }
-
- public ToolbarComponent assertIsUrlEditTextSelected() {
- fAssertTrue("The edit text is selected", isUrlEditTextSelected());
- return this;
- }
-
- public ToolbarComponent assertIsUrlEditTextNotSelected() {
- fAssertFalse("The edit text is not selected", isUrlEditTextSelected());
- return this;
- }
-
- public ToolbarComponent assertBackButtonIsNotEnabled() {
- fAssertFalse("The back button is not enabled", isBackButtonEnabled());
- return this;
- }
-
- /**
- * Returns the root View for the browser toolbar.
- */
- private View getToolbarView() {
- mSolo.waitForView(R.id.browser_toolbar);
- return mSolo.getView(R.id.browser_toolbar);
- }
-
- private EditText getUrlEditText() {
- return (EditText) getToolbarView().findViewById(R.id.url_edit_text);
- }
-
- private View getUrlDisplayLayout() {
- return getToolbarView().findViewById(R.id.display_layout);
- }
-
- private TextView getUrlTitleText() {
- return (TextView) getToolbarView().findViewById(R.id.url_bar_title);
- }
-
- private ImageButton getBackButton() {
- DeviceHelper.assertIsTablet();
- return (ImageButton) getToolbarView().findViewById(R.id.back);
- }
-
- private ImageButton getForwardButton() {
- DeviceHelper.assertIsTablet();
- return (ImageButton) getToolbarView().findViewById(R.id.forward);
- }
-
- private ImageButton getReloadButton() {
- DeviceHelper.assertIsTablet();
- return (ImageButton) getToolbarView().findViewById(R.id.reload);
- }
-
- private PageActionLayout getPageActionLayout() {
- return (PageActionLayout) getToolbarView().findViewById(R.id.page_action_layout);
- }
-
- private ImageButton getReaderModeButton() {
- final PageActionLayout pageActionLayout = getPageActionLayout();
- final int count = pageActionLayout.getChildCount();
-
- for (int i = 0; i < count; i++) {
- final View view = pageActionLayout.getChildAt(i);
- if (mStringHelper.CONTENT_DESCRIPTION_READER_MODE_BUTTON.equals(view.getContentDescription())) {
- return (ImageButton) view;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the View for the edit cancel button in the browser toolbar.
- */
- private View getEditCancelButton() {
- return getToolbarView().findViewById(R.id.edit_cancel);
- }
-
- private String getUrlFromContentDescription() {
- assertIsNotEditing();
-
- final CharSequence contentDescription = getUrlDisplayLayout().getContentDescription();
- if (contentDescription == null) {
- return "";
- } else {
- return contentDescription.toString();
- }
- }
-
- /**
- * Returns the title of the page. Note that this makes no assertions to Toolbar state and
- * may return a value that may never be visible to the user. Callers likely want to use
- * {@link assertTitle} instead.
- */
- public String getPotentiallyInconsistentTitle() {
- return getTitleHelper(false);
- }
-
- private String getTitleHelper(final boolean shouldAssertNotEditing) {
- if (shouldAssertNotEditing) {
- assertIsNotEditing();
- }
-
- return getUrlTitleText().getText().toString();
- }
-
- private boolean isEditing() {
- return getUrlDisplayLayout().getVisibility() != View.VISIBLE &&
- getUrlEditText().getVisibility() == View.VISIBLE;
- }
-
- public ToolbarComponent enterEditingMode() {
- assertIsNotEditing();
-
- mSolo.clickOnView(getUrlTitleText(), true);
-
- waitForEditing();
- WaitHelper.waitFor("UrlEditText to be input method target", new Condition() {
- @Override
- public boolean isSatisfied() {
- return getUrlEditText().isInputMethodTarget();
- }
- });
-
- return this;
- }
-
- public ToolbarComponent commitEditingMode() {
- assertIsEditing();
-
- WaitHelper.waitForPageLoad(new Runnable() {
- @Override
- public void run() {
- mSolo.sendKey(Solo.ENTER);
- }
- });
- waitForNotEditing();
-
- return this;
- }
-
- public ToolbarComponent dismissEditingMode() {
- assertIsEditing();
-
- if (DeviceHelper.isTablet()) {
- final EditText urlEditText = getUrlEditText();
- if (urlEditText.isFocused()) {
- mSolo.goBack();
- }
- mSolo.goBack();
- } else {
- mSolo.clickOnView(getEditCancelButton());
- }
-
- waitForNotEditing();
-
- return this;
- }
-
- public ToolbarComponent enterUrl(final String url) {
- fAssertNotNull("url is not null", url);
-
- assertIsEditing();
-
- final EditText urlEditText = getUrlEditText();
- fAssertTrue("The UrlEditText is the input method target",
- urlEditText.isInputMethodTarget());
-
- mSolo.clearEditText(urlEditText);
- mSolo.typeText(urlEditText, url);
-
- return this;
- }
-
- public ToolbarComponent pressBackButton() {
- final ImageButton backButton = getBackButton();
- return pressButton(backButton, "back");
- }
-
- public ToolbarComponent pressForwardButton() {
- final ImageButton forwardButton = getForwardButton();
- return pressButton(forwardButton, "forward");
- }
-
- public ToolbarComponent pressReloadButton() {
- final ImageButton reloadButton = getReloadButton();
- return pressButton(reloadButton, "reload");
- }
-
- public ToolbarComponent pressReaderModeButton() {
- final ImageButton readerModeButton = waitForReaderModeButton();
- pressButton(readerModeButton, "reader mode");
-
- return this;
- }
-
- private ToolbarComponent pressButton(final View view, final String buttonName) {
- fAssertNotNull("The " + buttonName + " button View is not null", view);
- fAssertTrue("The " + buttonName + " button is enabled", view.isEnabled());
- fAssertEquals("The " + buttonName + " button is visible",
- View.VISIBLE, view.getVisibility());
- assertIsNotEditing();
-
- WaitHelper.waitForPageLoad(new Runnable() {
- @Override
- public void run() {
- mSolo.clickOnView(view);
- }
- });
-
- return this;
- }
-
- private void waitForEditing() {
- WaitHelper.waitFor("Toolbar to enter editing mode", new Condition() {
- @Override
- public boolean isSatisfied() {
- return isEditing();
- }
- });
- }
-
- private void waitForNotEditing() {
- WaitHelper.waitFor("Toolbar to exit editing mode", new Condition() {
- @Override
- public boolean isSatisfied() {
- return !isEditing();
- }
- });
- }
-
- private ImageButton waitForReaderModeButton() {
- final ImageButton[] readerModeButton = new ImageButton[1];
-
- WaitHelper.waitFor("the Reader mode button to be visible", new Condition() {
- @Override
- public boolean isSatisfied() {
- return (readerModeButton[0] = getReaderModeButton()) != null;
- }
- }, READER_MODE_WAIT_MS);
-
- return readerModeButton[0];
- }
-
- private boolean isUrlEditTextSelected() {
- return getUrlEditText().isSelected();
- }
-
- private boolean isBackButtonEnabled() {
- return getBackButton().isEnabled();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/AssertionHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/AssertionHelper.java
deleted file mode 100644
index 894d134d1..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/AssertionHelper.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.helpers;
-
-import java.util.Arrays;
-
-import org.mozilla.gecko.Assert;
-import org.mozilla.gecko.tests.UITestContext;
-
-/**
- * Provides assertions in a JUnit-like API that wraps the robocop Assert interface.
- */
-public final class AssertionHelper {
- // Assert.ok has a "diag" ("diagnostic") parameter that has no useful purpose.
- private static final String DIAG_STRING = "";
-
- private static Assert sAsserter;
-
- private AssertionHelper() { /* To disallow instantiation. */ }
-
- protected static void init(final UITestContext context) {
- sAsserter = context.getAsserter();
- }
-
- public static void fAssertArrayEquals(final String message, final byte[] expecteds, final byte[] actuals) {
- sAsserter.ok(Arrays.equals(expecteds, actuals), message, DIAG_STRING);
- }
-
- public static void fAssertArrayEquals(final String message, final char[] expecteds, final char[] actuals) {
- sAsserter.ok(Arrays.equals(expecteds, actuals), message, DIAG_STRING);
- }
-
- public static void fAssertArrayEquals(final String message, final short[] expecteds, final short[] actuals) {
- sAsserter.ok(Arrays.equals(expecteds, actuals), message, DIAG_STRING);
- }
-
- public static void fAssertArrayEquals(final String message, final int[] expecteds, final int[] actuals) {
- sAsserter.ok(Arrays.equals(expecteds, actuals), message, DIAG_STRING);
- }
-
- public static void fAssertArrayEquals(final String message, final long[] expecteds, final long[] actuals) {
- sAsserter.ok(Arrays.equals(expecteds, actuals), message, DIAG_STRING);
- }
-
- public static void fAssertArrayEquals(final String message, final Object[] expecteds, final Object[] actuals) {
- sAsserter.ok(Arrays.equals(expecteds, actuals), message, DIAG_STRING);
- }
-
- public static void fAssertEquals(final String message, final double expected, final double actual, final double delta) {
- if (Double.compare(expected, actual) != 0) {
- sAsserter.ok(Math.abs(expected - actual) <= delta, message, DIAG_STRING);
- }
- }
-
- public static void fAssertEquals(final String message, final long expected, final long actual) {
- sAsserter.is(actual, expected, message);
- }
-
- public static void fAssertEquals(final String message, final Object expected, final Object actual) {
- sAsserter.is(actual, expected, message);
- }
-
- public static void fAssertNotEquals(final String message, final double unexpected, final double actual, final double delta) {
- sAsserter.ok(Math.abs(unexpected - actual) > delta, message, DIAG_STRING);
- }
-
- public static void fAssertNotEquals(final String message, final long unexpected, final long actual) {
- sAsserter.isnot(actual, unexpected, message);
- }
-
- public static void fAssertNotEquals(final String message, final Object unexpected, final Object actual) {
- sAsserter.isnot(actual, unexpected, message);
- }
-
- public static void fAssertFalse(final String message, final boolean actual) {
- sAsserter.ok(!actual, message, DIAG_STRING);
- }
-
- public static void fAssertNotNull(final String message, final Object actual) {
- sAsserter.isnot(actual, null, message);
- }
-
- public static void fAssertNotSame(final String message, final Object unexpected, final Object actual) {
- sAsserter.ok(unexpected != actual, message, DIAG_STRING);
- }
-
- public static void fAssertNull(final String message, final Object actual) {
- sAsserter.is(actual, null, message);
- }
-
- public static void fAssertSame(final String message, final Object expected, final Object actual) {
- sAsserter.ok(expected == actual, message, DIAG_STRING);
- }
-
- public static void fAssertTrue(final String message, final boolean actual) {
- sAsserter.ok(actual, message, DIAG_STRING);
- }
-
- public static void fAssertIsPixel(final String message, final int actual, final int r, final int g, final int b) {
- sAsserter.ispixel(actual, r, g, b, message);
- }
-
- public static void fAssertIsNotPixel(final String message, final int actual, final int r, final int g, final int b) {
- sAsserter.isnotpixel(actual, r, g, b, message);
- }
-
- public static void fFail(final String message) {
- sAsserter.ok(false, message, DIAG_STRING);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/DeviceHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/DeviceHelper.java
deleted file mode 100644
index 476bd34dd..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/DeviceHelper.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.helpers;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
-
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.tests.UITestContext;
-
-import android.app.Activity;
-import android.os.Build;
-import android.util.DisplayMetrics;
-
-import com.robotium.solo.Solo;
-
-/**
- * Provides general hardware (ex: configuration) and software (ex: version) information
- * about the current test device and allows changing its configuration.
- */
-public final class DeviceHelper {
- public enum Type {
- PHONE,
- TABLET
- }
-
- public enum AndroidVersion {
- v2x,
- v3x,
- v4x
- }
-
- private static Activity sActivity;
- private static Solo sSolo;
-
- private static Type sDeviceType;
- private static AndroidVersion sAndroidVersion;
-
- private static int sScreenHeight;
- private static int sScreenWidth;
-
- private DeviceHelper() { /* To disallow instantiation. */ }
-
- public static void assertIsTablet() {
- fAssertTrue("The device is a tablet", isTablet());
- }
-
- protected static void init(final UITestContext context) {
- sActivity = context.getActivity();
- sSolo = context.getSolo();
-
- setAndroidVersion();
- setScreenDimensions();
- setDeviceType();
- }
-
- private static void setAndroidVersion() {
- int sdk = Build.VERSION.SDK_INT;
- if (sdk < Build.VERSION_CODES.HONEYCOMB) {
- sAndroidVersion = AndroidVersion.v2x;
- } else if (sdk > Build.VERSION_CODES.HONEYCOMB_MR2) {
- sAndroidVersion = AndroidVersion.v4x;
- } else {
- sAndroidVersion = AndroidVersion.v3x;
- }
- }
-
- private static void setScreenDimensions() {
- final DisplayMetrics dm = new DisplayMetrics();
- sActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
-
- sScreenHeight = dm.heightPixels;
- sScreenWidth = dm.widthPixels;
- }
-
- private static void setDeviceType() {
- sDeviceType = (GeckoAppShell.isTablet() ? Type.TABLET : Type.PHONE);
- }
-
- public static int getScreenHeight() {
- return sScreenHeight;
- }
-
- public static int getScreenWidth() {
- return sScreenWidth;
- }
-
- public static AndroidVersion getAndroidVersion() {
- return sAndroidVersion;
- }
-
- public static boolean isPhone() {
- return (sDeviceType == Type.PHONE);
- }
-
- public static boolean isTablet() {
- return (sDeviceType == Type.TABLET);
- }
-
- public static void setLandscapeRotation() {
- sSolo.setActivityOrientation(Solo.LANDSCAPE);
- }
-
- public static void setPortraitOrientation() {
- sSolo.setActivityOrientation(Solo.LANDSCAPE);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/FrameworkHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/FrameworkHelper.java
deleted file mode 100644
index d3c4d6390..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/FrameworkHelper.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.helpers;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail;
-
-import java.lang.reflect.Field;
-
-import android.content.Context;
-import android.view.View;
-
-/**
- * Provides helper functions for accessing Android framework features
- *
- * This class uses reflection to access framework functionalities that are
- * unavailable through the regular Android API. Using reflection in this
- * case is okay because it does not touch Gecko classes that go through
- * ProGuard.
- */
-public final class FrameworkHelper {
-
- private FrameworkHelper() { /* To disallow instantiation. */ }
-
- private static Field getClassField(final Class<?> clazz, final String fieldName)
- throws NoSuchFieldException {
- Class<?> cls = clazz;
- do {
- try {
- return cls.getDeclaredField(fieldName);
- } catch (final Exception e) {
- // NoSuchFieldException is a documented exception of getDeclaredField
- // and is frequently observed here. No other exceptions are documented
- // for getDeclaredField. However, on Android 2.3, NoSuchMethodException
- // is also observed, when called on some classes. This appears to be
- // an Android bug reportedly fixed in Honeycomb. Since NoSuchMethodException
- // is not declared, it cannot be caught, so we catch all Exceptions.
- cls = cls.getSuperclass();
- }
- } while (cls != null);
- // We tried getDeclaredField before; now try getField instead.
- // getField behaves differently in that getField traverses the inheritance
- // list, but it only works on public fields. While getField won't get us
- // anything new, it makes code cleaner by throwing an exception for us.
- return clazz.getField(fieldName);
- }
-
- private static Object getField(final Object obj, final String fieldName) {
- try {
- final Field field = getClassField(obj.getClass(), fieldName);
- final boolean accessible = field.isAccessible();
- field.setAccessible(true);
- final Object ret = field.get(obj);
- field.setAccessible(accessible);
- return ret;
- } catch (final NoSuchFieldException e) {
- // We expect a valid field name; if it's not valid,
- // the caller is doing something wrong and should be fixed.
- fFail("Argument field should be a valid field name: " + e.toString());
- } catch (final IllegalAccessException e) {
- // This should not happen. If it does, setAccessible above is not working.
- fFail("Field should be accessible: " + e.toString());
- }
- throw new IllegalStateException("Should not continue from previous failures");
- }
-
- private static void setField(final Object obj, final String fieldName, final Object value) {
- try {
- final Field field = getClassField(obj.getClass(), fieldName);
- final boolean accessible = field.isAccessible();
- field.setAccessible(true);
- field.set(obj, value);
- field.setAccessible(accessible);
- return;
- } catch (final NoSuchFieldException e) {
- // We expect a valid field name; if it's not valid,
- // the caller is doing something wrong and should be fixed.
- fFail("Argument field should be a valid field name: " + e.toString());
- } catch (final IllegalAccessException e) {
- // This should not happen. If it does, setAccessible above is not working.
- fFail("Field should be accessible: " + e.toString());
- }
- throw new IllegalStateException("Cannot continue from previous failures");
- }
-
- public static Context getViewContext(final View v) {
- return (Context) getField(v, "mContext");
- }
-
- public static void setViewContext(final View v, final Context c) {
- setField(v, "mContext", c);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/GeckoClickHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/GeckoClickHelper.java
deleted file mode 100644
index b8d1ef0ce..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/GeckoClickHelper.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.mozilla.gecko.tests.helpers;
-
-import android.app.Activity;
-import android.util.DisplayMetrics;
-
-import com.robotium.solo.Solo;
-
-import org.mozilla.gecko.Driver;
-import org.mozilla.gecko.tests.StringHelper;
-import org.mozilla.gecko.tests.UITestContext;
-
-/**
- * Provides helper functions for clicking elements rendered by the Gecko engine.
- */
-public class GeckoClickHelper {
- private static Solo sSolo;
- private static Activity sActivity;
- private static Driver sDriver;
-
- protected static void init(final UITestContext context) {
- sSolo = context.getSolo();
- sActivity = context.getActivity();
- sDriver = context.getDriver();
- }
-
- private GeckoClickHelper() { /* To disallow instantiation. */ }
-
- /**
- * Long press the link and select "Open Link in New Tab" from the context menu.
- *
- * The link should be positioned at the top of the page, at least 60px high and
- * aligned to the middle.
- */
- public static void openCentralizedLinkInNewTab() {
- openLinkContextMenu();
-
- // Click on "Open Link in New Tab"
- sSolo.clickOnText(StringHelper.get().CONTEXT_MENU_ITEMS_IN_NORMAL_TAB[0]);
- }
-
- private static void openLinkContextMenu() {
- DisplayMetrics dm = new DisplayMetrics();
- sActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
-
- sSolo.clickLongOnScreen(
- sDriver.getGeckoLeft() + sDriver.getGeckoWidth() / 2,
- sDriver.getGeckoTop() + 30 * dm.density
- );
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/GeckoHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/GeckoHelper.java
deleted file mode 100644
index cd75b7255..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/GeckoHelper.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.helpers;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Actions.EventExpecter;
-import org.mozilla.gecko.GeckoThread;
-import org.mozilla.gecko.tests.UITestContext;
-
-import android.app.Activity;
-
-/**
- * Provides helper functions for accessing the underlying Gecko engine.
- */
-public final class GeckoHelper {
- private static Activity sActivity;
- private static Actions sActions;
-
- private GeckoHelper() { /* To disallow instantiation. */ }
-
- protected static void init(final UITestContext context) {
- sActivity = context.getActivity();
- sActions = context.getActions();
- }
-
- public static void blockForReady() {
- blockForEvent("Gecko:Ready");
- }
-
- /**
- * Blocks for the "Gecko:DelayedStartup" event, which occurs after "Gecko:Ready" and the
- * first page load.
- */
- public static void blockForDelayedStartup() {
- blockForEvent("Gecko:DelayedStartup");
- }
-
- private static void blockForEvent(final String eventName) {
- final EventExpecter eventExpecter = sActions.expectGeckoEvent(eventName);
-
- if (!GeckoThread.isRunning()) {
- eventExpecter.blockForEvent();
- }
-
- eventExpecter.unregisterListener();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/HelperInitializer.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/HelperInitializer.java
deleted file mode 100644
index 229dc1062..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/HelperInitializer.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.helpers;
-
-import org.mozilla.gecko.tests.UITestContext;
-
-/**
- * AssertionHelper is statically imported in many places. Thus we want to hide
- * its init method outside of this package. We initialize the remaining helper
- * classes from here so that all the init methods are package protected.
- */
-public final class HelperInitializer {
-
- private HelperInitializer() { /* To disallow instantiation. */ }
-
- public static void init(final UITestContext context) {
- // Other helpers make assertions so init AssertionHelper first.
- AssertionHelper.init(context);
-
- DeviceHelper.init(context);
- GeckoClickHelper.init(context);
- GeckoHelper.init(context);
- JavascriptBridge.init(context);
- NavigationHelper.init(context);
- RobotiumHelper.init(context);
- WaitHelper.init(context);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/JavascriptBridge.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/JavascriptBridge.java
deleted file mode 100644
index 1b0ece1cd..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/JavascriptBridge.java
+++ /dev/null
@@ -1,394 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.helpers;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import junit.framework.AssertionFailedError;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Actions.EventExpecter;
-import org.mozilla.gecko.Assert;
-import org.mozilla.gecko.tests.UITestContext;
-
-/**
- * Javascript bridge allows calls to and from JavaScript.
- *
- * To establish communication, create an instance of JavascriptBridge in Java and pass in
- * an object that will receive calls from JavaScript. For example:
- *
- * {@code final JavascriptBridge js = new JavascriptBridge(javaObj);}
- *
- * Next, create an instance of JavaBridge in JavaScript and pass in another object
- * that will receive calls from Java. For example:
- *
- * {@code let java = new JavaBridge(jsObj);}
- *
- * Once a link is established, calls can be made using the methods syncCall and asyncCall.
- * syncCall waits for the call to finish before returning. For example:
- *
- * {@code js.syncCall("abc", 1, 2, 3);} will synchronously call the JavaScript method
- * jsObj.abc and pass in arguments 1, 2, and 3.
- *
- * {@code java.asyncCall("def", 4, 5, 6);} will asynchronously call the Java method
- * javaObj.def and pass in arguments 4, 5, and 6.
- *
- * Supported argument types include int, double, boolean, String, and JSONObject. Note
- * that only implicit conversion is done, meaning if a floating point argument is passed
- * from JavaScript to Java, the call will fail if the Java method has an int argument.
- *
- * Because JavascriptBridge and JavaBridge use one underlying communication channel,
- * creating multiple instances of them will not create independent links.
- *
- * Note also that because Robocop tests finish as soon as the Java test method returns,
- * the last call to JavaScript from Java must be a synchronous call. Otherwise, the test
- * will finish before the JavaScript method is run. Calls to Java from JavaScript do not
- * have this requirement. Because of these considerations, calls from Java to JavaScript
- * are usually synchronous and calls from JavaScript to Java are usually asynchronous.
- * See testJavascriptBridge.java for examples.
- */
-public final class JavascriptBridge {
-
- private static enum MessageStatus {
- QUEUE_EMPTY, // Did not process a message; queue was empty.
- PROCESSED, // A message other than sync was processed.
- REPLIED, // A sync message was processed.
- SAVED, // An async message was saved; see processMessage().
- };
-
- @SuppressWarnings("serial")
- public static class CallException extends RuntimeException {
- public CallException() {
- super();
- }
-
- public CallException(final String msg) {
- super(msg);
- }
-
- public CallException(final String msg, final Throwable e) {
- super(msg, e);
- }
-
- public CallException(final Throwable e) {
- super(e);
- }
- }
-
- public static final String EVENT_TYPE = "Robocop:JS";
-
- private static Actions sActions;
- private static Assert sAsserter;
-
- // Target of JS-to-Java calls
- private final Object mTarget;
- // List of public methods in subclass
- private final Method[] mMethods;
- // Parser for handling xpcshell assertions
- private final JavascriptMessageParser mLogParser;
- // Expecter of our internal Robocop event
- private final EventExpecter mExpecter;
- // Saved async message; see processMessage() for its purpose.
- private JSONObject mSavedAsyncMessage;
- // Number of levels in the synchronous call stack
- private int mCallStackDepth;
- // If JavaBridge has been loaded
- private boolean mJavaBridgeLoaded;
-
- /* package */ static void init(final UITestContext context) {
- sActions = context.getActions();
- sAsserter = context.getAsserter();
- }
-
- public JavascriptBridge(final Object target) {
- mTarget = target;
- mMethods = target.getClass().getMethods();
- mExpecter = sActions.expectGeckoEvent(EVENT_TYPE);
- // The JS here is unrelated to a test harness, so we
- // have our message parser end on assertion failure.
- mLogParser = new JavascriptMessageParser(sAsserter, true);
- }
-
- /**
- * Synchronously calls a method in Javascript.
- *
- * @param method Name of the method to call
- * @param args Arguments to pass to the Javascript method; must be a list of
- * values allowed by JSONObject.
- */
- public void syncCall(final String method, final Object... args) {
- mCallStackDepth++;
-
- sendMessage("sync-call", method, args);
- try {
- while (processPendingMessage() != MessageStatus.REPLIED) {
- }
- } catch (final AssertionFailedError e) {
- // Most likely an event expecter time out
- throw new CallException("Cannot call " + method, e);
- }
-
- // If syncCall was called reentrantly from processPendingMessage(), mCallStackDepth
- // will be greater than 1 here. In that case we don't have to wait for pending calls
- // because the outermost syncCall will do it for us.
- if (mCallStackDepth == 1) {
- // We want to wait for all asynchronous calls to finish,
- // because the test may end immediately after this method returns.
- finishPendingCalls();
- }
- mCallStackDepth--;
- }
-
- /**
- * Asynchronously calls a method in Javascript.
- *
- * @param method Name of the method to call
- * @param args Arguments to pass to the Javascript method; must be a list of
- * values allowed by JSONObject.
- */
- public void asyncCall(final String method, final Object... args) {
- sendMessage("async-call", method, args);
- }
-
- /**
- * Disconnect the bridge.
- */
- public void disconnect() {
- mExpecter.unregisterListener();
- }
-
- /**
- * Process a new message; wait for new message if necessary.
- *
- * @return MessageStatus value to indicate result of processing the message
- */
- private MessageStatus processPendingMessage() {
- // We're on the test thread.
- // We clear mSavedAsyncMessage in maybeProcessPendingMessage() but not here,
- // because we always have a new message for processing here, so we never
- // get a chance to clear mSavedAsyncMessage.
- try {
- final String message = mExpecter.blockForEventData();
- return processMessage(new JSONObject(message));
- } catch (final JSONException e) {
- throw new IllegalStateException("Invalid message", e);
- }
- }
-
- /**
- * Process a message if a new or saved message is available.
- *
- * @return MessageStatus value to indicate result of processing the message
- */
- private MessageStatus maybeProcessPendingMessage() {
- // We're on the test thread.
- final String message = mExpecter.blockForEventDataWithTimeout(0);
- if (message != null) {
- try {
- return processMessage(new JSONObject(message));
- } catch (final JSONException e) {
- throw new IllegalStateException("Invalid message", e);
- }
- }
- if (mSavedAsyncMessage != null) {
- // processMessage clears mSavedAsyncMessage.
- return processMessage(mSavedAsyncMessage);
- }
- return MessageStatus.QUEUE_EMPTY;
- }
-
- /**
- * Wait for all asynchronous messages from Javascript to be processed.
- */
- private void finishPendingCalls() {
- MessageStatus result;
- do {
- result = maybeProcessPendingMessage();
- if (result == MessageStatus.REPLIED) {
- throw new IllegalStateException("Sync reply was unexpected");
- }
- } while (result != MessageStatus.QUEUE_EMPTY);
- }
-
- private void ensureJavaBridgeLoaded() {
- while (!mJavaBridgeLoaded) {
- processPendingMessage();
- }
- }
-
- private void sendMessage(final String innerType, final String method, final Object[] args) {
- ensureJavaBridgeLoaded();
-
- // Call from Java to Javascript
- final JSONObject message = new JSONObject();
- final JSONArray jsonArgs = new JSONArray();
- try {
- if (args != null) {
- for (final Object arg : args) {
- jsonArgs.put(convertToJSONValue(arg));
- }
- }
- message.put("type", EVENT_TYPE)
- .put("innerType", innerType)
- .put("method", method)
- .put("args", jsonArgs);
- } catch (final JSONException e) {
- throw new IllegalStateException("Unable to create JSON message", e);
- }
- sActions.sendGeckoEvent(EVENT_TYPE, message.toString());
- }
-
- private MessageStatus processMessage(JSONObject message) {
- final String type;
- final String methodName;
- final JSONArray argsArray;
- final Object[] args;
- try {
- if (!EVENT_TYPE.equals(message.getString("type"))) {
- throw new IllegalStateException("Message type is not " + EVENT_TYPE);
- }
- type = message.getString("innerType");
-
- switch (type) {
- case "progress":
- // Javascript harness message
- mLogParser.logMessage(message.getString("message"));
- return MessageStatus.PROCESSED;
-
- case "notify-loaded":
- mJavaBridgeLoaded = true;
- return MessageStatus.PROCESSED;
-
- case "sync-reply":
- // Reply to Java-to-Javascript sync call
- return MessageStatus.REPLIED;
-
- case "sync-call":
- case "async-call":
-
- if ("async-call".equals(type)) {
- // Save this async message until another async message arrives, then we
- // process the saved message and save the new one. This is done as a
- // form of tail call optimization, by making sync-replies come before
- // async-calls. On the other hand, if (message == mSavedAsyncMessage),
- // it means we're currently processing the saved message and should clear
- // mSavedAsyncMessage.
- final JSONObject newSavedMessage =
- (message != mSavedAsyncMessage ? message : null);
- message = mSavedAsyncMessage;
- mSavedAsyncMessage = newSavedMessage;
- if (message == null) {
- // Saved current message and there wasn't an already saved one.
- return MessageStatus.SAVED;
- }
- }
-
- methodName = message.getString("method");
- argsArray = message.getJSONArray("args");
- args = new Object[argsArray.length()];
- for (int i = 0; i < args.length; i++) {
- args[i] = convertFromJSONValue(argsArray.get(i));
- }
- invokeMethod(methodName, args);
-
- if ("sync-call".equals(type)) {
- // Reply for sync messages
- sendMessage("sync-reply", methodName, null);
- }
- return MessageStatus.PROCESSED;
- }
-
- throw new IllegalStateException("Message type is unexpected");
-
- } catch (final JSONException e) {
- throw new IllegalStateException("Unable to retrieve JSON message", e);
- }
- }
-
- /**
- * Given a method name and a list of arguments,
- * call the most suitable method in the subclass.
- */
- private Object invokeMethod(final String methodName, final Object[] args) {
- final Class<?>[] argTypes = new Class<?>[args.length];
- for (int i = 0; i < argTypes.length; i++) {
- if (args[i] == null) {
- argTypes[i] = Object.class;
- } else {
- argTypes[i] = args[i].getClass();
- }
- }
-
- // Try using argument types directly without casting.
- try {
- return invokeMethod(mTarget.getClass().getMethod(methodName, argTypes), args);
- } catch (final NoSuchMethodException e) {
- // getMethod() failed; try fallback below.
- }
-
- // One scenario for getMethod() to fail above is that we don't have the exact
- // argument types in argTypes (e.g. JS gave us an int but we're using a double,
- // or JS gave us a null and we don't know its intended type), or the number of
- // arguments is incorrect. Now we find all the methods with the given name and
- // try calling them one-by-one. If one call fails, we move to the next call.
- // Java will try to convert our arguments to the right types.
- Throwable lastException = null;
- for (final Method method : mMethods) {
- if (!method.getName().equals(methodName)) {
- continue;
- }
- try {
- return invokeMethod(method, args);
- } catch (final IllegalArgumentException e) {
- lastException = e;
- // Try the next method
- } catch (final UnsupportedOperationException e) {
- // "Cannot access method" exception below, see if there are other public methods
- lastException = e;
- // Try the next method
- }
- }
- // Now we're out of options
- throw new UnsupportedOperationException(
- "Cannot call method " + methodName + " (not public? wrong argument types?)",
- lastException);
- }
-
- private Object invokeMethod(final Method method, final Object[] args) {
- try {
- return method.invoke(mTarget, args);
- } catch (final IllegalAccessException e) {
- throw new UnsupportedOperationException(
- "Cannot access method " + method.getName(), e);
- } catch (final InvocationTargetException e) {
- final Throwable cause = e.getCause();
- if (cause instanceof CallException) {
- // Don't wrap CallExceptions; this can happen if a call is nested on top
- // of existing sync calls, and the nested call throws a CallException
- throw (CallException) cause;
- }
- throw new CallException("Failed to invoke " + method.getName(), cause);
- }
- }
-
- private Object convertFromJSONValue(final Object value) {
- if (value == JSONObject.NULL) {
- return null;
- }
- return value;
- }
-
- private Object convertToJSONValue(final Object value) {
- if (value == null) {
- return JSONObject.NULL;
- }
- return value;
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/JavascriptMessageParser.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/JavascriptMessageParser.java
deleted file mode 100644
index 6237f1adc..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/JavascriptMessageParser.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.helpers;
-
-import org.mozilla.gecko.Assert;
-
-import junit.framework.AssertionFailedError;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Route messages from Javascript's head.js test framework into Java's
- * Mochitest framework.
- */
-public final class JavascriptMessageParser {
-
- /**
- * The Javascript test harness sends test events to Java.
- * Each such test event is wrapped in a Robocop:JS event.
- */
- public static final String EVENT_TYPE = "Robocop:JS";
-
- // Messages matching this pattern are handled specially. Messages not
- // matching this pattern are still printed. This pattern should be able
- // to handle having multiple lines in a message.
- private static final Pattern testMessagePattern =
- Pattern.compile("TEST-([A-Z\\-]+) \\| (.*?) \\| (.*)", Pattern.DOTALL);
-
- private final Assert asserter;
- // Used to help print stack traces neatly.
- private String lastTestName = "";
- // Have we seen a message saying the test is finished?
- private boolean testFinishedMessageSeen = false;
- private final boolean endOnAssertionFailure;
-
- /**
- * Constructs a message parser for test result messages sent from JavaScript. When seeing an
- * assertion failure, the message parser can use the given {@link org.mozilla.gecko.Assert}
- * instance to immediately end the test (typically if the underlying JS framework is not able
- * to end the test itself) or to swallow the Errors - this functionality is determined by the
- * <code>endOnAssertionFailure</code> parameter.
- *
- * @param asserter The Assert instance to which test results should be passed.
- * @param endOnAssertionFailure
- * true if the test should end if we see a JS assertion failure, false otherwise.
- */
- public JavascriptMessageParser(final Assert asserter, final boolean endOnAssertionFailure) {
- this.asserter = asserter;
- this.endOnAssertionFailure = endOnAssertionFailure;
- }
-
- public boolean isTestFinished() {
- return testFinishedMessageSeen;
- }
-
- public void logMessage(final String str) {
- final Matcher m = testMessagePattern.matcher(str.trim());
-
- if (m.matches()) {
- final String type = m.group(1);
- final String name = m.group(2);
- final String message = m.group(3);
-
- if ("INFO".equals(type)) {
- asserter.info(name, message);
- testFinishedMessageSeen = testFinishedMessageSeen ||
- "exiting test".equals(message);
- } else if ("PASS".equals(type)) {
- asserter.ok(true, name, message);
- } else if ("UNEXPECTED-FAIL".equals(type)) {
- try {
- asserter.ok(false, name, message);
- } catch (AssertionFailedError e) {
- // Above, we call the assert, allowing it to log.
- // Now we can end the test, if applicable.
- if (this.endOnAssertionFailure) {
- throw e;
- }
- // Otherwise, swallow the Error. The JS framework we're
- // logging messages from is likely capable of ending tests
- // when it needs to, and we want to see all of its failures,
- // not just the first one!
- }
- } else if ("KNOWN-FAIL".equals(type)) {
- asserter.todo(false, name, message);
- } else if ("UNEXPECTED-PASS".equals(type)) {
- asserter.todo(true, name, message);
- }
-
- lastTestName = name;
- } else {
- // Generally, these extra lines are stack traces from failures,
- // so we print them with the name of the last test seen.
- asserter.info(lastTestName, str.trim());
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/NavigationHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/NavigationHelper.java
deleted file mode 100644
index e3ccc8236..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/NavigationHelper.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.helpers;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
-
-import org.mozilla.gecko.tests.UITestContext;
-import org.mozilla.gecko.tests.UITestContext.ComponentType;
-import org.mozilla.gecko.tests.components.AppMenuComponent;
-import org.mozilla.gecko.tests.components.ToolbarComponent;
-
-import com.robotium.solo.Solo;
-
-/**
- * Provides helper functionality for navigating around the Firefox UI. These functions will often
- * combine actions taken on multiple components to perform larger interactions.
- */
-final public class NavigationHelper {
- private static UITestContext sContext;
- private static Solo sSolo;
-
- private static AppMenuComponent sAppMenu;
- private static ToolbarComponent sToolbar;
-
- protected static void init(final UITestContext context) {
- sContext = context;
- sSolo = context.getSolo();
-
- sAppMenu = (AppMenuComponent) context.getComponent(ComponentType.APPMENU);
- sToolbar = (ToolbarComponent) context.getComponent(ComponentType.TOOLBAR);
- }
-
- public static void enterAndLoadUrl(String url) {
- fAssertNotNull("url is not null", url);
-
- url = adjustUrl(url);
- sToolbar.enterEditingMode()
- .enterUrl(url)
- .commitEditingMode();
- }
-
- /**
- * Returns a new URL with the docshell HTTP server host prefix.
- */
- public static String adjustUrl(final String url) {
- fAssertNotNull("url is not null", url);
-
- if (url.startsWith("about:") || url.startsWith("chrome:")) {
- return url;
- }
-
- return sContext.getAbsoluteHostnameUrl(url);
- }
-
- public static void goBack() {
- if (DeviceHelper.isTablet()) {
- sToolbar.pressBackButton(); // Waits for page load & asserts isNotEditing.
- return;
- }
-
- sToolbar.assertIsNotEditing();
- WaitHelper.waitForPageLoad(new Runnable() {
- @Override
- public void run() {
- // TODO: Lower soft keyboard first if applicable. Note that
- // Solo.hideSoftKeyboard() does not clear focus (which might be fine since
- // Gecko would be the element focused).
- sSolo.goBack();
- }
- });
- }
-
- public static void goForward() {
- if (DeviceHelper.isTablet()) {
- sToolbar.pressForwardButton(); // Waits for page load & asserts isNotEditing.
- return;
- }
-
- sToolbar.assertIsNotEditing();
- WaitHelper.waitForPageLoad(new Runnable() {
- @Override
- public void run() {
- sAppMenu.pressMenuItem(AppMenuComponent.MenuItem.FORWARD);
- }
- });
- }
-
- public static void reload() {
- if (DeviceHelper.isTablet()) {
- sToolbar.pressReloadButton(); // Waits for page load & asserts isNotEditing.
- return;
- }
-
- sToolbar.assertIsNotEditing();
- WaitHelper.waitForPageLoad(new Runnable() {
- @Override
- public void run() {
- sAppMenu.pressMenuItem(AppMenuComponent.MenuItem.RELOAD);
- }
- });
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/RobotiumHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/RobotiumHelper.java
deleted file mode 100644
index 2536eb9db..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/RobotiumHelper.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.helpers;
-
-import com.robotium.solo.Solo;
-
-import org.mozilla.gecko.tests.UITestContext;
-
-import java.util.regex.Pattern;
-
-/**
- * Provides helper functions for using Robotium.
- */
-public final class RobotiumHelper {
- private static Solo sSolo;
-
- private RobotiumHelper() { /* To disallow instantiation. */ }
-
- protected static void init(final UITestContext context) {
- sSolo = context.getSolo();
- }
-
- /**
- * Same as Solo.waitForText(), but matching against full text, without regular expressions.
- */
- public static boolean waitForExactText(final String text,
- final int minimumNumberOfMatches,
- final long timeout) {
- String matchText = "^" + Pattern.quote(text) + "$";
- return sSolo.waitForText(matchText, minimumNumberOfMatches, timeout);
- }
-
- /**
- * Same as Solo.searchText(), but matching against full text, without regular expressions.
- */
- public static boolean searchExactText(final String text,
- final boolean onlyVisible) {
- String matchText = "^" + Pattern.quote(text) + "$";
- return sSolo.searchText(matchText, onlyVisible);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/WaitHelper.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/WaitHelper.java
deleted file mode 100644
index f6e616652..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/helpers/WaitHelper.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests.helpers;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
-
-import android.os.SystemClock;
-
-import java.util.concurrent.Callable;
-import java.util.regex.Pattern;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Actions.EventExpecter;
-import org.mozilla.gecko.tests.UITestContext;
-import org.mozilla.gecko.tests.UITestContext.ComponentType;
-import org.mozilla.gecko.tests.components.ToolbarComponent;
-
-import com.robotium.solo.Condition;
-import com.robotium.solo.Solo;
-
-/**
- * Provides functionality related to waiting on certain events to happen.
- */
-public final class WaitHelper {
- // TODO: Make public for when Solo.waitForCondition is used directly (i.e. do not want
- // assertion from waitFor)?
- // DEFAULT_MAX_WAIT_MS of 5000 was intermittently insufficient during
- // initialization on Android 2.3 emulator -- bug 1114655
- private static final int DEFAULT_MAX_WAIT_MS = 15000;
- private static final int PAGE_LOAD_WAIT_MS = 10000;
- private static final int CHANGE_WAIT_MS = 15000;
-
- // TODO: via lucasr - Add ThrobberVisibilityChangeVerifier?
- private static final ChangeVerifier[] PAGE_LOAD_VERIFIERS = new ChangeVerifier[] {
- new ToolbarTitleTextChangeVerifier()
- };
-
- private static UITestContext sContext;
- private static Solo sSolo;
- private static Actions sActions;
-
- private static ToolbarComponent sToolbar;
-
- private WaitHelper() { /* To disallow instantiation. */ }
-
- protected static void init(final UITestContext context) {
- sContext = context;
- sSolo = context.getSolo();
- sActions = context.getActions();
-
- sToolbar = (ToolbarComponent) context.getComponent(ComponentType.TOOLBAR);
- }
-
- /**
- * Waits for the given {@link solo.Condition} using the default wait duration; will throw an
- * AssertionError if the duration is elapsed and the condition is not satisfied.
- */
- public static void waitFor(String message, final Condition condition) {
- message = "Waiting for " + message + ".";
- fAssertTrue(message, sSolo.waitForCondition(condition, DEFAULT_MAX_WAIT_MS));
- }
-
- /**
- * Waits for the given {@link solo.Condition} using the given wait duration; will throw an
- * AssertionError if the duration is elapsed and the condition is not satisfied.
- */
- public static void waitFor(String message, final Condition condition, final int waitMillis) {
- message = "Waiting for " + message + " with timeout " + waitMillis + ".";
- fAssertTrue(message, sSolo.waitForCondition(condition, waitMillis));
- }
-
- /**
- * Waits for the given Callable to return something that is not null, using the given wait
- * duration; will throw an AssertionError if the duration is elapsed and the callable has not
- * returned a non-null object.
- *
- * @return the value returned by the Callable. Or null if the duration has elapsed.
- */
- public static <V> V waitFor(String message, final Callable<V> callable, int waitMillis) {
- sContext.dumpLog("WaitHelper", "Waiting for " + message + " with timeout " + waitMillis + ".");
-
- final Object[] value = new Object[1];
-
- Condition condition = new Condition() {
- @Override
- public boolean isSatisfied() {
- try {
- V result = callable.call();
- value[0] = result;
- return result != null;
- } catch (Exception e) {
- return false;
- }
- }
- };
-
- sSolo.waitForCondition(condition, waitMillis);
-
- return (V) value[0];
- }
-
- /**
- * Waits for the Gecko event declaring the page has loaded. Takes in and runs a Runnable
- * that will perform the action that will cause the page to load.
- */
- public static void waitForPageLoad(final Runnable initiatingAction) {
- fAssertNotNull("initiatingAction is not null", initiatingAction);
-
- // Some changes to the UI occur in response to the same event we listen to for when
- // the page has finished loading (e.g. a page title update). As such, we ensure this
- // UI state has changed before returning from this method; here we store the initial
- // state.
- final ChangeVerifier[] pageLoadVerifiers = PAGE_LOAD_VERIFIERS;
- for (final ChangeVerifier verifier : pageLoadVerifiers) {
- verifier.storeState();
- }
-
- // Wait for the page load and title changed event.
- final EventExpecter[] eventExpecters = new EventExpecter[] {
- sActions.expectGeckoEvent("DOMContentLoaded"),
- sActions.expectGeckoEvent("DOMTitleChanged")
- };
-
- initiatingAction.run();
-
- // PAGE_LOAD_WAIT_MS is the total time we wait for all events to finish.
- final long expecterStartMillis = SystemClock.uptimeMillis();
- for (final EventExpecter expecter : eventExpecters) {
- final int eventWaitTimeMillis = PAGE_LOAD_WAIT_MS - (int)(SystemClock.uptimeMillis() - expecterStartMillis);
- expecter.blockForEventDataWithTimeout(eventWaitTimeMillis);
- expecter.unregisterListener();
- }
-
- // The timeout wait time should be the aggregate time for all ChangeVerifiers.
- final long verifierStartMillis = SystemClock.uptimeMillis();
-
- // Verify remaining state has changed.
- for (final ChangeVerifier verifier : pageLoadVerifiers) {
- // If we timeout, either the state is set to the same value (which is fine), or
- // the state has not yet changed. Since we can't be sure it will ever change, move
- // on and let the assertions fail if applicable.
- final int verifierWaitMillis = CHANGE_WAIT_MS - (int)(SystemClock.uptimeMillis() - verifierStartMillis);
- final boolean hasTimedOut = !sSolo.waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return verifier.hasStateChanged();
- }
- }, verifierWaitMillis);
-
- sContext.dumpLog(verifier.getLogTag(),
- (hasTimedOut ? "timed out." : "was satisfied."));
- }
- }
-
- /**
- * Implementations of this interface verify that the state of the test has changed from
- * the invocation of storeState to the invocation of hasStateChanged. A boolean will be
- * returned from hasStateChanged, indicating this change of status.
- */
- private interface ChangeVerifier {
- String getLogTag();
-
- /**
- * Stores the initial state of the system. This system state is used to diff against
- * the end state to determine if the system has changed. Since this is just a diff
- * (with a timeout), this method could potentially store state inconsistent with
- * what is visible to the user.
- */
- void storeState();
- boolean hasStateChanged();
- }
-
- private static class ToolbarTitleTextChangeVerifier implements ChangeVerifier {
- private static final String LOGTAG = ToolbarTitleTextChangeVerifier.class.getSimpleName();
-
- // A regex that matches the page title that shows up while the page is loading.
- private static final Pattern LOADING_PREFIX = Pattern.compile("[A-Za-z]{3,9}://");
-
- private CharSequence mOldTitleText;
-
- @Override
- public String getLogTag() {
- return LOGTAG;
- }
-
- @Override
- public void storeState() {
- mOldTitleText = sToolbar.getPotentiallyInconsistentTitle();
- sContext.dumpLog(LOGTAG, "stored title, \"" + mOldTitleText + "\".");
- }
-
- @Override
- public boolean hasStateChanged() {
- // TODO: Additionally, consider Solo.waitForText.
- // TODO: Robocop sleeps .5 sec between calls. Cache title view?
- final CharSequence title = sToolbar.getPotentiallyInconsistentTitle();
-
- // TODO: Handle the case where the URL is shown instead of page title by preference.
- // HACK: We want to wait until the title changes to the state a tester may assert
- // (e.g. the page title). However, the title is set to the URL before the title is
- // loaded from the server and set as the final page title; we ignore the
- // intermediate URL loading state here.
- final boolean isLoading = LOADING_PREFIX.matcher(title).lookingAt();
- final boolean hasStateChanged = !isLoading && !mOldTitleText.equals(title);
-
- if (hasStateChanged) {
- sContext.dumpLog(LOGTAG, "state changed to title, \"" + title + "\".");
- }
- return hasStateChanged;
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testANRReporter.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testANRReporter.java
deleted file mode 100644
index e3afeb8d9..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testANRReporter.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.AppConstants;
-
-import android.content.Context;
-import android.content.Intent;
-
-import com.robotium.solo.Condition;
-
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-
-import org.json.JSONObject;
-
-/**
- * Tests the proper operation of the ANR reporter.
- */
-public class testANRReporter extends BaseTest {
-
- private static final String ANR_ACTION = "android.intent.action.ANR";
- private static final String PING_DIR = "saved-telemetry-pings";
- private static final int WAIT_FOR_PING_TIMEOUT = 60000;
- private static final String ANR_PATH = "/data/anr/traces.txt";
- private static final String SAMPLE_ANR
- = "----- pid 1 at 2014-01-15 18:55:51 -----\n"
- + "Cmd line: " + AppConstants.ANDROID_PACKAGE_NAME + "\n"
- + "\n"
- + "JNI: CheckJNI is off; workarounds are off; pins=0; globals=397\n"
- + "\n"
- + "DALVIK THREADS:\n"
- + "(mutexes: tll=0 tsl=0 tscl=0 ghl=0)\n"
- + "\n"
- + "\"main\" prio=5 tid=1 WAIT\n"
- + " | group=\"main\" sCount=1 dsCount=0 obj=0x41d6bc90 self=0x41d5a3c8\n"
- + " | sysTid=3485 nice=0 sched=0/0 cgrp=apps handle=1074852180\n"
- + " | state=S schedstat=( 0 0 0 ) utm=1065 stm=152 core=0\n"
- + " at java.lang.Object.wait(Native Method)\n"
- + " - waiting on <0x427ab340> (a org.mozilla.gecko.GeckoEditable$5)\n"
- + " at java.lang.Object.wait(Object.java:364)\n"
- + " at org.mozilla.gecko.GeckoEditable$5.run(GeckoEditable.java:746)\n"
- + " at android.os.Handler.handleCallback(Handler.java:733)\n"
- + " at android.os.Handler.dispatchMessage(Handler.java:95)\n"
- + " at android.os.Looper.loop(Looper.java:137)\n"
- + " at android.app.ActivityThread.main(ActivityThread.java:4998)\n"
- + " at java.lang.reflect.Method.invokeNative(Native Method)\n"
- + " at java.lang.reflect.Method.invoke(Method.java:515)\n"
- + " at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)\n"
- + " at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)\n"
- + " at dalvik.system.NativeStart.main(Native Method)\n"
- + "\n"
- + "\"Gecko\" prio=5 tid=16 SUSPENDED\n"
- + " | group=\"main\" sCount=1 dsCount=0 obj=0x426e2b28 self=0x76ae92e8\n"
- + " | sysTid=3541 nice=0 sched=0/0 cgrp=apps handle=1991153472\n"
- + " | state=S schedstat=( 0 0 0 ) utm=1118 stm=145 core=0\n"
- + " #00 pc 00000904 /system/lib/libc.so (__futex_syscall3+4294832136)\n"
- + " #01 pc 0000eec4 /system/lib/libc.so (__pthread_cond_timedwait_relative+48)\n"
- + " #02 pc 0000ef24 /system/lib/libc.so (__pthread_cond_timedwait+64)\n"
- + " #03 pc 000536b7 /system/lib/libdvm.so\n"
- + " #04 pc 00053c79 /system/lib/libdvm.so (dvmChangeStatus(Thread*, ThreadStatus)+34)\n"
- + " #05 pc 00049507 /system/lib/libdvm.so\n"
- + " #06 pc 0004d84b /system/lib/libdvm.so\n"
- + " #07 pc 0003f1df /dev/ashmem/libxul.so (deleted)\n"
- + " at org.mozilla.gecko.mozglue.GeckoLoader.nativeRun(Native Method)\n"
- + " at org.mozilla.gecko.GeckoAppShell.runGecko(GeckoAppShell.java:384)\n"
- + " at org.mozilla.gecko.GeckoThread.run(GeckoThread.java:177)\n"
- + "\n"
- + "----- end 1 -----\n"
- + "\n"
- + "\n"
- + "----- pid 2 at 2013-01-25 13:27:01 -----\n"
- + "Cmd line: system_server\n"
- + "\n"
- + "----- end 2 -----\n";
-
- private boolean mDone;
-
- private JSONObject readPingFile(final File pingFile) throws Exception {
- final long fileSize = pingFile.length();
- if (fileSize == 0 || fileSize > Integer.MAX_VALUE) {
- throw new Exception("Invalid ping file size");
- }
- final char[] buffer = new char[(int) fileSize];
- final FileReader reader = new FileReader(pingFile);
- try {
- final int readSize = reader.read(buffer);
- if (readSize == 0 || readSize > buffer.length) {
- throw new Exception("Invalid number of bytes read");
- }
- } finally {
- reader.close();
- }
- return new JSONObject(new String(buffer));
- }
-
- public void testANRReporter() throws Exception {
- blockForGeckoReady();
-
- // Cannot test ANR reporter if it's disabled.
- if (!AppConstants.MOZ_ANDROID_ANR_REPORTER) {
- mAsserter.ok(true, "ANR reporter is disabled", null);
- return;
- }
-
- // For the ANR reporter to work, we need to provide sample ANR traces to it.
- // Therefore, we need the ANR file to exist and writable. If not, we don't
- // have the right permissions to create the file, so we just bail.
- final File anrFile = new File(ANR_PATH);
- if (!anrFile.exists()) {
- mAsserter.ok(true, "ANR file does not exist", null);
- return;
- }
- if (!anrFile.canWrite()) {
- mAsserter.ok(true, "ANR file is not writable", null);
- return;
- }
-
- final FileWriter anrWriter = new FileWriter(anrFile);
- try {
- anrWriter.write(SAMPLE_ANR);
- } finally {
- anrWriter.close();
- }
-
- // Block the UI thread to simulate an ANR
- final Runnable uiBlocker = new Runnable() {
- @Override
- public synchronized void run() {
- while (!mDone) {
- try {
- wait();
- } catch (final InterruptedException e) {
- }
- }
- }
- };
- getActivity().runOnUiThread(uiBlocker);
-
- // Make sure our initial ping directory is empty.
- final File pingDir = new File(mProfile, PING_DIR);
- final String[] initialFiles = pingDir.list();
- mAsserter.ok(initialFiles == null || initialFiles.length == 0,
- "Ping directory is empty", null);
-
- final Intent anrIntent = new Intent(ANR_ACTION);
- anrIntent.setPackage(AppConstants.ANDROID_PACKAGE_NAME);
- mAsserter.is(anrIntent.getPackage(), AppConstants.ANDROID_PACKAGE_NAME,
- "Successfully set package name");
-
- final Context testContext = getInstrumentation().getContext();
- mAsserter.isnot(testContext, null, "testContext should not be null");
-
- // Trigger the ANR.
- mAsserter.info("Triggering ANR", null);
- testContext.sendBroadcast(anrIntent);
-
- // ANR reporter is supposed to ignore duplicate ANRs.
- // This will be checked later when we look for ping files.
- mAsserter.info("Triggering second ANR", null);
- testContext.sendBroadcast(new Intent(anrIntent));
-
- waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- mAsserter.info("Waiting for ping", null);
-
- try {
- // Sleep to allow the ANR reporter thread time to process the ANR.
- Thread.sleep(1000);
- } catch (final InterruptedException e) {
- }
-
- final File[] newFiles = pingDir.listFiles();
- if (newFiles == null || newFiles.length == 0) {
- // Keep waiting.
- return false;
- }
- // Make sure we have a complete file. We skip assertions and catch all
- // exceptions here because the condition may not be satisfied now but may
- // be satisfied later. After the wait is over, we will repeat the same
- // steps with assertions and exceptions.
- try {
- return readPingFile(newFiles[0]).has("slug");
- } catch (final Exception e) {
- return false;
- }
- }
- }, WAIT_FOR_PING_TIMEOUT);
-
- mAsserter.ok(pingDir.exists(), "Ping directory exists", null);
- mAsserter.ok(pingDir.isDirectory(), "Ping directory is a directory", null);
-
- final File[] newFiles = pingDir.listFiles();
- mAsserter.isnot(newFiles, null, "Ping directory is not empty");
- mAsserter.is(newFiles.length, 1, "ANR reporter wrote one ping");
- mAsserter.ok(newFiles[0].exists(), "Ping exists", null);
- mAsserter.ok(newFiles[0].isFile(), "Ping is a file", null);
- mAsserter.ok(newFiles[0].canRead(), "Ping is readable", null);
- mAsserter.info("Found ping file", newFiles[0].getPath());
-
- // Check standard properties required by Telemetry server.
- final JSONObject pingObject = readPingFile(newFiles[0]);
- mAsserter.ok(pingObject.has("slug"), "Ping has slug property", null);
- mAsserter.ok(pingObject.has("reason"), "Ping has reason property", null);
- mAsserter.ok(pingObject.has("payload"), "Ping has payload property", null);
-
- final JSONObject pingPayload = pingObject.getJSONObject("payload");
- mAsserter.ok(pingPayload.has("ver"), "Payload has ver property", null);
- mAsserter.ok(pingPayload.has("info"), "Payload has info property", null);
- mAsserter.ok(pingPayload.has("androidANR"), "Payload has androidANR property", null);
-
- final JSONObject pingInfo = pingPayload.getJSONObject("info");
- mAsserter.ok(pingInfo.has("reason"), "Info has reason property", null);
- mAsserter.ok(pingInfo.has("appName"), "Info has appName property", null);
- mAsserter.ok(pingInfo.has("appUpdateChannel"), "Info has appUpdateChannel property", null);
- mAsserter.ok(pingInfo.has("appVersion"), "Info has appVersion property", null);
- mAsserter.ok(pingInfo.has("appBuildID"), "Info has appBuildID property", null);
-
- // Do some profile clean up. This is not absolutely necessary because the profile
- // is blown away after test runs anyways, so we don't check return values here.
- for (final File ping : newFiles) {
- ping.delete();
- }
- pingDir.delete();
-
- // Unblock UI thread
- synchronized (uiBlocker) {
- mDone = true;
- uiBlocker.notify();
- }
-
- // Clear the sample ANR
- final FileWriter anrClearer = new FileWriter(anrFile);
- anrClearer.close();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutHomePageNavigation.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutHomePageNavigation.java
deleted file mode 100644
index 68f3a38db..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutHomePageNavigation.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.home.HomeConfig.PanelType;
-import org.mozilla.gecko.tests.helpers.DeviceHelper;
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-
-/**
- * Tests functionality related to navigating between the various about:home panels.
- */
-public class testAboutHomePageNavigation extends UITest {
- // TODO: Define this test dynamically by creating dynamic representations of the Page
- // enum for both phone and tablet, then swiping through the panels. This will also
- // benefit having a HomePager with custom panels.
- public void testAboutHomePageNavigation() {
- GeckoHelper.blockForDelayedStartup();
-
- mAboutHome.assertVisible()
- .assertCurrentPanel(PanelType.TOP_SITES);
-
- mAboutHome.swipeToPanelOnRight();
- mAboutHome.assertCurrentPanel(PanelType.BOOKMARKS);
-
- // Ideally these helpers would just be their own tests. However, by keeping this within
- // one method, we're saving test setUp and tearDown resources.
- if (DeviceHelper.isTablet()) {
- helperTestTablet();
- } else {
- helperTestPhone();
- }
- }
-
- private void helperTestTablet() {
- mAboutHome.swipeToPanelOnRight();
- mAboutHome.assertCurrentPanel(PanelType.COMBINED_HISTORY);
-
- // Edge case.
- mAboutHome.swipeToPanelOnRight();
- mAboutHome.assertCurrentPanel(PanelType.COMBINED_HISTORY);
-
- mAboutHome.swipeToPanelOnLeft();
- mAboutHome.assertCurrentPanel(PanelType.BOOKMARKS);
-
- mAboutHome.swipeToPanelOnLeft();
- mAboutHome.assertCurrentPanel(PanelType.TOP_SITES);
-
- // Edge case.
- mAboutHome.swipeToPanelOnLeft();
- mAboutHome.assertCurrentPanel(PanelType.TOP_SITES);
- }
-
- private void helperTestPhone() {
- // Edge case.
- mAboutHome.swipeToPanelOnLeft();
- mAboutHome.assertCurrentPanel(PanelType.BOOKMARKS);
-
- mAboutHome.swipeToPanelOnLeft();
- mAboutHome.assertCurrentPanel(PanelType.TOP_SITES);
-
- mAboutHome.swipeToPanelOnLeft();
- mAboutHome.assertCurrentPanel(PanelType.COMBINED_HISTORY);
-
- // Edge case.
- mAboutHome.swipeToPanelOnLeft();
- mAboutHome.assertCurrentPanel(PanelType.COMBINED_HISTORY);
-
- mAboutHome.swipeToPanelOnRight();
- mAboutHome.assertCurrentPanel(PanelType.TOP_SITES);
- }
-
- // TODO: bug 943706 - reimplement this old test code.
- /*
- // Removed by Bug 896576 - [fig] Remove [getAllPagesList] from BaseTest
- // ListView list = getAllPagesList("about:firefox");
-
- // Test normal sliding of the list left and right
- ViewPager pager = (ViewPager)mSolo.getView(ViewPager.class, 0);
- mAsserter.is(pager.getCurrentItem(), 0, "All pages is selected");
-
- int width = mDriver.getGeckoWidth() / 2;
- int y = mDriver.getGeckoHeight() / 2;
- mActions.drag(width, 0, y, y);
- mAsserter.is(pager.getCurrentItem(), 1, "Bookmarks page is selected");
-
- mActions.drag(0, width, y, y);
- mAsserter.is(pager.getCurrentItem(), 0, "All pages is selected");
-
- // Test tapping on the tab strip changes tabs
- TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0);
- mSolo.clickOnView(tabwidget.getChildAt(1));
- mAsserter.is(pager.getCurrentItem(), 1, "Clicking on tab selected bookmarks page");
-
- // Test typing in the awesomebar changes tabs and prevents panning
- mSolo.typeText(0, "woot");
- mAsserter.is(pager.getCurrentItem(), 0, "Searching switched to all pages tab");
- mSolo.scrollToSide(Solo.LEFT);
- mAsserter.is(pager.getCurrentItem(), 0, "Dragging left is not allowed when searching");
-
- mSolo.scrollToSide(Solo.RIGHT);
- mAsserter.is(pager.getCurrentItem(), 0, "Dragging right is not allowed when searching");
-
- mSolo.goBack();
- */
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutHomeVisibility.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutHomeVisibility.java
deleted file mode 100644
index 3be6ed53f..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutHomeVisibility.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.home.HomeConfig;
-import org.mozilla.gecko.home.HomeConfig.PanelType;
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-import org.mozilla.gecko.tests.helpers.NavigationHelper;
-
-/**
- * Tests the visibility of about:home after various interactions with the browser.
- */
-public class testAboutHomeVisibility extends UITest {
- public void testAboutHomeVisibility() {
- GeckoHelper.blockForReady();
-
- // Check initial state on about:home.
- mToolbar.assertTitle(mStringHelper.ABOUT_HOME_URL);
- mAboutHome.assertVisible()
- .assertCurrentPanel(PanelType.TOP_SITES);
-
- // Go to blank 01.
- NavigationHelper.enterAndLoadUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- mToolbar.assertTitle(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- mAboutHome.assertNotVisible();
-
- // Go to blank 02.
- NavigationHelper.enterAndLoadUrl(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL);
- mToolbar.assertTitle(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL);
- mAboutHome.assertNotVisible();
-
- // Enter editing mode, where the about:home UI should be visible.
- mToolbar.enterEditingMode();
- mAboutHome.assertVisible()
- .assertCurrentPanel(PanelType.TOP_SITES);
-
- // Dismiss editing mode, where the about:home UI should be gone.
- mToolbar.dismissEditingMode();
- mAboutHome.assertNotVisible();
-
- // Loading about:home should show about:home again.
- NavigationHelper.enterAndLoadUrl(mStringHelper.ABOUT_HOME_URL);
- mToolbar.assertTitle(mStringHelper.ABOUT_HOME_URL);
- mAboutHome.assertVisible()
- .assertCurrentPanel(PanelType.TOP_SITES);
-
- // We can navigate to about:home panels by panel UUID.
- mAboutHome.navigateToBuiltinPanelType(PanelType.BOOKMARKS)
- .assertVisible()
- .assertCurrentPanel(PanelType.BOOKMARKS);
- mAboutHome.navigateToBuiltinPanelType(PanelType.COMBINED_HISTORY)
- .assertVisible()
- .assertCurrentPanel(PanelType.COMBINED_HISTORY);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutPage.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutPage.java
deleted file mode 100644
index 6a00acd96..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAboutPage.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-
-/* Tests related to the about: page:
- * - check that about: loads from the URL bar
- * - check that about: loads from Settings/About...
- */
-public class testAboutPage extends PixelTest {
-
- public void testAboutPage() {
- blockForGeckoReady();
-
- // Load the about: page and verify its title.
- String url = mStringHelper.ABOUT_SCHEME;
- loadAndPaint(url);
-
- verifyUrlInContentDescription(url);
-
- // Open a new page to remove the about: page from the current tab.
- url = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- loadUrlAndWait(url);
-
- // At this point the page title should have been set.
- verifyUrlInContentDescription(url);
-
- // Set up listeners to catch the page load we're about to do.
- Actions.EventExpecter tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
- Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
-
- selectSettingsItem(mStringHelper.MOZILLA_SECTION_LABEL, mStringHelper.ABOUT_LABEL);
-
- // Wait for the new tab and page to load
- tabEventExpecter.blockForEvent();
- contentEventExpecter.blockForEvent();
-
- tabEventExpecter.unregisterListener();
- contentEventExpecter.unregisterListener();
-
- // Make sure the about: page was loaded.
- verifyUrlInContentDescription(mStringHelper.ABOUT_SCHEME);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAccessibleCarets.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAccessibleCarets.java
deleted file mode 100644
index d064eb1dd..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAccessibleCarets.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.Tab;
-import org.mozilla.gecko.Tabs;
-
-import android.util.Log;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-
-public class testAccessibleCarets extends JavascriptTest {
- private static final String LOGTAG = "testAccessibleCarets";
- private static final String TAB_CHANGE_EVENT = "testAccessibleCarets:TabChange";
-
- private final TabsListener tabsListener;
-
-
- public testAccessibleCarets() {
- super("testAccessibleCarets.js");
-
- tabsListener = new TabsListener();
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- Tabs.registerOnTabsChangedListener(tabsListener);
- }
-
- @Override
- public void tearDown() throws Exception {
- Tabs.unregisterOnTabsChangedListener(tabsListener);
-
- super.tearDown();
- }
-
- @Override
- public void testJavascript() throws Exception {
- // This feature is currently only available in Nightly.
- if (!AppConstants.NIGHTLY_BUILD) {
- mAsserter.dumpLog(LOGTAG + " is disabled on non-Nightly builds: returning");
- return;
- }
- super.testJavascript();
- }
-
- /**
- * Observes tab change events to broadcast to the test script.
- */
- private class TabsListener implements Tabs.OnTabsChangedListener {
- @Override
- public void onTabChanged(Tab tab, Tabs.TabEvents msg, String data) {
- switch (msg) {
- case STOP:
- final JSONObject args = new JSONObject();
- try {
- args.put("tabId", tab.getId());
- args.put("event", msg.toString());
- } catch (JSONException e) {
- Log.e(LOGTAG, "Error building JSON arguments for " + TAB_CHANGE_EVENT, e);
- return;
- }
- mActions.sendGeckoEvent(TAB_CHANGE_EVENT, args.toString());
- break;
- }
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testActivityStreamContextMenu.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testActivityStreamContextMenu.java
deleted file mode 100644
index b4b06a236..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testActivityStreamContextMenu.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.support.design.widget.NavigationView;
-import android.support.v4.app.Fragment;
-import android.view.KeyEvent;
-import android.view.MenuItem;
-import android.view.View;
-
-import com.robotium.solo.Condition;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.home.activitystream.ActivityStream;
-import org.mozilla.gecko.home.activitystream.menu.ActivityStreamContextMenu;
-
-/**
- * This test is unfortunately closely coupled to the current implementation, however it is still
- * useful in that it tests the bookmark/history state specific menu items for correctness.
- */
-public class testActivityStreamContextMenu extends BaseTest {
- public void testActivityStreamContextMenu() {
- blockForGeckoReady();
-
- final String testURL = "http://mozilla.org";
-
- BrowserDB db = BrowserDB.from(getActivity());
- db.removeHistoryEntry(getActivity().getContentResolver(), testURL);
- db.removeBookmarksWithURL(getActivity().getContentResolver(), testURL);
-
- testMenuForUrl(testURL, false, false);
-
- db.addBookmark(getActivity().getContentResolver(), "foobar", testURL);
- testMenuForUrl(testURL, true, false);
-
- db.updateVisitedHistory(getActivity().getContentResolver(), testURL);
- testMenuForUrl(testURL, true, true);
-
- db.removeBookmarksWithURL(getActivity().getContentResolver(), testURL);
- testMenuForUrl(testURL, false, true);
- }
-
- /**
- * Test that the menu shows the expected menu items for a given URL, and that these items have
- * the correct state.
- */
- private void testMenuForUrl(final String url, final boolean isBookmarked, final boolean isVisited) {
- final View anchor = new View(getActivity());
-
- final ActivityStreamContextMenu menu = ActivityStreamContextMenu.show(getActivity(), anchor, ActivityStreamContextMenu.MenuMode.HIGHLIGHT, "foobar", url, null, null, 100, 100);
-
- final int expectedBookmarkString;
- if (isBookmarked) {
- expectedBookmarkString = R.string.bookmark_remove;
- } else {
- expectedBookmarkString = R.string.bookmark;
- }
-
- final MenuItem bookmarkItem = menu.getItemByID(R.id.bookmark);
- assertMenuItemHasString(bookmarkItem, expectedBookmarkString);
-
- final MenuItem deleteItem = menu.getItemByID(R.id.delete);
- assertMenuItemIsVisible(deleteItem, isVisited);
-
- menu.dismiss();
- }
-
- private void assertMenuItemIsVisible(final MenuItem item, final boolean shouldBeVisible) {
- waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return (item.isVisible() == shouldBeVisible);
- }
- }, 5000);
-
- mAsserter.is(item.isVisible(), shouldBeVisible, "menu item \"" + item.getTitle() + "\" should be visible");
- }
-
- private void assertMenuItemHasString(final MenuItem item, final int stringID) {
- waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return item.isEnabled();
- }
- }, 5000);
-
- final String expectedTitle = getActivity().getResources().getString(stringID);
- mAsserter.is(item.getTitle(), expectedTitle, "Title does not match expected title");
- }
-}
-
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAddSearchEngine.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAddSearchEngine.java
deleted file mode 100644
index 44bd1f903..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAddSearchEngine.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.File;
-import java.util.ArrayList;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.home.HomePager;
-import org.mozilla.gecko.home.SearchEngineBar;
-import org.mozilla.gecko.R;
-
-import android.widget.ImageView;
-import android.widget.ListView;
-
-import com.robotium.solo.Condition;
-
-/**
- * Test adding a search engine from an input field context menu.
- * 1. Get the number of existing search engines from the SearchEngine:Data event and as displayed in about:home.
- * 2. Load a page with a text field, open the context menu and add a search engine from the page.
- * 3. Get the number of search engines after adding the new one and verify it has increased by 1.
- */
-public class testAddSearchEngine extends AboutHomeTest {
- private final int MAX_WAIT_TEST_MS = 5000;
- private final String SEARCH_TEXT = "Firefox for Android";
- private final String ADD_SEARCHENGINE_OPTION_TEXT = "Add as Search Engine";
-
- public void testAddSearchEngine() {
- String blankPageURL = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- String searchEngineURL = getAbsoluteUrl(mStringHelper.ROBOCOP_SEARCH_URL);
-
- blockForGeckoReady();
- int height = mDriver.getGeckoTop() + 150;
- int width = mDriver.getGeckoLeft() + 150;
-
- inputAndLoadUrl(blankPageURL);
- waitForText(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
-
- // Get the searchengine data by clicking the awesomebar - this causes Gecko to send Java the list
- // of search engines.
- Actions.EventExpecter searchEngineDataEventExpector = mActions.expectGeckoEvent("SearchEngines:Data");
- focusUrlBar();
- mActions.sendKeys(SEARCH_TEXT);
- String eventData = searchEngineDataEventExpector.blockForEventData();
- searchEngineDataEventExpector.unregisterListener();
-
- ArrayList<String> searchEngines;
- try {
- // Parse the data to get the number of searchengines.
- searchEngines = getSearchEnginesNames(eventData);
- } catch (JSONException e) {
- mAsserter.ok(false, "Fatal exception in testAddSearchEngine while decoding JSON search engine string from Gecko prior to addition of new engine.", e.toString());
- return;
- }
- final int initialNumSearchEngines = searchEngines.size();
- mAsserter.dumpLog("Search Engines list = " + searchEngines.toString());
-
- // Verify that the number of displayed search engines is the same as the one received through the SearchEngines:Data event.
- verifyDisplayedSearchEnginesCount(initialNumSearchEngines);
-
- // Load the page for the search engine to add.
- inputAndLoadUrl(searchEngineURL);
- verifyUrlBarTitle(searchEngineURL);
-
- // Used to long-tap on the search input box for the search engine to add.
- getInstrumentation().waitForIdleSync();
- mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height));
- mSolo.clickLongOnScreen(width,height);
-
- ImageView view = waitForViewWithDescription(ImageView.class, ADD_SEARCHENGINE_OPTION_TEXT);
- mAsserter.isnot(view, null, "The action mode was opened");
-
- // Add the search engine
- mSolo.clickOnView(view);
- waitForText("Cancel");
- clickOnButton("OK");
- mAsserter.ok(!mSolo.searchText(ADD_SEARCHENGINE_OPTION_TEXT), "Adding the Search Engine", "The add Search Engine pop-up has been closed");
- waitForText(mStringHelper.ROBOCOP_SEARCH_TITLE); // Make sure the pop-up is closed and we are back at the searchengine page
-
- // Load Robocop Blank 1 again to give the time for the searchengine to be added
- // TODO: This is a potential source of intermittent oranges - it's a race condition!
- loadUrl(blankPageURL);
- waitForText(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
-
- // Load search engines again and check that the quantity of engines has increased by 1.
- searchEngineDataEventExpector = mActions.expectGeckoEvent("SearchEngines:Data");
- focusUrlBar();
- mActions.sendKeys(SEARCH_TEXT);
- eventData = searchEngineDataEventExpector.blockForEventData();
-
- try {
- // Parse the data to get the number of searchengines
- searchEngines = getSearchEnginesNames(eventData);
- } catch (JSONException e) {
- mAsserter.ok(false, "Fatal exception in testAddSearchEngine while decoding JSON search engine string from Gecko after adding of new engine.", e.toString());
- return;
- }
-
- mAsserter.dumpLog("Search Engines list = " + searchEngines.toString());
- mAsserter.is(searchEngines.size(), initialNumSearchEngines + 1, "Checking the number of Search Engines has increased");
-
- // Verify that the number of displayed searchengines is the same as the one received through the SearchEngines:Data event.
- verifyDisplayedSearchEnginesCount(initialNumSearchEngines + 1);
- searchEngineDataEventExpector.unregisterListener();
-
- // Verify that the search plugin XML file for the new engine ended up where we expected it to.
- // This file name is created in nsSearchService.js based on the name of the new engine.
- final File f = GeckoProfile.get(getActivity()).getFile("searchplugins/robocop-search-engine.xml");
- mAsserter.ok(f.exists(), "Checking that new search plugin file exists", "");
- }
-
- /**
- * Helper method to decode a list of search engine names from the provided search engine information
- * JSON string sent from Gecko.
- * @param searchEngineData The JSON string representing the search engine array to process
- * @return An ArrayList<String> containing the names of all the search engines represented in
- * the provided JSON message.
- * @throws JSONException In the event that the JSON provided cannot be decoded.
- */
- public ArrayList<String> getSearchEnginesNames(String searchEngineData) throws JSONException {
- JSONObject data = new JSONObject(searchEngineData);
- JSONArray engines = data.getJSONArray("searchEngines");
-
- ArrayList<String> searchEngineNames = new ArrayList<String>();
- for (int i = 0; i < engines.length(); i++) {
- JSONObject engineJSON = engines.getJSONObject(i);
- searchEngineNames.add(engineJSON.getString("name"));
- }
- return searchEngineNames;
- }
-
- /**
- * Method to verify that the displayed number of search engines matches the expected number.
- * @param expectedCount The expected number of search engines.
- */
- public void verifyDisplayedSearchEnginesCount(final int expectedCount) {
- mSolo.clearEditText(0);
- mActions.sendKeys(SEARCH_TEXT);
- boolean correctNumSearchEnginesDisplayed = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- ListView searchResultList = findListViewWithTag(HomePager.LIST_TAG_BROWSER_SEARCH);
- if (searchResultList == null || searchResultList.getAdapter() == null) {
- return false;
- }
-
- SearchEngineBar searchEngineBar = (SearchEngineBar) mSolo.getView(R.id.search_engine_bar);
- if (searchEngineBar == null || searchEngineBar.getAdapter() == null) {
- return false;
- }
-
- final int actualCount = searchResultList.getAdapter().getCount()
- + searchEngineBar.getAdapter().getItemCount()
- - 1; // Subtract one for the search engine bar label (Bug 1172071)
-
- return (actualCount == expectedCount);
- }
- }, MAX_WAIT_TEST_MS);
-
- // Exit about:home
- mSolo.goBack();
- waitForText(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
- mAsserter.ok(correctNumSearchEnginesDisplayed, expectedCount + " Search Engines should be displayed" , "The correct number of Search Engines has been displayed");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAddonManager.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAddonManager.java
deleted file mode 100644
index 4256d93c4..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAddonManager.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.json.JSONObject;
-import org.mozilla.gecko.Actions;
-
-import android.util.DisplayMetrics;
-
-/**
- * This test performs the following steps to check the behavior of the Add-on Manager:
- *
- * 1) Open the Add-on Manager from the Add-ons menu item, and then close it.
- * 2) Open the Add-on Manager by visiting about:addons in the URL bar.
- * 3) Open a new tab, select the Add-ons menu item, then verify that the existing
- * Add-on Manager tab was selected, instead of opening a new tab.
- */
-public class testAddonManager extends PixelTest {
- public void testAddonManager() {
- Actions.EventExpecter tabEventExpecter;
- Actions.EventExpecter contentEventExpecter;
- final String aboutAddonsURL = mStringHelper.ABOUT_ADDONS_URL;
-
- blockForGeckoReady();
-
- // Use the menu to open the Addon Manger
- selectMenuItem(mStringHelper.ADDONS_LABEL);
-
- // Set up listeners to catch the page load we're about to do
- tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
- contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
-
- // Wait for the new tab and page to load
- tabEventExpecter.blockForEvent();
- contentEventExpecter.blockForEvent();
-
- tabEventExpecter.unregisterListener();
- contentEventExpecter.unregisterListener();
-
- // Verify the url
- verifyUrlBarTitle(aboutAddonsURL);
-
- // Close the Add-on Manager
- mSolo.goBack();
-
- // Load the about:addons page and verify it was loaded
- loadAndPaint(aboutAddonsURL);
- verifyUrlBarTitle(aboutAddonsURL);
-
- // Setup wait for tab to spawn and load
- tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
- contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
-
- // Open a new tab
- final String blankURL = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- addTab(blankURL);
-
- // Wait for the new tab and page to load
- tabEventExpecter.blockForEvent();
- contentEventExpecter.blockForEvent();
-
- tabEventExpecter.unregisterListener();
- contentEventExpecter.unregisterListener();
-
- // Verify tab count has increased
- verifyTabCount(2);
-
- // Verify the page was opened
- verifyUrlBarTitle(blankURL);
-
- // Addons Manager is not opened 2 separate times when opened from the menu
- selectMenuItem(mStringHelper.ADDONS_LABEL);
-
- // Verify tab count not increased
- verifyTabCount(2);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAdobeFlash.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAdobeFlash.java
deleted file mode 100644
index 13f7f817a..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAdobeFlash.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.json.JSONObject;
-import org.mozilla.gecko.PaintedSurface;
-
-import android.os.Build;
-
-/**
- * Tests that Flash is working
- * - loads a page containing a Flash plugin
- * - verifies it rendered properly
- */
-public class testAdobeFlash extends PixelTest {
- public void testLoad() {
- // This test only works on ICS and higher
- if (Build.VERSION.SDK_INT < 15) {
- blockForGeckoReady();
- return;
- }
-
- // Enable plugins
- setPreferenceAndWaitForChange("plugin.enable", "1");
-
- blockForGeckoReady();
-
- String url = getAbsoluteUrl(mStringHelper.ROBOCOP_ADOBE_FLASH_URL);
- PaintedSurface painted = loadAndGetPainted(url);
-
- mAsserter.ispixel(painted.getPixelAt(0, 0), 0, 0xff, 0, "Pixel at 0, 0");
- mAsserter.ispixel(painted.getPixelAt(50, 50), 0, 0xff, 0, "Pixel at 50, 50");
- mAsserter.ispixel(painted.getPixelAt(101, 0), 0xff, 0xff, 0xff, "Pixel at 101, 0");
- mAsserter.ispixel(painted.getPixelAt(0, 101), 0xff, 0xff, 0xff, "Pixel at 0, 101");
-
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAppMenuPathways.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAppMenuPathways.java
deleted file mode 100644
index 69efb4dec..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAppMenuPathways.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.json.JSONObject;
-import org.mozilla.gecko.Tabs;
-import org.mozilla.gecko.tests.components.AppMenuComponent;
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-import org.mozilla.gecko.tests.helpers.NavigationHelper;
-
-import com.robotium.solo.Solo;
-
-/**
- * Set of tests to test UI App menu and submenus the user interact with.
- */
-public class testAppMenuPathways extends UITest {
-
- /**
- * Robocop supports only a single test function per test class. Therefore, we
- * have a single top-level test function that dispatches to sub-tests.
- */
- public void testAppMenuPathways() {
- GeckoHelper.blockForReady();
-
- _testHardwareMenuKeyOpenClose();
- _testSaveAsPDFPathway();
- }
-
- public void _testHardwareMenuKeyOpenClose() {
- mAppMenu.assertMenuIsNotOpen();
-
- mSolo.sendKey(Solo.MENU);
- mAppMenu.waitForMenuOpen();
- mAppMenu.assertMenuIsOpen();
-
- mSolo.sendKey(Solo.MENU);
- mAppMenu.waitForMenuClose();
- mAppMenu.assertMenuIsNotOpen();
- }
-
- public void _testSaveAsPDFPathway() {
- // Page menu should be disabled in about:home.
- mAppMenu.assertMenuItemIsDisabledAndVisible(AppMenuComponent.PageMenuItem.SAVE_AS_PDF);
-
- // Generate a mock Content:LocationChange message with video mime-type for the current tab (tabId = 0).
- final JSONObject message = new JSONObject();
- try {
- message.put("contentType", "video/webm");
- message.put("baseDomain", "webmfiles.org");
- message.put("type", "Content:LocationChange");
- message.put("sameDocument", false);
- message.put("userRequested", "");
- message.put("uri", getAbsoluteIpUrl("/big-buck-bunny_trailer.webm"));
- message.put("tabID", 0);
- } catch (Exception ex) {
- mAsserter.ok(false, "exception in testSaveAsPDFPathway", ex.toString());
- }
-
- // Mock video playback with the generated message and Content:LocationChange event.
- Tabs.getInstance().handleMessage("Content:LocationChange", message);
-
- // Save as pdf menu is disabled while playing video.
- mAppMenu.assertMenuItemIsDisabledAndVisible(AppMenuComponent.PageMenuItem.SAVE_AS_PDF);
-
- // The above mock video playback test changes Java state, but not the associated JS state.
- // Navigate to a new page so that the Java state is cleared.
- NavigationHelper.enterAndLoadUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- mToolbar.assertTitle(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
-
- // Test save as pdf functionality.
- // The following call doesn't wait for the resulting pdf but checks that no exception are thrown.
- // NOTE: save as pdf functionality must be done at the end as it is slow and cause other test operations to fail.
- mAppMenu.pressMenuItem(AppMenuComponent.PageMenuItem.SAVE_AS_PDF);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAxisLocking.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAxisLocking.java
deleted file mode 100644
index 72bf62e04..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAxisLocking.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.PaintedSurface;
-
-/**
- * Basic test for axis locking behaviour.
- * - Load page and verify it draws
- * - Drag page upwards 100 pixels at a 5-degree angle off the vertical axis
- * - Verify that the 5-degree angle was thrown out and it dragged vertically
- * - Drag page upwards at a 45-degree angle
- * - Verify that the 45-degree angle was not thrown out and it dragged diagonally
- */
-public class testAxisLocking extends PixelTest {
- public void testAxisLocking() {
- String url = getAbsoluteUrl(mStringHelper.ROBOCOP_BOXES_URL);
-
- MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop());
-
- blockForGeckoReady();
-
- // load page and check we're at 0,0
- loadAndVerifyBoxes(url);
-
- // drag page upwards by 100 pixels with a slight angle. verify that
- // axis locking prevents any horizontal scrolling
- Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
- meh.dragSync(20, 150, 10, 50);
- PaintedSurface painted = waitForPaint(paintExpecter);
- paintExpecter.unregisterListener();
- try {
- checkScrollWithBoxes(painted, 0, 100);
- // since checkScrollWithBoxes only checks 4 points, it may not pick up a
- // sub-100 pixel horizontal shift. so we check another point manually to make sure.
- int[] color = getBoxColorAt(0, 100);
- mAsserter.ispixel(painted.getPixelAt(99, 0), color[0], color[1], color[2], "Pixel at 99, 0 indicates no horizontal scroll");
-
- // now drag at a 45-degree angle to ensure we break the axis lock, and
- // verify that we have both horizontal and vertical scrolling
- paintExpecter = mActions.expectPaint();
- meh.dragSync(150, 150, 50, 50);
- } finally {
- painted.close();
- }
-
- painted = waitForPaint(paintExpecter);
- paintExpecter.unregisterListener();
- try {
- checkScrollWithBoxes(painted, 100, 200);
- } finally {
- painted.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBackButtonInEditMode.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBackButtonInEditMode.java
deleted file mode 100644
index b391f7920..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBackButtonInEditMode.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-
-import android.view.View;
-
-/**
- * Tests that verify the behavior of back button in edit mode.
- */
-public class testBackButtonInEditMode extends UITest {
- public void testBackButtonInEditMode() {
- GeckoHelper.blockForReady();
-
- // Verify back button behavior for edit mode.
- mToolbar.enterEditingMode()
- .assertIsUrlEditTextSelected();
- checkBackPressInEditMode();
- checkExitUsingBackButton();
-
- // Verify back button behavior in edit mode after input.
- mToolbar.enterEditingMode()
- .enterUrl("dummy")
- .assertIsUrlEditTextSelected();
- checkBackPressInEditMode();
- checkExitUsingBackButton();
-
- // Verify the swipe behavior in edit mode.
- mToolbar.enterEditingMode()
- .assertIsUrlEditTextSelected();
- mAboutHome.swipeToPanelOnLeft();
- mToolbar.assertIsUrlEditTextNotSelected()
- .assertIsEditing();
- checkExitUsingBackButton();
- }
-
- private void checkBackPressInEditMode() {
- // Press back button and verify URLEditText is not selected.
- getSolo().goBack();
- mToolbar.assertIsUrlEditTextNotSelected()
- .assertIsEditing();
- }
-
- private void checkExitUsingBackButton() {
- getSolo().goBack();
- mToolbar.assertIsNotEditing();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmark.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmark.java
deleted file mode 100644
index 041b76e2f..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmark.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import com.robotium.solo.Condition;
-
-public class testBookmark extends AboutHomeTest {
- private static String BOOKMARK_URL;
- private static final int WAIT_FOR_BOOKMARKED_TIMEOUT = 10000;
-
- public void testBookmark() {
- BOOKMARK_URL = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- runAboutHomeTest();
- runMenuTest();
- }
-
- public void runMenuTest() {
- mAsserter.is(mDatabaseHelper.isBookmark(BOOKMARK_URL), false, "Page is not bookmarked initially");
- setUpBookmark(); // loads the page, taps the star button, and waits for the "Bookmark Added" message
- waitForBookmarked(true);
-
- cleanUpBookmark(); // loads the page, taps the star button, and waits for the "Bookmark Removed" message
- waitForBookmarked(false);
- }
-
- public void runAboutHomeTest() {
- blockForGeckoReady();
- for (String url : mStringHelper.DEFAULT_BOOKMARKS_URLS) {
- mAsserter.ok(mDatabaseHelper.isBookmark(url), "Checking that " + url + " is bookmarked by default", url + " is bookmarked");
- }
-
- mDatabaseHelper.addMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, BOOKMARK_URL);
- waitForBookmarked(true);
-
- isBookmarkDisplayed(BOOKMARK_URL);
- loadBookmark(BOOKMARK_URL);
- verifyUrlBarTitle(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
-
- mDatabaseHelper.deleteBookmark(BOOKMARK_URL);
- waitForBookmarked(false);
- }
-
- private void waitForBookmarked(final boolean isBookmarked) {
- boolean bookmarked = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return (isBookmarked) ?
- mDatabaseHelper.isBookmark(BOOKMARK_URL) :
- !mDatabaseHelper.isBookmark(BOOKMARK_URL);
- }
- }, WAIT_FOR_BOOKMARKED_TIMEOUT);
- mAsserter.is(bookmarked, true, BOOKMARK_URL + " was " + (isBookmarked ? "added as a bookmark" : "removed from bookmarks"));
- }
-
- private void setUpBookmark() {
- // Bookmark a page for the test
- loadUrl(BOOKMARK_URL);
- waitForText(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
- toggleBookmark();
- mAsserter.is(waitForText(mStringHelper.BOOKMARK_ADDED_LABEL), true, "bookmark added successfully");
- }
-
- private void cleanUpBookmark() {
- // Go back to the page we bookmarked
- loadUrl(BOOKMARK_URL);
- waitForText(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
- toggleBookmark();
- mAsserter.is(waitForText(mStringHelper.BOOKMARK_REMOVED_LABEL), true, "bookmark removed successfully");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarkFolders.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarkFolders.java
deleted file mode 100644
index 6205337ea..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarkFolders.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.home.HomePager;
-import org.mozilla.gecko.sync.Utils;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.net.Uri;
-import android.view.View;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.robotium.solo.Condition;
-
-public class testBookmarkFolders extends AboutHomeTest {
- private static String DESKTOP_BOOKMARK_URL;
-
- public void testBookmarkFolders() {
- DESKTOP_BOOKMARK_URL = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL);
-
- setUpDesktopBookmarks();
- checkBookmarkList();
- }
-
- private void checkBookmarkList() {
- openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
- waitForText(mStringHelper.DESKTOP_FOLDER_LABEL);
- clickOnBookmarkFolder(mStringHelper.DESKTOP_FOLDER_LABEL);
- waitForText(mStringHelper.TOOLBAR_FOLDER_LABEL);
-
- // Verify the number of folders displayed in the Desktop Bookmarks folder is correct
- ListView desktopFolderContent = findListViewWithTag(HomePager.LIST_TAG_BOOKMARKS);
- ListAdapter adapter = desktopFolderContent.getAdapter();
-
- // Three folders and "Up to Bookmarks".
- mAsserter.is(adapter.getCount(), 4, "Checking that the correct number of folders is displayed in the Desktop Bookmarks folder");
-
- clickOnBookmarkFolder(mStringHelper.TOOLBAR_FOLDER_LABEL);
-
- // Go up in the bookmark folder hierarchy
- clickOnBookmarkFolder(String.format(mStringHelper.BOOKMARKS_UP_TO, mStringHelper.DESKTOP_FOLDER_LABEL));
- mAsserter.ok(waitForText(mStringHelper.BOOKMARKS_MENU_FOLDER_LABEL), "Going up in the folder hierarchy", "We are back in the Desktop Bookmarks folder");
-
- clickOnBookmarkFolder(String.format(mStringHelper.BOOKMARKS_UP_TO, mStringHelper.BOOKMARKS_ROOT_LABEL));
- mAsserter.ok(waitForText(mStringHelper.DESKTOP_FOLDER_LABEL), "Going up in the folder hierarchy", "We are back in the main Bookmarks List View");
-
- clickOnBookmarkFolder(mStringHelper.DESKTOP_FOLDER_LABEL);
- clickOnBookmarkFolder(mStringHelper.TOOLBAR_FOLDER_LABEL);
- isBookmarkDisplayed(DESKTOP_BOOKMARK_URL);
-
- // Open the bookmark from a bookmark folder hierarchy
- loadBookmark(DESKTOP_BOOKMARK_URL);
- verifyUrlBarTitle(DESKTOP_BOOKMARK_URL);
- openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
-
- // Check that folders don't have a context menu
- boolean success = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- View desktopFolder = getBookmarkFolderView(mStringHelper.DESKTOP_FOLDER_LABEL);
- if (desktopFolder == null) {
- return false;
- }
- mSolo.clickLongOnView(desktopFolder);
- return true; }
- }, MAX_WAIT_MS);
-
- mAsserter.ok(success, "Trying to long click on the Desktop Bookmarks","Desktop Bookmarks folder could not be long clicked");
-
- final String contextMenuString = mStringHelper.BOOKMARK_CONTEXT_MENU_ITEMS[0];
- mAsserter.ok(!waitForText(contextMenuString), "Folders do not have context menus", "The context menu was not opened");
-
- // Even if no context menu is opened long clicking a folder still opens it. We need to close it.
- clickOnBookmarkFolder(String.format(mStringHelper.BOOKMARKS_UP_TO, mStringHelper.BOOKMARKS_ROOT_LABEL));
- }
-
- private void clickOnBookmarkFolder(final String folderName) {
- boolean success = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- View bookmarksFolder = getBookmarkFolderView(folderName);
- if (bookmarksFolder == null) {
- return false;
- }
- mSolo.waitForView(bookmarksFolder);
- mSolo.clickOnView(bookmarksFolder);
- return true;
- }
- }, MAX_WAIT_MS);
- mAsserter.ok(success, "Trying to click on the " + folderName + " folder","The " + folderName + " folder was clicked");
- }
-
- private View getBookmarkFolderView(String folderName) {
- openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
- mSolo.hideSoftKeyboard();
- getInstrumentation().waitForIdleSync();
-
- ListView bookmarksTabList = findListViewWithTag(HomePager.LIST_TAG_BOOKMARKS);
- if (!waitForNonEmptyListToLoad(bookmarksTabList)) {
- return null;
- }
-
- ListAdapter adapter = bookmarksTabList.getAdapter();
- if (adapter == null) {
- return null;
- }
-
- for (int i = 0; i < adapter.getCount(); i++ ) {
- View bookmarkView = bookmarksTabList.getChildAt(i);
- if (bookmarkView instanceof TextView) {
- TextView folderTextView = (TextView) bookmarkView;
- if (folderTextView.getText().equals(folderName)) {
- return bookmarkView;
- }
- }
- }
-
- return null;
- }
-
- // Add a bookmark in the Desktop folder so we can check the folder navigation in the bookmarks page
- private void setUpDesktopBookmarks() {
- blockForGeckoReady();
-
- // Get the folder id of the mStringHelper.DESKTOP_FOLDER_LABEL folder
- Long desktopFolderId = mDatabaseHelper.getFolderIdFromGuid("toolbar");
-
- // Generate a Guid for the bookmark
- final String generatedGuid = Utils.generateGuid();
- mAsserter.ok((generatedGuid != null), "Generating a random Guid for the bookmark", "We could not generate a Guid for the bookmark");
-
- // Insert the bookmark
- ContentResolver resolver = getActivity().getContentResolver();
- Uri bookmarksUri = mDatabaseHelper.buildUri(DatabaseHelper.BrowserDataType.BOOKMARKS);
-
- long now = System.currentTimeMillis();
- ContentValues values = new ContentValues();
- values.put("title", mStringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
- values.put("url", DESKTOP_BOOKMARK_URL);
- values.put("parent", desktopFolderId);
- values.put("modified", now);
- values.put("type", 1);
- values.put("guid", generatedGuid);
- values.put("position", 10);
- values.put("created", now);
-
- int updated = resolver.update(bookmarksUri,
- values,
- "url = ?",
- new String[] { DESKTOP_BOOKMARK_URL });
- if (updated == 0) {
- Uri uri = resolver.insert(bookmarksUri, values);
- mAsserter.ok(true, "Inserted at: ", uri.toString());
- } else {
- mAsserter.ok(false, "Failed to insert the Desktop bookmark", "Something went wrong");
- }
- }
-
- @Override
- public void tearDown() throws Exception {
- mDatabaseHelper.deleteBookmark(DESKTOP_BOOKMARK_URL);
- super.tearDown();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarkKeyword.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarkKeyword.java
deleted file mode 100644
index 363954bfa..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarkKeyword.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-
-public class testBookmarkKeyword extends AboutHomeTest {
- public void testBookmarkKeyword() {
- blockForGeckoReady();
-
- final String url = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- final String keyword = "testkeyword";
-
- // Add a bookmark, and update it to have a keyword.
- mDatabaseHelper.addMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, url);
- mDatabaseHelper.updateBookmark(url, mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, keyword);
-
- // Enter the keyword in the urlbar.
- inputAndLoadUrl(keyword);
-
- // Make sure the title of the page appeared.
- verifyUrlBarTitle(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
-
- // Delete the bookmark to clean up.
- mDatabaseHelper.deleteBookmark(url);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarklets.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarklets.java
deleted file mode 100644
index 4ae57104c..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarklets.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-
-import com.robotium.solo.Condition;
-
-
-public class testBookmarklets extends BaseTest {
- public void testBookmarklets() {
- final String url = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- final String title = "alertBookmarklet";
- final String js = "javascript:alert(12 + 10)";
- final String expected = "22";
- boolean alerted;
-
- blockForGeckoReady();
-
- // Load a standard page so bookmarklets work
- loadUrlAndWait(url);
-
- // Verify that user-entered bookmarklets do *not* work
- enterUrl(js);
- mActions.sendSpecialKey(Actions.SpecialKey.ENTER);
- alerted = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return mSolo.searchButton("OK", true) || mSolo.searchText(expected, true);
- }
- }, 3000);
- mAsserter.is(alerted, false, "Alert was not shown for user-entered bookmarklet");
-
- // Verify that non-user-entered bookmarklets do work
- loadUrl(js);
- alerted = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return mSolo.searchButton("OK", true) && mSolo.searchText(expected, true);
- }
- }, 10000);
- mAsserter.is(alerted, true, "Alert was shown for bookmarklet");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarksPanel.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarksPanel.java
deleted file mode 100644
index a7e9505da..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBookmarksPanel.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Element;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.util.StringUtils;
-
-public class testBookmarksPanel extends AboutHomeTest {
- public void testBookmarksPanel() {
- final String BOOKMARK_URL = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- JSONObject data = null;
-
- // Make sure our default bookmarks are loaded.
- // Technically this will race with the check below.
- initializeProfile();
-
- // Add a mobile bookmark.
- mDatabaseHelper.addMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, BOOKMARK_URL);
-
- openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
-
- // Check that the default bookmarks are displayed.
- // We need to wait for the distribution to have been processed
- // before this will succeed.
- for (String url : mStringHelper.DEFAULT_BOOKMARKS_URLS) {
- isBookmarkDisplayed(url);
- }
-
- assertAllContextMenuOptionsArePresent(mStringHelper.DEFAULT_BOOKMARKS_URLS[1],
- mStringHelper.DEFAULT_BOOKMARKS_URLS[0]);
-
- openBookmarkContextMenu(mStringHelper.DEFAULT_BOOKMARKS_URLS[0]);
-
- // Test that "Open in New Tab" works
- final Element tabCount = mDriver.findElement(getActivity(), R.id.tabs_counter);
- final int tabCountInt = Integer.parseInt(tabCount.getText());
- Actions.EventExpecter tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
- mSolo.clickOnText(mStringHelper.BOOKMARK_CONTEXT_MENU_ITEMS[0]);
- try {
- data = new JSONObject(tabEventExpecter.blockForEventData());
- } catch (JSONException e) {
- mAsserter.ok(false, "exception getting event data", e.toString());
- }
- tabEventExpecter.unregisterListener();
- mAsserter.ok(mSolo.searchText(mStringHelper.TITLE_PLACE_HOLDER), "Checking that the tab is not changed", "The tab was not changed");
- // extra check here on the Tab:Added message to be sure the right tab opened
- int tabID = 0;
- try {
- mAsserter.is(mStringHelper.ABOUT_FIREFOX_URL, data.getString("uri"), "Checking tab uri");
- tabID = data.getInt("tabID");
- } catch (JSONException e) {
- mAsserter.ok(false, "exception accessing event data", e.toString());
- }
- // close tab so about:firefox can be selected again
- closeTab(tabID);
-
- // Test that "Open in Private Tab" works
- openBookmarkContextMenu(mStringHelper.DEFAULT_BOOKMARKS_URLS[0]);
- tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
- mSolo.clickOnText(mStringHelper.BOOKMARK_CONTEXT_MENU_ITEMS[1]);
- try {
- data = new JSONObject(tabEventExpecter.blockForEventData());
- } catch (JSONException e) {
- mAsserter.ok(false, "exception getting event data", e.toString());
- }
- tabEventExpecter.unregisterListener();
- mAsserter.ok(mSolo.searchText(mStringHelper.TITLE_PLACE_HOLDER), "Checking that the tab is not changed", "The tab was not changed");
- // extra check here on the Tab:Added message to be sure the right tab opened, again
- try {
- mAsserter.is(mStringHelper.ABOUT_FIREFOX_URL, data.getString("uri"), "Checking tab uri");
- } catch (JSONException e) {
- mAsserter.ok(false, "exception accessing event data", e.toString());
- }
-
- // Test that "Edit" works
- String[] editedBookmarkValues = new String[] { "New bookmark title", "www.NewBookmark.url", "newBookmarkKeyword" };
- editBookmark(BOOKMARK_URL, editedBookmarkValues);
- checkBookmarkEdit(editedBookmarkValues[1], editedBookmarkValues);
-
- // Test that "Remove" works
- openBookmarkContextMenu(editedBookmarkValues[1]);
- mSolo.clickOnText(mStringHelper.BOOKMARK_CONTEXT_MENU_ITEMS[5]);
- waitForText(mStringHelper.BOOKMARK_REMOVED_LABEL);
- mAsserter.ok(!mDatabaseHelper.isBookmark(editedBookmarkValues[1]), "Checking that the bookmark was removed", "The bookmark was removed");
- }
-
- /**
- * Asserts that all context menu items are present on the given links. For one link,
- * the context menu is expected to not have the "Share" context menu item.
- *
- * @param shareableURL A URL that is expected to have the "Share" context menu item
- * @param nonShareableURL A URL that is expected not to have the "Share" context menu item.
- */
- private void assertAllContextMenuOptionsArePresent(final String shareableURL,
- final String nonShareableURL) {
- mAsserter.ok(StringUtils.isShareableUrl(shareableURL), "Ensuring url is shareable", "");
- mAsserter.ok(!StringUtils.isShareableUrl(nonShareableURL), "Ensuring url is not shareable", "");
-
- openBookmarkContextMenu(shareableURL);
- for (String contextMenuOption : mStringHelper.BOOKMARK_CONTEXT_MENU_ITEMS) {
- mAsserter.ok(mSolo.searchText(contextMenuOption),
- "Checking that the context menu option is present",
- contextMenuOption + " is present");
- }
-
- // Close the menu.
- mSolo.goBack();
-
- openBookmarkContextMenu(nonShareableURL);
- for (String contextMenuOption : mStringHelper.BOOKMARK_CONTEXT_MENU_ITEMS) {
- // This link is not shareable: skip the "Share" option.
- if ("Share".equals(contextMenuOption)) {
- continue;
- }
-
- mAsserter.ok(mSolo.searchText(contextMenuOption),
- "Checking that the context menu option is present",
- contextMenuOption + " is present");
- }
-
- // The use of Solo.searchText is potentially fragile as It will only
- // scroll the most recently drawn view. Works fine for now though.
- mAsserter.ok(!mSolo.searchText("Share"),
- "Checking that the Share option is not present",
- "Share option is not present");
-
- // Close the menu.
- mSolo.goBack();
- }
-
- /**
- * @param bookmarkUrl URL of the bookmark to edit
- * @param values String array with the new values for all fields
- */
- private void editBookmark(String bookmarkUrl, String[] values) {
- openBookmarkContextMenu(bookmarkUrl);
- mSolo.clickOnText(mStringHelper.CONTEXT_MENU_EDIT);
- waitForText(mStringHelper.EDIT_BOOKMARK);
-
- // Update the fields with the new values
- for (int i = 0; i < values.length; i++) {
- mSolo.clearEditText(i);
- mSolo.clickOnEditText(i);
- mActions.sendKeys(values[i]);
- }
-
- mSolo.clickOnButton(mStringHelper.OK);
- waitForText(mStringHelper.BOOKMARK_UPDATED_LABEL);
- }
-
- /**
- * @param bookmarkUrl String with the original url
- * @param values String array with the new values for all fields
- */
- private void checkBookmarkEdit(String bookmarkUrl, String[] values) {
- openBookmarkContextMenu(bookmarkUrl);
- mSolo.clickOnText(mStringHelper.CONTEXT_MENU_EDIT);
- waitForText(mStringHelper.EDIT_BOOKMARK);
-
- // Check the values of the fields
- for (String value : values) {
- mAsserter.ok(mSolo.searchText(value), "Checking that the value is correct", "The value = " + value + " is correct");
- }
-
- mSolo.clickOnButton("Cancel");
- waitForText(mStringHelper.BOOKMARKS_LABEL);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserDatabaseHelperUpgrades.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserDatabaseHelperUpgrades.java
deleted file mode 100644
index eec5c4b33..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserDatabaseHelperUpgrades.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.*;
-
-import android.database.sqlite.SQLiteDatabase;
-import android.util.Log;
-
-import org.mozilla.gecko.db.BrowserDatabaseHelper;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-
-// TODO: Move to junit 3 tests, once those run in automation. There is no ui testing to do so it's a better fit.
-/**
- * This test runs upgrades for the databases in (robocop-assets)/browser_db_upgrade. Currently,
- * (robocop-assets)=mobile/android/tests/browser/robocop/assets/.
- *
- * It copies the old database from the robocop assets directory into a temporary file and opens a SQLiteHelper
- * on the database to verify it gets upgraded to the correct version. If there is an issue with the upgrade,
- * generally a SQLiteException will be thrown and the test will fail. For example:
- * android.database.sqlite.SQLiteException: duplicate column name: calculated_pages_times_rating (code 1): , while compiling: ALTER TABLE book_information ADD COLUMN calculated_pages_times_rating INTEGER;
- *
- * Alternative upgrade tests:
- * * Robolectric 2.3+ uses a real SQLite database implementation so we could run our upgrades there. However, the
- * SQLite implementation may not be the same as we run on Android. Benefits: speed & we don't need the application to
- * run (and thus a valid DB of the latest version) to run these tests.
- * * We could copy the current database creation code into a new test, create the database, and then try to upgrade
- * it. However, the tables are empty and thus not a realistic migration plan (e.g. foreign key constraints).
- *
- * TO EDIT THIS TEST:
- * * Copy the current version of the database into (robocop-assets)/browser_db_upgrade/v##.db database. You can do
- * this via Margaret's copy profile addon - take browser.db from the profile directory. This db copy should contain a
- * used profile - e.g. history items, bookmarks. A good way to get a used profile is to sign into sync.
- * * MAKE SURE YOU COPY YOUR DB FIRST. Then make your changes to the DB schema code.
- * * Test!
- * * Note: when the application starts for testing, it may need to upgrade the database from your existing version. If
- * this fails, the application will crash and the test may fail to start.
- *
- * IMPORTANT:
- * Test DBs must be created on the oldest version of Android that is currently supported. SQLite
- * is not forwards compatible. E.g. uploading a DB created on a 6.0 device will cause failures
- * when robocop tests running on 4.3 are unable to load it.
- *
- * Implementation inspired by:
- * http://riggaroo.co.za/automated-testing-sqlite-database-upgrades-android/
- */
-public class testBrowserDatabaseHelperUpgrades extends UITest {
- private static final int TEST_FROM_VERSION = 27; // We only started testing on this version.
-
- private ArrayList<File> temporaryDbFiles;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- // TODO: We already install & remove the profile directory each run so it'd be safer for clean-up to store
- // this there. That being said, temporary files are still stored in the application directory so these temporary
- // files will get cleaned up when the application is uninstalled or when data is cleared.
- temporaryDbFiles = new ArrayList<>();
- }
-
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
- for (final File dbFile : temporaryDbFiles) {
- dbFile.delete();
- }
- }
-
- /**
- * @throws IOException if the database cannot be copied.
- */
- public void test() throws IOException {
- for (int i = TEST_FROM_VERSION; i < BrowserDatabaseHelper.DATABASE_VERSION; ++i) {
- Log.d(LOGTAG, "Testing upgrade from version: " + i);
- final String tempDbPath = copyDatabase(i);
-
- final SQLiteDatabase db = SQLiteDatabase.openDatabase(tempDbPath, null, 0);
- try {
- fAssertEquals("Input DB isn't the expected version",
- i, db.getVersion());
- } finally {
- db.close();
- }
-
- final BrowserDatabaseHelper dbHelperToUpgrade = new BrowserDatabaseHelper(getActivity(), tempDbPath);
- // Ideally, we'd test upgrading version i to version i + 1 but this method does not permit that. Alas!
- final SQLiteDatabase upgradedDb = dbHelperToUpgrade.getWritableDatabase();
- try {
- fAssertEquals("DB helper should upgrade to latest version",
- BrowserDatabaseHelper.DATABASE_VERSION, upgradedDb.getVersion());
- } finally {
- upgradedDb.close();
- }
- }
- }
-
- /**
- * Copies the database from the assets directory to a temporary test file.
- *
- * @param version version of the database to copy.
- * @return the String path to the new copy of the database
- * @throws IOException if reading the existing database or writing the temporary database fails
- */
- private String copyDatabase(final int version) throws IOException {
- final InputStream inputStream = openDbFromAssets(version);
- try {
- final File dbDestination = File.createTempFile("temporaryDB-v" + version + "_", "db");
- temporaryDbFiles.add(dbDestination);
- Log.d(LOGTAG, "Moving DB from assets to " + dbDestination.getPath());
-
- final OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(dbDestination));
- try {
- final byte[] buffer = new byte[1024];
- int len;
- while ((len = inputStream.read(buffer)) > 0) {
- outputStream.write(buffer, 0, len);
- }
- outputStream.flush();
- } finally {
- outputStream.close();
- }
-
- return dbDestination.getPath();
- } finally {
- inputStream.close();
- }
- }
-
- private InputStream openDbFromAssets(final int version) throws IOException {
- final String dbAssetPath = String.format("browser_db_upgrade" + File.separator + String.format("v%d.db", version));
- Log.d(LOGTAG, "Opening DB from assets: " + dbAssetPath);
- try {
- return new BufferedInputStream(getInstrumentation().getContext().getAssets().open(dbAssetPath));
- } catch (final FileNotFoundException e) {
- throw new IllegalStateException("If you're upgrading the browser.db version, " +
- "you need to provide an old version of the database for this test! See the javadoc.", e);
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserDiscovery.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserDiscovery.java
deleted file mode 100644
index 2dab2996c..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserDiscovery.java
+++ /dev/null
@@ -1,13 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-
-
-public class testBrowserDiscovery extends JavascriptTest {
- public testBrowserDiscovery() {
- super("testBrowserDiscovery.js");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java
deleted file mode 100644
index e0ebb5c8e..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java
+++ /dev/null
@@ -1,1921 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserContract.UrlAnnotations.SyncStatus;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.URLMetadata;
-import org.mozilla.gecko.db.URLMetadataTable;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.OperationApplicationException;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Build;
-import android.util.Log;
-
-/*
- * This test is meant to exercise all operations exposed by Fennec's
- * history and bookmarks content provider. It does so in an isolated
- * environment (see ContentProviderTest) without affecting any UI-related
- * code.
- */
-public class testBrowserProvider extends ContentProviderTest {
- private long mMobileFolderId;
-
- private void loadMobileFolderId() throws Exception {
- Cursor c = null;
- try {
- c = getBookmarkByGuid(BrowserContract.Bookmarks.MOBILE_FOLDER_GUID);
- mAsserter.is(c.moveToFirst(), true, "Mobile bookmarks folder is present");
-
- mMobileFolderId = c.getLong(c.getColumnIndex(BrowserContract.Bookmarks._ID));
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
-
- private void ensureEmptyDatabase() throws Exception {
- Cursor c;
-
- String guid = BrowserContract.Bookmarks.GUID;
-
- mProvider.delete(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"),
- guid + " != ? AND " +
- guid + " != ? AND " +
- guid + " != ? AND " +
- guid + " != ? AND " +
- guid + " != ? AND " +
- guid + " != ?",
- new String[] { BrowserContract.Bookmarks.PLACES_FOLDER_GUID,
- BrowserContract.Bookmarks.MOBILE_FOLDER_GUID,
- BrowserContract.Bookmarks.MENU_FOLDER_GUID,
- BrowserContract.Bookmarks.TAGS_FOLDER_GUID,
- BrowserContract.Bookmarks.TOOLBAR_FOLDER_GUID,
- BrowserContract.Bookmarks.UNFILED_FOLDER_GUID });
-
- c = mProvider.query(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), null, null, null, null);
- assertCountIsAndClose(c, 6, "All non-special bookmarks and folders were deleted");
-
- mProvider.delete(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"), null, null);
- c = mProvider.query(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), null, null, null, null);
- assertCountIsAndClose(c, 0, "All history entries were deleted");
-
- /**
- * There's no reason why the following two parts should fail.
- * But sometimes they do, and I'm not going to spend the time
- * to figure out why in an unrelated bug.
- */
-
- mProvider.delete(appendUriParam(BrowserContract.Favicons.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"), null, null);
- c = mProvider.query(appendUriParam(BrowserContract.Favicons.CONTENT_URI,
- BrowserContract.PARAM_SHOW_DELETED, "1"),
- null, null, null, null);
-
- if (c.getCount() > 0) {
- mAsserter.dumpLog("Unexpected favicons in ensureEmptyDatabase.");
- }
- c.close();
-
- mAsserter.dumpLog("ensureEmptyDatabase: Favicon deletion completed."); // Bug 968951 debug.
- // assertCountIsAndClose(c, 0, "All favicons were deleted");
-
- mProvider.delete(appendUriParam(BrowserContract.Thumbnails.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"), null, null);
- c = mProvider.query(appendUriParam(BrowserContract.Thumbnails.CONTENT_URI,
- BrowserContract.PARAM_SHOW_DELETED, "1"),
- null, null, null, null);
-
- if (c.getCount() > 0) {
- mAsserter.dumpLog("Unexpected thumbnails in ensureEmptyDatabase.");
- }
- c.close();
-
- mAsserter.dumpLog("ensureEmptyDatabase: Thumbnail deletion completed."); // Bug 968951 debug.
- // assertCountIsAndClose(c, 0, "All thumbnails were deleted");
- }
-
- private ContentValues createBookmark(String title, String url, long parentId,
- int type, int position, String tags, String description, String keyword) throws Exception {
- ContentValues bookmark = new ContentValues();
-
- bookmark.put(BrowserContract.Bookmarks.TITLE, title);
- bookmark.put(BrowserContract.Bookmarks.URL, url);
- bookmark.put(BrowserContract.Bookmarks.PARENT, parentId);
- bookmark.put(BrowserContract.Bookmarks.TYPE, type);
- bookmark.put(BrowserContract.Bookmarks.POSITION, position);
- bookmark.put(BrowserContract.Bookmarks.TAGS, tags);
- bookmark.put(BrowserContract.Bookmarks.DESCRIPTION, description);
- bookmark.put(BrowserContract.Bookmarks.KEYWORD, keyword);
-
- return bookmark;
- }
-
- private ContentValues createOneBookmark() throws Exception {
- return createBookmark("Example", "http://example.com", mMobileFolderId,
- BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
- }
-
- private Cursor getBookmarksByParent(long parent) throws Exception {
- // Order by position.
- return mProvider.query(BrowserContract.Bookmarks.CONTENT_URI, null,
- BrowserContract.Bookmarks.PARENT + " = ?",
- new String[] { String.valueOf(parent) },
- BrowserContract.Bookmarks.POSITION);
- }
-
- private Cursor getBookmarkByGuid(String guid) throws Exception {
- return mProvider.query(BrowserContract.Bookmarks.CONTENT_URI, null,
- BrowserContract.Bookmarks.GUID + " = ?",
- new String[] { guid },
- null);
- }
-
- private Cursor getBookmarkById(long id) throws Exception {
- return getBookmarkById(BrowserContract.Bookmarks.CONTENT_URI, id, null);
- }
-
- private Cursor getBookmarkById(long id, String[] projection) throws Exception {
- return getBookmarkById(BrowserContract.Bookmarks.CONTENT_URI, id, projection);
- }
-
- private Cursor getBookmarkById(Uri bookmarksUri, long id) throws Exception {
- return getBookmarkById(bookmarksUri, id, null);
- }
-
- private Cursor getBookmarkById(Uri bookmarksUri, long id, String[] projection) throws Exception {
- return mProvider.query(bookmarksUri, projection,
- BrowserContract.Bookmarks._ID + " = ?",
- new String[] { String.valueOf(id) },
- null);
- }
-
- private ContentValues createHistoryEntry(String title, String url, int visits, long lastVisited) throws Exception {
- ContentValues historyEntry = new ContentValues();
-
- historyEntry.put(BrowserContract.History.TITLE, title);
- historyEntry.put(BrowserContract.History.URL, url);
- historyEntry.put(BrowserContract.History.VISITS, visits);
- historyEntry.put(BrowserContract.History.DATE_LAST_VISITED, lastVisited);
-
- return historyEntry;
- }
-
- private ContentValues createFaviconEntry(String pageUrl, String data) throws Exception {
- ContentValues faviconEntry = new ContentValues();
-
- faviconEntry.put(BrowserContract.Favicons.PAGE_URL, pageUrl);
- faviconEntry.put(BrowserContract.Favicons.URL, pageUrl + "/favicon.ico");
- faviconEntry.put(BrowserContract.Favicons.DATA, data.getBytes("UTF8"));
-
- return faviconEntry;
- }
-
- private ContentValues createThumbnailEntry(String pageUrl, String data) throws Exception {
- ContentValues thumbnailEntry = new ContentValues();
-
- thumbnailEntry.put(BrowserContract.Thumbnails.URL, pageUrl);
- thumbnailEntry.put(BrowserContract.Thumbnails.DATA, data.getBytes("UTF8"));
-
- return thumbnailEntry;
- }
-
- private ContentValues createUrlMetadataEntry(final String url, final String tileImage, final String tileColor,
- final String touchIcon) {
- final ContentValues values = new ContentValues();
- values.put(URLMetadataTable.URL_COLUMN, url);
- values.put(URLMetadataTable.TILE_IMAGE_URL_COLUMN, tileImage);
- values.put(URLMetadataTable.TILE_COLOR_COLUMN, tileColor);
- values.put(URLMetadataTable.TOUCH_ICON_COLUMN, touchIcon);
- return values;
- }
-
- private ContentValues createUrlAnnotationEntry(final String url, final String key, final String value,
- final long dateCreated) {
- final ContentValues values = new ContentValues();
- values.put(BrowserContract.UrlAnnotations.URL, url);
- values.put(BrowserContract.UrlAnnotations.KEY, key);
- values.put(BrowserContract.UrlAnnotations.VALUE, value);
- values.put(BrowserContract.UrlAnnotations.DATE_CREATED, dateCreated);
- values.put(BrowserContract.UrlAnnotations.DATE_MODIFIED, dateCreated);
- return values;
- }
-
- private ContentValues createOneHistoryEntry() throws Exception {
- return createHistoryEntry("Example", "http://example.com", 10, System.currentTimeMillis());
- }
-
- private Cursor getHistoryEntryById(long id) throws Exception {
- return getHistoryEntryById(BrowserContract.History.CONTENT_URI, id, null);
- }
-
- private Cursor getHistoryEntryById(long id, String[] projection) throws Exception {
- return getHistoryEntryById(BrowserContract.History.CONTENT_URI, id, projection);
- }
-
- private Cursor getHistoryEntryById(Uri historyUri, long id) throws Exception {
- return getHistoryEntryById(historyUri, id, null);
- }
-
- private Cursor getHistoryEntryById(Uri historyUri, long id, String[] projection) throws Exception {
- return mProvider.query(historyUri, projection,
- BrowserContract.History._ID + " = ?",
- new String[] { String.valueOf(id) },
- null);
- }
-
- private Cursor getFaviconsByUrl(String url) throws Exception {
- return mProvider.query(BrowserContract.Combined.CONTENT_URI, null,
- BrowserContract.Combined.URL + " = ?",
- new String[] { url },
- null);
- }
-
- private Cursor getThumbnailByUrl(String url) throws Exception {
- return mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null,
- BrowserContract.Thumbnails.URL + " = ?",
- new String[] { url },
- null);
- }
-
- private Cursor getUrlAnnotationByUrl(final String url) throws Exception {
- return mProvider.query(BrowserContract.UrlAnnotations.CONTENT_URI, null,
- BrowserContract.UrlAnnotations.URL + " = ?",
- new String[] { url },
- null);
- }
-
- private Cursor getUrlMetadataByUrl(final String url) throws Exception {
- return mProvider.query(URLMetadataTable.CONTENT_URI, null,
- URLMetadataTable.URL_COLUMN + " = ?",
- new String[] { url },
- null);
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp(sBrowserProviderCallable, BrowserContract.AUTHORITY, "browser.db");
-
- mTests.add(new TestSpecialFolders());
-
- mTests.add(new TestInsertBookmarks());
- mTests.add(new TestInsertBookmarksFavicons());
- mTests.add(new TestDeleteBookmarks());
- mTests.add(new TestDeleteBookmarksFavicons());
- mTests.add(new TestUpdateBookmarks());
- mTests.add(new TestUpdateBookmarksFavicons());
- mTests.add(new TestPositionBookmarks());
-
- mTests.add(new TestInsertHistory());
- mTests.add(new TestInsertHistoryFavicons());
- mTests.add(new TestDeleteHistory());
- mTests.add(new TestDeleteHistoryFavicons());
- mTests.add(new TestUpdateHistory());
- mTests.add(new TestUpdateHistoryFavicons());
- mTests.add(new TestUpdateOrInsertHistory());
- mTests.add(new TestInsertHistoryThumbnails());
- mTests.add(new TestUpdateHistoryThumbnails());
- mTests.add(new TestDeleteHistoryThumbnails());
-
- mTests.add(new TestInsertUrlAnnotations());
- mTests.add(new TestInsertUrlMetadata());
-
- mTests.add(new TestBatchOperations());
-
- mTests.add(new TestCombinedView());
- mTests.add(new TestCombinedViewDisplay());
- mTests.add(new TestCombinedViewWithDeletedBookmark());
-
- mTests.add(new TestBrowserProviderNotifications());
- }
-
- public void testBrowserProvider() throws Exception {
- loadMobileFolderId();
-
- for (int i = 0; i < mTests.size(); i++) {
- Runnable test = mTests.get(i);
-
- final String testName = test.getClass().getSimpleName();
- setTestName(testName);
- ensureEmptyDatabase();
- mAsserter.dumpLog("testBrowserProvider: Database empty - Starting " + testName + ".");
- test.run();
- }
- }
-
- private class TestBatchOperations extends TestCase {
- static final int TESTCOUNT = 100;
-
- public void testApplyBatch() throws Exception {
- ArrayList<ContentProviderOperation> mOperations
- = new ArrayList<ContentProviderOperation>();
-
- // Test a bunch of inserts with applyBatch
- ContentValues values = new ContentValues();
- ContentProviderOperation.Builder builder = null;
-
- for (int i = 0; i < TESTCOUNT; i++) {
- values.clear();
- values.put(BrowserContract.History.VISITS, i);
- values.put(BrowserContract.History.TITLE, "Test" + i);
- values.put(BrowserContract.History.URL, "http://www.test.org/" + i);
-
- // Insert
- builder = ContentProviderOperation.newInsert(BrowserContract.History.CONTENT_URI);
- builder.withValues(values);
- // Queue the operation
- mOperations.add(builder.build());
- }
-
- ContentProviderResult[] applyResult =
- mProvider.applyBatch(mOperations);
-
- boolean allFound = true;
- for (int i = 0; i < TESTCOUNT; i++) {
- Cursor cursor = mProvider.query(BrowserContract.History.CONTENT_URI,
- null,
- BrowserContract.History.URL + " = ?",
- new String[] { "http://www.test.org/" + i },
- null);
-
- if (!cursor.moveToFirst())
- allFound = false;
- cursor.close();
- }
- mAsserter.is(allFound, true, "Found all batchApply entries");
- mOperations.clear();
-
- // Update all visits to 1
- values.clear();
- values.put(BrowserContract.History.VISITS, 1);
- for (int i = 0; i < TESTCOUNT; i++) {
- builder = ContentProviderOperation.newUpdate(BrowserContract.History.CONTENT_URI);
- builder.withSelection(BrowserContract.History.URL + " = ?",
- new String[] {"http://www.test.org/" + i});
- builder.withValues(values);
- builder.withExpectedCount(1);
- // Queue the operation
- mOperations.add(builder.build());
- }
-
- boolean seenException = false;
- try {
- applyResult = mProvider.applyBatch(mOperations);
- } catch (OperationApplicationException ex) {
- seenException = true;
- }
- mAsserter.is(seenException, false, "Batch updating succeeded");
- mOperations.clear();
-
- // Delete all visits
- for (int i = 0; i < TESTCOUNT; i++) {
- builder = ContentProviderOperation.newDelete(BrowserContract.History.CONTENT_URI);
- builder.withSelection(BrowserContract.History.URL + " = ?",
- new String[] {"http://www.test.org/" + i});
- builder.withExpectedCount(1);
- // Queue the operation
- mOperations.add(builder.build());
- }
- try {
- applyResult = mProvider.applyBatch(mOperations);
- } catch (OperationApplicationException ex) {
- seenException = true;
- }
- mAsserter.is(seenException, false, "Batch deletion succeeded");
- }
-
- // Force a Constraint error, see if later operations still apply correctly
- public void testApplyBatchErrors() throws Exception {
- ArrayList<ContentProviderOperation> mOperations
- = new ArrayList<ContentProviderOperation>();
-
- // Test a bunch of inserts with applyBatch
- ContentProviderOperation.Builder builder = null;
- ContentValues values = createFaviconEntry("http://www.test.org", "FAVICON");
- builder = ContentProviderOperation.newInsert(BrowserContract.Favicons.CONTENT_URI);
- builder.withValues(values);
- mOperations.add(builder.build());
-
- // Make a duplicate, this will fail because of a UNIQUE constraint
- builder = ContentProviderOperation.newInsert(BrowserContract.Favicons.CONTENT_URI);
- builder.withValues(values);
- mOperations.add(builder.build());
-
- // This is valid and should be in the table afterwards
- values.put(BrowserContract.Favicons.URL, "http://www.test.org/valid.ico");
- builder = ContentProviderOperation.newInsert(BrowserContract.Favicons.CONTENT_URI);
- builder.withValues(values);
- mOperations.add(builder.build());
-
- boolean seenException = false;
-
- try {
- ContentProviderResult[] applyResult =
- mProvider.applyBatch(mOperations);
- } catch (OperationApplicationException ex) {
- seenException = true;
- }
-
- // This test may need to go away if Bug 717428 is fixed.
- mAsserter.is(seenException, true, "Expected failure in favicons table");
-
- boolean allFound = true;
- Cursor cursor = mProvider.query(BrowserContract.Favicons.CONTENT_URI,
- null,
- BrowserContract.Favicons.URL + " = ?",
- new String[] { "http://www.test.org/valid.ico" },
- null);
-
- if (!cursor.moveToFirst())
- allFound = false;
- cursor.close();
-
- mAsserter.is(allFound, true, "Found all applyBatch (with error) entries");
- }
-
- public void testBulkInsert() throws Exception {
- // Test a bunch of inserts with bulkInsert
- ContentValues allVals[] = new ContentValues[TESTCOUNT];
- for (int i = 0; i < TESTCOUNT; i++) {
- allVals[i] = new ContentValues();
- allVals[i].put(BrowserContract.History.URL, i);
- allVals[i].put(BrowserContract.History.TITLE, "Test" + i);
- allVals[i].put(BrowserContract.History.URL, "http://www.test.org/" + i);
- }
-
- int inserts = mProvider.bulkInsert(BrowserContract.History.CONTENT_URI, allVals);
- mAsserter.is(inserts, TESTCOUNT, "Excepted number of inserts matches");
-
- boolean allFound = true;
- for (int i = 0; i < TESTCOUNT; i++) {
- Cursor cursor = mProvider.query(BrowserContract.History.CONTENT_URI,
- null,
- BrowserContract.History.URL + " = ?",
- new String[] { "http://www.test.org/" + i },
- null);
-
- if (!cursor.moveToFirst())
- allFound = false;
- cursor.close();
- }
- mAsserter.is(allFound, true, "Found all bulkInsert entries");
- }
-
- @Override
- public void test() throws Exception {
- testApplyBatch();
- // Clean up
- ensureEmptyDatabase();
-
- testBulkInsert();
- ensureEmptyDatabase();
-
- testApplyBatchErrors();
- }
- }
-
- private class TestSpecialFolders extends TestCase {
- @Override
- public void test() throws Exception {
- Cursor c = mProvider.query(BrowserContract.Bookmarks.CONTENT_URI,
- new String[] { BrowserContract.Bookmarks._ID,
- BrowserContract.Bookmarks.GUID,
- BrowserContract.Bookmarks.PARENT },
- BrowserContract.Bookmarks.GUID + " = ? OR " +
- BrowserContract.Bookmarks.GUID + " = ? OR " +
- BrowserContract.Bookmarks.GUID + " = ? OR " +
- BrowserContract.Bookmarks.GUID + " = ? OR " +
- BrowserContract.Bookmarks.GUID + " = ? OR " +
- BrowserContract.Bookmarks.GUID + " = ?",
- new String[] { BrowserContract.Bookmarks.PLACES_FOLDER_GUID,
- BrowserContract.Bookmarks.MOBILE_FOLDER_GUID,
- BrowserContract.Bookmarks.MENU_FOLDER_GUID,
- BrowserContract.Bookmarks.TAGS_FOLDER_GUID,
- BrowserContract.Bookmarks.TOOLBAR_FOLDER_GUID,
- BrowserContract.Bookmarks.UNFILED_FOLDER_GUID},
- null);
-
- mAsserter.is(c.getCount(), 6, "Right number of special folders");
-
- int rootId = BrowserContract.Bookmarks.FIXED_ROOT_ID;
-
- while (c.moveToNext()) {
- int id = c.getInt(c.getColumnIndex(BrowserContract.Bookmarks._ID));
- String guid = c.getString(c.getColumnIndex(BrowserContract.Bookmarks.GUID));
- int parentId = c.getInt(c.getColumnIndex(BrowserContract.Bookmarks.PARENT));
-
- if (guid.equals(BrowserContract.Bookmarks.PLACES_FOLDER_GUID)) {
- mAsserter.is(id, rootId, "The id of places folder is correct");
- }
-
- mAsserter.is(parentId, rootId,
- "The PARENT of the " + guid + " special folder is correct");
- }
-
- c.close();
- }
- }
-
- private class TestInsertBookmarks extends TestCase {
- private long insertWithNullCol(String colName) throws Exception {
- ContentValues b = createOneBookmark();
- b.putNull(colName);
- long id = -1;
-
- try {
- id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
- } catch (Exception e) {}
-
- return id;
- }
-
- @Override
- public void test() throws Exception {
- ContentValues b = createOneBookmark();
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
-
- final Cursor c = getBookmarkById(id);
- try {
- mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
-
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TITLE)), b.getAsString(BrowserContract.Bookmarks.TITLE),
- "Inserted bookmark has correct title");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.URL)), b.getAsString(BrowserContract.Bookmarks.URL),
- "Inserted bookmark has correct URL");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TAGS)), b.getAsString(BrowserContract.Bookmarks.TAGS),
- "Inserted bookmark has correct tags");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.KEYWORD)), b.getAsString(BrowserContract.Bookmarks.KEYWORD),
- "Inserted bookmark has correct keyword");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.DESCRIPTION)), b.getAsString(BrowserContract.Bookmarks.DESCRIPTION),
- "Inserted bookmark has correct description");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.POSITION)), b.getAsString(BrowserContract.Bookmarks.POSITION),
- "Inserted bookmark has correct position");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TYPE)), b.getAsString(BrowserContract.Bookmarks.TYPE),
- "Inserted bookmark has correct type");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.PARENT)), b.getAsString(BrowserContract.Bookmarks.PARENT),
- "Inserted bookmark has correct parent ID");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.IS_DELETED)), String.valueOf(0),
- "Inserted bookmark has correct is-deleted state");
-
- id = insertWithNullCol(BrowserContract.Bookmarks.POSITION);
- mAsserter.is(id, -1L,
- "Should not be able to insert bookmark with null position");
-
- id = insertWithNullCol(BrowserContract.Bookmarks.TYPE);
- mAsserter.is(id, -1L,
- "Should not be able to insert bookmark with null type");
-
- if (Build.VERSION.SDK_INT >= 8 &&
- Build.VERSION.SDK_INT < 16) {
- b = createOneBookmark();
- b.put(BrowserContract.Bookmarks.PARENT, -1);
- id = -1;
-
- try {
- id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
- } catch (Exception e) {}
-
- mAsserter.is(id, -1L,
- "Should not be able to insert bookmark with invalid parent");
- }
-
- b = createOneBookmark();
- b.remove(BrowserContract.Bookmarks.TYPE);
- id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
- final Cursor c2 = getBookmarkById(id);
- try {
- mAsserter.is(c2.moveToFirst(), true, "Inserted bookmark found");
- mAsserter.is(c2.getString(c2.getColumnIndex(BrowserContract.Bookmarks.TYPE)), String.valueOf(BrowserContract.Bookmarks.TYPE_BOOKMARK),
- "Inserted bookmark has correct default type");
- } finally {
- c2.close();
- }
- } finally {
- c.close();
- }
- }
- }
-
- private class TestInsertBookmarksFavicons extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues b = createOneBookmark();
-
- final String favicon = "FAVICON";
- final String pageUrl = b.getAsString(BrowserContract.Bookmarks.URL);
-
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
-
- // Insert the favicon into the favicons table
- mProvider.insert(BrowserContract.Favicons.CONTENT_URI, createFaviconEntry(pageUrl, favicon));
-
- Cursor c = getBookmarkById(id, new String[] { BrowserContract.Bookmarks.FAVICON });
-
- mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Bookmarks.FAVICON)), "UTF8"),
- favicon, "Inserted bookmark has corresponding favicon image");
- c.close();
-
- c = getFaviconsByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
- favicon, "Inserted favicon has corresponding favicon image");
- c.close();
- }
- }
-
- private class TestDeleteBookmarks extends TestCase {
- private long insertOneBookmark() throws Exception {
- ContentValues b = createOneBookmark();
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
-
- Cursor c = getBookmarkById(id);
- mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
- c.close();
-
- return id;
- }
-
- @Override
- public void test() throws Exception {
- long id = insertOneBookmark();
-
- int deleted = mProvider.delete(BrowserContract.Bookmarks.CONTENT_URI,
- BrowserContract.Bookmarks._ID + " = ?",
- new String[] { String.valueOf(id) });
-
- mAsserter.is((deleted == 1), true, "Inserted bookmark was deleted");
-
- Cursor c = getBookmarkById(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), id);
- mAsserter.is(c.moveToFirst(), true, "Deleted bookmark was only marked as deleted");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TITLE)), null,
- "Deleted bookmark title is null");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.URL)), null,
- "Deleted bookmark URL is null");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TAGS)), null,
- "Deleted bookmark tags is null");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.KEYWORD)), null,
- "Deleted bookmark keyword is null");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.DESCRIPTION)), null,
- "Deleted bookmark description is null");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.POSITION)), String.valueOf(0),
- "Deleted bookmark has correct position");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.PARENT)), null,
- "Deleted bookmark parent ID is null");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.IS_DELETED)), String.valueOf(1),
- "Deleted bookmark has correct is-deleted state");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.FAVICON_ID)), null,
- "Deleted bookmark Favicon ID is null");
- mAsserter.isnot(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.GUID)), null,
- "Deleted bookmark GUID is not null");
- c.close();
-
- deleted = mProvider.delete(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"),
- BrowserContract.Bookmarks._ID + " = ?",
- new String[] { String.valueOf(id) });
-
- mAsserter.is((deleted == 1), true, "Inserted bookmark was deleted");
-
- c = getBookmarkById(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), id);
- mAsserter.is(c.moveToFirst(), false, "Inserted bookmark is now actually deleted");
- c.close();
-
- id = insertOneBookmark();
-
- deleted = mProvider.delete(ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, id), null, null);
- mAsserter.is((deleted == 1), true,
- "Inserted bookmark was deleted using URI with id");
-
- c = getBookmarkById(id);
- mAsserter.is(c.moveToFirst(), false,
- "Inserted bookmark can't be found after deletion using URI with ID");
- c.close();
-
- if (Build.VERSION.SDK_INT >= 8 &&
- Build.VERSION.SDK_INT < 16) {
- ContentValues b = createBookmark("Folder", null, mMobileFolderId,
- BrowserContract.Bookmarks.TYPE_FOLDER, 0, "folderTags", "folderDescription", "folderKeyword");
-
- long parentId = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
- c = getBookmarkById(parentId);
- mAsserter.is(c.moveToFirst(), true, "Inserted bookmarks folder found");
- c.close();
-
- b = createBookmark("Example", "http://example.com", parentId,
- BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
-
- id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
- c = getBookmarkById(id);
- mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
- c.close();
-
- deleted = 0;
- try {
- Uri uri = ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, parentId);
- deleted = mProvider.delete(appendUriParam(uri, BrowserContract.PARAM_IS_SYNC, "1"), null, null);
- } catch(Exception e) {}
-
- mAsserter.is((deleted == 0), true,
- "Should not be able to delete folder that causes orphan bookmarks");
- }
- }
- }
-
- private class TestDeleteBookmarksFavicons extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues b = createOneBookmark();
-
- final String pageUrl = b.getAsString(BrowserContract.Bookmarks.URL);
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
-
- // Insert the favicon into the favicons table
- mProvider.insert(BrowserContract.Favicons.CONTENT_URI, createFaviconEntry(pageUrl, "FAVICON"));
-
- Cursor c = getFaviconsByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
- c.close();
-
- mProvider.delete(ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, id), null, null);
-
- c = getFaviconsByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), false, "Favicon is deleted with last reference to it");
- c.close();
- }
- }
-
- private class TestUpdateBookmarks extends TestCase {
- private int updateWithNullCol(long id, String colName) throws Exception {
- ContentValues u = new ContentValues();
- u.putNull(colName);
-
- int updated = 0;
-
- try {
- updated = mProvider.update(BrowserContract.Bookmarks.CONTENT_URI, u,
- BrowserContract.Bookmarks._ID + " = ?",
- new String[] { String.valueOf(id) });
- } catch (Exception e) {}
-
- return updated;
- }
-
- @Override
- public void test() throws Exception {
- ContentValues b = createOneBookmark();
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
-
- Cursor c = getBookmarkById(id);
- mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
-
- long dateCreated = c.getLong(c.getColumnIndex(BrowserContract.Bookmarks.DATE_CREATED));
- long dateModified = c.getLong(c.getColumnIndex(BrowserContract.Bookmarks.DATE_MODIFIED));
-
- ContentValues u = new ContentValues();
- u.put(BrowserContract.Bookmarks.TITLE, b.getAsString(BrowserContract.Bookmarks.TITLE) + "CHANGED");
- u.put(BrowserContract.Bookmarks.URL, b.getAsString(BrowserContract.Bookmarks.URL) + "/more/stuff");
- u.put(BrowserContract.Bookmarks.TAGS, b.getAsString(BrowserContract.Bookmarks.TAGS) + "CHANGED");
- u.put(BrowserContract.Bookmarks.DESCRIPTION, b.getAsString(BrowserContract.Bookmarks.DESCRIPTION) + "CHANGED");
- u.put(BrowserContract.Bookmarks.KEYWORD, b.getAsString(BrowserContract.Bookmarks.KEYWORD) + "CHANGED");
- u.put(BrowserContract.Bookmarks.TYPE, BrowserContract.Bookmarks.TYPE_FOLDER);
- u.put(BrowserContract.Bookmarks.POSITION, 10);
-
- int updated = mProvider.update(BrowserContract.Bookmarks.CONTENT_URI, u,
- BrowserContract.Bookmarks._ID + " = ?",
- new String[] { String.valueOf(id) });
-
- mAsserter.is((updated == 1), true, "Inserted bookmark was updated");
- c.close();
-
- c = getBookmarkById(id);
- mAsserter.is(c.moveToFirst(), true, "Updated bookmark found");
-
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TITLE)), u.getAsString(BrowserContract.Bookmarks.TITLE),
- "Inserted bookmark has correct title");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.URL)), u.getAsString(BrowserContract.Bookmarks.URL),
- "Inserted bookmark has correct URL");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TAGS)), u.getAsString(BrowserContract.Bookmarks.TAGS),
- "Inserted bookmark has correct tags");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.KEYWORD)), u.getAsString(BrowserContract.Bookmarks.KEYWORD),
- "Inserted bookmark has correct keyword");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.DESCRIPTION)), u.getAsString(BrowserContract.Bookmarks.DESCRIPTION),
- "Inserted bookmark has correct description");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.POSITION)), u.getAsString(BrowserContract.Bookmarks.POSITION),
- "Inserted bookmark has correct position");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TYPE)), u.getAsString(BrowserContract.Bookmarks.TYPE),
- "Inserted bookmark has correct type");
-
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Bookmarks.DATE_CREATED)),
- dateCreated,
- "Updated bookmark has same creation date");
-
- mAsserter.isnot(c.getLong(c.getColumnIndex(BrowserContract.Bookmarks.DATE_MODIFIED)),
- dateModified,
- "Updated bookmark has new modification date");
-
- updated = updateWithNullCol(id, BrowserContract.Bookmarks.POSITION);
- mAsserter.is((updated > 0), false,
- "Should not be able to update bookmark with null position");
-
- updated = updateWithNullCol(id, BrowserContract.Bookmarks.TYPE);
- mAsserter.is((updated > 0), false,
- "Should not be able to update bookmark with null type");
-
- u = new ContentValues();
- u.put(BrowserContract.Bookmarks.URL, "http://examples2.com");
-
- updated = mProvider.update(ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, id), u, null, null);
- c.close();
-
- c = getBookmarkById(id);
- mAsserter.is(c.moveToFirst(), true, "Updated bookmark found");
-
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.URL)), u.getAsString(BrowserContract.Bookmarks.URL),
- "Updated bookmark has correct URL using URI with id");
- c.close();
- }
- }
-
- private class TestUpdateBookmarksFavicons extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues b = createOneBookmark();
-
- final String favicon = "FAVICON";
- final String newFavicon = "NEW_FAVICON";
- final String pageUrl = b.getAsString(BrowserContract.Bookmarks.URL);
-
- mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b);
-
- // Insert the favicon into the favicons table
- ContentValues f = createFaviconEntry(pageUrl, favicon);
- long faviconId = ContentUris.parseId(mProvider.insert(BrowserContract.Favicons.CONTENT_URI, f));
-
- Cursor c = getFaviconsByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
- favicon, "Inserted favicon has corresponding favicon image");
-
- ContentValues u = createFaviconEntry(pageUrl, newFavicon);
- mProvider.update(BrowserContract.Favicons.CONTENT_URI, u, null, null);
- c.close();
-
- c = getFaviconsByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Updated favicon found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
- newFavicon, "Updated favicon has corresponding favicon image");
- c.close();
- }
- }
-
- /**
- * Create a folder of one thousand and one bookmarks, then impose an order
- * on them.
- *
- * Verify that the reordering worked by querying.
- */
- private class TestPositionBookmarks extends TestCase {
-
- public String makeGUID(final long in) {
- String part = String.valueOf(in);
- return "aaaaaaaaaaaa".substring(0, (12 - part.length())) + part;
- }
-
- public void compareCursorToItems(final Cursor c, final String[] items, final int count) {
- mAsserter.is(c.moveToFirst(), true, "Folder has children.");
-
- int posColumn = c.getColumnIndex(BrowserContract.Bookmarks.POSITION);
- int guidColumn = c.getColumnIndex(BrowserContract.Bookmarks.GUID);
- int i = 0;
-
- while (!c.isAfterLast()) {
- String guid = c.getString(guidColumn);
- long pos = c.getLong(posColumn);
- if ((pos != i) || (guid == null) || (!guid.equals(items[i]))) {
- mAsserter.is(pos, (long) i, "Position matches sequence.");
- mAsserter.is(guid, items[i], "GUID matches sequence.");
- }
- ++i;
- c.moveToNext();
- }
-
- mAsserter.is(i, count, "Folder has the right number of children.");
- c.close();
- }
-
- public static final int NUMBER_OF_CHILDREN = 1001;
- @Override
- public void test() throws Exception {
- // Create the containing folder.
- ContentValues folder = createBookmark("FolderFolder", "", mMobileFolderId,
- BrowserContract.Bookmarks.TYPE_FOLDER, 0, "",
- "description", "keyword");
- folder.put(BrowserContract.Bookmarks.GUID, "folderfolder");
- long folderId = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, folder));
-
- mAsserter.dumpLog("TestPositionBookmarks: Folder inserted"); // Bug 968951 debug.
-
- // Create the children.
- String[] items = new String[NUMBER_OF_CHILDREN];
-
- // Reuse the same ContentValues.
- ContentValues item = createBookmark("Test Bookmark", "http://example.com", folderId,
- BrowserContract.Bookmarks.TYPE_FOLDER, 0, "",
- "description", "keyword");
-
- for (int i = 0; i < NUMBER_OF_CHILDREN; ++i) {
- String guid = makeGUID(i);
- items[i] = guid;
- item.put(BrowserContract.Bookmarks.GUID, guid);
- item.put(BrowserContract.Bookmarks.POSITION, i);
- item.put(BrowserContract.Bookmarks.URL, "http://example.com/" + guid);
- item.put(BrowserContract.Bookmarks.TITLE, "Test Bookmark " + guid);
- mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, item);
- }
-
- mAsserter.dumpLog("TestPositionBookmarks: Bookmarks inserted"); // Bug 968951 debug.
-
- Cursor c;
-
- // Verify insertion.
- c = getBookmarksByParent(folderId);
- mAsserter.dumpLog("TestPositionBookmarks: Got bookmarks by parent"); // Bug 968951 debug.
- compareCursorToItems(c, items, NUMBER_OF_CHILDREN);
- c.close();
-
- // Now permute the items array.
- Random rand = new Random();
- for (int i = 0; i < NUMBER_OF_CHILDREN; ++i) {
- final int newPosition = rand.nextInt(NUMBER_OF_CHILDREN);
- final String switched = items[newPosition];
- items[newPosition] = items[i];
- items[i] = switched;
- }
-
- // Impose the positions.
- long updated = mProvider.update(BrowserContract.Bookmarks.POSITIONS_CONTENT_URI, null, null, items);
- mAsserter.is(updated, (long) NUMBER_OF_CHILDREN, "Updated " + NUMBER_OF_CHILDREN + " positions.");
-
- // Verify that the database was updated.
- c = getBookmarksByParent(folderId);
- compareCursorToItems(c, items, NUMBER_OF_CHILDREN);
- c.close();
- }
- }
-
- private class TestInsertHistory extends TestCase {
- private long insertWithNullCol(String colName) throws Exception {
- ContentValues h = createOneHistoryEntry();
- h.putNull(colName);
- long id = -1;
-
- try {
- id = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, h));
- } catch (Exception e) {}
-
- return id;
- }
-
- @Override
- public void test() throws Exception {
- ContentValues h = createOneHistoryEntry();
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, h));
- Cursor c = getHistoryEntryById(id);
-
- mAsserter.is(c.moveToFirst(), true, "Inserted history entry found");
-
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.TITLE)), h.getAsString(BrowserContract.History.TITLE),
- "Inserted history entry has correct title");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.URL)), h.getAsString(BrowserContract.History.URL),
- "Inserted history entry has correct URL");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.VISITS)), h.getAsString(BrowserContract.History.VISITS),
- "Inserted history entry has correct number of visits");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.DATE_LAST_VISITED)), h.getAsString(BrowserContract.History.DATE_LAST_VISITED),
- "Inserted history entry has correct last visited date");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.IS_DELETED)), String.valueOf(0),
- "Inserted history entry has correct is-deleted state");
-
- id = insertWithNullCol(BrowserContract.History.URL);
- mAsserter.is(id, -1L,
- "Should not be able to insert history with null URL");
-
- id = insertWithNullCol(BrowserContract.History.VISITS);
- mAsserter.is(id, -1L,
- "Should not be able to insert history with null number of visits");
- c.close();
- }
- }
-
- private class TestInsertHistoryFavicons extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues h = createOneHistoryEntry();
-
- final String favicon = "FAVICON";
- final String pageUrl = h.getAsString(BrowserContract.History.URL);
-
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, h));
-
- // Insert the favicon into the favicons table
- mProvider.insert(BrowserContract.Favicons.CONTENT_URI, createFaviconEntry(pageUrl, favicon));
-
- Cursor c = getHistoryEntryById(id, new String[] { BrowserContract.History.FAVICON });
-
- mAsserter.is(c.moveToFirst(), true, "Inserted history entry found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.History.FAVICON)), "UTF8"),
- favicon, "Inserted history entry has corresponding favicon image");
- c.close();
-
- c = getFaviconsByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
- favicon, "Inserted favicon has corresponding favicon image");
- c.close();
- }
- }
-
- private class TestDeleteHistory extends TestCase {
- private long insertOneHistoryEntry() throws Exception {
- ContentValues h = createOneHistoryEntry();
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, h));
-
- Cursor c = getHistoryEntryById(id);
- mAsserter.is(c.moveToFirst(), true, "Inserted history entry found");
- c.close();
-
- return id;
- }
-
- @Override
- public void test() throws Exception {
- long id = insertOneHistoryEntry();
-
- int deleted = mProvider.delete(BrowserContract.History.CONTENT_URI,
- BrowserContract.History._ID + " = ?",
- new String[] { String.valueOf(id) });
-
- mAsserter.is((deleted == 1), true, "Inserted history entry was deleted");
-
- Cursor c = getHistoryEntryById(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), id);
- mAsserter.is(c.moveToFirst(), true, "Deleted history entry was only marked as deleted");
-
- deleted = mProvider.delete(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"),
- BrowserContract.History._ID + " = ?",
- new String[] { String.valueOf(id) });
-
- mAsserter.is((deleted == 1), true, "Inserted history entry was deleted");
- c.close();
-
- c = getHistoryEntryById(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), id);
- mAsserter.is(c.moveToFirst(), false, "Inserted history is now actually deleted");
-
- id = insertOneHistoryEntry();
-
- deleted = mProvider.delete(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), null, null);
- mAsserter.is((deleted == 1), true,
- "Inserted history entry was deleted using URI with id");
- c.close();
-
- c = getHistoryEntryById(id);
- mAsserter.is(c.moveToFirst(), false,
- "Inserted history entry can't be found after deletion using URI with ID");
- c.close();
- }
- }
-
- private class TestDeleteHistoryFavicons extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues h = createOneHistoryEntry();
-
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, h));
- final String pageUrl = h.getAsString(BrowserContract.History.URL);
-
- // Insert the favicon into the favicons table
- mProvider.insert(BrowserContract.Favicons.CONTENT_URI, createFaviconEntry(pageUrl, "FAVICON"));
-
- Cursor c = getFaviconsByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
-
- mProvider.delete(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), null, null);
- c.close();
-
- c = getFaviconsByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), false, "Favicon is deleted with last reference to it");
- c.close();
- }
- }
-
- private class TestUpdateHistory extends TestCase {
- private int updateWithNullCol(long id, String colName) throws Exception {
- ContentValues u = new ContentValues();
- u.putNull(colName);
-
- int updated = 0;
-
- try {
- updated = mProvider.update(BrowserContract.History.CONTENT_URI, u,
- BrowserContract.History._ID + " = ?",
- new String[] { String.valueOf(id) });
- } catch (Exception e) {}
-
- return updated;
- }
-
- @Override
- public void test() throws Exception {
- ContentValues h = createOneHistoryEntry();
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, h));
-
- Cursor c = getHistoryEntryById(id);
- mAsserter.is(c.moveToFirst(), true, "Inserted history entry found");
-
- long dateCreated = c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED));
- long dateModified = c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED));
-
- ContentValues u = new ContentValues();
- u.put(BrowserContract.History.VISITS, h.getAsInteger(BrowserContract.History.VISITS) + 1);
- u.put(BrowserContract.History.DATE_LAST_VISITED, System.currentTimeMillis());
- u.put(BrowserContract.History.TITLE, h.getAsString(BrowserContract.History.TITLE) + "CHANGED");
- u.put(BrowserContract.History.URL, h.getAsString(BrowserContract.History.URL) + "/more/stuff");
-
- int updated = mProvider.update(BrowserContract.History.CONTENT_URI, u,
- BrowserContract.History._ID + " = ?",
- new String[] { String.valueOf(id) });
-
- mAsserter.is((updated == 1), true, "Inserted history entry was updated");
- c.close();
-
- c = getHistoryEntryById(id);
- mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
-
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.TITLE)), u.getAsString(BrowserContract.History.TITLE),
- "Updated history entry has correct title");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.URL)), u.getAsString(BrowserContract.History.URL),
- "Updated history entry has correct URL");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.VISITS)), u.getAsString(BrowserContract.History.VISITS),
- "Updated history entry has correct number of visits");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.DATE_LAST_VISITED)), u.getAsString(BrowserContract.History.DATE_LAST_VISITED),
- "Updated history entry has correct last visited date");
-
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED)),
- dateCreated,
- "Updated history entry has same creation date");
-
- mAsserter.isnot(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED)),
- dateModified,
- "Updated history entry has new modification date");
-
- updated = updateWithNullCol(id, BrowserContract.History.URL);
- mAsserter.is((updated > 0), false,
- "Should not be able to update history with null URL");
-
- updated = updateWithNullCol(id, BrowserContract.History.VISITS);
- mAsserter.is((updated > 0), false,
- "Should not be able to update history with null number of visits");
-
- u = new ContentValues();
- u.put(BrowserContract.History.URL, "http://examples2.com");
-
- updated = mProvider.update(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), u, null, null);
- c.close();
-
- c = getHistoryEntryById(id);
- mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
-
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.URL)), u.getAsString(BrowserContract.History.URL),
- "Updated history entry has correct URL using URI with id");
- c.close();
- }
- }
-
- private class TestUpdateHistoryFavicons extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues h = createOneHistoryEntry();
-
- final String favicon = "FAVICON";
- final String newFavicon = "NEW_FAVICON";
- final String pageUrl = h.getAsString(BrowserContract.History.URL);
-
- mProvider.insert(BrowserContract.History.CONTENT_URI, h);
-
- // Insert the favicon into the favicons table
- mProvider.insert(BrowserContract.Favicons.CONTENT_URI, createFaviconEntry(pageUrl, favicon));
-
- Cursor c = getFaviconsByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
- favicon, "Inserted favicon has corresponding favicon image");
-
- ContentValues u = createFaviconEntry(pageUrl, newFavicon);
-
- mProvider.update(BrowserContract.Favicons.CONTENT_URI, u, null, null);
- c.close();
-
- c = getFaviconsByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Updated favicon found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
- newFavicon, "Updated favicon has corresponding favicon image");
- c.close();
- }
- }
-
- private class TestUpdateOrInsertHistory extends TestCase {
- private final String TEST_URL_1 = "http://example.com";
- private final String TEST_URL_2 = "http://example.org";
- private final String TEST_TITLE = "Example";
-
- private long getHistoryEntryIdByUrl(String url) {
- Cursor c = mProvider.query(BrowserContract.History.CONTENT_URI,
- new String[] { BrowserContract.History._ID },
- BrowserContract.History.URL + " = ?",
- new String[] { url },
- null);
- c.moveToFirst();
- long id = c.getLong(0);
- c.close();
-
- return id;
- }
-
- @Override
- public void test() throws Exception {
- Uri updateHistoryUri = BrowserContract.History.CONTENT_URI.buildUpon().
- appendQueryParameter("increment_visits", "true").build();
- Uri updateOrInsertHistoryUri = BrowserContract.History.CONTENT_URI.buildUpon().
- appendQueryParameter("insert_if_needed", "true").
- appendQueryParameter("increment_visits", "true").build();
-
- // Update a non-existent history entry, without specifying visits or title
- ContentValues values = new ContentValues();
- values.put(BrowserContract.History.URL, TEST_URL_1);
-
- int updated = mProvider.update(updateHistoryUri, values,
- BrowserContract.History.URL + " = ?",
- new String[] { TEST_URL_1 });
- mAsserter.is((updated == 0), true, "History entry was not updated");
- Cursor c = mProvider.query(BrowserContract.History.CONTENT_URI, null, null, null, null);
- mAsserter.is(c.moveToFirst(), false, "History entry was not inserted");
- c.close();
-
- // Now let's try with update-or-insert.
- updated = mProvider.update(updateOrInsertHistoryUri, values,
- BrowserContract.History.URL + " = ?",
- new String[] { TEST_URL_1 });
- mAsserter.is((updated == 1), true, "History entry was inserted");
-
- long id = getHistoryEntryIdByUrl(TEST_URL_1);
- c = getHistoryEntryById(id);
- mAsserter.is(c.moveToFirst(), true, "History entry was inserted");
-
- long dateCreated = c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED));
- long dateModified = c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED));
-
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS)), 1L,
- "Inserted history entry has correct default number of visits");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.TITLE)), TEST_URL_1,
- "Inserted history entry has correct default title");
-
- // Update the history entry, without specifying an additional visit count
- values = new ContentValues();
- values.put(BrowserContract.History.DATE_LAST_VISITED, System.currentTimeMillis());
- values.put(BrowserContract.History.TITLE, TEST_TITLE);
-
- updated = mProvider.update(updateOrInsertHistoryUri, values,
- BrowserContract.History._ID + " = ?",
- new String[] { String.valueOf(id) });
- mAsserter.is((updated == 1), true, "Inserted history entry was updated");
- c.close();
-
- c = getHistoryEntryById(id);
- mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
-
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.TITLE)), TEST_TITLE,
- "Updated history entry has correct title");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS)), 2L,
- "Updated history entry has correct number of visits");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED)), dateCreated,
- "Updated history entry has same creation date");
- mAsserter.isnot(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED)), dateModified,
- "Updated history entry has new modification date");
-
- // Create a new history entry, specifying visits and history
- values = new ContentValues();
- values.put(BrowserContract.History.URL, TEST_URL_2);
- values.put(BrowserContract.History.TITLE, TEST_TITLE);
- values.put(BrowserContract.History.VISITS, 10);
-
- updated = mProvider.update(updateOrInsertHistoryUri, values,
- BrowserContract.History.URL + " = ?",
- new String[] { values.getAsString(BrowserContract.History.URL) });
- mAsserter.is((updated == 1), true, "History entry was inserted");
-
- id = getHistoryEntryIdByUrl(TEST_URL_2);
- c.close();
-
- c = getHistoryEntryById(id);
- mAsserter.is(c.moveToFirst(), true, "History entry was inserted");
-
- dateCreated = c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED));
- dateModified = c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED));
-
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS)), 10L,
- "Inserted history entry has correct specified number of visits");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.TITLE)), TEST_TITLE,
- "Inserted history entry has correct specified title");
-
- // Update the history entry, specifying additional visit count.
- // The expectation is that the value is ignored, and count is bumped by 1 only.
- // At the same time, a visit is inserted into the visits table.
- // See junit4 tests in BrowserProviderHistoryVisitsTest.
- values = new ContentValues();
- values.put(BrowserContract.History.VISITS, 10);
-
- updated = mProvider.update(updateOrInsertHistoryUri, values,
- BrowserContract.History._ID + " = ?",
- new String[] { String.valueOf(id) });
- mAsserter.is((updated == 1), true, "Inserted history entry was updated");
- c.close();
-
- c = getHistoryEntryById(id);
- mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
-
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.TITLE)), TEST_TITLE,
- "Updated history entry has correct unchanged title");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.URL)), TEST_URL_2,
- "Updated history entry has correct unchanged URL");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS)), 11L,
- "Updated history entry has correct number of visits");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED)), dateCreated,
- "Updated history entry has same creation date");
- mAsserter.isnot(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED)), dateModified,
- "Updated history entry has new modification date");
- c.close();
-
- }
- }
-
- private class TestInsertHistoryThumbnails extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues h = createOneHistoryEntry();
-
- final String thumbnail = "THUMBNAIL";
- final String pageUrl = h.getAsString(BrowserContract.History.URL);
-
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, h));
-
- // Insert the thumbnail into the thumbnails table
- mProvider.insert(BrowserContract.Thumbnails.CONTENT_URI, createThumbnailEntry(pageUrl, thumbnail));
-
- Cursor c = getThumbnailByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Inserted thumbnail found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Thumbnails.DATA)), "UTF8"),
- thumbnail, "Inserted thumbnail has corresponding thumbnail image");
- c.close();
- }
- }
-
- private class TestUpdateHistoryThumbnails extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues h = createOneHistoryEntry();
-
- final String thumbnail = "THUMBNAIL";
- final String newThumbnail = "NEW_THUMBNAIL";
- final String pageUrl = h.getAsString(BrowserContract.History.URL);
-
- mProvider.insert(BrowserContract.History.CONTENT_URI, h);
-
- // Insert the thumbnail into the thumbnails table
- mProvider.insert(BrowserContract.Thumbnails.CONTENT_URI, createThumbnailEntry(pageUrl, thumbnail));
-
- Cursor c = getThumbnailByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Inserted thumbnail found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Thumbnails.DATA)), "UTF8"),
- thumbnail, "Inserted thumbnail has corresponding thumbnail image");
-
- ContentValues u = createThumbnailEntry(pageUrl, newThumbnail);
-
- mProvider.update(BrowserContract.Thumbnails.CONTENT_URI, u, null, null);
- c.close();
-
- c = getThumbnailByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Updated thumbnail found");
-
- mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Thumbnails.DATA)), "UTF8"),
- newThumbnail, "Updated thumbnail has corresponding thumbnail image");
- c.close();
- }
- }
-
- private class TestDeleteHistoryThumbnails extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues h = createOneHistoryEntry();
-
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, h));
- final String pageUrl = h.getAsString(BrowserContract.History.URL);
-
- // Insert the thumbnail into the thumbnails table
- mProvider.insert(BrowserContract.Thumbnails.CONTENT_URI, createThumbnailEntry(pageUrl, "THUMBNAIL"));
-
- Cursor c = getThumbnailByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), true, "Inserted thumbnail found");
-
- mProvider.delete(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), null, null);
- c.close();
-
- c = getThumbnailByUrl(pageUrl);
- mAsserter.is(c.moveToFirst(), false, "Thumbnail is deleted with last reference to it");
- c.close();
- }
- }
-
- private class TestInsertUrlAnnotations extends TestCase {
- @Override
- public void test() throws Exception {
- testInsertionViaContentProvider();
- testInsertionViaUrlAnnotations();
- }
-
- private void testInsertionViaContentProvider() throws Exception {
- final String url = "http://mozilla.org";
- final String key = "todo";
- final String value = "v";
- final long dateCreated = System.currentTimeMillis();
-
- mProvider.insert(BrowserContract.UrlAnnotations.CONTENT_URI, createUrlAnnotationEntry(url, key, value, dateCreated));
-
- final Cursor c = getUrlAnnotationByUrl(url);
- try {
- mAsserter.is(c.moveToFirst(), true, "Inserted url annotation found");
- assertKeyValueSync(c, key, value);
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.UrlAnnotations.DATE_CREATED)), dateCreated,
- "Inserted url annotation has correct date created");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.UrlAnnotations.DATE_MODIFIED)), dateCreated,
- "Inserted url annotation has correct date modified");
- } finally {
- c.close();
- }
- }
-
- private void testInsertionViaUrlAnnotations() throws Exception {
- final String url = "http://hello.org";
- final String key = "toTheUniverse";
- final String value = "42a";
- final long timeBeforeCreation = System.currentTimeMillis();
-
- BrowserDB.from(getTestProfile()).getUrlAnnotations().insertAnnotation(mResolver, url, key, value);
-
- final Cursor c = getUrlAnnotationByUrl(url);
- try {
- mAsserter.is(c.moveToFirst(), true, "Inserted url annotation found");
- assertKeyValueSync(c, key, value);
- mAsserter.is(true, c.getLong(c.getColumnIndex(BrowserContract.UrlAnnotations.DATE_CREATED)) >= timeBeforeCreation,
- "Inserted url annotation has date created greater than or equal to time saved before insertion");
- mAsserter.is(true, c.getLong(c.getColumnIndex(BrowserContract.UrlAnnotations.DATE_MODIFIED)) >= timeBeforeCreation,
- "Inserted url annotation has correct date modified greater than or equal to time saved before insertion");
- } finally {
- c.close();
- }
- }
-
- private void assertKeyValueSync(final Cursor c, final String key, final String value) {
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.UrlAnnotations.KEY)), key,
- "Inserted url annotation has correct key");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.UrlAnnotations.VALUE)), value,
- "Inserted url annotation has correct value");
- mAsserter.is(c.getInt(c.getColumnIndex(BrowserContract.UrlAnnotations.SYNC_STATUS)), SyncStatus.NEW.getDBValue(),
- "Inserted url annotation has default sync status");
- }
- }
-
- private class TestInsertUrlMetadata extends TestCase {
- @Override
- public void test() throws Exception {
- testInsertionViaContentProvider();
- testInsertionViaUrlMetadata();
- // testRetrievalViaUrlMetadata depends on data added in the previous two tests
- testRetrievalViaUrlMetadata();
- }
-
- final String url1 = "http://mozilla.org";
- final String url2 = "http://hello.org";
-
- private void testInsertionViaContentProvider() throws Exception {
- final String tileImage = "http://mozilla.org/tileImage.png";
- final String tileColor = "#FF0000";
- final String touchIcon = "http://mozilla.org/touchIcon.png";
-
- // We can only use update since the redirection machinery doesn't exist for insert
- mProvider.update(URLMetadataTable.CONTENT_URI.buildUpon().appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build(),
- createUrlMetadataEntry(url1, tileImage, tileColor, touchIcon),
- URLMetadataTable.URL_COLUMN + "=?",
- new String[] {url1}
- );
-
- final Cursor c = getUrlMetadataByUrl(url1);
- try {
- mAsserter.is(c.getCount(), 1, "URL metadata inserted via Content Provider not found");
- } finally {
- c.close();
- }
- }
-
- private void testInsertionViaUrlMetadata() throws Exception {
- final String tileImage = "http://hello.org/tileImage.png";
- final String tileColor = "#FF0000";
- final String touchIcon = "http://hello.org/touchIcon.png";
-
- final Map<String, Object> data = new HashMap<>();
- data.put(URLMetadataTable.URL_COLUMN, url2);
- data.put(URLMetadataTable.TILE_IMAGE_URL_COLUMN, tileImage);
- data.put(URLMetadataTable.TILE_COLOR_COLUMN, tileColor);
- data.put(URLMetadataTable.TOUCH_ICON_COLUMN, touchIcon);
-
- BrowserDB.from(getTestProfile()).getURLMetadata().save(mResolver, data);
-
- final Cursor c = getUrlMetadataByUrl(url2);
- try {
- mAsserter.is(c.moveToFirst(), true, "URL metadata inserted via UrlMetadata not found");
- } finally {
- c.close();
- }
- }
-
- private void testRetrievalViaUrlMetadata() {
- // LocalURLMetadata has some caching of results: we need to test that this caching
- // doesn't prevent us from accessing data that might not have been loaded into the cache.
- // We do this by first doing queries with a subset of data, then later querying additional
- // data for a given URL. E.g. even if the first query results in only the requested
- // column being cached, the subsequent query should still retrieve all requested columns.
- // (In this case the URL may be cached but without all data, we need to make sure that
- // this state is correctly handled.)
- URLMetadata metadata = BrowserDB.from(getTestProfile()).getURLMetadata();
-
- Map<String, Map<String, Object>> results;
- Map<String, Object> urlData;
-
- // 1: retrieve just touch Icons for URL 1
- results = metadata.getForURLs(mResolver,
- Collections.singletonList(url1),
- Collections.singletonList(URLMetadataTable.TOUCH_ICON_COLUMN));
-
- mAsserter.is(results.containsKey(url1), true, "URL 1 not found in results");
-
- urlData = results.get(url1);
- mAsserter.is(urlData.containsKey(URLMetadataTable.TOUCH_ICON_COLUMN), true, "touchIcon column missing in UrlMetadata results");
-
- // 2: retrieve just tile color for URL 2
- results = metadata.getForURLs(mResolver,
- Collections.singletonList(url2),
- Collections.singletonList(URLMetadataTable.TILE_COLOR_COLUMN));
-
- mAsserter.is(results.containsKey(url2), true, "URL 2 not found in results");
-
- urlData = results.get(url2);
- mAsserter.is(urlData.containsKey(URLMetadataTable.TILE_COLOR_COLUMN), true, "touchIcon column missing in UrlMetadata results");
-
-
- // 3: retrieve all columns for both URLs
- final List<String> urls = Arrays.asList(url1, url2);
-
- results = metadata.getForURLs(mResolver,
- urls,
- Arrays.asList(URLMetadataTable.TILE_IMAGE_URL_COLUMN,
- URLMetadataTable.TILE_COLOR_COLUMN,
- URLMetadataTable.TOUCH_ICON_COLUMN
- ));
-
- mAsserter.is(results.containsKey(url1), true, "URL 1 not found in results");
- mAsserter.is(results.containsKey(url2), true, "URL 2 not found in results");
-
-
- for (final String url : urls) {
- urlData = results.get(url);
- mAsserter.is(urlData.containsKey(URLMetadataTable.TILE_IMAGE_URL_COLUMN), true, "touchIcon column missing in UrlMetadata results");
- mAsserter.is(urlData.containsKey(URLMetadataTable.TILE_COLOR_COLUMN), true, "touchIcon column missing in UrlMetadata results");
- mAsserter.is(urlData.containsKey(URLMetadataTable.TOUCH_ICON_COLUMN), true, "touchIcon column missing in UrlMetadata results");
- }
- }
- }
-
- private class TestCombinedView extends TestCase {
- @Override
- public void test() throws Exception {
- final String TITLE_1 = "Test Page 1";
- final String TITLE_2 = "Test Page 2";
- final String TITLE_3_HISTORY = "Test Page 3 (History Entry)";
- final String TITLE_3_BOOKMARK = "Test Page 3 (Bookmark Entry)";
- final String TITLE_3_BOOKMARK2 = "Test Page 3 (Bookmark Entry 2)";
-
- final String URL_1 = "http://example1.com";
- final String URL_2 = "http://example2.com";
- final String URL_3 = "http://example3.com";
-
- final int VISITS = 10;
- final long LAST_VISITED = System.currentTimeMillis();
-
- // Create a basic history entry
- ContentValues basicHistory = createHistoryEntry(TITLE_1, URL_1, VISITS, LAST_VISITED);
- long basicHistoryId = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, basicHistory));
-
- // Create a basic bookmark entry
- ContentValues basicBookmark = createBookmark(TITLE_2, URL_2, mMobileFolderId,
- BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
- long basicBookmarkId = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, basicBookmark));
-
- // Create a history entry and bookmark entry with the same URL to
- // represent a visited bookmark
- ContentValues combinedHistory = createHistoryEntry(TITLE_3_HISTORY, URL_3, VISITS, LAST_VISITED);
- long combinedHistoryId = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, combinedHistory));
-
-
- ContentValues combinedBookmark = createBookmark(TITLE_3_BOOKMARK, URL_3, mMobileFolderId,
- BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
- long combinedBookmarkId = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, combinedBookmark));
-
- ContentValues combinedBookmark2 = createBookmark(TITLE_3_BOOKMARK2, URL_3, mMobileFolderId,
- BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
- long combinedBookmarkId2 = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, combinedBookmark2));
-
- // Create a bookmark folder to make sure it _doesn't_ show up in the results
- ContentValues folderBookmark = createBookmark("", "", mMobileFolderId,
- BrowserContract.Bookmarks.TYPE_FOLDER, 0, "tags", "description", "keyword");
- mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, folderBookmark);
-
- // Sort entries by url so we can check them individually
- final Cursor c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, BrowserContract.Combined.URL);
-
- try {
- mAsserter.is(c.getCount(), 3, "3 combined entries found");
-
- // First combined entry is basic history entry
- mAsserter.is(c.moveToFirst(), true, "Found basic history entry");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined._ID)), 0L,
- "Combined _id column should always be 0");
- // TODO: Should we change BrowserProvider to make this return -1, not 0?
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)), 0L,
- "Bookmark id should be 0 for basic history entry");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.HISTORY_ID)), basicHistoryId,
- "Basic history entry has correct history id");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)), TITLE_1,
- "Basic history entry has correct title");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.URL)), URL_1,
- "Basic history entry has correct url");
- mAsserter.is(c.getInt(c.getColumnIndex(BrowserContract.Combined.VISITS)), VISITS,
- "Basic history entry has correct number of visits");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED)), LAST_VISITED,
- "Basic history entry has correct last visit time");
-
- // Second combined entry is basic bookmark entry
- mAsserter.is(c.moveToNext(), true, "Found basic bookmark entry");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined._ID)), 0L,
- "Combined _id column should always be 0");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)), basicBookmarkId,
- "Basic bookmark entry has correct bookmark id");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.HISTORY_ID)), -1L,
- "History id should be -1 for basic bookmark entry");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)), TITLE_2,
- "Basic bookmark entry has correct title");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.URL)), URL_2,
- "Basic bookmark entry has correct url");
- mAsserter.is(c.getInt(c.getColumnIndex(BrowserContract.Combined.VISITS)), -1,
- "Visits should be -1 for basic bookmark entry");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED)), -1L,
- "Basic entry has correct last visit time");
-
- // Third combined entry is a combined history/bookmark entry
- mAsserter.is(c.moveToNext(), true, "Found third combined entry");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined._ID)), 0L,
- "Combined _id column should always be 0");
- // The bookmark data (bookmark_id and title) associated with the combined entry is non-deterministic,
- // it might end up with data coming from any of the matching bookmark entries.
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)) == combinedBookmarkId ||
- c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)) == combinedBookmarkId2, true,
- "Combined entry has correct bookmark id");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)).equals(TITLE_3_BOOKMARK) ||
- c.getString(c.getColumnIndex(BrowserContract.Combined.TITLE)).equals(TITLE_3_BOOKMARK2), true,
- "Combined entry has title corresponding to bookmark entry");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.HISTORY_ID)), combinedHistoryId,
- "Combined entry has correct history id");
- mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Combined.URL)), URL_3,
- "Combined entry has correct url");
- mAsserter.is(c.getInt(c.getColumnIndex(BrowserContract.Combined.VISITS)), VISITS,
- "Combined entry has correct number of visits");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED)), LAST_VISITED,
- "Combined entry has correct last visit time");
- } finally {
- c.close();
- }
- }
- }
-
- private class TestCombinedViewDisplay extends TestCase {
- @Override
- public void test() throws Exception {
- final String TITLE_1 = "Test Page 1";
- final String TITLE_2 = "Test Page 2";
- final String TITLE_3_HISTORY = "Test Page 3 (History Entry)";
- final String TITLE_3_BOOKMARK = "Test Page 3 (Bookmark Entry)";
-
- final String URL_1 = "http://example.com";
- final String URL_2 = "http://example.org";
- final String URL_3 = "http://examples2.com";
-
- final int VISITS = 10;
- final long LAST_VISITED = System.currentTimeMillis();
-
- // Create a basic history entry
- ContentValues basicHistory = createHistoryEntry(TITLE_1, URL_1, VISITS, LAST_VISITED);
- ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, basicHistory));
-
- // Create a basic bookmark entry
- ContentValues basicBookmark = createBookmark(TITLE_2, URL_2, mMobileFolderId,
- BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
- mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, basicBookmark);
-
- // Create a history entry and bookmark entry with the same URL to
- // represent a visited bookmark
- ContentValues combinedHistory = createHistoryEntry(TITLE_3_HISTORY, URL_3, VISITS, LAST_VISITED);
- mProvider.insert(BrowserContract.History.CONTENT_URI, combinedHistory);
-
- ContentValues combinedBookmark = createBookmark(TITLE_3_BOOKMARK, URL_3, mMobileFolderId,
- BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
- mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, combinedBookmark);
-
- final Cursor c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
- try {
- mAsserter.is(c.getCount(), 3, "3 combined entries found");
- } finally {
- c.close();
- }
- }
- }
-
- private class TestCombinedViewWithDeletedBookmark extends TestCase {
- @Override
- public void test() throws Exception {
- final String TITLE = "Test Page 1";
- final String URL = "http://example.com";
- final int VISITS = 10;
- final long LAST_VISITED = System.currentTimeMillis();
-
- // Create a combined history entry
- ContentValues combinedHistory = createHistoryEntry(TITLE, URL, VISITS, LAST_VISITED);
- mProvider.insert(BrowserContract.History.CONTENT_URI, combinedHistory);
-
- // Create a combined bookmark entry
- ContentValues combinedBookmark = createBookmark(TITLE, URL, mMobileFolderId,
- BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
- long combinedBookmarkId = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, combinedBookmark));
-
- Cursor c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
- mAsserter.is(c.getCount(), 1, "1 combined entry found");
-
- mAsserter.is(c.moveToFirst(), true, "Found combined entry with bookmark id");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)), combinedBookmarkId,
- "Bookmark id should be set correctly on combined entry");
-
- int deleted = mProvider.delete(BrowserContract.Bookmarks.CONTENT_URI,
- BrowserContract.Bookmarks._ID + " = ?",
- new String[] { String.valueOf(combinedBookmarkId) });
-
- mAsserter.is((deleted == 1), true, "Inserted combined bookmark was deleted");
- c.close();
-
- c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
- mAsserter.is(c.getCount(), 1, "1 combined entry found");
-
- mAsserter.is(c.moveToFirst(), true, "Found combined entry without bookmark id");
- mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID)), 0L,
- "Bookmark id should not be set to removed bookmark id");
- c.close();
- }
- }
-
- /*
- * Verify that insert, update, delete, and bulkInsert operations
- * notify the ambient content resolver. Each operation calls the
- * content resolver notifyChange method synchronously, so it is
- * okay to test sequentially.
- */
- private class TestBrowserProviderNotifications extends TestCase {
- public static final String LOGTAG = "TestBPNotifications";
-
- protected void ensureOnlyChangeNotifiedStartsWith(Uri expectedUri, String operation) {
- if (expectedUri == null) {
- throw new IllegalArgumentException("expectedUri must not be null");
- }
-
- if (mResolver.notifyChangeList.size() != 1) {
- // Log to help post-mortem debugging
- Log.w(LOGTAG, "after operation, notifyChangeList = " + mResolver.notifyChangeList);
- }
-
- mAsserter.is((long) mResolver.notifyChangeList.size(),
- 1L,
- "Content observer was notified exactly once by " + operation);
-
- Uri uri = mResolver.notifyChangeList.poll();
-
- mAsserter.isnot(uri,
- null,
- "Notification from " + operation + " was valid");
-
- mAsserter.ok(uri.toString().startsWith(expectedUri.toString()),
- "Content observer was notified exactly once by " + operation,
- uri.toString() + " starts with expected prefix " + expectedUri);
- }
-
- @Override
- public void test() throws Exception {
- // Insert
- final ContentValues h = createOneHistoryEntry();
-
- mResolver.notifyChangeList.clear();
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.History.CONTENT_URI, h));
-
- mAsserter.isnot(id,
- -1L,
- "Inserted item has valid id");
-
- ensureOnlyChangeNotifiedStartsWith(BrowserContract.History.CONTENT_URI, "insert");
-
- // Update
- mResolver.notifyChangeList.clear();
- h.put(BrowserContract.History.TITLE, "http://newexample.com");
-
- long numUpdated = mProvider.update(BrowserContract.History.CONTENT_URI, h,
- BrowserContract.History._ID + " = ?",
- new String[] { String.valueOf(id) });
-
- mAsserter.is(numUpdated,
- 1L,
- "Correct number of items are updated");
-
- ensureOnlyChangeNotifiedStartsWith(BrowserContract.History.CONTENT_URI, "update");
-
- // Delete
- mResolver.notifyChangeList.clear();
- long numDeleted = mProvider.delete(BrowserContract.History.CONTENT_URI, null, null);
-
- mAsserter.is(numDeleted,
- 1L,
- "Correct number of items are deleted");
-
- ensureOnlyChangeNotifiedStartsWith(BrowserContract.History.CONTENT_URI, "delete");
-
- // Bulk insert
- final ContentValues[] hs = new ContentValues[] { createOneHistoryEntry() };
-
- mResolver.notifyChangeList.clear();
- long numBulkInserted = mProvider.bulkInsert(BrowserContract.History.CONTENT_URI, hs);
-
- mAsserter.is(numBulkInserted,
- 1L,
- "Correct number of items are bulkInserted");
-
- ensureOnlyChangeNotifiedStartsWith(BrowserContract.History.CONTENT_URI, "bulkInsert");
- }
- }
-
- /**
- * Assert that the provided cursor has the expected number of rows,
- * closing the cursor afterwards.
- */
- private void assertCountIsAndClose(Cursor c, int expectedCount, String message) {
- try {
- mAsserter.is(c.getCount(), expectedCount, message);
- } finally {
- c.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserSearchVisibility.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserSearchVisibility.java
deleted file mode 100644
index d8fc793fc..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserSearchVisibility.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.support.v4.app.Fragment;
-import android.view.KeyEvent;
-import android.view.View;
-
-import com.robotium.solo.Condition;
-
-/**
- * Test for browser search visibility.
- * Sends queries from url bar input and verifies that browser search
- * visibility is correct.
- */
-public class testBrowserSearchVisibility extends BaseTest {
- public void testSearchSuggestions() {
- blockForGeckoReady();
-
- focusUrlBar();
-
- // search should not be visible when editing mode starts
- assertBrowserSearchVisibility(false);
-
- mActions.sendKeys("a");
-
- // search should be visible when entry is not empty
- assertBrowserSearchVisibility(true);
-
- mActions.sendKeys("b");
-
- // search continues to be visible when more text is added
- assertBrowserSearchVisibility(true);
-
- mActions.sendKeyCode(KeyEvent.KEYCODE_DEL);
-
- // search continues to be visible when not all text is deleted
- assertBrowserSearchVisibility(true);
-
- mActions.sendKeyCode(KeyEvent.KEYCODE_DEL);
-
- // search should not be visible, entry is empty now
- assertBrowserSearchVisibility(false);
- }
-
- private void assertBrowserSearchVisibility(final boolean isVisible) {
- waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- final Fragment browserSearch = getBrowserSearch();
-
- // The fragment should not be present at all. Testing if the
- // fragment is present but has no defined view is not a valid
- // state.
- if (browserSearch == null)
- return !isVisible;
-
- final View v = browserSearch.getView();
- if (isVisible && v != null && v.getVisibility() == View.VISIBLE)
- return true;
-
- return false;
- }
- }, 5000);
- }
-}
-
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBug1217581.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBug1217581.java
deleted file mode 100644
index fe3c047a3..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBug1217581.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-
-import org.mozilla.gecko.Telemetry;
-
-public class testBug1217581 extends BaseTest {
- // Take arbitrary histogram names used by Fennec.
- private static final String TEST_HISTOGRAM_NAME = "FENNEC_SYNC_NUMBER_OF_SYNCS_COMPLETED";
- private static final String TEST_KEYED_HISTOGRAM_NAME = "FX_MIGRATION_ERRORS";
- private static final String TEST_KEY_NAME = "testBug1217581";
-
-
- public void testBug1217581() {
- blockForGeckoReady();
-
- mAsserter.ok(true, "Checking that adding to a keyed histogram then adding to a normal histogram does not cause a crash.", "");
- Telemetry.addToKeyedHistogram(TEST_KEYED_HISTOGRAM_NAME, TEST_KEY_NAME, 1);
- Telemetry.addToHistogram(TEST_HISTOGRAM_NAME, 1);
- mAsserter.ok(true, "Adding to a keyed histogram then to a normal histogram was a success!", "");
-
- mAsserter.ok(true, "Checking that adding to a normal histogram then adding to a keyed histogram does not cause a crash.", "");
- Telemetry.addToHistogram(TEST_HISTOGRAM_NAME, 1);
- Telemetry.addToKeyedHistogram(TEST_KEYED_HISTOGRAM_NAME, TEST_KEY_NAME, 1);
- mAsserter.ok(true, "Adding to a normal histogram then to a keyed histogram was a success!", "");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testCheck2.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testCheck2.java
deleted file mode 100644
index fc538b5bf..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testCheck2.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.json.JSONObject;
-
-public class testCheck2 extends PixelTest {
- @Override
- protected Type getTestType() {
- return Type.TALOS;
- }
-
- public void testCheck2() {
- String url = getAbsoluteUrl("/startup_test/fennecmark/cnn/cnn.com/index.html");
-
- // Enable double-tap zooming
- setPreferenceAndWaitForChange("browser.ui.zoom.force-user-scalable", true);
-
- blockForGeckoReady();
- loadAndPaint(url);
-
- mDriver.setupScrollHandling();
-
- /*
- * for this test, we load the timecube page, and replay a recorded sequence of events
- * that is a user panning/zooming around the page. specific things in the sequence
- * include:
- * - scroll on one axis followed by scroll on another axis
- * - pinch zoom (in and out)
- * - double-tap zoom (in and out)
- * - multi-fling panning with different velocities on each fling
- *
- * this checkerboarding metric is going to be more of a "functional" style test than
- * a "unit" style test; i.e. it covers a little bit of a lot of things to measure
- * overall performance, but doesn't really allow identifying which part is slow.
- */
-
- MotionEventReplayer mer = new MotionEventReplayer(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop(),
- mDriver.getGeckoWidth(), mDriver.getGeckoHeight());
-
- float completeness = 0.0f;
- mDriver.startCheckerboardRecording();
- // replay the events
- try {
- mer.replayEvents(getAsset("testcheck2-motionevents"));
- // give it some time to draw any final frames
- Thread.sleep(1000);
- completeness = mDriver.stopCheckerboardRecording();
- } catch (Exception e) {
- e.printStackTrace();
- mAsserter.ok(false, "Exception while replaying events", e.toString());
- }
-
- mAsserter.dumpLog("__start_report" + completeness + "__end_report");
- System.out.println("Completeness score: " + completeness);
- long msecs = System.currentTimeMillis();
- mAsserter.dumpLog("__startTimestamp" + msecs + "__endTimestamp");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testCheck3.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testCheck3.java
deleted file mode 100644
index 28915bdbc..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testCheck3.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.json.JSONObject;
-
-public class testCheck3 extends PixelTest {
- @Override
- protected Type getTestType() {
- return Type.TALOS;
- }
-
- public void testCheck3() {
- String url = getAbsoluteUrl("/facebook.com/www.facebook.com/barackobama.html");
-
- // Enable double-tap zooming
- setPreferenceAndWaitForChange("browser.ui.zoom.force-user-scalable", true);
-
- blockForGeckoReady();
- loadAndPaint(url);
-
- mDriver.setupScrollHandling();
-
- /*
- * for this test, we load the timecube page, and replay a recorded sequence of events
- * that is a user panning/zooming around the page. specific things in the sequence
- * include:
- * - scroll on one axis followed by scroll on another axis
- * - pinch zoom (in and out)
- * - double-tap zoom (in and out)
- * - multi-fling panning with different velocities on each fling
- *
- * this checkerboarding metric is going to be more of a "functional" style test than
- * a "unit" style test; i.e. it covers a little bit of a lot of things to measure
- * overall performance, but doesn't really allow identifying which part is slow.
- */
-
- MotionEventReplayer mer = new MotionEventReplayer(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop(),
- mDriver.getGeckoWidth(), mDriver.getGeckoHeight());
-
- float completeness = 0.0f;
- mDriver.startCheckerboardRecording();
- // replay the events
- try {
- mer.replayEvents(getAsset("testcheck2-motionevents"));
- // give it some time to draw any final frames
- Thread.sleep(1000);
- completeness = mDriver.stopCheckerboardRecording();
- } catch (Exception e) {
- e.printStackTrace();
- mAsserter.ok(false, "Exception while replaying events", e.toString());
- }
-
- mAsserter.dumpLog("__start_report" + completeness + "__end_report");
- System.out.println("Completeness score: " + completeness);
- long msecs = System.currentTimeMillis();
- mAsserter.dumpLog("__startTimestamp" + msecs + "__endTimestamp");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDBUtils.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDBUtils.java
deleted file mode 100644
index 700c1c255..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDBUtils.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import org.mozilla.gecko.db.DBUtils;
-
-import java.io.File;
-import java.io.IOException;
-
-public class testDBUtils extends BaseTest {
- public void testDBUtils() throws IOException {
- final File cacheDir = getInstrumentation().getContext().getCacheDir();
- final File dbFile = File.createTempFile("testDBUtils", ".db", cacheDir);
- final SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
- try {
- mAsserter.ok(db != null, "Created DB.", null);
- db.execSQL("CREATE TABLE foo (x INTEGER NOT NULL DEFAULT 0, y TEXT)");
- final ContentValues v = new ContentValues();
- v.put("x", 5);
- v.put("y", "a");
- db.insert("foo", null, v);
- v.put("x", 2);
- v.putNull("y");
- db.insert("foo", null, v);
- v.put("x", 3);
- v.put("y", "z");
- db.insert("foo", null, v);
-
- DBUtils.UpdateOperation[] ops = {DBUtils.UpdateOperation.BITWISE_OR, DBUtils.UpdateOperation.ASSIGN};
- ContentValues[] values = {new ContentValues(), new ContentValues()};
- values[0].put("x", 0xff);
- values[1].put("y", "hello");
-
- final int updated = DBUtils.updateArrays(db, "foo", values, ops, "x >= 3", null);
-
- mAsserter.ok(updated == 2, "Updated two rows.", null);
- final Cursor out = db.query("foo", new String[]{"x", "y"}, null, null, null, null, "x");
- try {
- mAsserter.ok(out.moveToNext(), "Has first result.", null);
- mAsserter.ok(2 == out.getInt(0), "1: First column was untouched.", null);
- mAsserter.ok(out.isNull(1), "1: Second column was untouched.", null);
-
- mAsserter.ok(out.moveToNext(), "Has second result.", null);
- mAsserter.ok((0xff | 3) == out.getInt(0), "2: First column was ORed correctly.", null);
- mAsserter.ok("hello".equals(out.getString(1)), "2: Second column was assigned correctly.", null);
-
- mAsserter.ok(out.moveToNext(), "Has third result.", null);
- mAsserter.ok((0xff | 5) == out.getInt(0), "3: First column was ORed correctly.", null);
- mAsserter.ok("hello".equals(out.getString(1)), "3: Second column was assigned correctly.", null);
-
- mAsserter.ok(!out.moveToNext(), "No more results.", null);
- } finally {
- out.close();
- }
-
- } finally {
- try {
- db.close();
- } catch (Exception e) {
- }
- dbFile.delete();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDistribution.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDistribution.java
deleted file mode 100644
index 4cc08cc5c..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDistribution.java
+++ /dev/null
@@ -1,556 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URI;
-import java.util.Locale;
-import java.util.jar.JarInputStream;
-import java.util.NoSuchElementException;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.BrowserLocaleManager;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.GeckoSharedPrefs;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.distribution.Distribution;
-import org.mozilla.gecko.distribution.ReferrerDescriptor;
-import org.mozilla.gecko.distribution.ReferrerReceiver;
-import org.mozilla.gecko.preferences.DistroSharedPrefsImport;
-import org.mozilla.gecko.preferences.GeckoPreferences;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
-
-/**
- * Tests distribution customization.
- * mock-package.zip should contain the following directory structure:
- *
- * distribution/
- * preferences.json
- * bookmarks.json
- * searchplugins/
- * common/
- * engine.xml
- * suggestedsites/
- * locales/
- * en-US/
- * suggestedsites.json
- * extensions/
- * distribution.test@mozilla.org.xpi
- */
-public class testDistribution extends ContentProviderTest {
- private static final String CLASS_REFERRER_RECEIVER = "org.mozilla.gecko.distribution.ReferrerReceiver";
- private static final String ACTION_INSTALL_REFERRER = "com.android.vending.INSTALL_REFERRER";
- private static final int WAIT_TIMEOUT_MSEC = 10000;
- public static final String LOGTAG = "GeckoTestDistribution";
-
- public static class TestableDistribution extends Distribution {
- @Override
- protected JarInputStream fetchDistribution(URI uri,
- HttpURLConnection connection) throws IOException {
- Log.i(LOGTAG, "Not downloading: this is a test.");
- return null;
- }
-
- public TestableDistribution(Context context) {
- super(context);
- }
-
- public void go() {
- doInit();
- }
-
- public static void clearReferrerDescriptorForTesting() {
- referrer = null;
- }
-
- public static ReferrerDescriptor getReferrerDescriptorForTesting() {
- return referrer;
- }
- }
-
- private static final String MOCK_PACKAGE = "mock-package.zip";
- private static final int PREF_REQUEST_ID = 0x7357;
-
- private Activity mActivity;
-
- /**
- * This is a hack.
- *
- * Startup results in us writing prefs -- we fetch the Distribution, which
- * caches its state. Our tests try to wipe those prefs, but apparently
- * sometimes race with startup, which leads to us not getting one of our
- * expected messages. The test fails.
- *
- * This hack waits for any existing background tasks -- such as the one that
- * writes prefs -- to finish before we begin the test.
- */
- private void waitForBackgroundHappiness() {
- final Object signal = new Object();
- final Runnable done = new Runnable() {
- @Override
- public void run() {
- synchronized (signal) {
- signal.notify();
- }
- }
- };
- synchronized (signal) {
- ThreadUtils.postToBackgroundThread(done);
- try {
- signal.wait();
- } catch (InterruptedException e) {
- mAsserter.ok(false, "InterruptedException waiting on background thread.", e.toString());
- }
- }
- mAsserter.dumpLog("Background task completed. Proceeding.");
- }
-
- public void testDistribution() throws Exception {
- mActivity = getActivity();
-
- String mockPackagePath = getMockPackagePath();
-
- // Wait for any startup-related background distribution shenanigans to
- // finish. This reduces the chance of us racing with startup pref writes.
- waitForBackgroundHappiness();
-
- // Pre-clear distribution pref, run basic preferences and en-US localized preferences Tests
- clearDistributionPref();
- clearDistributionFromDataData();
-
- setTestLocale("en-US");
- try {
- initDistribution(mockPackagePath);
- } catch(NoSuchElementException e) {
- // TODO: determine why this exception is intermittently thrown
- Log.w(LOGTAG, "NoSuchElementException on first initDistribution -- will retry");
- mSolo.sleep(4000);
- initDistribution(mockPackagePath);
- }
- checkPreferences();
- checkAndroidPreferences();
- checkLocalizedPreferences("en-US");
- checkSearchPlugin();
- checkAddon();
-
- // Pre-clear distribution pref, and run es-MX localized preferences Test
- clearDistributionPref();
- clearDistributionFromDataData();
- setTestLocale("es-MX");
- initDistribution(mockPackagePath);
- checkLocalizedPreferences("es-MX");
-
- // Test the (stubbed) download interaction.
- setTestLocale("en-US");
- clearDistributionPref();
- clearDistributionFromDataData();
- doTestValidReferrerIntent();
-
- clearDistributionPref();
- clearDistributionFromDataData();
- doTestInvalidReferrerIntent();
- }
-
- private void setOSLocale(Locale locale) {
- Locale.setDefault(locale);
- BrowserLocaleManager.storeAndNotifyOSLocale(GeckoSharedPrefs.forProfile(mActivity), locale);
- }
-
- private abstract class ExpectNoDistributionCallback implements Distribution.ReadyCallback {
- @Override
- public void distributionFound(final Distribution distribution) {
- mAsserter.ok(false, "No distributionFound.", "Wasn't expecting a distribution!");
- synchronized (distribution) {
- distribution.notifyAll();
- }
- }
-
- @Override
- public void distributionArrivedLate(final Distribution distribution) {
- mAsserter.ok(false, "No distributionArrivedLate.", "Wasn't expecting a late distribution!");
- }
- }
-
- private void doReferrerTest(String ref, final TestableDistribution distribution, final Distribution.ReadyCallback distributionReady) throws InterruptedException {
- final Intent intent = new Intent(ACTION_INSTALL_REFERRER);
- intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, CLASS_REFERRER_RECEIVER);
- intent.putExtra("referrer", ref);
-
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.i(LOGTAG, "Test received " + intent.getAction());
-
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- distribution.addOnDistributionReadyCallback(distributionReady);
- distribution.go();
- }
- });
- }
- };
-
- IntentFilter intentFilter = new IntentFilter(ReferrerReceiver.ACTION_REFERRER_RECEIVED);
- final LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(mActivity);
- localBroadcastManager.registerReceiver(receiver, intentFilter);
-
- Log.i(LOGTAG, "Broadcasting referrer intent.");
- try {
- mActivity.sendBroadcast(intent, null);
- synchronized (distribution) {
- distribution.wait(WAIT_TIMEOUT_MSEC);
- }
- } finally {
- localBroadcastManager.unregisterReceiver(receiver);
- }
- }
-
- public void doTestValidReferrerIntent() throws Exception {
- // Equivalent to
- // am broadcast -a com.android.vending.INSTALL_REFERRER \
- // -n org.mozilla.fennec/org.mozilla.gecko.distribution.ReferrerReceiver \
- // --es "referrer" "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=distribution"
- final String ref = "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=distribution";
- final TestableDistribution distribution = new TestableDistribution(mActivity);
- final Distribution.ReadyCallback distributionReady = new ExpectNoDistributionCallback() {
- @Override
- public void distributionNotFound() {
- Log.i(LOGTAG, "Test told distribution processing is done.");
- mAsserter.ok(!distribution.exists(), "Not processed.", "No download because we're offline.");
- ReferrerDescriptor referrerValue = TestableDistribution.getReferrerDescriptorForTesting();
- mAsserter.dumpLog("Referrer was " + referrerValue);
- mAsserter.is(referrerValue.content, "testcontent", "Referrer content");
- mAsserter.is(referrerValue.medium, "testmedium", "Referrer medium");
- mAsserter.is(referrerValue.campaign, "distribution", "Referrer campaign");
- synchronized (distribution) {
- distribution.notifyAll();
- }
- }
- };
-
- doReferrerTest(ref, distribution, distributionReady);
- }
-
- /**
- * Test processing if the campaign isn't "distribution". The intent shouldn't
- * result in a download, and won't be saved as the temporary referrer,
- * even if we *do* include it in a Campaign:Set message.
- */
- public void doTestInvalidReferrerIntent() throws Exception {
- // Equivalent to
- // am broadcast -a com.android.vending.INSTALL_REFERRER \
- // -n org.mozilla.fennec/org.mozilla.gecko.distribution.ReferrerReceiver \
- // --es "referrer" "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=testname"
- final String ref = "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=testname";
- final TestableDistribution distribution = new TestableDistribution(mActivity);
- final Distribution.ReadyCallback distributionReady = new ExpectNoDistributionCallback() {
- @Override
- public void distributionNotFound() {
- mAsserter.ok(!distribution.exists(), "Not processed.", "No download because campaign was wrong.");
- ReferrerDescriptor referrerValue = TestableDistribution.getReferrerDescriptorForTesting();
- mAsserter.is(referrerValue, null, "No referrer.");
- synchronized (distribution) {
- distribution.notifyAll();
- }
- }
- };
-
- doReferrerTest(ref, distribution, distributionReady);
- }
-
- // Initialize the distribution from the mock package.
- private Distribution initDistribution(String aPackagePath) {
- // Call Distribution.init with the mock package.
- Actions.EventExpecter distributionSetExpecter = mActions.expectGeckoEvent("Distribution:Set:OK");
- Distribution dist = Distribution.init(mActivity, aPackagePath, "prefs-" + System.currentTimeMillis());
- distributionSetExpecter.blockForEvent();
- distributionSetExpecter.unregisterListener();
- DistroSharedPrefsImport.importPreferences(mActivity, dist);
- return dist;
- }
-
- // Test distribution and preferences values stored in preferences.json
- private void checkPreferences() {
- String prefID = "distribution.id";
- String prefAbout = "distribution.about";
- String prefVersion = "distribution.version";
- String prefTestBoolean = "distribution.test.boolean";
- String prefTestString = "distribution.test.string";
- String prefTestInt = "distribution.test.int";
-
- try {
- final String[] prefNames = { prefID,
- prefAbout,
- prefVersion,
- prefTestBoolean,
- prefTestString,
- prefTestInt };
-
- final JSONArray preferences = getPrefs(prefNames);
- for (int i = 0; i < preferences.length(); i++) {
- JSONObject pref = (JSONObject) preferences.get(i);
- String name = pref.getString("name");
-
- if (name.equals(prefID)) {
- mAsserter.is(pref.getString("value"), "test-partner", "check " + prefID);
- } else if (name.equals(prefAbout)) {
- mAsserter.is(pref.getString("value"), "Test Partner", "check " + prefAbout);
- } else if (name.equals(prefVersion)) {
- mAsserter.is(pref.getInt("value"), 1, "check " + prefVersion);
- } else if (name.equals(prefTestBoolean)) {
- mAsserter.is(pref.getBoolean("value"), true, "check " + prefTestBoolean);
- } else if (name.equals(prefTestString)) {
- mAsserter.is(pref.getString("value"), "test", "check " + prefTestString);
- } else if (name.equals(prefTestInt)) {
- mAsserter.is(pref.getInt("value"), 5, "check " + prefTestInt);
- }
- }
-
- } catch (JSONException e) {
- mAsserter.ok(false, "exception getting preferences", e.toString());
- }
- }
-
- private void checkAndroidPreferences() {
- final SharedPreferences sharedPreferences = GeckoSharedPrefs.forProfile(getActivity());
- String prefTestBoolean = "android.distribution.test.boolean";
- String prefTestString = "android.distribution.test.string";
- String prefTestInt = "android.distribution.test.int";
- String prefTestLong = "android.distribution.test.long";
-
- final String[] prefNames = { prefTestBoolean,
- prefTestString,
- prefTestInt,
- prefTestLong };
-
- try {
- for (String name : prefNames) {
- if (name.equals(prefTestBoolean)) {
- mAsserter.is(sharedPreferences.getBoolean(GeckoPreferences.NON_PREF_PREFIX + name, false), true, "check " + prefTestBoolean);
- } else if (name.equals(prefTestString)) {
- mAsserter.is(sharedPreferences.getString(GeckoPreferences.NON_PREF_PREFIX + name, ""), "test", "check " + prefTestString);
- } else if (name.equals(prefTestInt)) {
- mAsserter.is(sharedPreferences.getInt(GeckoPreferences.NON_PREF_PREFIX + name, 0), 1, "check " + prefTestInt);
- } else if (name.equals(prefTestLong)) {
- mAsserter.is(sharedPreferences.getLong(GeckoPreferences.NON_PREF_PREFIX + name, 0), 2147483648l, "check " + prefTestLong);
- }
- }
- } catch (ClassCastException e) {
- mAsserter.ok(false, "exception getting preferences", e.toString());
- }
- }
-
- private void checkSearchPlugin() {
- Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("SearchEngines:Data");
- mActions.sendGeckoEvent("SearchEngines:GetVisible", null);
-
- try {
- JSONObject data = new JSONObject(eventExpecter.blockForEventData());
- eventExpecter.unregisterListener();
- JSONArray searchEngines = data.getJSONArray("searchEngines");
- boolean foundEngine = false;
- for (int i = 0; i < searchEngines.length(); i++) {
- JSONObject engine = (JSONObject) searchEngines.get(i);
- String name = engine.getString("name");
- if (name.equals("Test search engine")) {
- foundEngine = true;
- break;
- }
- }
- mAsserter.ok(foundEngine, "check search plugin", "found test search plugin");
- } catch (JSONException e) {
- mAsserter.ok(false, "exception getting search plugins", e.toString());
- }
- }
-
- private void checkAddon() {
- try {
- final String[] prefNames = { "distribution.test.addonEnabled" };
- final JSONArray preferences = getPrefs(prefNames);
- final JSONObject pref = (JSONObject) preferences.get(0);
- mAsserter.is(pref.getBoolean("value"), true, "check distribution add-on is enabled");
- } catch (JSONException e) {
- mAsserter.ok(false, "exception getting preferences", e.toString());
- }
- }
-
- private JSONArray getPrefs(String[] prefNames) throws JSONException {
- final JSONArray result = new JSONArray();
-
- mActions.getPrefs(prefNames, new Actions.PrefHandlerBase() {
- private void addItem(String pref, Object value) {
- try {
- final JSONObject item = new JSONObject();
- item.put("name", pref).put("value", value);
- result.put(item);
- } catch (final JSONException e) {
- mAsserter.ok(false, "exception getting prefs", e.toString());
- }
- }
-
- @Override // Actions.PrefHandlerBase
- public void prefValue(String pref, boolean value) {
- addItem(pref, value);
- }
-
- @Override // Actions.PrefHandlerBase
- public void prefValue(String pref, int value) {
- addItem(pref, value);
- }
-
- @Override // Actions.PrefHandlerBase
- public void prefValue(String pref, String value) {
- addItem(pref, value);
- }
- }).waitForFinish();
-
- return result;
- }
-
- // Sets the distribution locale preference for the test.
- private void setTestLocale(String locale) {
- BrowserLocaleManager.getInstance().setSelectedLocale(mActivity, locale);
- }
-
- // Test localized distribution and preferences values stored in preferences.json
- private void checkLocalizedPreferences(final String aLocale) {
- final String prefAbout = "distribution.about";
- final String prefLocalizeable = "distribution.test.localizeable";
- final String prefLocalizeableOverride = "distribution.test.localizeable-override";
- final String[] prefNames = { prefAbout, prefLocalizeable, prefLocalizeableOverride };
-
- mActions.getPrefs(prefNames, new Actions.PrefHandlerBase() {
- @Override // Actions.PrefHandlerBase
- public void prefValue(String name, String value) {
- if (name.equals(prefAbout)) {
- if (aLocale.equals("en-US")) {
- mAsserter.is(value, "Test Partner", "check " + prefAbout);
- } else if (aLocale.equals("es-MX")) {
- mAsserter.is(value, "Afiliado de Prueba", "check " + prefAbout);
- }
- } else if (name.equals(prefLocalizeable)) {
- if (aLocale.equals("en-US")) {
- mAsserter.is(value, "http://test.org/en-US/en-US/", "check " + prefLocalizeable);
- } else if (aLocale.equals("es-MX")) {
- mAsserter.is(value, "http://test.org/es-MX/es-MX/", "check " + prefLocalizeable);
- }
- } else if (name.equals(prefLocalizeableOverride)) {
- if (aLocale.equals("en-US")) {
- mAsserter.is(value, "http://cheese.com", "check " + prefLocalizeableOverride);
- } else if (aLocale.equals("es-MX")) {
- mAsserter.is(value, "http://test.org/es-MX/", "check " + prefLocalizeableOverride);
- }
- } else {
- // Raise exception.
- super.prefValue(name, value);
- }
- }
- }).waitForFinish();
- }
-
- // Copies the mock package to the data directory and returns the file path to it.
- private String getMockPackagePath() {
- String mockPackagePath = "";
-
- try {
- InputStream inStream = getAsset(MOCK_PACKAGE);
- File dataDir = new File(mActivity.getApplicationInfo().dataDir);
- File outFile = new File(dataDir, MOCK_PACKAGE);
-
- OutputStream outStream = new FileOutputStream(outFile);
- int b;
- while ((b = inStream.read()) != -1) {
- outStream.write(b);
- }
- inStream.close();
- outStream.close();
-
- mockPackagePath = outFile.getPath();
-
- } catch (Exception e) {
- mAsserter.ok(false, "exception copying mock distribution package to data directory", e.toString());
- }
-
- return mockPackagePath;
- }
-
- /**
- * Clears the distribution pref to return distribution state to STATE_UNKNOWN,
- * and wipes the in-memory referrer pigeonhole.
- */
- private void clearDistributionPref() {
- mAsserter.dumpLog("Clearing distribution pref.");
- SharedPreferences settings = mActivity.getSharedPreferences("GeckoApp", Activity.MODE_PRIVATE);
- String keyName = mActivity.getPackageName() + ".distribution_state";
- settings.edit().remove(keyName).commit();
- TestableDistribution.clearReferrerDescriptorForTesting();
- }
-
- /**
- * Clears any distribution found in /data/data.
- */
- private void clearDistributionFromDataData() throws Exception {
- File dataDir = new File(mActivity.getApplicationInfo().dataDir);
-
- // Recursively delete distribution files that Distribution.init copied to data directory.
- File distDir = new File(dataDir, "distribution");
- if (distDir.exists()) {
- mAsserter.dumpLog("Clearing distribution from " + distDir.getAbsolutePath());
- delete(distDir);
- } else {
- mAsserter.dumpLog("No distribution to clear from " + distDir.getAbsolutePath());
- }
- }
-
- @Override
- public void setUp() throws Exception {
- // TODO: Set up the content provider after setting the distribution.
- super.setUp(sBrowserProviderCallable, BrowserContract.AUTHORITY, "browser.db");
- }
-
- private void delete(File file) throws Exception {
- if (file.isDirectory()) {
- File[] files = file.listFiles();
- for (File f : files) {
- delete(f);
- }
- }
- mAsserter.ok(file.delete(), "clean up distribution files", "deleted " + file.getPath());
- }
-
- @Override
- public void tearDown() throws Exception {
- File dataDir = new File(mActivity.getApplicationInfo().dataDir);
-
- // Delete mock package from data directory.
- File mockPackage = new File(dataDir, MOCK_PACKAGE);
- mAsserter.ok(mockPackage.delete(), "clean up mock package", "deleted " + mockPackage.getPath());
-
- clearDistributionFromDataData();
- clearDistributionPref();
-
- super.tearDown();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDoorHanger.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDoorHanger.java
deleted file mode 100644
index 2c3feb3a8..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testDoorHanger.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.widget.CheckBox;
-import android.view.View;
-import com.robotium.solo.Condition;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.gecko.Actions;
-
-/* This test will test if doorhangers are displayed and dismissed
- The test will test:
- * geolocation doorhangers - sharing and not sharing the location dismisses the doorhanger
- * opening a new tab hides the doorhanger
- * offline storage permission doorhangers - allowing and not allowing offline storage dismisses the doorhanger
- * Password Manager doorhangers - Remember and Not Now options dismiss the doorhanger
-*/
-public class testDoorHanger extends BaseTest {
- private boolean offlineAllowedByDefault = true;
-
- public void testDoorHanger() {
- String GEO_URL = getAbsoluteUrl(mStringHelper.ROBOCOP_GEOLOCATION_URL);
- String BLANK_URL = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- String OFFLINE_STORAGE_URL = getAbsoluteUrl(mStringHelper.ROBOCOP_OFFLINE_STORAGE_URL);
-
- blockForGeckoReady();
-
- // Test geolocation notification
- loadUrlAndWait(GEO_URL);
- waitForText(mStringHelper.GEO_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.GEO_MESSAGE), true, "Geolocation doorhanger has been displayed");
-
- // Test "Share" button hides the notification
- waitForCheckBox();
- mSolo.clickOnCheckBox(0);
- mSolo.clickOnButton(mStringHelper.GEO_ALLOW);
- waitForTextDismissed(mStringHelper.GEO_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.GEO_MESSAGE), false, "Geolocation doorhanger has been hidden when allowing share");
-
- // Re-trigger geolocation notification
- loadUrlAndWait(GEO_URL);
- waitForText(mStringHelper.GEO_MESSAGE);
-
- // Test "Don't share" button hides the notification
- waitForCheckBox();
- mSolo.clickOnCheckBox(0);
- mSolo.clickOnButton(mStringHelper.GEO_DENY);
- waitForTextDismissed(mStringHelper.GEO_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.GEO_MESSAGE), false, "Geolocation doorhanger has been hidden when denying share");
-
- /* FIXME: disabled on fig - bug 880060 (for some reason this fails because of some raciness)
- // Re-trigger geolocation notification
- loadUrlAndWait(GEO_URL);
- waitForText(GEO_MESSAGE);
-
- // Add a new tab
- addTab(BLANK_URL);
-
- // Make sure doorhanger is hidden
- mAsserter.is(mSolo.searchText(GEO_MESSAGE), false, "Geolocation doorhanger notification is hidden when opening a new tab");
- */
-
- // Save offline-allow-by-default preferences first
- mActions.getPrefs(new String[] { "offline-apps.allow_by_default" },
- new Actions.PrefHandlerBase() {
- @Override // Actions.PrefHandlerBase
- public void prefValue(String pref, boolean value) {
- mAsserter.is(pref, "offline-apps.allow_by_default", "Expecting correct pref name");
- offlineAllowedByDefault = value;
- }
- }).waitForFinish();
-
- setPreferenceAndWaitForChange("offline-apps.allow_by_default", false);
-
- // Load offline storage page
- loadUrlAndWait(OFFLINE_STORAGE_URL);
- waitForText(mStringHelper.OFFLINE_MESSAGE);
-
- // Test doorhanger dismissed when tapping "Don't share"
- waitForCheckBox();
- mSolo.clickOnCheckBox(0);
- mSolo.clickOnButton(mStringHelper.OFFLINE_DENY);
- waitForTextDismissed(mStringHelper.OFFLINE_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.OFFLINE_MESSAGE), false, "Offline storage doorhanger notification is hidden when denying storage");
-
- // Load offline storage page
- loadUrlAndWait(OFFLINE_STORAGE_URL);
- waitForText(mStringHelper.OFFLINE_MESSAGE);
-
- // Test doorhanger dismissed when tapping "Allow" and is not displayed again
- mSolo.clickOnButton(mStringHelper.OFFLINE_ALLOW);
- waitForTextDismissed(mStringHelper.OFFLINE_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.OFFLINE_MESSAGE), false, "Offline storage doorhanger notification is hidden when allowing storage");
- loadUrlAndWait(OFFLINE_STORAGE_URL);
- mAsserter.is(mSolo.searchText(mStringHelper.OFFLINE_MESSAGE), false, "Offline storage doorhanger is no longer triggered");
-
- // Revert offline setting
- setPreferenceAndWaitForChange("offline-apps.allow_by_default", offlineAllowedByDefault);
-
- // Load new login page
- loadUrlAndWait(getAbsoluteUrl(mStringHelper.ROBOCOP_LOGIN_01_URL));
- waitForText(mStringHelper.LOGIN_MESSAGE);
-
- // Test doorhanger is dismissed when tapping "Remember".
- mSolo.clickOnButton(mStringHelper.LOGIN_ALLOW);
- waitForTextDismissed(mStringHelper.LOGIN_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.LOGIN_MESSAGE), false, "Login doorhanger notification is hidden when allowing saving password");
-
- // Load login page
- loadUrlAndWait(getAbsoluteUrl(mStringHelper.ROBOCOP_LOGIN_02_URL));
- waitForText(mStringHelper.LOGIN_MESSAGE);
-
- // Test doorhanger is dismissed when tapping "Never".
- mSolo.clickOnButton(mStringHelper.LOGIN_DENY);
- waitForTextDismissed(mStringHelper.LOGIN_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.LOGIN_MESSAGE), false, "Login doorhanger notification is hidden when denying saving password");
-
- testPopupBlocking();
- }
-
- private void testPopupBlocking() {
- String POPUP_URL = getAbsoluteUrl(mStringHelper.ROBOCOP_POPUP_URL);
-
- setPreferenceAndWaitForChange("dom.disable_open_during_load", true);
-
- // Load page with popup
- loadUrlAndWait(POPUP_URL);
- waitForText(mStringHelper.POPUP_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.POPUP_MESSAGE), true, "Popup blocker is displayed");
-
- // Wait for the popup to be shown.
- Actions.EventExpecter tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
-
- waitForCheckBox();
- mSolo.clickOnCheckBox(0);
- mSolo.clickOnButton(mStringHelper.POPUP_ALLOW);
- waitForTextDismissed(mStringHelper.POPUP_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.POPUP_MESSAGE), false, "Popup blocker is hidden when popup allowed");
-
- try {
- final JSONObject data = new JSONObject(tabEventExpecter.blockForEventData());
-
- // Check to make sure the popup window was opened.
- mAsserter.is("data:text/plain;charset=utf-8,a", data.getString("uri"), "Checking popup URL");
-
- // Close the popup window.
- closeTab(data.getInt("tabID"));
-
- } catch (JSONException e) {
- mAsserter.ok(false, "exception getting event data", e.toString());
- }
- tabEventExpecter.unregisterListener();
-
- // Load page with popup
- loadUrlAndWait(POPUP_URL);
- waitForText(mStringHelper.POPUP_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.POPUP_MESSAGE), true, "Popup blocker is displayed");
-
- waitForCheckBox();
- mSolo.clickOnCheckBox(0);
- mSolo.clickOnButton(mStringHelper.POPUP_DENY);
- waitForTextDismissed(mStringHelper.POPUP_MESSAGE);
- mAsserter.is(mSolo.searchText(mStringHelper.POPUP_MESSAGE), false, "Popup blocker is hidden when popup denied");
-
- // Check that we're on the same page to verify that the popup was not shown.
- verifyUrl(POPUP_URL);
-
- setPreferenceAndWaitForChange("dom.disable_open_during_load", false);
- }
-
- // wait for a CheckBox view that is clickable
- private void waitForCheckBox() {
- waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- for (CheckBox view : mSolo.getCurrentViews(CheckBox.class)) {
- // checking isClickable alone is not sufficient --
- // intermittent "cannot click" errors persist unless
- // additional checks are used
- if (view.isClickable() &&
- view.getVisibility() == View.VISIBLE &&
- view.getWidth() > 0 &&
- view.getHeight() > 0) {
- return true;
- }
- }
- return false;
- }
- }, MAX_WAIT_MS);
- }
-
- // wait until the specified text is *not* displayed
- private void waitForTextDismissed(final String text) {
- waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return !mSolo.searchText(text);
- }
- }, MAX_WAIT_MS);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testEventDispatcher.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testEventDispatcher.java
deleted file mode 100644
index ad40459d5..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testEventDispatcher.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.*;
-
-import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.util.BundleEventListener;
-import org.mozilla.gecko.util.EventCallback;
-import org.mozilla.gecko.util.GeckoEventListener;
-import org.mozilla.gecko.util.NativeEventListener;
-import org.mozilla.gecko.util.NativeJSObject;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import android.os.Bundle;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Tests the proper operation of EventDispatcher,
- * including associated NativeJSObject objects.
- */
-public class testEventDispatcher extends JavascriptBridgeTest
- implements BundleEventListener, GeckoEventListener, NativeEventListener {
-
- private static final String TEST_JS = "testEventDispatcher.js";
- private static final String GECKO_EVENT = "Robocop:TestGeckoEvent";
- private static final String GECKO_RESPONSE_EVENT = "Robocop:TestGeckoResponse";
- private static final String NATIVE_EVENT = "Robocop:TestNativeEvent";
- private static final String NATIVE_RESPONSE_EVENT = "Robocop:TestNativeResponse";
- private static final String NATIVE_EXCEPTION_EVENT = "Robocop:TestNativeException";
- private static final String UI_EVENT = "Robocop:TestUIEvent";
- private static final String UI_RESPONSE_EVENT = "Robocop:TestUIResponse";
- private static final String BACKGROUND_EVENT = "Robocop:TestBackgroundEvent";
- private static final String BACKGROUND_RESPONSE_EVENT = "Robocop:TestBackgrondResponse";
-
- private static final long WAIT_FOR_BUNDLE_EVENT_TIMEOUT_MILLIS = 20000; // 20 seconds
-
- private NativeJSObject savedMessage;
-
- private boolean handledGeckoEvent;
- private boolean handledNativeEvent;
- private boolean handledAsyncEvent;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- EventDispatcher.getInstance().registerGeckoThreadListener(
- (GeckoEventListener) this, GECKO_EVENT, GECKO_RESPONSE_EVENT);
- EventDispatcher.getInstance().registerGeckoThreadListener(
- (NativeEventListener) this,
- NATIVE_EVENT, NATIVE_RESPONSE_EVENT, NATIVE_EXCEPTION_EVENT);
- EventDispatcher.getInstance().registerUiThreadListener(
- this, UI_EVENT, UI_RESPONSE_EVENT);
- EventDispatcher.getInstance().registerBackgroundThreadListener(
- this, BACKGROUND_EVENT, BACKGROUND_RESPONSE_EVENT);
- }
-
- @Override
- public void tearDown() throws Exception {
- EventDispatcher.getInstance().unregisterGeckoThreadListener(
- (GeckoEventListener) this, GECKO_EVENT, GECKO_RESPONSE_EVENT);
- EventDispatcher.getInstance().unregisterGeckoThreadListener(
- (NativeEventListener) this,
- NATIVE_EVENT, NATIVE_RESPONSE_EVENT, NATIVE_EXCEPTION_EVENT);
- EventDispatcher.getInstance().unregisterUiThreadListener(
- this, UI_EVENT, UI_RESPONSE_EVENT);
- EventDispatcher.getInstance().unregisterBackgroundThreadListener(
- this, BACKGROUND_EVENT, BACKGROUND_RESPONSE_EVENT);
-
- super.tearDown();
- }
-
- private synchronized void waitForAsyncEvent() {
- final long startTime = System.nanoTime();
- while (!handledAsyncEvent) {
- if (System.nanoTime() - startTime
- >= WAIT_FOR_BUNDLE_EVENT_TIMEOUT_MILLIS * 1e6 /* ns per ms */) {
- fFail("Should have completed event before timeout");
- }
- try {
- wait(1000); // Wait for 1 second at a time.
- } catch (final InterruptedException e) {
- // Attempt waiting again.
- }
- }
- handledAsyncEvent = false;
- }
-
- private synchronized void notifyAsyncEvent() {
- handledAsyncEvent = true;
- notifyAll();
- }
-
- public void testEventDispatcher() {
- blockForReadyAndLoadJS(TEST_JS);
-
- getJS().syncCall("send_test_message", GECKO_EVENT);
- fAssertTrue("Should have handled Gecko event synchronously", handledGeckoEvent);
-
- getJS().syncCall("send_message_for_response", GECKO_RESPONSE_EVENT, "success");
- getJS().syncCall("send_message_for_response", GECKO_RESPONSE_EVENT, "error");
-
- getJS().syncCall("send_test_message", NATIVE_EVENT);
- fAssertTrue("Should have handled native event synchronously", handledNativeEvent);
-
- getJS().syncCall("send_message_for_response", NATIVE_RESPONSE_EVENT, "success");
- getJS().syncCall("send_message_for_response", NATIVE_RESPONSE_EVENT, "error");
-
- getJS().syncCall("send_test_message", NATIVE_EXCEPTION_EVENT);
-
- getJS().syncCall("send_test_message", UI_EVENT);
- waitForAsyncEvent();
-
- getJS().syncCall("send_message_for_response", UI_RESPONSE_EVENT, "success");
- waitForAsyncEvent();
-
- getJS().syncCall("send_message_for_response", UI_RESPONSE_EVENT, "error");
- waitForAsyncEvent();
-
- getJS().syncCall("send_test_message", BACKGROUND_EVENT);
- waitForAsyncEvent();
-
- getJS().syncCall("send_message_for_response", BACKGROUND_RESPONSE_EVENT, "success");
- waitForAsyncEvent();
-
- getJS().syncCall("send_message_for_response", BACKGROUND_RESPONSE_EVENT, "error");
- waitForAsyncEvent();
-
- getJS().syncCall("finish_test");
- }
-
- @Override
- public void handleMessage(final String event, final Bundle message,
- final EventCallback callback) {
-
- if (UI_EVENT.equals(event) || UI_RESPONSE_EVENT.equals(event)) {
- fAssertTrue("UI event should be on UI thread", ThreadUtils.isOnUiThread());
-
- } else if (BACKGROUND_EVENT.equals(event) || BACKGROUND_RESPONSE_EVENT.equals(event)) {
- fAssertTrue("Background event should be on background thread",
- ThreadUtils.isOnBackgroundThread());
-
- } else {
- fFail("Event type should be valid: " + event);
- }
-
- if (UI_EVENT.equals(event) || BACKGROUND_EVENT.equals(event)) {
- checkBundle(message);
- checkBundle(message.getBundle("object"));
-
- } else if (UI_RESPONSE_EVENT.equals(event) || BACKGROUND_RESPONSE_EVENT.equals(event)) {
- final String response = message.getString("response");
- if ("success".equals(response)) {
- callback.sendSuccess(response);
- } else if ("error".equals(response)) {
- callback.sendError(response);
- } else {
- fFail("Response type should be valid: " + response);
- }
-
- } else {
- fFail("Event type should be valid: " + event);
- }
-
- notifyAsyncEvent();
- }
-
- @Override
- public void handleMessage(final String event, final JSONObject message) {
- ThreadUtils.assertOnGeckoThread();
-
- try {
- if (GECKO_EVENT.equals(event)) {
- checkJSONObject(message);
- checkJSONObject(message.getJSONObject("object"));
- handledGeckoEvent = true;
-
- } else if (GECKO_RESPONSE_EVENT.equals(event)) {
- final String response = message.getString("response");
- if ("success".equals(response)) {
- EventDispatcher.sendResponse(message, response);
- } else if ("error".equals(response)) {
- EventDispatcher.sendError(message, response);
- } else {
- fFail("Response type should be valid: " + response);
- }
-
- } else {
- fFail("Event type should be valid: " + event);
- }
- } catch (final JSONException e) {
- fFail(e.toString());
- }
- }
-
- @Override
- public void handleMessage(final String event, final NativeJSObject message,
- final EventCallback callback) {
- ThreadUtils.assertOnGeckoThread();
-
- if (NATIVE_EVENT.equals(event)) {
- checkNativeJSObject(message);
- checkNativeJSObject(message.getObject("object"));
- fAssertNotSame("optObject returns existent value",
- null, message.optObject("object", null));
- fAssertSame("optObject returns fallback value if nonexistent",
- null, message.optObject("nonexistent_object", null));
-
- final NativeJSObject[] objectArray = message.getObjectArray("objectArray");
- fAssertNotNull("Native object array should exist", objectArray);
- fAssertEquals("Native object array has correct length", 2, objectArray.length);
- fAssertSame("Native object array index 0 has correct value", null, objectArray[0]);
- fAssertNotSame("Native object array index 1 has correct value", null, objectArray[1]);
- checkNativeJSObject(objectArray[1]);
- fAssertNotSame("optObjectArray returns existent value",
- null, message.optObjectArray("objectArray", null));
- fAssertSame("optObjectArray returns fallback value if nonexistent",
- null, message.optObjectArray("nonexistent_objectArray", null));
-
- final Bundle bundle = message.toBundle();
- checkBundle(bundle);
- checkBundle(bundle.getBundle("object"));
- fAssertNotSame("optBundle returns property value if it exists",
- null, message.optBundle("object", null));
- fAssertSame("optBundle returns fallback value if property does not exist",
- null, message.optBundle("nonexistent_object", null));
-
- final Bundle[] bundleArray = message.getBundleArray("objectArray");
- fAssertNotNull("Native bundle array should exist", bundleArray);
- fAssertEquals("Native bundle array has correct length", 2, bundleArray.length);
- fAssertSame("Native bundle array index 0 has correct value", null, bundleArray[0]);
- fAssertNotSame("Native bundle array index 1 has correct value", null, bundleArray[1]);
- checkBundle(bundleArray[1]);
- fAssertNotSame("optBundleArray returns existent value",
- null, message.optBundleArray("objectArray", null));
- fAssertSame("optBundleArray returns fallback value if nonexistent",
- null, message.optBundleArray("nonexistent_objectArray", null));
-
- handledNativeEvent = true;
-
- } else if (NATIVE_RESPONSE_EVENT.equals(event)) {
- final String response = message.getString("response");
- if ("success".equals(response)) {
- callback.sendSuccess(response);
- } else if ("error".equals(response)) {
- callback.sendError(response);
- } else {
- fFail("Response type should be valid: " + response);
- }
-
- // Save this message for post-disposal check.
- savedMessage = message;
-
- } else if (NATIVE_EXCEPTION_EVENT.equals(event)) {
- // Make sure we throw the right exceptions.
- try {
- message.getString(null);
- fFail("null property name should throw IllegalArgumentException");
- } catch (final IllegalArgumentException e) {
- }
-
- try {
- message.getString("nonexistent_string");
- fFail("Nonexistent property name should throw InvalidPropertyException");
- } catch (final NativeJSObject.InvalidPropertyException e) {
- }
-
- try {
- message.getString("int");
- fFail("Wrong property type should throw InvalidPropertyException");
- } catch (final NativeJSObject.InvalidPropertyException e) {
- }
-
- fAssertNotSame("Should have saved a message", null, savedMessage);
- try {
- savedMessage.toString();
- fFail("Using NativeJSContainer should throw after disposal");
- } catch (final NullPointerException e) {
- }
-
- // Save this test for last; make sure EventDispatcher catches InvalidPropertyException.
- message.getString("nonexistent_string");
- fFail("EventDispatcher should catch InvalidPropertyException");
-
- } else {
- fFail("Event type should be valid: " + event);
- }
- }
-
- private void checkBundle(final Bundle bundle) {
- fAssertEquals("Bundle boolean has correct value", true, bundle.getBoolean("boolean"));
- fAssertEquals("Bundle int has correct value", 1, bundle.getInt("int"));
- fAssertEquals("Bundle double has correct value", 0.5, bundle.getDouble("double"));
- fAssertEquals("Bundle string has correct value", "foo", bundle.getString("string"));
-
- final boolean[] booleanArray = bundle.getBooleanArray("booleanArray");
- fAssertNotNull("Bundle boolean array should exist", booleanArray);
- fAssertEquals("Bundle boolean array has correct length", 2, booleanArray.length);
- fAssertEquals("Bundle boolean array index 0 has correct value", false, booleanArray[0]);
- fAssertEquals("Bundle boolean array index 1 has correct value", true, booleanArray[1]);
-
- final int[] intArray = bundle.getIntArray("intArray");
- fAssertNotNull("Bundle int array should exist", intArray);
- fAssertEquals("Bundle int array has correct length", 2, intArray.length);
- fAssertEquals("Bundle int array index 0 has correct value", 2, intArray[0]);
- fAssertEquals("Bundle int array index 1 has correct value", 3, intArray[1]);
-
- final double[] doubleArray = bundle.getDoubleArray("doubleArray");
- fAssertNotNull("Bundle double array should exist", doubleArray);
- fAssertEquals("Bundle double array has correct length", 2, doubleArray.length);
- fAssertEquals("Bundle double array index 0 has correct value", 1.5, doubleArray[0]);
- fAssertEquals("Bundle double array index 1 has correct value", 2.5, doubleArray[1]);
-
- final String[] stringArray = bundle.getStringArray("stringArray");
- fAssertNotNull("Bundle string array should exist", stringArray);
- fAssertEquals("Bundle string array has correct length", 2, stringArray.length);
- fAssertEquals("Bundle string array index 0 has correct value", "bar", stringArray[0]);
- fAssertEquals("Bundle string array index 1 has correct value", "baz", stringArray[1]);
- }
-
- private void checkJSONObject(final JSONObject object) throws JSONException {
- fAssertEquals("JSON boolean has correct value", true, object.getBoolean("boolean"));
- fAssertEquals("JSON int has correct value", 1, object.getInt("int"));
- fAssertEquals("JSON double has correct value", 0.5, object.getDouble("double"));
- fAssertEquals("JSON string has correct value", "foo", object.getString("string"));
-
- final JSONArray booleanArray = object.getJSONArray("booleanArray");
- fAssertNotNull("JSON boolean array should exist", booleanArray);
- fAssertEquals("JSON boolean array has correct length", 2, booleanArray.length());
- fAssertEquals("JSON boolean array index 0 has correct value",
- false, booleanArray.getBoolean(0));
- fAssertEquals("JSON boolean array index 1 has correct value",
- true, booleanArray.getBoolean(1));
-
- final JSONArray intArray = object.getJSONArray("intArray");
- fAssertNotNull("JSON int array should exist", intArray);
- fAssertEquals("JSON int array has correct length", 2, intArray.length());
- fAssertEquals("JSON int array index 0 has correct value",
- 2, intArray.getInt(0));
- fAssertEquals("JSON int array index 1 has correct value",
- 3, intArray.getInt(1));
-
- final JSONArray doubleArray = object.getJSONArray("doubleArray");
- fAssertNotNull("JSON double array should exist", doubleArray);
- fAssertEquals("JSON double array has correct length", 2, doubleArray.length());
- fAssertEquals("JSON double array index 0 has correct value",
- 1.5, doubleArray.getDouble(0));
- fAssertEquals("JSON double array index 1 has correct value",
- 2.5, doubleArray.getDouble(1));
-
- final JSONArray stringArray = object.getJSONArray("stringArray");
- fAssertNotNull("JSON string array should exist", stringArray);
- fAssertEquals("JSON string array has correct length", 2, stringArray.length());
- fAssertEquals("JSON string array index 0 has correct value",
- "bar", stringArray.getString(0));
- fAssertEquals("JSON string array index 1 has correct value",
- "baz", stringArray.getString(1));
- }
-
- private void checkNativeJSObject(final NativeJSObject object) {
- fAssertEquals("Native boolean has correct value",
- true, object.getBoolean("boolean"));
- fAssertEquals("optBoolean returns existent value",
- true, object.optBoolean("boolean", false));
- fAssertEquals("optBoolean returns fallback value if nonexistent",
- false, object.optBoolean("nonexistent_boolean", false));
-
- fAssertEquals("Native int has correct value",
- 1, object.getInt("int"));
- fAssertEquals("optInt returns existent value",
- 1, object.optInt("int", 0));
- fAssertEquals("optInt returns fallback value if nonexistent",
- 0, object.optInt("nonexistent_int", 0));
-
- fAssertEquals("Native double has correct value",
- 0.5, object.getDouble("double"));
- fAssertEquals("optDouble returns existent value",
- 0.5, object.optDouble("double", -0.5));
- fAssertEquals("optDouble returns fallback value if nonexistent",
- -0.5, object.optDouble("nonexistent_double", -0.5));
-
- fAssertEquals("Native string has correct value",
- "foo", object.getString("string"));
- fAssertEquals("optDouble returns existent value",
- "foo", object.optString("string", "bar"));
- fAssertEquals("optDouble returns fallback value if nonexistent",
- "bar", object.optString("nonexistent_string", "bar"));
-
- final boolean[] booleanArray = object.getBooleanArray("booleanArray");
- fAssertNotNull("Native boolean array should exist", booleanArray);
- fAssertEquals("Native boolean array has correct length", 2, booleanArray.length);
- fAssertEquals("Native boolean array index 0 has correct value", false, booleanArray[0]);
- fAssertEquals("Native boolean array index 1 has correct value", true, booleanArray[1]);
- fAssertNotSame("optBooleanArray returns existent value",
- null, object.optBooleanArray("booleanArray", null));
- fAssertSame("optBooleanArray returns fallback value if nonexistent",
- null, object.optBooleanArray("nonexistent_booleanArray", null));
-
- final int[] intArray = object.getIntArray("intArray");
- fAssertNotNull("Native int array should exist", intArray);
- fAssertEquals("Native int array has correct length", 2, intArray.length);
- fAssertEquals("Native int array index 0 has correct value", 2, intArray[0]);
- fAssertEquals("Native int array index 1 has correct value", 3, intArray[1]);
- fAssertNotSame("optIntArray returns existent value",
- null, object.optIntArray("intArray", null));
- fAssertSame("optIntArray returns fallback value if nonexistent",
- null, object.optIntArray("nonexistent_intArray", null));
-
- final double[] doubleArray = object.getDoubleArray("doubleArray");
- fAssertNotNull("Native double array should exist", doubleArray);
- fAssertEquals("Native double array has correct length", 2, doubleArray.length);
- fAssertEquals("Native double array index 0 has correct value", 1.5, doubleArray[0]);
- fAssertEquals("Native double array index 1 has correct value", 2.5, doubleArray[1]);
- fAssertNotSame("optDoubleArray returns existent value",
- null, object.optDoubleArray("doubleArray", null));
- fAssertSame("optDoubleArray returns fallback value if nonexistent",
- null, object.optDoubleArray("nonexistent_doubleArray", null));
-
- final String[] stringArray = object.getStringArray("stringArray");
- fAssertNotNull("Native string array should exist", stringArray);
- fAssertEquals("Native string array has correct length", 2, stringArray.length);
- fAssertEquals("Native string array index 0 has correct value", "bar", stringArray[0]);
- fAssertEquals("Native string array index 1 has correct value", "baz", stringArray[1]);
- fAssertNotSame("optStringArray returns existent value",
- null, object.optStringArray("stringArray", null));
- fAssertSame("optStringArray returns fallback value if nonexistent",
- null, object.optStringArray("nonexistent_stringArray", null));
-
- fAssertEquals("Native has(null) is false", false, object.has("null"));
- fAssertEquals("Native has(emptyString) is true", true, object.has("emptyString"));
-
- fAssertEquals("Native optBoolean returns fallback value if null",
- true, object.optBoolean("null", true));
- fAssertEquals("Native optInt returns fallback value if null",
- 42, object.optInt("null", 42));
- fAssertEquals("Native optDouble returns fallback value if null",
- -3.1415926535, object.optDouble("null", -3.1415926535));
- fAssertEquals("Native optString returns fallback value if null",
- "baz", object.optString("null", "baz"));
-
- fAssertNotEquals("Native optString does not return fallback value if emptyString",
- "baz", object.optString("emptyString", "baz"));
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFilePicker.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFilePicker.java
deleted file mode 100644
index c613eca8f..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFilePicker.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail;
-
-import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.GeckoApp;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.util.GeckoEventListener;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-public class testFilePicker extends JavascriptTest implements GeckoEventListener {
- private static final String TEST_FILENAME = "/mnt/sdcard/my-favorite-martian.png";
-
- public testFilePicker() {
- super("testFilePicker.js");
- }
-
- @Override
- public void handleMessage(String event, final JSONObject message) {
- // We handle the FilePicker message here so we can send back hard coded file information. We
- // don't want to try to emulate "picking" a file using the Android intent chooser.
- if (event.equals("FilePicker:Show")) {
- try {
- message.put("file", TEST_FILENAME);
- } catch (JSONException ex) {
- fFail("Can't add filename to message " + TEST_FILENAME);
- }
-
- mActions.sendGeckoEvent("FilePicker:Result", message.toString());
- }
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- GeckoApp.getEventDispatcher().registerGeckoThreadListener(this, "FilePicker:Show");
- }
-
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
-
- GeckoApp.getEventDispatcher().unregisterGeckoThreadListener(this, "FilePicker:Show");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFilterOpenTab.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFilterOpenTab.java
deleted file mode 100644
index 3c57b864a..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFilterOpenTab.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.PrivateTab;
-import org.mozilla.gecko.Tab;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.TabsProvider;
-
-import android.content.ContentProvider;
-import android.content.Context;
-import android.database.Cursor;
-
-/**
- * Tests that local tabs are filtered prior to upload.
- * - create a set of tabs and persists them through TabsAccessor.
- * - verifies that tabs are filtered by querying.
- */
-public class testFilterOpenTab extends ContentProviderTest {
- private static final String[] TABS_PROJECTION_COLUMNS = new String[] {
- BrowserContract.Tabs.TITLE,
- BrowserContract.Tabs.URL,
- BrowserContract.Clients.GUID,
- BrowserContract.Clients.NAME
- };
-
- private static final String LOCAL_TABS_SELECTION = BrowserContract.Tabs.CLIENT_GUID + " IS NULL";
-
- /**
- * Factory function that makes new ContentProvider instances.
- * <p>
- * We want a fresh provider each test, so this should be invoked in
- * <code>setUp</code> before each individual test.
- */
- protected static Callable<ContentProvider> sTabProviderCallable = new Callable<ContentProvider>() {
- @Override
- public ContentProvider call() {
- return new TabsProvider();
- }
- };
-
- private Cursor getTabsFromLocalClient() throws Exception {
- return mProvider.query(BrowserContract.Tabs.CONTENT_URI,
- TABS_PROJECTION_COLUMNS,
- LOCAL_TABS_SELECTION,
- null,
- null);
- }
-
- private Tab createTab(int id, String url, boolean external, int parentId, String title) {
- return new Tab((Context) getActivity(), id, url, external, parentId, title);
- }
-
- private Tab createPrivateTab(int id, String url, boolean external, int parentId, String title) {
- return new PrivateTab((Context) getActivity(), id, url, external, parentId, title);
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp(sTabProviderCallable, BrowserContract.TABS_AUTHORITY, "tabs.db");
- mTests.add(new TestInsertLocalTabs());
- }
-
- public void testFilterOpenTab() throws Exception {
- blockForGeckoReady();
-
- for (int i = 0; i < mTests.size(); i++) {
- Runnable test = mTests.get(i);
-
- setTestName(test.getClass().getSimpleName());
- test.run();
- }
- }
-
- private class TestInsertLocalTabs extends TestCase {
- @Override
- public void test() throws Exception {
- final String TITLE1 = "Google";
- final String URL1 = "http://www.google.com/";
- final String TITLE2 = "Mozilla Start Page";
- final String URL2 = "about:home";
- final String TITLE3 = "Chrome Weave URL";
- final String URL3 = "chrome://weave/";
- final String TITLE4 = "What You Cache Is What You Get";
- final String URL4 = "wyciwyg://1/test.com";
- final String TITLE5 = "Root Folder";
- final String URL5 = "file:///";
-
- // Create a list of local tabs.
- List<Tab> tabs = new ArrayList<Tab>(6);
- Tab tab1 = createTab(1, URL1, false, 0, TITLE1);
- Tab tab2 = createTab(2, URL2, false, 0, TITLE2);
- Tab tab3 = createTab(3, URL3, false, 0, TITLE3);
- Tab tab4 = createTab(4, URL4, false, 0, TITLE4);
- Tab tab5 = createTab(5, URL5, false, 0, TITLE5);
- Tab tab6 = createPrivateTab(6, URL1, false, 0, TITLE1);
- tabs.add(tab1);
- tabs.add(tab2);
- tabs.add(tab3);
- tabs.add(tab4);
- tabs.add(tab5);
- tabs.add(tab6);
-
- // Persist the created tabs. Normally, you should be careful that you get a profile on the
- // original thread, and do the work in a background one, but for testing we don't.
- final DatabaseHelper helper = new DatabaseHelper(getActivity(), mAsserter);
- helper.getProfileDB().getTabsAccessor().persistLocalTabs(mResolver, tabs);
-
- // Get the persisted tab and check if urls are filtered.
- Cursor c = getTabsFromLocalClient();
- assertCountIsAndClose(c, 1, 1 + " tabs entries found");
- }
- }
-
- /**
- * Assert that the provided cursor has the expected number of rows,
- * closing the cursor afterwards.
- */
- private void assertCountIsAndClose(Cursor c, int expectedCount, String message) {
- try {
- mAsserter.is(c.getCount(), expectedCount, message);
- } finally {
- c.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFindInPage.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFindInPage.java
deleted file mode 100644
index 2797fdf5b..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFindInPage.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Element;
-import org.mozilla.gecko.R;
-
-import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.util.GeckoEventListener;
-
-import org.json.JSONObject;
-
-import com.robotium.solo.Condition;
-
-public class testFindInPage extends JavascriptTest implements GeckoEventListener {
- private static final int WAIT_FOR_CONDITION_MS = 3000;
-
- protected Element next, close;
-
- public testFindInPage() {
- super("testFindInPage.js");
- }
-
- @Override
- public void handleMessage(String event, final JSONObject message) {
- if (event.equals("Test:FindInPage")) {
- try {
- final String text = message.getString("text");
- final int nrOfMatches = Integer.parseInt(message.getString("nrOfMatches"));
- findText(text, nrOfMatches);
- } catch (Exception e) {
- fFail("Can't extract find query from JSON");
- }
- }
-
- if (event.equals("Test:CloseFindInPage")) {
- try {
- close.click();
- } catch (Exception e) {
- fFail("FindInPage prompt not opened");
- }
- }
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- EventDispatcher.getInstance().registerGeckoThreadListener(this,
- "Test:FindInPage",
- "Test:CloseFindInPage");
- }
-
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
-
- EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
- "Test:FindInPage",
- "Test:CloseFindInPage");
- }
-
- public void findText(String text, int nrOfMatches){
- selectMenuItem(mStringHelper.FIND_IN_PAGE_LABEL);
- close = mDriver.findElement(getActivity(), R.id.find_close);
- boolean success = waitForCondition ( new Condition() {
- @Override
- public boolean isSatisfied() {
- next = mDriver.findElement(getActivity(), R.id.find_next);
- if (next != null) {
- return true;
- } else {
- return false;
- }
- }
- }, WAIT_FOR_CONDITION_MS);
- mAsserter.ok(success, "Looking for the next search match button in the Find in Page UI", "Found the next match button");
-
- // TODO: Find a better way to wait and then enter the text
- // Without the sleep this seems to work but the actions are not updated in the UI
- mSolo.sleep(500);
-
- mActions.sendKeys(text);
- mActions.sendSpecialKey(Actions.SpecialKey.ENTER);
-
- // Advance a few matches to scroll the page
- for (int i=1;i < nrOfMatches;i++) {
- success = waitForCondition ( new Condition() {
- @Override
- public boolean isSatisfied() {
- if (next.click()) {
- return true;
- } else {
- return false;
- }
- }
- }, WAIT_FOR_CONDITION_MS);
- mSolo.sleep(500); // TODO: Find a better way to wait here because waitForCondition is not enough
- mAsserter.ok(success, "Checking if the next button was clicked", "button was clicked");
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFlingCorrectness.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFlingCorrectness.java
deleted file mode 100644
index e173a8c16..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFlingCorrectness.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.PaintedSurface;
-
-/**
- * Basic fling correctness test.
- * - Loads a page and verifies it draws
- * - Drags page upwards by 200 pixels to get ready for a fling
- * - Fling the page downwards so we get back to the top and verify.
- */
-public class testFlingCorrectness extends PixelTest {
- public void testFlingCorrectness() {
- String url = getAbsoluteUrl(mStringHelper.ROBOCOP_BOXES_URL);
-
- MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop());
-
- blockForGeckoReady();
-
- // load page and check we're at 0,0
- loadAndVerifyBoxes(url);
-
- // drag page upwards by 200 pixels (use two drags instead of one in case
- // the screen size is small)
- Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
- meh.dragSync(10, 150, 10, 50);
- meh.dragSync(10, 150, 10, 50);
- PaintedSurface painted = waitForPaint(paintExpecter);
- paintExpecter.unregisterListener();
- try {
- checkScrollWithBoxes(painted, 0, 200);
- } finally {
- painted.close();
- }
-
- // now fling page downwards using a 100-pixel drag but a velocity of 15px/sec, so that
- // we scroll the full 200 pixels back to the top of the page
- paintExpecter = mActions.expectPaint();
- meh.flingSync(10, 50, 10, 150, 15);
- painted = waitForPaint(paintExpecter);
- paintExpecter.unregisterListener();
- try {
- checkScrollWithBoxes(painted, 0, 0);
- } finally {
- painted.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFormHistory.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFormHistory.java
deleted file mode 100644
index 40968b9be..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testFormHistory.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.File;
-
-import org.mozilla.gecko.db.BrowserContract.FormHistory;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.net.Uri;
-
-/**
- * A basic form history contentprovider test.
- * - inserts an element in form history when it is not yet set up
- * - inserts an element in form history
- * - updates an element in form history
- * - deletes an element in form history
- */
-public class testFormHistory extends BaseTest {
- private static final String DB_NAME = "formhistory.sqlite";
-
- public void testFormHistory() {
- Context context = (Context)getActivity();
- ContentResolver cr = context.getContentResolver();
- ContentValues[] cvs = new ContentValues[1];
- cvs[0] = new ContentValues();
-
- blockForGeckoReady();
-
- Uri formHistoryUri;
- Uri insertUri;
- Uri expectedUri;
- int numUpdated;
- int numDeleted;
-
- cvs[0].put("fieldname", "fieldname");
- cvs[0].put("value", "value");
- cvs[0].put("timesUsed", "0");
- cvs[0].put("guid", "guid");
-
- // Attempt to insert into the db
- formHistoryUri = FormHistory.CONTENT_URI;
- Uri.Builder builder = formHistoryUri.buildUpon();
- formHistoryUri = builder.appendQueryParameter("profilePath", mProfile).build();
-
- insertUri = cr.insert(formHistoryUri, cvs[0]);
- expectedUri = formHistoryUri.buildUpon().appendPath("1").build();
- mAsserter.is(expectedUri.toString(), insertUri.toString(), "Insert returned correct uri");
- SqliteCompare(DB_NAME, "SELECT * FROM moz_formhistory", cvs);
-
- cvs[0].put("fieldname", "fieldname2");
- cvs[0].putNull("guid");
-
- numUpdated = cr.update(formHistoryUri, cvs[0], null, null);
- mAsserter.is(1, numUpdated, "Correct number updated");
- SqliteCompare(DB_NAME, "SELECT * FROM moz_formhistory", cvs);
-
- numDeleted = cr.delete(formHistoryUri, null, null);
- mAsserter.is(1, numDeleted, "Correct number deleted");
- cvs = new ContentValues[0];
- SqliteCompare(DB_NAME, "SELECT * FROM moz_formhistory", cvs);
-
- cvs = new ContentValues[1];
- cvs[0] = new ContentValues();
- cvs[0].put("fieldname", "fieldname");
- cvs[0].put("value", "value");
- cvs[0].put("timesUsed", "0");
- cvs[0].putNull("guid");
-
- insertUri = cr.insert(formHistoryUri, cvs[0]);
- expectedUri = formHistoryUri.buildUpon().appendPath("1").build();
- mAsserter.is(expectedUri.toString(), insertUri.toString(), "Insert returned correct uri");
- SqliteCompare(DB_NAME, "SELECT * FROM moz_formhistory", cvs);
-
- cvs[0].put("guid", "guid");
-
- numUpdated = cr.update(formHistoryUri, cvs[0], null, null);
- mAsserter.is(1, numUpdated, "Correct number updated");
- SqliteCompare(DB_NAME, "SELECT * FROM moz_formhistory", cvs);
-
- numDeleted = cr.delete(formHistoryUri, null, null);
- mAsserter.is(1, numDeleted, "Correct number deleted");
- cvs = new ContentValues[0];
- SqliteCompare(DB_NAME, "SELECT * FROM moz_formhistory", cvs);
- }
-
- @Override
- public void tearDown() throws Exception {
- // remove the entire signons.sqlite file
- File profile = new File(mProfile);
- File db = new File(profile, "formhistory.sqlite");
- if (db.delete()) {
- mAsserter.dumpLog("tearDown deleted "+db.toString());
- } else {
- mAsserter.dumpLog("tearDown did not delete "+db.toString());
- }
-
- super.tearDown();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGeckoProfile.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGeckoProfile.java
deleted file mode 100644
index eb9a705be..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGeckoProfile.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.File;
-import java.util.Enumeration;
-import java.util.Hashtable;
-
-import org.mozilla.gecko.GeckoApp;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.GeckoProfileDirectories;
-import org.mozilla.gecko.GeckoSharedPrefs;
-import org.mozilla.gecko.util.INIParser;
-import org.mozilla.gecko.util.INISection;
-
-import android.content.Context;
-import android.text.TextUtils;
-
-/**
- * This patch tests GeckoProfile. It has unit tests for basic getting and removing of profiles, as well as
- * some guest mode tests. It does not test locking and unlocking profiles yet. It does not test the file management in GeckoProfile.
- */
-
-public class testGeckoProfile extends PixelTest {
- private final String TEST_PROFILE_NAME = "testProfile";
- private File mozDir;
- public void testGeckoProfile() {
- blockForGeckoReady();
-
- try {
- mozDir = GeckoProfileDirectories.getMozillaDirectory(getActivity());
- } catch(Exception ex) {
- // If we can't get the moz dir, something is wrong. Just fail quickly.
- mAsserter.ok(false, "Couldn't get moz dir", ex.toString());
- return;
- }
-
- checkProfileCreationDeletion();
- checkGuestProfile();
- }
-
- // This getter just passes an activity. Passing null should throw.
- private void checkDefaultGetter() {
- // "Default" is a custom profile set up by the test harness.
- mAsserter.info("Test using the test profile", GeckoProfile.CUSTOM_PROFILE);
- GeckoProfile profile = GeckoProfile.get(getActivity());
- verifyProfile(profile, GeckoProfile.CUSTOM_PROFILE, ((GeckoApp) getActivity()).getProfile().getDir(), true);
-
- try {
- profile = GeckoProfile.get(null);
- mAsserter.ok(false, "Passing a null context should throw", profile.toString());
- } catch(Exception ex) {
- mAsserter.ok(true, "Passing a null context should throw", ex.toString());
- }
- }
-
- // Test get(Context, String) methods
- private void checkNamedGetter(String name) {
- mAsserter.info("Test using a named profile", name);
- GeckoProfile profile = GeckoProfile.get(getActivity(), name);
- if (name != null) {
- verifyProfile(profile, name, findDir(name), false);
- removeProfile(profile, true);
- } else {
- // Passing in null for a profile name, should get you the default
- File defaultProfile = ((GeckoApp) getActivity()).getProfile().getDir();
- verifyProfile(profile, GeckoProfile.CUSTOM_PROFILE, defaultProfile, true);
- }
- }
-
- // Test get(Context, String, String) methods
- private void checkNameAndPathGetter(String name, boolean createBefore) {
- if (name == null) {
- checkNameAndPathGetter(name, null, createBefore);
- } else {
- checkNameAndPathGetter(name, name + "_FORCED_DIR", createBefore);
- }
- }
-
- // Test get(Context, String, String) methods
- private void checkNameAndPathGetter(String name, String path, boolean createBefore) {
- mAsserter.info("Test using a named profile and path", name + ", " + path);
- checkNameAndDirGetter(name, /* useFile */ false, path, /* file */ null, createBefore);
- }
-
- private void checkNameAndFileGetter(String name, boolean createBefore) {
- if (name == null) {
- checkNameAndFileGetter(name, null, createBefore);
- } else {
- checkNameAndFileGetter(name, new File(mozDir, name + "_FORCED_DIR"), createBefore);
- }
- }
-
- private void checkNameAndFileGetter(String name, File f, boolean createBefore) {
- mAsserter.info("Test using a named profile and File", name + ", " + f);
- checkNameAndDirGetter(name, /* useFile */ true, /* path */ null, f, createBefore);
- }
-
- private void checkNameAndDirGetter(final String name, final boolean useFile,
- String path, final File file,
- final boolean createBefore) {
- final File f;
- if (useFile) {
- f = file;
- } else if (!TextUtils.isEmpty(path)) {
- f = new File(mozDir, path);
- path = f.getAbsolutePath();
- } else {
- f = null;
- }
-
- if (f != null && createBefore) {
- // For some tests we create explicitly beforehand
- f.mkdir();
- }
-
- final File testProfileDir = ((GeckoApp) getActivity()).getProfile().getDir();
- final String expectedName = name != null ? name : GeckoProfile.CUSTOM_PROFILE;
-
- final GeckoProfile profile;
- if (useFile) {
- profile = GeckoProfile.get(getActivity(), name, file);
- } else {
- profile = GeckoProfile.get(getActivity(), name, path);
- }
-
- if (name != null || f != null) {
- // GeckoProfile will create a directory and add an ini section if f is null
- // here. Therefore, when f is null, shouldHaveFound is false for the
- // verifyProfile call, and inProfileIni is true for the removeProfile call.
- verifyProfile(profile, expectedName, f, f != null);
- removeProfile(profile, f == null);
- if (name == null) {
- // A side effect of calling GeckoProfile.get with null name is it changes
- // the test profile's directory to the new directory. Restore it back.
- GeckoProfile.get(getActivity(), null, testProfileDir);
- mAsserter.is(GeckoProfile.get(getActivity()).getDir(), testProfileDir,
- "Test profile should be restored");
- }
- } else {
- // Passing in null for a profile name and path, should get you the default
- verifyProfile(profile, expectedName, testProfileDir, true);
- }
- }
-
- private void checkProfileCreationDeletion() {
- // Test
- checkDefaultGetter();
-
- int index = 0;
- checkNamedGetter(TEST_PROFILE_NAME + (index++)); // 0
- checkNamedGetter(null);
-
- // name and path
- checkNameAndPathGetter(TEST_PROFILE_NAME + (index++), true);
- checkNameAndPathGetter(TEST_PROFILE_NAME + (index++), false);
- checkNameAndPathGetter(null, false);
- // null name and path
- checkNameAndPathGetter(null, TEST_PROFILE_NAME + (index++) + "_FORCED_DIR", true);
- checkNameAndPathGetter(null, TEST_PROFILE_NAME + (index++) + "_FORCED_DIR", false);
- // name and null path
- checkNameAndPathGetter(TEST_PROFILE_NAME + (index++), null, false);
- checkNameAndPathGetter(TEST_PROFILE_NAME + (index++), "", false);
- // null name and null path
- checkNameAndPathGetter(null, null, false);
- checkNameAndPathGetter(null, "", false);
-
- // name and path
- checkNameAndFileGetter(TEST_PROFILE_NAME + (index++), true);
- checkNameAndFileGetter(TEST_PROFILE_NAME + (index++), false);
- checkNameAndFileGetter(null, false);
- // null name and path
- checkNameAndFileGetter(null, new File(mozDir, TEST_PROFILE_NAME + (index++) + "_FORCED_DIR"), true);
- checkNameAndFileGetter(null, new File(mozDir, TEST_PROFILE_NAME + (index++) + "_FORCED_DIR"), false);
- // name and null path
- checkNameAndFileGetter(TEST_PROFILE_NAME + (index++), null, false);
- // null name and null path
- checkNameAndFileGetter(null, null, false);
- }
-
- // Tests of Guest profile methods
- private void checkGuestProfile() {
- final File testProfileDir = ((GeckoApp) getActivity()).getProfile().getDir();
-
- mAsserter.info("Test getting a guest profile", "");
- GeckoProfile profile = GeckoProfile.getGuestProfile(getActivity());
- verifyProfile(profile, GeckoProfile.CUSTOM_PROFILE, getActivity().getFileStreamPath("guest"), true);
- mAsserter.ok(profile.inGuestMode(), "Profile is in guest mode", profile.getName());
-
- final File dir = profile.getDir();
- mAsserter.info("Test deleting a guest profile", "");
- mAsserter.ok(GeckoProfile.removeProfile(getActivity(), profile), "Cleaned up unlocked guest profile", profile.getName());
- mAsserter.ok(!dir.exists(), "Guest dir was deleted", dir.toString());
-
- // Restore test profile directory, which was changed in the last GeckoProfile.get call.
- GeckoProfile.get(getActivity(), null, testProfileDir);
- mAsserter.is(GeckoProfile.get(getActivity()).getDir(), testProfileDir,
- "Test profile should be restored");
- }
-
- // Runs generic tests on a profile to make sure it looks correct
- private void verifyProfile(GeckoProfile profile, String name, File requestedDir, boolean shouldHaveFound) {
- mAsserter.is(profile.getName(), name, "Profile name is correct");
-
- File dir = null;
- if (!shouldHaveFound) {
- mAsserter.is(findDir(name), null, "Dir with name doesn't exist yet");
-
- dir = profile.getDir();
- mAsserter.isnot(requestedDir, dir, "Profile should not have used expectedDir");
-
- // The used dir should be based on the name passed in.
- requestedDir = findDir(name);
- } else {
- dir = profile.getDir();
- }
-
- mAsserter.is(dir, requestedDir, "Profile dir is correct");
- mAsserter.ok(dir.exists(), "Profile dir exists after getting it", dir.toString());
- }
-
- // Tries to find a profile in profiles.ini. Makes sure its name and path match what is expected
- private void findInProfilesIni(final String name, final File dir, final boolean shouldFind) {
- final File mozDir;
- try {
- mozDir = GeckoProfileDirectories.getMozillaDirectory(getActivity());
- } catch(Exception ex) {
- mAsserter.ok(false, "Couldn't get moz dir", ex.toString());
- return;
- }
-
- final INIParser parser = GeckoProfileDirectories.getProfilesINI(mozDir);
- final Hashtable<String, INISection> sections = parser.getSections();
-
- boolean found = false;
- for (Enumeration<INISection> e = sections.elements(); e.hasMoreElements();) {
- final INISection section = e.nextElement();
- String iniName = section.getStringProperty("Name");
- if (iniName == null || !iniName.equals(name)) {
- continue;
- }
-
- found = true;
-
- String iniPath = section.getStringProperty("Path");
- mAsserter.is(name, iniName, "Section with name found");
- mAsserter.is(dir.getName(), iniPath, "Section has correct path");
- }
-
- mAsserter.is(found, shouldFind, "Found profile where expected");
- }
-
- // Tries to remove a profile from Gecko profile. Verifies that it's removed from profiles.ini and its directory is deleted.
- // TODO: Reconsider profile removal. Firefox would not normally remove a
- // profile. Outstanding tasks may still try to access files in the profile.
- private void removeProfile(GeckoProfile profile, boolean inProfilesIni) {
- final String name = profile.getName();
- final File dir = profile.getDir();
- findInProfilesIni(name, dir, inProfilesIni);
- mAsserter.ok(dir.exists(), "Profile dir exists before removing", dir.toString());
- mAsserter.ok(GeckoProfile.removeProfile(getActivity(), profile), "Remove was successful", name);
- mAsserter.ok(!dir.exists(), "Profile dir was deleted when it was removed", dir.toString());
- findInProfilesIni(name, dir, false);
- }
-
- // Looks for a dir whose name ends with the passed-in string.
- private File findDir(String name) {
- final File root;
- try {
- root = GeckoProfileDirectories.getMozillaDirectory(getActivity());
- } catch(Exception ex) {
- return null;
- }
-
- File[] dirs = root.listFiles();
- for (File dir : dirs) {
- if (dir.getName().endsWith(name)) {
- return dir;
- }
- }
-
- return null;
- }
-
- @Override
- public void tearDown() throws Exception {
- // Clear SharedPreferences.
- final Context context = getInstrumentation().getContext();
- GeckoSharedPrefs.forProfile(context).edit().clear().apply();
-
- super.tearDown();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGeckoRequest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGeckoRequest.java
deleted file mode 100644
index ac4a9862c..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGeckoRequest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import com.robotium.solo.Condition;
-
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.tests.helpers.AssertionHelper;
-import org.mozilla.gecko.tests.helpers.WaitHelper;
-import org.mozilla.gecko.util.GeckoRequest;
-import org.mozilla.gecko.util.NativeJSObject;
-
-/**
- * Tests sending and receiving Gecko requests using the GeckoRequest API.
- */
-public class testGeckoRequest extends JavascriptBridgeTest {
- private static final String TEST_JS = "testGeckoRequest.js";
- private static final String REQUEST_EVENT = "Robocop:GeckoRequest";
- private static final String REQUEST_EXCEPTION_EVENT = "Robocop:GeckoRequestException";
- private static final int MAX_WAIT_MS = 5000;
-
- public void testGeckoRequest() {
- blockForReadyAndLoadJS(TEST_JS);
-
- // Register a listener for this request.
- getJS().syncCall("add_request_listener", REQUEST_EVENT);
-
- // Make sure we receive the expected response.
- checkFooRequest();
-
- // Try registering a second listener for this request, which should fail.
- getJS().syncCall("add_second_request_listener", REQUEST_EVENT);
-
- // Unregister the listener for this request.
- getJS().syncCall("remove_request_listener", REQUEST_EVENT);
-
- // Make sure we don't receive a response after removing the listener.
- checkUnregisteredRequest();
-
- // Check that we still receive a response for listeners that throw.
- getJS().syncCall("add_exception_listener", REQUEST_EXCEPTION_EVENT);
- checkExceptionRequest();
- getJS().syncCall("remove_request_listener", REQUEST_EXCEPTION_EVENT);
-
- getJS().syncCall("finish_test");
- }
-
- private void checkFooRequest() {
- final AtomicBoolean responseReceived = new AtomicBoolean(false);
- final String data = "foo";
-
- GeckoAppShell.sendRequestToGecko(new GeckoRequest(REQUEST_EVENT, data) {
- @Override
- public void onResponse(NativeJSObject nativeJSObject) {
- // Ensure we receive the expected response from Gecko.
- final String result = nativeJSObject.getString("result");
- AssertionHelper.fAssertEquals("Sent and received request data", data + "bar", result);
- responseReceived.set(true);
- }
- });
-
- WaitHelper.waitFor("Received response for registered listener", new Condition() {
- @Override
- public boolean isSatisfied() {
- return responseReceived.get();
- }
- }, MAX_WAIT_MS);
- }
-
- private void checkExceptionRequest() {
- final AtomicBoolean responseReceived = new AtomicBoolean(false);
- final AtomicBoolean errorReceived = new AtomicBoolean(false);
-
- GeckoAppShell.sendRequestToGecko(new GeckoRequest(REQUEST_EXCEPTION_EVENT, null) {
- @Override
- public void onResponse(NativeJSObject nativeJSObject) {
- responseReceived.set(true);
- }
-
- @Override
- public void onError(NativeJSObject error) {
- errorReceived.set(true);
- }
- });
-
- WaitHelper.waitFor("Received error for listener with exception", new Condition() {
- @Override
- public boolean isSatisfied() {
- return errorReceived.get();
- }
- }, MAX_WAIT_MS);
-
- AssertionHelper.fAssertTrue("onResponse not called for listener with exception", !responseReceived.get());
- }
-
- private void checkUnregisteredRequest() {
- final AtomicBoolean responseReceived = new AtomicBoolean(false);
-
- GeckoAppShell.sendRequestToGecko(new GeckoRequest(REQUEST_EVENT, null) {
- @Override
- public void onResponse(NativeJSObject nativeJSObject) {
- responseReceived.set(true);
- }
- });
-
- // This check makes sure that we do *not* receive a response for an unregistered listener,
- // meaning waitForCondition() should always time out.
- getSolo().waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return responseReceived.get();
- }
- }, MAX_WAIT_MS);
-
- AssertionHelper.fAssertTrue("Did not receive response for unregistered listener", !responseReceived.get());
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGetUserMedia.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGetUserMedia.java
deleted file mode 100644
index 405ddef7a..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testGetUserMedia.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.AppConstants;
-
-import android.widget.Spinner;
-import android.view.View;
-
-import com.robotium.solo.Condition;
-
-import android.hardware.Camera;
-import android.os.Build;
-
-public class testGetUserMedia extends BaseTest {
- private static final String LOGTAG = testGetUserMedia.class.getSimpleName();
-
- private static final String GUM_MESSAGE = "Would you like to share your camera and microphone with";
- private static final String GUM_ALLOW = "^Share$";
- private static final String GUM_DENY = "^Don't Share$";
-
- private static final String GUM_BACK_CAMERA = "Back facing camera";
- private static final String GUM_SELECT_TAB = "Choose a tab to stream";
-
- private static final String GUM_PAGE_TITLE = "gUM Test Page";
- private static final String GUM_PAGE_FAILED = "failed gumtest";
- private static final String GUM_PAGE_AUDIO = "audio gumtest";
- private static final String GUM_PAGE_VIDEO = "video gumtest";
- private static final String GUM_PAGE_AUDIOVIDEO = "audiovideo gumtest";
-
- public void testGetUserMedia() {
- // TabShare.js is disabled on release builds.
- if (AppConstants.RELEASE_OR_BETA) {
- mAsserter.dumpLog(LOGTAG + " is disabled on release builds: returning");
- return;
- }
-
- // Only try GUM test if the device has a camera (emulation).
- if (Camera.getNumberOfCameras() <= 0) {
- return;
- }
-
- blockForGeckoReady();
-
- final String GUM_CAMERA_URL = getAbsoluteUrl("/robocop/robocop_getusermedia2.html");
- final String GUM_TAB_URL = getAbsoluteUrl("/robocop/robocop_getusermedia.html");
- // Browser constraint needs HTTPS
- final String GUM_TAB_HTTPS_URL = GUM_TAB_URL.replace("http://mochi.test:8888", "https://example.com");
-
- // Tests on Camera page will test camera enumeration code, but
- // the actual cameras don't seem to work on the emulators, so
- // the enumeration is all that gets tested.
-
- // Test GUM notification showing
- loadUrlAndWait(GUM_CAMERA_URL);
- waitForText(GUM_MESSAGE);
- mAsserter.is(mSolo.searchText(GUM_MESSAGE), true, "getUserMedia doorhanger has been displayed");
- waitForSpinner();
- // At least one camera detected
- mAsserter.is(mSolo.searchText(GUM_BACK_CAMERA), true, "getUserMedia found a camera");
- mSolo.clickOnButton(GUM_DENY);
- waitForTextDismissed(GUM_MESSAGE);
- mAsserter.is(mSolo.searchText(GUM_MESSAGE), false, "getUserMedia doorhanger hidden after dismissal");
- verifyUrlBarTitle(GUM_CAMERA_URL);
-
- // Cameras don't work on the testing hardware, so stream a tab
- loadUrlAndWait(GUM_TAB_HTTPS_URL);
- waitForText(GUM_MESSAGE);
- mAsserter.is(mSolo.searchText(GUM_MESSAGE), true, "getUserMedia doorhanger has been displayed");
- waitForSpinner();
- mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), true, "Video source selection available");
- mAsserter.is(mSolo.searchText("MICROPHONE TO USE"), true, "Microphone selection available");
- mAsserter.is(mSolo.searchText("Microphone 1"), true, "Microphone 1 available");
- mSolo.clickOnText("Microphone 1");
- waitForText("No Audio");
- mAsserter.is(mSolo.searchText("No Audio"), true, "No 'No Audio' selection available");
- mSolo.clickOnText("No Audio");
- waitForTextDismissed("Microphone 1");
- mAsserter.is(mSolo.searchText("Microphone 1"), false, "Audio selection hidden after dismissal");
- mAsserter.is(mSolo.searchText(GUM_ALLOW), true, "Share button available after selection");
- mSolo.clickOnButton(GUM_ALLOW);
- waitForTextDismissed(GUM_MESSAGE);
- mAsserter.is(mSolo.searchText(GUM_MESSAGE), false, "getUserMedia doorhanger hidden after dismissal");
- waitForText(GUM_SELECT_TAB);
- mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), true, "Tab selection dialog displayed");
- mSolo.clickOnText(GUM_PAGE_TITLE);
- waitForTextDismissed(GUM_SELECT_TAB);
- mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), false, "Tab selection dialog hidden");
- verifyUrlBarTitle(GUM_TAB_HTTPS_URL);
-
- // Android 2.3 testers fail because of audio issues:
- // E/AudioRecord( 650): Unsupported configuration: sampleRate 44100, format 1, channelCount 1
- // E/libOpenSLES( 650): android_audioRecorder_realize(0x26d7d8) error creating AudioRecord object
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- return;
- }
-
- loadUrlAndWait(GUM_TAB_HTTPS_URL);
- waitForText(GUM_MESSAGE);
- mAsserter.is(mSolo.searchText(GUM_MESSAGE), true, "getUserMedia doorhanger has been displayed");
-
- waitForSpinner();
- mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), true, "Video source selection available");
- mSolo.clickOnButton(GUM_ALLOW);
- waitForTextDismissed(GUM_MESSAGE);
- waitForText(GUM_SELECT_TAB);
- mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), true, "Tab selection dialog displayed");
- mSolo.clickOnText(GUM_PAGE_TITLE);
- waitForTextDismissed(GUM_SELECT_TAB);
- mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), false, "Tab selection dialog hidden");
- verifyUrlBarTitle(GUM_TAB_HTTPS_URL);
-
- loadUrlAndWait(GUM_TAB_HTTPS_URL);
- waitForText(GUM_MESSAGE);
- mAsserter.is(mSolo.searchText(GUM_MESSAGE), true, "getUserMedia doorhanger has been displayed");
-
- waitForSpinner();
- mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), true, "Video source selection available");
- mSolo.clickOnText(GUM_SELECT_TAB);
- waitForText("No Video");
- mAsserter.is(mSolo.searchText("No Video"), true, "'No video' source selection available");
- mSolo.clickOnText("No Video");
- waitForTextDismissed(GUM_SELECT_TAB);
- mSolo.clickOnButton(GUM_ALLOW);
- waitForTextDismissed(GUM_MESSAGE);
- mAsserter.is(mSolo.searchText(GUM_MESSAGE), false, "getUserMedia doorhanger hidden after dismissal");
- verifyUrlBarTitle(GUM_TAB_HTTPS_URL);
- }
-
- // wait for a Spinner view that is clickable
- private void waitForSpinner() {
- waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- for (Spinner view : mSolo.getCurrentViews(Spinner.class)) {
- if (view.isClickable() &&
- view.getVisibility() == View.VISIBLE &&
- view.getWidth() > 0 &&
- view.getHeight() > 0) {
- return true;
- }
- }
- return false;
- }
- }, MAX_WAIT_MS);
- }
-
- // wait until the specified text is *not* displayed
- private void waitForTextDismissed(final String text) {
- waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return !mSolo.searchText(text);
- }
- }, MAX_WAIT_MS);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHistory.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHistory.java
deleted file mode 100644
index 1f2fbbd38..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHistory.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ListView;
-
-import org.mozilla.gecko.home.HomePager;
-
-import com.robotium.solo.Condition;
-
-public class testHistory extends AboutHomeTest {
- private View mFirstChild;
-
- public void testHistory() {
- blockForGeckoReady();
-
- String url = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- String url2 = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL);
- String url3 = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_03_URL);
-
- inputAndLoadUrl(url);
- verifyUrlBarTitle(url);
- inputAndLoadUrl(url2);
- verifyUrlBarTitle(url2);
- inputAndLoadUrl(url3);
- verifyUrlBarTitle(url3);
-
- openAboutHomeTab(AboutHomeTabs.HISTORY);
-
- final ListView hList = findListViewWithTag(HomePager.LIST_TAG_HISTORY);
- mAsserter.is(waitForNonEmptyListToLoad(hList), true, "list is properly loaded");
-
- // Click on the history item and wait for the page to load
- // wait for the history list to be populated
- mFirstChild = null;
- boolean success = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- mFirstChild = hList.getChildAt(1);
- if (mFirstChild == null) {
- return false;
- }
- if (mFirstChild instanceof android.view.ViewGroup) {
- ViewGroup group = (ViewGroup)mFirstChild;
- if (group.getChildCount() < 1) {
- return false;
- }
- for (int i = 0; i < group.getChildCount(); i++) {
- View grandChild = group.getChildAt(i);
- if (grandChild instanceof android.widget.TextView) {
- mAsserter.ok(true, "found TextView:", ((android.widget.TextView)grandChild).getText().toString());
- }
- }
- } else {
- mAsserter.dumpLog("first child not a ViewGroup: "+mFirstChild);
- return false;
- }
- return true;
- }
- }, MAX_WAIT_MS);
-
- mAsserter.isnot(mFirstChild, null, "Got history item");
- mSolo.clickOnView(mFirstChild);
-
- // The first item here (since it was just visited) should be a "Switch to tab" item
- // i.e. don't expect a DOMContentLoaded event
- verifyUrlBarTitle(mStringHelper.ROBOCOP_BLANK_PAGE_03_URL);
- verifyUrl(url3);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHistoryService.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHistoryService.java
deleted file mode 100644
index 4c605f6c3..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHistoryService.java
+++ /dev/null
@@ -1,12 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-public class testHistoryService extends JavascriptTest {
-
- public testHistoryService() {
- super("testHistoryService.js");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHomeBanner.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHomeBanner.java
deleted file mode 100644
index be36ae5a0..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHomeBanner.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-import org.mozilla.gecko.tests.helpers.NavigationHelper;
-
-public class testHomeBanner extends UITest {
-
- private static final String TEST_URL = "chrome://roboextender/content/robocop_home_banner.html";
- private static final String TEXT = "The quick brown fox jumps over the lazy dog.";
-
- public void testHomeBanner() {
- GeckoHelper.blockForReady();
-
- // Make sure the banner is not visible to start.
- mAboutHome.assertVisible()
- .assertBannerNotVisible();
-
- // These test methods depend on being run in this order.
- addBannerTest();
-
- // Make sure the banner hides when the user starts interacting with the url bar.
- hideOnToolbarFocusTest();
-
- // Make sure to test dismissing the banner after everything else, since dismissing
- // the banner will prevent it from showing up again.
- dismissBannerTest();
- }
-
- /**
- * Adds a banner message, verifies that it appears when it should, and verifies that
- * onshown/onclick handlers are called in JS.
- *
- * Note: This test does not remove the message after it is done.
- */
- private void addBannerTest() {
- // Load about:home and make sure the onshown handler is called.
- Actions.EventExpecter eventExpecter = getActions().expectGeckoEvent("TestHomeBanner:MessageShown");
- addBannerMessage();
- NavigationHelper.enterAndLoadUrl(mStringHelper.ABOUT_HOME_URL);
- eventExpecter.blockForEvent();
-
- // Verify that the banner is visible with the correct text.
- mAboutHome.assertBannerText(TEXT);
-
- // Verify that the banner isn't visible after navigating away from about:home.
- NavigationHelper.enterAndLoadUrl(mStringHelper.ABOUT_FIREFOX_URL);
- mAboutHome.assertBannerNotVisible();
- }
-
-
- private void hideOnToolbarFocusTest() {
- NavigationHelper.enterAndLoadUrl(mStringHelper.ABOUT_HOME_URL);
- mAboutHome.assertVisible()
- .assertBannerVisible();
-
- mToolbar.enterEditingMode();
- mAboutHome.assertBannerNotVisible();
-
- mToolbar.dismissEditingMode();
- mAboutHome.assertBannerVisible();
- }
-
- /**
- * Adds a banner message, verifies that its ondismiss handler is called in JS,
- * and verifies that the banner is no longer shown after it is dismissed.
- *
- * Note: This test does not remove the message after it is done.
- */
- private void dismissBannerTest() {
- NavigationHelper.enterAndLoadUrl(mStringHelper.ABOUT_HOME_URL);
- mAboutHome.assertVisible();
-
- // Test to make sure the ondismiss handler is called when the close button is clicked.
- final Actions.EventExpecter eventExpecter = getActions().expectGeckoEvent("TestHomeBanner:MessageDismissed");
- mAboutHome.dismissBanner();
- eventExpecter.blockForEvent();
-
- mAboutHome.assertBannerNotVisible();
- }
-
- /**
- * Loads the roboextender page to add a message to the banner.
- */
- private void addBannerMessage() {
- final Actions.EventExpecter eventExpecter = getActions().expectGeckoEvent("TestHomeBanner:MessageAdded");
- NavigationHelper.enterAndLoadUrl(TEST_URL + "#addMessage");
- eventExpecter.blockForEvent();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHomeListsProvider.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHomeListsProvider.java
deleted file mode 100644
index fbe2df82f..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testHomeListsProvider.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class testHomeListsProvider extends ContentProviderTest {
- // This test does not run, so it just needs to compile. The test was
- // disabled at the time the real Contract was removed; to leave a skeleton
- // for a future re-implementor, we include this dummy Contract class.
- private static class Contract {
- public static final Uri CONTENT_URI = null;
- public static final Uri CONTENT_FAKE_URI = null;
-
- public static final String _ID = null;
- public static final String PROVIDER_ID = null;
- public static final String TITLE = null;
- public static final String URL = null;
- }
-
- @SuppressWarnings("unused")
- private void ensureEmptyDatabase() throws Exception {
- // Delete all the list entries.
- mProvider.delete(Contract.CONTENT_URI, null, null);
-
- final Cursor c = mProvider.query(Contract.CONTENT_URI, null, null, null, null);
- mAsserter.is(c.getCount(), 0, "All list entries were deleted");
- c.close();
- }
-
- @Override
- public void setUp() throws Exception {
- // This test is disabled, so this just needs to compile.
- super.setUp(null, null, "homelists.db");
-
- mTests.add(new TestFakeItems());
-
- // Disabled until database support lands
- //mTests.add(new TestInsertItem());
- }
-
- public void testListsProvider() throws Exception {
- for (int i = 0; i < mTests.size(); i++) {
- Runnable test = mTests.get(i);
-
- setTestName(test.getClass().getSimpleName());
- // Disabled until database support lands
- //ensureEmptyDatabase();
- test.run();
- }
- }
-
- abstract class Test implements Runnable {
- @Override
- public void run() {
- try {
- test();
- } catch (Exception e) {
- mAsserter.is(true, false, "Test " + this.getClass().getName() +
- " threw exception: " + e);
- }
- }
-
- public abstract void test() throws Exception;
- }
-
- class TestFakeItems extends Test {
- @Override
- public void test() throws Exception {
- final long id = 1;
- final String providerId = "fake-provider";
- final String title = "Example";
- final String url = "http://example.com";
-
- final Cursor c = mProvider.query(Contract.CONTENT_FAKE_URI, null, null, null, null);
- mAsserter.is(c.moveToFirst(), true, "Fake list item found");
-
- mAsserter.is(c.getLong(c.getColumnIndex(Contract._ID)), id, "Fake list item has correct ID");
- mAsserter.is(c.getString(c.getColumnIndex(Contract.PROVIDER_ID)), providerId, "Fake list item has correct provider ID");
- mAsserter.is(c.getString(c.getColumnIndex(Contract.TITLE)), title, "Fake list item has correct title");
- mAsserter.is(c.getString(c.getColumnIndex(Contract.URL)), url, "Fake list item has correct URL");
-
- c.close();
- }
- }
-
- class TestInsertItem extends Test {
- @Override
- public void test() throws Exception {
- final String providerId = "{c77da387-4c80-0c45-9f22-70276c29b3ed}";
- final String title = "Mozilla";
- final String url = "https://mozilla.org";
-
- // Insert a new list item with test values.
- final ContentValues cv = new ContentValues();
- cv.put(Contract.PROVIDER_ID, providerId);
- cv.put(Contract.TITLE, title);
- cv.put(Contract.URL, url);
-
- final long id = ContentUris.parseId(mProvider.insert(Contract.CONTENT_URI, cv));
-
- // Check that the item was inserted correctly.
- final Cursor c = mProvider.query(Contract.CONTENT_URI, null, Contract._ID + " = ?", new String[] { String.valueOf(id) }, null);
- mAsserter.is(c.moveToFirst(), true, "Inserted list item found");
-
- mAsserter.is(c.getString(c.getColumnIndex(Contract.PROVIDER_ID)), providerId, "Inserted list item has correct provider ID");
- mAsserter.is(c.getString(c.getColumnIndex(Contract.TITLE)), title, "Inserted list item has correct title");
- mAsserter.is(c.getString(c.getColumnIndex(Contract.URL)), url, "Inserted list item has correct URL");
-
- c.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testICODecoder.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testICODecoder.java
deleted file mode 100644
index 5cbbd1be9..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testICODecoder.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.graphics.Bitmap;
-
-import org.mozilla.gecko.icons.decoders.ICODecoder;
-import org.mozilla.gecko.icons.decoders.IconDirectoryEntry;
-import org.mozilla.gecko.icons.decoders.LoadFaviconResult;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNull;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
-
-public class testICODecoder extends UITest {
-
- private int mGolemNumIconDirEntries;
-
- public void testICODecoder() throws IOException {
- testMicrosoftFavicon();
- testNvidiaFavicon();
- testGolemFavicon();
- testMissingHeader();
- testCorruptIconDirectory();
- }
-
- /**
- * Decode and verify a Microsoft favicon with six different sizes:
- * 128x128, 72x72, 48x48, 32x32, 24x24, 16x16
- * Each of the six BMPs supposedly has zero colour depth.
- */
- private void testMicrosoftFavicon() throws IOException {
- byte[] icoBytes = readICO("microsoft_favicon.ico");
- fAssertEquals("Expecting Microsoft favicon to be 17174 bytes.", 17174, icoBytes.length);
-
- ICODecoder decoder = new ICODecoder(getInstrumentation().getTargetContext(), icoBytes, 0,
- icoBytes.length);
- LoadFaviconResult result = decoder.decode();
- fAssertNotNull("Expecting Microsoft favicon to not fail decoding.", result);
-
- int largestBitmap = Integer.MAX_VALUE;
-
- int[] possibleSizes = {16, 24, 32, 48, 72, 128};
- for (int i = 0; i < possibleSizes.length; i++) {
- if (possibleSizes[i] > decoder.getLargestFaviconSize()) {
- largestBitmap = possibleSizes[i];
-
- // Verify that all bitmaps but the smallest larger than Favicons.largestFaviconSize
- // have been discarded.
- for (int j = i + 1; j < possibleSizes.length; j++) {
- Bitmap selectedBitmap = result.getBestBitmap(possibleSizes[j]);
- fAssertNotNull("Expecting a best bitmap to be found for " +
- possibleSizes[j] + "x" + possibleSizes[j], selectedBitmap);
-
- fAssertEquals("Expecting best bitmap to have width " + possibleSizes[i],
- possibleSizes[i], selectedBitmap.getWidth());
- fAssertEquals("Expecting best bitmap to have height " + possibleSizes[i],
- possibleSizes[i], selectedBitmap.getHeight());
-
- // Reset the result's bitmap iterator.
- result = decoder.decode();
- }
-
- break;
- }
- }
-
- int[] expectedSizes = {
- // If we request a 33x33 we should get a 48x48.
- 33, 48,
- // If we request a 24x24 we should get a 24x24.
- 24, 24,
- // If we request a 8x8 we should get a 16x16.
- 8, 16,
- };
-
- for (int i = 0; i < expectedSizes.length - 1; i += 2) {
- if (expectedSizes[i + 1] > largestBitmap) {
- // This bitmap has been discarded.
- continue;
- }
-
- Bitmap selectedBitmap = result.getBestBitmap(expectedSizes[i]);
- fAssertNotNull("Expecting a best bitmap to have been found for " +
- expectedSizes[i] + "x" + expectedSizes[i], selectedBitmap);
-
- fAssertEquals("Expecting best bitmap to have width " + expectedSizes[i + 1],
- expectedSizes[i + 1], selectedBitmap.getWidth());
- fAssertEquals("Expecting best bitmap to have height " + expectedSizes[i + 1],
- expectedSizes[i + 1], selectedBitmap.getHeight());
-
- // Reset the result's bitmap iterator.
- result = decoder.decode();
- }
- }
-
- /**
- * Decode and verify a NVIDIA favicon with three different colour depths,
- * and three different sizes for each colour depth. All payloads are BMP.
- */
- private void testNvidiaFavicon() throws IOException {
- byte[] icoBytes = readICO("nvidia_favicon.ico");
- fAssertEquals("Expecting NVIDIA favicon to be 25214 bytes.", 25214, icoBytes.length);
-
- ICODecoder decoder = new ICODecoder(getInstrumentation().getTargetContext(), icoBytes, 0,
- icoBytes.length);
- fAssertNotNull("Expecting NVIDIA favicon to not fail decoding.", decoder.decode());
-
- // Verify the best entry is correctly chosen for each width.
- // We expect 32 bpp in all cases even if 32 bpp exceeds IconDirectoryEntry.maxBPP.
- // This is okay because IconDirectoryEntry.maxBPP is a "desired bpp" not the absolute max.
- // This was chosen because we think it gives better results to select a higher bpp and let
- // Android downscale the bpp, rather than showing a bitmap of potentially significantly
- // lower color depth.
- IconDirectoryEntry[] expectedEntries = {
- new IconDirectoryEntry(16, 16, 0, 32, 1128, 24086, false),
- new IconDirectoryEntry(32, 32, 0, 32, 4264, 19822, false),
- new IconDirectoryEntry(48, 48, 0, 32, 9640, 10182, false)
- };
-
- IconDirectoryEntry[] directory = decoder.getIconDirectory();
- fAssertTrue("NVIDIA icon directory must contain at least one entry.", directory.length > 0);
- for (int i = 0; i < directory.length; i++) {
- if (expectedEntries[i].getWidth() > directory[directory.length - 1].getWidth()) {
- // This test-case has been discarded due to being over-sized. Next.
- // All subsequent cases will be too.
- fAssertTrue("At least one test-case should not have been discarded.", i > 0);
- break;
- }
-
- // Verify the actual Icon Directory entry was as expected.
- fAssertEquals(directory[i] + " is expected to be equal to " + expectedEntries[i],
- 0, directory[i].compareTo(expectedEntries[i]));
- }
- }
-
- /**
- * Decode and verify a Golem.de favicon with five bitmaps: 256x256, 48x48, 32x32, 24x24, 16x16
- * Only the 256x256 is a PNG payload. All others are BMP.
- */
- private void testGolemFavicon() throws IOException {
- byte[] icoBytes = readICO("golem_favicon.ico");
- fAssertEquals("Expecting Golem favicon to be 40648 bytes.", 40648, icoBytes.length);
-
- ICODecoder decoder = new ICODecoder(getInstrumentation().getTargetContext(), icoBytes, 0,
- icoBytes.length);
- fAssertNotNull("Expecting Golem favicon to not fail decoding.", decoder.decode());
-
- // Verify the five entries were correctly identified.
- IconDirectoryEntry[] expectedEntries = {
- new IconDirectoryEntry(16, 16, 0, 32, 1128, 39250, false),
- new IconDirectoryEntry(24, 24, 0, 32, 2488, 37032, false),
- new IconDirectoryEntry(32, 32, 0, 32, 4392, 32640, false),
- new IconDirectoryEntry(48, 48, 0, 32, 9832, 22808, false),
- new IconDirectoryEntry(256, 256, 0, 32, 22722, 86, true)
- };
-
- IconDirectoryEntry[] directory = decoder.getIconDirectory();
- fAssertTrue("Golem icon directory must contain at least one entry.", directory.length > 0);
- for (int i = 0; i < directory.length; i++) {
- if (expectedEntries[i].getWidth() > directory[directory.length - 1].getWidth()) {
- // This test-case has been discarded due to being over-sized.
- // All subsequent cases will be too.
- fAssertTrue("At least one test-case should not have been discarded.", i > 0);
- break;
- }
-
- // Verify the actual Icon Directory entry was as expected.
- fAssertEquals(directory[i] + " is expected to be equal to " + expectedEntries[i],
- 0, directory[i].compareTo(expectedEntries[i]));
- }
-
- // How many icon directory entries in the non-maimed favicon?
- mGolemNumIconDirEntries = directory.length;
- }
-
- /**
- * Verify that deleting the header will make decoding fail.
- */
- private void testMissingHeader() throws IOException {
- byte[] icoBytes = readICO("microsoft_favicon.ico");
- fAssertEquals("Expecting Microsoft favicon to be 17174 bytes.", 17174, icoBytes.length);
-
- int offsetNoHeader = ICODecoder.ICO_HEADER_LENGTH_BYTES;
- int lenNoHeader = icoBytes.length - ICODecoder.ICO_HEADER_LENGTH_BYTES;
- ICODecoder decoder = new ICODecoder(getInstrumentation().getTargetContext(), icoBytes,
- offsetNoHeader, lenNoHeader);
- fAssertNull("Expecting Microsoft favicon to fail decoding.", decoder.decode());
- }
-
- /**
- * Verify that decoding does not fail if the number of icon directory entries is smaller than
- * the number given in the header.
- */
- private void testCorruptIconDirectory() throws IOException {
- byte[] icoBytes = readICO("golem_favicon.ico");
- fAssertEquals("Expecting Golem favicon to be 40648 bytes.", 40648, icoBytes.length);
-
- byte[] icoMaimed = new byte[icoBytes.length - ICODecoder.ICO_ICONDIRENTRY_LENGTH_BYTES];
- // Copy the header and first four icon directory entries into icoMaimed.
- System.arraycopy(icoBytes, 0, icoMaimed, 0,
- ICODecoder.ICO_HEADER_LENGTH_BYTES + 4 * ICODecoder.ICO_ICONDIRENTRY_LENGTH_BYTES);
- // Skip the last icon directory entry.
- System.arraycopy(icoBytes,
- ICODecoder.ICO_HEADER_LENGTH_BYTES + 5 * ICODecoder.ICO_ICONDIRENTRY_LENGTH_BYTES,
- icoMaimed,
- ICODecoder.ICO_HEADER_LENGTH_BYTES + 4 * ICODecoder.ICO_ICONDIRENTRY_LENGTH_BYTES,
- icoBytes.length - ICODecoder.ICO_HEADER_LENGTH_BYTES - 5 * ICODecoder.ICO_ICONDIRENTRY_LENGTH_BYTES);
-
- ICODecoder decoder = new ICODecoder(getInstrumentation().getTargetContext(), icoMaimed, 0,
- icoMaimed.length);
- fAssertNotNull("Expecting Golem favicon to not fail decoding.", decoder.decode());
- fAssertEquals("Expecting Golem favicon icon directory to contain one less bitmap.",
- mGolemNumIconDirEntries - 1, decoder.getIconDirectory().length);
- }
-
- private byte[] readICO(String fileName) throws IOException {
- String filePath = "ico_decoder_favicons" + File.separator + fileName;
- InputStream icoStream = getInstrumentation().getContext().getAssets().open(filePath);
- ByteArrayOutputStream byteStream = new ByteArrayOutputStream(icoStream.available());
-
- int readByte;
- while ((readByte = icoStream.read()) != -1) {
- byteStream.write(readByte);
- }
-
- return byteStream.toByteArray();
- }
-}
-
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java
deleted file mode 100644
index f9a6bcef7..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
-import static org.mozilla.gecko.tests.helpers.WaitHelper.waitFor;
-
-import org.mozilla.gecko.tests.components.GeckoViewComponent.InputConnectionTest;
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-import org.mozilla.gecko.tests.helpers.NavigationHelper;
-
-import com.robotium.solo.Condition;
-
-import android.view.KeyEvent;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-
-/**
- * Tests the proper operation of GeckoInputConnection
- */
-public class testInputConnection extends JavascriptBridgeTest {
-
- private static final String INITIAL_TEXT = "foo";
-
- public void testInputConnection() throws InterruptedException {
- GeckoHelper.blockForReady();
-
- final String url = mStringHelper.ROBOCOP_INPUT_URL;
- NavigationHelper.enterAndLoadUrl(url);
- mToolbar.assertTitle(url);
-
- // First run tests inside the normal input field.
- getJS().syncCall("focus_input", INITIAL_TEXT);
- mGeckoView.mTextInput
- .waitForInputConnection()
- .testInputConnection(new BasicInputConnectionTest());
-
- // Then switch focus to the text area and rerun tests.
- getJS().syncCall("focus_text_area", INITIAL_TEXT);
- mGeckoView.mTextInput
- .waitForInputConnection()
- .testInputConnection(new BasicInputConnectionTest());
-
- // Then switch focus to the content editable and rerun tests.
- getJS().syncCall("focus_content_editable", INITIAL_TEXT);
- mGeckoView.mTextInput
- .waitForInputConnection()
- .testInputConnection(new BasicInputConnectionTest());
-
- // Then switch focus to the design mode document and rerun tests.
- getJS().syncCall("focus_design_mode", INITIAL_TEXT);
- mGeckoView.mTextInput
- .waitForInputConnection()
- .testInputConnection(new BasicInputConnectionTest());
-
- // Then switch focus to the resetting input field, and run tests there.
- getJS().syncCall("focus_resetting_input", "");
- mGeckoView.mTextInput
- .waitForInputConnection()
- .testInputConnection(new ResettingInputConnectionTest());
-
- // Then switch focus to the hiding input field, and run tests there.
- getJS().syncCall("focus_hiding_input", "");
- mGeckoView.mTextInput
- .waitForInputConnection()
- .testInputConnection(new HidingInputConnectionTest());
-
- getJS().syncCall("finish_test");
- }
-
- private class BasicInputConnectionTest extends InputConnectionTest {
- @Override
- public void test(final InputConnection ic, EditorInfo info) {
- waitFor("focus change", new Condition() {
- @Override
- public boolean isSatisfied() {
- return INITIAL_TEXT.equals(getText(ic));
- }
- });
-
- // Test setSelection
- ic.setSelection(0, 3);
- assertSelection("Can set selection to range", ic, 0, 3);
- ic.setSelection(-3, 6);
- // Test both forms of assert
- assertTextAndSelection("Can handle invalid range", ic, INITIAL_TEXT, 0, 3);
- ic.setSelection(3, 3);
- assertSelectionAt("Can collapse selection", ic, 3);
- ic.setSelection(4, 4);
- assertTextAndSelectionAt("Can handle invalid cursor", ic, INITIAL_TEXT, 3);
-
- // Test commitText
- ic.commitText("", 10); // Selection past end of new text
- assertTextAndSelectionAt("Can commit empty text", ic, "foo", 3);
- ic.commitText("bar", 1); // Selection at end of new text
- assertTextAndSelectionAt("Can commit text (select after)", ic, "foobar", 6);
- ic.commitText("foo", -1); // Selection at start of new text
- assertTextAndSelectionAt("Can commit text (select before)", ic, "foobarfoo", 5);
-
- // Test deleteSurroundingText
- ic.deleteSurroundingText(1, 0);
- assertTextAndSelectionAt("Can delete text before", ic, "foobrfoo", 4);
- ic.deleteSurroundingText(1, 1);
- assertTextAndSelectionAt("Can delete text before/after", ic, "foofoo", 3);
- ic.deleteSurroundingText(0, 10);
- assertTextAndSelectionAt("Can delete text after", ic, "foo", 3);
- ic.deleteSurroundingText(0, 0);
- assertTextAndSelectionAt("Can delete empty text", ic, "foo", 3);
-
- // Test setComposingText
- ic.setComposingText("foo", 1);
- assertTextAndSelectionAt("Can start composition", ic, "foofoo", 6);
- ic.setComposingText("", 1);
- assertTextAndSelectionAt("Can set empty composition", ic, "foo", 3);
- ic.setComposingText("bar", 1);
- assertTextAndSelectionAt("Can update composition", ic, "foobar", 6);
-
- // Test finishComposingText
- ic.finishComposingText();
- assertTextAndSelectionAt("Can finish composition", ic, "foobar", 6);
-
- // Test setComposingRegion
- ic.setComposingRegion(0, 3);
- assertTextAndSelectionAt("Can set composing region", ic, "foobar", 6);
-
- ic.setComposingText("far", 1);
- assertTextAndSelectionAt("Can set composing region text", ic, "farbar", 3);
-
- ic.setComposingRegion(1, 4);
- assertTextAndSelectionAt("Can set existing composing region", ic, "farbar", 3);
-
- ic.setComposingText("rab", 3);
- assertTextAndSelectionAt("Can set new composing region text", ic, "frabar", 6);
-
- // Test getTextBeforeCursor
- fAssertEquals("Can retrieve text before cursor", "bar", ic.getTextBeforeCursor(3, 0));
-
- // Test getTextAfterCursor
- fAssertEquals("Can retrieve text after cursor", "", ic.getTextAfterCursor(3, 0));
-
- ic.finishComposingText();
- assertTextAndSelectionAt("Can finish composition", ic, "frabar", 6);
-
- // Test sendKeyEvent
- final KeyEvent shiftKey = new KeyEvent(KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_SHIFT_LEFT);
- final KeyEvent leftKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT);
- final KeyEvent tKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_T);
-
- ic.sendKeyEvent(shiftKey);
- ic.sendKeyEvent(leftKey);
- ic.sendKeyEvent(KeyEvent.changeAction(leftKey, KeyEvent.ACTION_UP));
- ic.sendKeyEvent(KeyEvent.changeAction(shiftKey, KeyEvent.ACTION_UP));
- assertTextAndSelection("Can select using key event", ic, "frabar", 6, 5);
-
- ic.sendKeyEvent(tKey);
- ic.sendKeyEvent(KeyEvent.changeAction(tKey, KeyEvent.ACTION_UP));
- assertTextAndSelectionAt("Can type using event", ic, "frabat", 6);
-
- ic.deleteSurroundingText(6, 0);
- assertTextAndSelectionAt("Can clear text", ic, "", 0);
-
- // Bug 1133802, duplication when setting the same composing text more than once.
- ic.setComposingText("foo", 1);
- assertTextAndSelectionAt("Can set the composing text", ic, "foo", 3);
- ic.setComposingText("foo", 1);
- assertTextAndSelectionAt("Can set the same composing text", ic, "foo", 3);
- ic.setComposingText("bar", 1);
- assertTextAndSelectionAt("Can set different composing text", ic, "bar", 3);
- ic.setComposingText("bar", 1);
- assertTextAndSelectionAt("Can set the same composing text", ic, "bar", 3);
- ic.setComposingText("bar", 1);
- assertTextAndSelectionAt("Can set the same composing text again", ic, "bar", 3);
- ic.finishComposingText();
- assertTextAndSelectionAt("Can finish composing text", ic, "bar", 3);
-
- ic.deleteSurroundingText(3, 0);
- assertTextAndSelectionAt("Can clear text", ic, "", 0);
-
- // Bug 1209465, cannot enter ideographic space character by itself (U+3000).
- ic.commitText("\u3000", 1);
- assertTextAndSelectionAt("Can commit ideographic space", ic, "\u3000", 1);
-
- ic.deleteSurroundingText(1, 0);
- assertTextAndSelectionAt("Can clear text", ic, "", 0);
-
- // Bug 1051556, exception due to committing text changes during flushing.
- ic.setComposingText("bad", 1);
- assertTextAndSelectionAt("Can set the composing text", ic, "bad", 3);
- getJS().asyncCall("test_reflush_changes");
- // Wait for text change notifications to come in.
- processGeckoEvents();
- assertTextAndSelectionAt("Can re-flush text changes", ic, "good", 4);
- ic.setComposingText("done", 1);
- assertTextAndSelectionAt("Can update composition after re-flushing", ic, "gooddone", 8);
- ic.finishComposingText();
- assertTextAndSelectionAt("Can finish composing text", ic, "gooddone", 8);
-
- ic.deleteSurroundingText(8, 0);
- assertTextAndSelectionAt("Can clear text", ic, "", 0);
-
- // Bug 1241558 - wrong selection due to ignoring selection notification.
- ic.setComposingText("foobar", 1);
- assertTextAndSelectionAt("Can set the composing text", ic, "foobar", 6);
- getJS().asyncCall("test_set_selection");
- // Wait for text change notifications to come in.
- processGeckoEvents();
- assertTextAndSelectionAt("Can select after committing", ic, "foobar", 3);
- ic.setComposingText("barfoo", 1);
- assertTextAndSelectionAt("Can compose after selecting", ic, "barfoo", 6);
- ic.beginBatchEdit();
- ic.setSelection(3, 3);
- ic.finishComposingText();
- ic.deleteSurroundingText(1, 1);
- ic.endBatchEdit();
- assertTextAndSelectionAt("Can delete after committing", ic, "baoo", 2);
-
- ic.deleteSurroundingText(2, 2);
- assertTextAndSelectionAt("Can clear text", ic, "", 0);
-
- // Bug 1275371 - shift+backspace should not forward delete on Android.
- final KeyEvent delKey = new KeyEvent(KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_DEL);
-
- ic.beginBatchEdit();
- ic.commitText("foo", 1);
- ic.setSelection(1, 1);
- ic.endBatchEdit();
- assertTextAndSelectionAt("Can commit text", ic, "foo", 1);
-
- ic.sendKeyEvent(shiftKey);
- ic.sendKeyEvent(delKey);
- ic.sendKeyEvent(KeyEvent.changeAction(delKey, KeyEvent.ACTION_UP));
- assertTextAndSelectionAt("Can backspace with shift+backspace", ic, "oo", 0);
-
- ic.sendKeyEvent(delKey);
- ic.sendKeyEvent(KeyEvent.changeAction(delKey, KeyEvent.ACTION_UP));
- ic.sendKeyEvent(KeyEvent.changeAction(shiftKey, KeyEvent.ACTION_UP));
- assertTextAndSelectionAt("Cannot forward delete with shift+backspace", ic, "oo", 0);
-
- ic.deleteSurroundingText(0, 2);
- assertTextAndSelectionAt("Can clear text", ic, "", 0);
-
- // Bug 1123514 - exception due to incorrect text replacement offsets.
- getJS().syncCall("test_bug1123514");
- // Gecko will change text to 'abc' when we input 'b', potentially causing
- // incorrect calculation of text replacement offsets.
- ic.commitText("b", 1);
- // We don't assert text here because this test only works for input/textarea,
- // so an assertion would fail for contentEditable/designMode.
- processGeckoEvents();
- processInputConnectionEvents();
-
- ic.deleteSurroundingText(2, 1);
- assertTextAndSelectionAt("Can clear text", ic, "", 0);
-
- // Make sure we don't leave behind stale events for the following test.
- processGeckoEvents();
- processInputConnectionEvents();
- }
- }
-
- /**
- * ResettingInputConnectionTest performs tests on the resetting input in
- * robocop_input.html. Any test that uses the normal input should be put in
- * BasicInputConnectionTest.
- */
- private class ResettingInputConnectionTest extends InputConnectionTest {
- @Override
- public void test(final InputConnection ic, EditorInfo info) {
- waitFor("focus change", new Condition() {
- @Override
- public boolean isSatisfied() {
- return "".equals(getText(ic));
- }
- });
-
- // Bug 1199658, duplication when page has JS that resets input field value.
-
- ic.commitText("foo", 1);
- assertTextAndSelectionAt("Can commit text (resetting)", ic, "foo", 3);
-
- ic.setComposingRegion(0, 3);
- // The bug appears after composition update events are processed. We only
- // issue these events after some back-and-forth calls between the Gecko thread
- // and the input connection thread. Therefore, to ensure these events are
- // issued and to ensure the bug appears, we have to process all Gecko events,
- // then all input connection events, and finally all Gecko events again.
- processGeckoEvents();
- processInputConnectionEvents();
- processGeckoEvents();
- assertTextAndSelectionAt("Can set composing region (resetting)", ic, "foo", 3);
-
- ic.setComposingText("foobar", 1);
- processGeckoEvents();
- processInputConnectionEvents();
- processGeckoEvents();
- assertTextAndSelectionAt("Can change composing text (resetting)", ic, "foobar", 6);
-
- ic.setComposingText("baz", 1);
- processGeckoEvents();
- processInputConnectionEvents();
- processGeckoEvents();
- assertTextAndSelectionAt("Can reset composing text (resetting)", ic, "baz", 3);
-
- ic.finishComposingText();
- assertTextAndSelectionAt("Can finish composing text (resetting)", ic, "baz", 3);
-
- ic.deleteSurroundingText(3, 0);
- assertTextAndSelectionAt("Can clear text", ic, "", 0);
-
- // Make sure we don't leave behind stale events for the following test.
- processGeckoEvents();
- processInputConnectionEvents();
- }
- }
-
- /**
- * HidingInputConnectionTest performs tests on the hiding input in
- * robocop_input.html. Any test that uses the normal input should be put in
- * BasicInputConnectionTest.
- */
- private class HidingInputConnectionTest extends InputConnectionTest {
- @Override
- public void test(final InputConnection ic, EditorInfo info) {
- waitFor("focus change", new Condition() {
- @Override
- public boolean isSatisfied() {
- return "".equals(getText(ic));
- }
- });
-
- // Bug 1254629, crash when hiding input during input.
- ic.commitText("foo", 1);
- assertTextAndSelectionAt("Can commit text (hiding)", ic, "foo", 3);
-
- ic.commitText("!", 1);
- // The '!' key causes the input to hide in robocop_input.html,
- // and there won't be a text/selection update as a result.
- assertTextAndSelectionAt("Can handle hiding input", ic, "foo", 3);
-
- // Make sure we don't leave behind stale events for the following test.
- processGeckoEvents();
- processInputConnectionEvents();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputUrlBar.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputUrlBar.java
deleted file mode 100644
index c12ccef98..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputUrlBar.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Element;
-import org.mozilla.gecko.R;
-
-import android.widget.EditText;
-
-/**
- * Basic test of text editing within the editing mode.
- * - Enter some text, move the cursor around, and modifying some text.
- * - Check that all edit entry text is selected after switching about:home tabs.
- */
-public final class testInputUrlBar extends BaseTest {
- private Element mUrlBarEditElement;
- private EditText mUrlBarEditView;
-
- public void testInputUrlBar() {
- blockForGeckoReady();
-
- startEditingMode();
- assertUrlBarText("");
-
- // Avoid any auto domain completion by using a prefix that matches
- // nothing, including about: pages
- mActions.sendKeys("zy");
- assertUrlBarText("zy");
-
- mActions.sendKeys("cd");
- assertUrlBarText("zycd");
-
- mActions.sendSpecialKey(Actions.SpecialKey.LEFT);
- mActions.sendSpecialKey(Actions.SpecialKey.LEFT);
-
- // Inserting "" should not do anything.
- mActions.sendKeys("");
- assertUrlBarText("zycd");
-
- mActions.sendKeys("ef");
- assertUrlBarText("zyefcd");
-
- mActions.sendSpecialKey(Actions.SpecialKey.RIGHT);
- mActions.sendKeys("gh");
- assertUrlBarText("zyefcghd");
-
- final EditText editText = mUrlBarEditView;
- runOnUiThreadSync(new Runnable() {
- @Override
- public void run() {
- // Select "ef"
- editText.setSelection(2);
- }
- });
- mActions.sendKeys("op");
- assertUrlBarText("zyopefcghd");
-
- runOnUiThreadSync(new Runnable() {
- @Override
- public void run() {
- // Select "cg"
- editText.setSelection(6, 8);
- }
- });
- mActions.sendKeys("qr");
- assertUrlBarText("zyopefqrhd");
-
- runOnUiThreadSync(new Runnable() {
- @Override
- public void run() {
- // Select "op"
- editText.setSelection(4,2);
- }
- });
- mActions.sendKeys("st");
- assertUrlBarText("zystefqrhd");
-
- runOnUiThreadSync(new Runnable() {
- @Override
- public void run() {
- editText.selectAll();
- }
- });
- mActions.sendKeys("uv");
- assertUrlBarText("uv");
-
- // Dismiss the VKB
- mSolo.goBack();
-
- // Dismiss editing mode
- mSolo.goBack();
-
- waitForText(mStringHelper.TITLE_PLACE_HOLDER);
-
- // URL bar should have forgotten about "uv" text.
- startEditingMode();
- assertUrlBarText("");
-
- int width = mDriver.getGeckoWidth() / 2;
- int y = mDriver.getGeckoHeight() / 2;
-
- // Slide to the right, force URL bar entry to lose input focus
- mActions.drag(width, 0, y, y);
-
- // Select text and replace the content
- mSolo.clickOnView(mUrlBarEditView);
- mActions.sendKeys("yz");
-
- String yz = getUrlBarText();
- mAsserter.ok("yz".equals(yz), "Is the URL bar text \"yz\"?", yz);
- }
-
- private void startEditingMode() {
- focusUrlBar();
-
- mUrlBarEditElement = mDriver.findElement(getActivity(), R.id.url_edit_text);
- final int id = mUrlBarEditElement.getId();
- mUrlBarEditView = (EditText) getActivity().findViewById(id);
- }
-
- private String getUrlBarText() {
- final String elementText = mUrlBarEditElement.getText();
- final String editText = mUrlBarEditView.getText().toString();
- mAsserter.is(editText, elementText, "Does URL bar editText == elementText?");
-
- return editText;
- }
-
- private void assertUrlBarText(String expectedText) {
- String actualText = getUrlBarText();
- mAsserter.is(actualText, expectedText, "Does URL bar actualText == expectedText?");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testJarReader.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testJarReader.java
deleted file mode 100644
index 9310599d3..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testJarReader.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.InputStream;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.util.GeckoJarReader;
-
-import android.content.Context;
-
-/**
- * A basic jar reader test. Tests reading a png from fennec's apk, as well
- * as loading some invalid jar urls.
- */
-public class testJarReader extends BaseTest {
- public void testJarReader() {
- // Invalid characters are escaped.
- final String s = GeckoJarReader.computeJarURI("some[1].apk", "something/else");
- mAsserter.ok(!s.contains("["), "Illegal characters are escaped away.", null);
- mAsserter.ok(!s.toLowerCase().contains("%2f"), "Path characters aren't escaped.", null);
-
- final Context context = getInstrumentation().getTargetContext().getApplicationContext();
- String appPath = getActivity().getApplication().getPackageResourcePath();
- mAsserter.isnot(appPath, null, "getPackageResourcePath is non-null");
-
- // Test reading a file from a jar url that looks correct.
- String url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME;
- InputStream stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png");
- mAsserter.isnot(stream, null, "JarReader returned non-null for valid file in valid jar");
-
- // Test looking for an non-existent file in a jar.
- url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME;
- stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png");
- mAsserter.is(stream, null, "JarReader returned null for non-existent file in valid jar");
-
- // Test looking for a file that doesn't exist in the APK.
- url = "jar:file://" + appPath + "!/" + "BAD" + AppConstants.OMNIJAR_NAME;
- stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png");
- mAsserter.is(stream, null, "JarReader returned null for valid file in invalid jar file");
-
- // Test looking for a file that doesn't exist in the APK.
- // Bug 1174922, prefixed string / length error.
- url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME + "BAD";
- stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png");
- mAsserter.is(stream, null, "JarReader returned null for valid file in other invalid jar file");
-
- // Test looking for an jar with an invalid url.
- url = "jar:file://" + appPath + "!" + "!/" + AppConstants.OMNIJAR_NAME;
- stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png");
- mAsserter.is(stream, null, "JarReader returned null for bad jar url");
-
- // Test looking for a file that doesn't exist on disk.
- url = "jar:file://" + appPath + "BAD" + "!/" + AppConstants.OMNIJAR_NAME;
- stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png");
- mAsserter.is(stream, null, "JarReader returned null for a non-existent APK");
-
- // This test completes very quickly. If it completes too soon, the
- // minidumps directory may not be created before the process is
- // taken down, causing bug 722166.
- blockForGeckoReady();
- }
-
- private String getData(InputStream stream) {
- return new java.util.Scanner(stream).useDelimiter("\\A").next();
- }
-
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testJavascriptBridge.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testJavascriptBridge.java
deleted file mode 100644
index 724b6b4ab..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testJavascriptBridge.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.*;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Tests the proper operation of JavascriptBridge and JavaBridge,
- * which are used by tests for communication between Java and JS.
- */
-public class testJavascriptBridge extends JavascriptBridgeTest {
-
- private static final String TEST_JS = "testJavascriptBridge.js";
-
- private boolean syncCallReceived;
-
- public void testJavascriptBridge() {
- blockForReadyAndLoadJS(TEST_JS);
- getJS().syncCall("check_js_int_arg", 1);
- }
-
- public void checkJavaIntArg(final int int2) {
- // Async call from JS
- fAssertEquals("Integer argument matches", 2, int2);
- getJS().syncCall("check_js_double_arg", 3.0D);
- }
-
- public void checkJavaDoubleArg(final double double4) {
- // Async call from JS
- fAssertEquals("Double argument matches", 4.0, double4);
- getJS().syncCall("check_js_boolean_arg", false);
- }
-
- public void checkJavaBooleanArg(final boolean booltrue) {
- // Async call from JS
- fAssertEquals("Boolean argument matches", true, booltrue);
- getJS().syncCall("check_js_string_arg", "foo");
- }
-
- public void checkJavaStringArg(final String stringbar) throws JSONException {
- // Async call from JS
- fAssertEquals("String argument matches", "bar", stringbar);
- final JSONObject obj = new JSONObject();
- obj.put("caller", "java");
- getJS().syncCall("check_js_object_arg", (JSONObject) obj);
- }
-
- public void checkJavaObjectArg(final JSONObject obj) throws JSONException {
- // Async call from JS
- fAssertEquals("Object argument matches", "js", obj.getString("caller"));
- getJS().syncCall("check_js_sync_call");
- }
-
- public void doJSSyncCall() {
- // Sync call from JS
- syncCallReceived = true;
- getJS().asyncCall("respond_to_js_sync_call");
- }
-
- public void checkJSSyncCallReceived() {
- fAssertTrue("Received sync call before end of test", syncCallReceived);
- // End of test
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLinkContextMenu.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLinkContextMenu.java
deleted file mode 100644
index 556ed0e07..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLinkContextMenu.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-public class testLinkContextMenu extends ContentContextMenuTest {
-
- // Test website strings
- private static String LINK_PAGE_URL;
- private static String BLANK_PAGE_URL;
- private static final String LINK_PAGE_TITLE = "Big Link";
-
- public void testLinkContextMenu() {
- final String linkMenuItems [] = mStringHelper.CONTEXT_MENU_ITEMS_IN_NORMAL_TAB;
-
- blockForGeckoReady();
-
- LINK_PAGE_URL=getAbsoluteUrl(mStringHelper.ROBOCOP_BIG_LINK_URL);
- BLANK_PAGE_URL=getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- loadUrlAndWait(LINK_PAGE_URL);
- waitForText(LINK_PAGE_TITLE);
-
- verifyContextMenuItems(linkMenuItems); // Verify context menu items are correct
- openTabFromContextMenu(linkMenuItems[0],2); // Test the "Open in New Tab" option - expecting 2 tabs: the original and the new one
- openTabFromContextMenu(linkMenuItems[1],2); // Test the "Open in Private Tab" option - expecting only 2 tabs in normal mode
- verifyCopyOption(linkMenuItems[2], BLANK_PAGE_URL); // Test the "Copy Link" option
- verifyShareOption(linkMenuItems[3], LINK_PAGE_TITLE); // Test the "Share Link" option
- verifyBookmarkLinkOption(linkMenuItems[4], BLANK_PAGE_URL); // Test the "Bookmark Link" option
- }
-
- @Override
- public void tearDown() throws Exception {
- mDatabaseHelper.deleteBookmark(BLANK_PAGE_URL);
- super.tearDown();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLoad.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLoad.java
deleted file mode 100644
index e62bd7899..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLoad.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-/**
- * A basic page load test.
- * - loads a page
- * - verifies it rendered properly
- * - verifies the displayed url is correct
- */
-public class testLoad extends PixelTest {
- public void testLoad() {
- String url = getAbsoluteUrl(mStringHelper.ROBOCOP_BOXES_URL);
-
- blockForGeckoReady();
-
- loadAndVerifyBoxes(url);
-
- verifyUrl(url);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLoginsProvider.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLoginsProvider.java
deleted file mode 100644
index 10dde28cd..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testLoginsProvider.java
+++ /dev/null
@@ -1,387 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.content.ContentProvider;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.Uri;
-
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserContract.DeletedLogins;
-import org.mozilla.gecko.db.BrowserContract.Logins;
-import org.mozilla.gecko.db.BrowserContract.LoginsDisabledHosts;
-import org.mozilla.gecko.db.LoginsProvider;
-
-import java.util.concurrent.Callable;
-
-import static org.mozilla.gecko.db.BrowserContract.CommonColumns._ID;
-import static org.mozilla.gecko.db.BrowserContract.DeletedLogins.TABLE_DELETED_LOGINS;
-import static org.mozilla.gecko.db.BrowserContract.Logins.TABLE_LOGINS;
-import static org.mozilla.gecko.db.BrowserContract.LoginsDisabledHosts.TABLE_DISABLED_HOSTS;
-
-public class testLoginsProvider extends ContentProviderTest {
-
- private static final String DB_NAME = "browser.db";
-
- private final TestCase[] TESTS_TO_RUN = {
- new InsertLoginsTest(),
- new UpdateLoginsTest(),
- new DeleteLoginsTest(),
- new InsertDeletedLoginsTest(),
- new InsertDeletedLoginsFailureTest(),
- new DisabledHostsInsertTest(),
- new DisabledHostsInsertFailureTest(),
- new InsertLoginsWithDefaultValuesTest(),
- new InsertLoginsWithDuplicateGuidFailureTest(),
- new DeleteLoginsByNonExistentGuidTest(),
- };
-
- /**
- * Factory function that makes new LoginsProvider instances.
- * <p>
- * We want a fresh provider each test, so this should be invoked in
- * <code>setUp</code> before each individual test.
- */
- private static final Callable<ContentProvider> sProviderFactory = new Callable<ContentProvider>() {
- @Override
- public ContentProvider call() {
- return new LoginsProvider();
- }
- };
-
- @Override
- public void setUp() throws Exception {
- super.setUp(sProviderFactory, BrowserContract.LOGINS_AUTHORITY, DB_NAME);
- for (TestCase test: TESTS_TO_RUN) {
- mTests.add(test);
- }
- }
-
- public void testLoginProviderTests() throws Exception {
- for (Runnable test : mTests) {
- final String testName = test.getClass().getSimpleName();
- setTestName(testName);
- ensureEmptyDatabase();
- mAsserter.dumpLog("testLoginsProvider: Database empty - Starting " + testName + ".");
- test.run();
- }
- }
-
- /**
- * Wipe DB.
- */
- private void ensureEmptyDatabase() {
- getWritableDatabase(Logins.CONTENT_URI).delete(TABLE_LOGINS, null, null);
- getWritableDatabase(DeletedLogins.CONTENT_URI).delete(TABLE_DELETED_LOGINS, null, null);
- getWritableDatabase(LoginsDisabledHosts.CONTENT_URI).delete(TABLE_DISABLED_HOSTS, null, null);
- }
-
- private SQLiteDatabase getWritableDatabase(Uri uri) {
- Uri testUri = appendUriParam(uri, BrowserContract.PARAM_IS_TEST, "1");
- DelegatingTestContentProvider delegateProvider = (DelegatingTestContentProvider) mProvider;
- LoginsProvider loginsProvider = (LoginsProvider) delegateProvider.getTargetProvider();
- return loginsProvider.getWritableDatabaseForTesting(testUri);
- }
-
- /**
- * LoginsProvider insert logins test.
- */
- private class InsertLoginsTest extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues contentValues = createLogin("http://www.example.com", "http://www.example.com",
- "http://www.example.com", "username1", "password1", "username1", "password1", "guid1");
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.Logins.CONTENT_URI, contentValues));
- verifyLoginExists(contentValues, id);
- Cursor cursor = mProvider.query(Logins.CONTENT_URI, null, Logins.GUID + " = ?", new String[] { "guid1" }, null);
- verifyRowMatches(contentValues, cursor, "logins found");
-
- // Empty ("") encrypted username and password are valid.
- contentValues = createLogin("http://www.example.com", "http://www.example.com",
- "http://www.example.com", "username1", "password1", "", "", "guid2");
- id = ContentUris.parseId(mProvider.insert(BrowserContract.Logins.CONTENT_URI, contentValues));
- verifyLoginExists(contentValues, id);
- cursor = mProvider.query(Logins.CONTENT_URI, null, Logins.GUID + " = ?", new String[] { "guid2" }, null);
- verifyRowMatches(contentValues, cursor, "logins found");
- }
- }
-
- /**
- * LoginsProvider updates logins test.
- */
- private class UpdateLoginsTest extends TestCase {
- @Override
- public void test() throws Exception {
- final String guid1 = "guid1";
- ContentValues contentValues = createLogin("http://www.example.com", "http://www.example.com",
- "http://www.example.com", "username1", "password1", "username1", "password1", guid1);
- long timeBeforeCreated = System.currentTimeMillis();
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.Logins.CONTENT_URI, contentValues));
- long timeAfterCreated = System.currentTimeMillis();
- verifyLoginExists(contentValues, id);
-
- Cursor cursor = getLoginById(id);
- try {
- mAsserter.ok(cursor.moveToFirst(), "cursor is not empty", "");
- verifyBounded(timeBeforeCreated, cursor.getLong(cursor.getColumnIndexOrThrow(Logins.TIME_CREATED)), timeAfterCreated);
- } finally {
- cursor.close();
- }
-
- contentValues.put(BrowserContract.Logins.ENCRYPTED_USERNAME, "username2");
- contentValues.put(Logins.ENCRYPTED_PASSWORD, "password2");
-
- Uri updateUri = Logins.CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).build();
- int numUpdated = mProvider.update(updateUri, contentValues, null, null);
- mAsserter.is(1, numUpdated, "Correct number updated");
- verifyLoginExists(contentValues, id);
-
- contentValues.put(BrowserContract.Logins.ENCRYPTED_USERNAME, "username1");
- contentValues.put(Logins.ENCRYPTED_PASSWORD, "password1");
-
- updateUri = Logins.CONTENT_URI;
- numUpdated = mProvider.update(updateUri, contentValues, Logins.GUID + " = ?", new String[]{guid1});
- mAsserter.is(1, numUpdated, "Correct number updated");
- verifyLoginExists(contentValues, id);
- }
- }
-
- /**
- * LoginsProvider deletion logins test.
- * - inserts a new logins
- * - deletes the logins and verify deleted-logins table has entry for deleted guid.
- */
- private class DeleteLoginsTest extends TestCase {
- @Override
- public void test() throws Exception {
- final String guid1 = "guid1";
- ContentValues contentValues = createLogin("http://www.example.com", "http://www.example.com",
- "http://www.example.com", "username1", "password1", "username1", "password1", guid1);
- long id = ContentUris.parseId(mProvider.insert(Logins.CONTENT_URI, contentValues));
- verifyLoginExists(contentValues, id);
-
- Uri deletedUri = Logins.CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).build();
- int numDeleted = mProvider.delete(deletedUri, null, null);
- mAsserter.is(1, numDeleted, "Correct number deleted");
- verifyNoRowExists(Logins.CONTENT_URI, "No login entry found");
-
- contentValues = new ContentValues();
- contentValues.put(DeletedLogins.GUID, guid1);
- Cursor cursor = mProvider.query(DeletedLogins.CONTENT_URI, null, null, null, null);
- verifyRowMatches(contentValues, cursor, "deleted-login found");
- cursor = mProvider.query(DeletedLogins.CONTENT_URI, null, DeletedLogins.GUID + " = ?", new String[] { guid1 }, null);
- verifyRowMatches(contentValues, cursor, "deleted-login found");
- }
- }
-
- /**
- * LoginsProvider re-insert logins test.
- * - inserts a row into deleted-logins
- * - insert the same login (matching guid) and verify deleted-logins table is empty.
- */
- private class InsertDeletedLoginsTest extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues contentValues = new ContentValues();
- contentValues.put(DeletedLogins.GUID, "guid1");
- long id = ContentUris.parseId(mProvider.insert(DeletedLogins.CONTENT_URI, contentValues));
- final Uri insertedUri = DeletedLogins.CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).build();
- Cursor cursor = mProvider.query(insertedUri, null, null, null, null);
- verifyRowMatches(contentValues, cursor, "deleted-login found");
- verifyNoRowExists(BrowserContract.Logins.CONTENT_URI, "No login entry found");
-
- contentValues = createLogin("http://www.example.com", "http://www.example.com",
- "http://www.example.com", "username1", "password1", "username1", "password1", "guid1");
- id = ContentUris.parseId(mProvider.insert(Logins.CONTENT_URI, contentValues));
- verifyLoginExists(contentValues, id);
- verifyNoRowExists(DeletedLogins.CONTENT_URI, "No deleted-login entry found");
- }
- }
-
- /**
- * LoginsProvider insert Deleted logins test.
- * - inserts a row into deleted-login without GUID.
- */
- private class InsertDeletedLoginsFailureTest extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues contentValues = new ContentValues();
- try {
- mProvider.insert(DeletedLogins.CONTENT_URI, contentValues);
- fail("Failed to throw IllegalArgumentException while missing GUID");
- } catch (Exception e) {
- mAsserter.is(e.getClass(), IllegalArgumentException.class, "IllegalArgumentException thrown for invalid GUID");
- }
- }
- }
-
- /**
- * LoginsProvider disabled host test.
- * - inserts a disabled-host
- * - delete the inserted disabled-host and verify disabled-hosts table is empty.
- */
- private class DisabledHostsInsertTest extends TestCase {
- @Override
- public void test() throws Exception {
- final String hostname = "localhost";
- final ContentValues contentValues = new ContentValues();
- contentValues.put(LoginsDisabledHosts.HOSTNAME, hostname);
- mProvider.insert(LoginsDisabledHosts.CONTENT_URI, contentValues);
- final Uri insertedUri = LoginsDisabledHosts.CONTENT_URI.buildUpon().appendPath("hostname").appendPath(hostname).build();
- final Cursor cursor = mProvider.query(insertedUri, null, null, null, null);
- verifyRowMatches(contentValues, cursor, "disabled-hosts found");
-
- final Uri deletedUri = LoginsDisabledHosts.CONTENT_URI.buildUpon().appendPath("hostname").appendPath(hostname).build();
- final int numDeleted = mProvider.delete(deletedUri, null, null);
- mAsserter.is(1, numDeleted, "Correct number deleted");
- verifyNoRowExists(LoginsDisabledHosts.CONTENT_URI, "No disabled-hosts entry found");
- }
- }
-
- /**
- * LoginsProvider disabled host insert failure testcase.
- * - inserts a disabled-host without providing hostname
- */
- private class DisabledHostsInsertFailureTest extends TestCase {
- @Override
- public void test() throws Exception {
- final String hostname = "localhost";
- final ContentValues contentValues = new ContentValues();
- try {
- mProvider.insert(LoginsDisabledHosts.CONTENT_URI, contentValues);
- fail("Failed to throw IllegalArgumentException while missing hostname");
- } catch (Exception e) {
- mAsserter.is(e.getClass(), IllegalArgumentException.class, "IllegalArgumentException thrown for invalid hostname");
- }
- }
- }
-
- /**
- * LoginsProvider login insertion with default values test.
- * - insert a login missing GUID, FORM_SUBMIT_URL, HTTP_REALM and verify default values are set.
- */
- private class InsertLoginsWithDefaultValuesTest extends TestCase {
- @Override
- protected void test() throws Exception {
- ContentValues contentValues = createLogin("http://www.example.com", "http://www.example.com",
- "http://www.example.com", "username1", "password1", "username1", "password1", null);
- // Remove GUID, HTTP_REALM, FORM_SUBMIT_URL from content values
- contentValues.remove(Logins.GUID);
- contentValues.remove(Logins.FORM_SUBMIT_URL);
- contentValues.remove(Logins.HTTP_REALM);
-
- long id = ContentUris.parseId(mProvider.insert(BrowserContract.Logins.CONTENT_URI, contentValues));
- Cursor cursor = getLoginById(id);
- assertNotNull(cursor);
- cursor.moveToFirst();
-
- mAsserter.isnot(cursor.getString(cursor.getColumnIndex(Logins.GUID)), null, "GUID is not null");
- mAsserter.is(cursor.getString(cursor.getColumnIndex(Logins.HTTP_REALM)), null, "HTTP_REALM is not null");
- mAsserter.is(cursor.getString(cursor.getColumnIndex(Logins.FORM_SUBMIT_URL)), null, "FORM_SUBMIT_URL is not null");
- mAsserter.isnot(cursor.getString(cursor.getColumnIndex(Logins.TIME_LAST_USED)), null, "TIME_LAST_USED is not null");
- mAsserter.isnot(cursor.getString(cursor.getColumnIndex(Logins.TIME_CREATED)), null, "TIME_CREATED is not null");
- mAsserter.isnot(cursor.getString(cursor.getColumnIndex(Logins.TIME_PASSWORD_CHANGED)), null, "TIME_PASSWORD_CHANGED is not null");
- mAsserter.is(cursor.getString(cursor.getColumnIndex(Logins.ENC_TYPE)), "0", "ENC_TYPE is 0");
- mAsserter.is(cursor.getString(cursor.getColumnIndex(Logins.TIMES_USED)), "0", "TIMES_USED is 0");
-
- // Verify other values.
- verifyRowMatches(contentValues, cursor, "Updated login found");
- }
- }
-
- /**
- * LoginsProvider login insertion with duplicate GUID test.
- * - insert two different logins with same GUID and verify that only one login exists.
- */
- private class InsertLoginsWithDuplicateGuidFailureTest extends TestCase {
- @Override
- protected void test() throws Exception {
- final String guid = "guid1";
- ContentValues contentValues = createLogin("http://www.example.com", "http://www.example.com",
- "http://www.example.com", "username1", "password1", "username1", "password1", guid);
- long id1 = ContentUris.parseId(mProvider.insert(BrowserContract.Logins.CONTENT_URI, contentValues));
- verifyLoginExists(contentValues, id1);
-
- // Insert another login with duplicate GUID.
- contentValues = createLogin("http://www.example2.com", "http://www.example2.com",
- "http://www.example2.com", "username2", "password2", "username2", "password2", guid);
- Uri insertUri = mProvider.insert(Logins.CONTENT_URI, contentValues);
- mAsserter.is(insertUri, null, "Duplicate Guid insertion id1");
-
- // Verify login with id1 still exists.
- verifyLoginExists(contentValues, id1);
- }
- }
-
- /**
- * LoginsProvider deletion by non-existent GUID test.
- * - delete a login with random GUID and verify that no entry was deleted.
- */
- private class DeleteLoginsByNonExistentGuidTest extends TestCase {
- @Override
- protected void test() throws Exception {
- Uri deletedUri = Logins.CONTENT_URI;
- int numDeleted = mProvider.delete(deletedUri, Logins.GUID + "= ?", new String[] { "guid1" });
- mAsserter.is(0, numDeleted, "Correct number deleted");
- }
- }
-
- private void verifyBounded(long left, long middle, long right) {
- mAsserter.ok(left <= middle, "Left <= middle", left + " <= " + middle);
- mAsserter.ok(middle <= right, "Middle <= right", middle + " <= " + right);
- }
-
- private Cursor getById(Uri uri, long id, String[] projection) {
- return mProvider.query(uri, projection,
- _ID + " = ?",
- new String[] { String.valueOf(id) },
- null);
- }
-
- private Cursor getLoginById(long id) {
- return getById(Logins.CONTENT_URI, id, null);
- }
-
- private void verifyLoginExists(ContentValues contentValues, long id) {
- Cursor cursor = getLoginById(id);
- verifyRowMatches(contentValues, cursor, "Updated login found");
- }
-
- private void verifyRowMatches(ContentValues contentValues, Cursor cursor, String name) {
- try {
- mAsserter.ok(cursor.moveToFirst(), name, "cursor is not empty");
- CursorMatches(cursor, contentValues);
- } finally {
- cursor.close();
- }
- }
-
- private void verifyNoRowExists(Uri contentUri, String name) {
- Cursor cursor = mProvider.query(contentUri, null, null, null, null);
- try {
- mAsserter.is(0, cursor.getCount(), name);
- } finally {
- cursor.close();
- }
- }
-
- private ContentValues createLogin(String hostname, String httpRealm, String formSubmitUrl,
- String usernameField, String passwordField, String encryptedUsername,
- String encryptedPassword, String guid) {
- final ContentValues values = new ContentValues();
- values.put(Logins.HOSTNAME, hostname);
- values.put(Logins.HTTP_REALM, httpRealm);
- values.put(Logins.FORM_SUBMIT_URL, formSubmitUrl);
- values.put(Logins.USERNAME_FIELD, usernameField);
- values.put(Logins.PASSWORD_FIELD, passwordField);
- values.put(Logins.ENCRYPTED_USERNAME, encryptedUsername);
- values.put(Logins.ENCRYPTED_PASSWORD, encryptedPassword);
- values.put(Logins.GUID, guid);
- return values;
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testMailToContextMenu.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testMailToContextMenu.java
deleted file mode 100644
index af674f441..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testMailToContextMenu.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-public class testMailToContextMenu extends ContentContextMenuTest {
-
- // Test website strings
- private static String MAILTO_PAGE_URL;
- private static final String mailtoMenuItems [] = {"Copy Email Address", "Share Email Address"};
-
- public void testMailToContextMenu() {
- final String MAILTO_PAGE_TITLE = mStringHelper.ROBOCOP_BIG_MAILTO_TITLE;
-
- blockForGeckoReady();
-
- MAILTO_PAGE_URL=getAbsoluteUrl(mStringHelper.ROBOCOP_BIG_MAILTO_URL);
- loadUrlAndWait(MAILTO_PAGE_URL);
- waitForText(MAILTO_PAGE_TITLE);
-
- verifyContextMenuItems(mailtoMenuItems);
- verifyCopyOption(mailtoMenuItems[0], "foo.bar@example.com"); // Test the "Copy Email Address" option
- verifyShareOption(mailtoMenuItems[1], MAILTO_PAGE_TITLE); // Test the "Share Email Address" option
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java
deleted file mode 100644
index 2ae2bb532..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertArrayEquals;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-import org.mozilla.gecko.background.nativecode.NativeCrypto;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-
-import android.os.SystemClock;
-
-/**
- * Tests the Java wrapper over native implementations of crypto code. Test vectors from:
- * * PBKDF2SHA256:
- * - <https://github.com/ircmaxell/PHP-PasswordLib/blob/master/test/Data/Vectors/pbkdf2-draft-josefsson-sha256.test-vectors>
- - <https://gitorious.org/scrypt/nettle-scrypt/blobs/37c0d5288e991604fe33dba2f1724986a8dddf56/testsuite/pbkdf2-test.c>
- * SHA-1:
- - <http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c>
- */
-public class testNativeCrypto extends UITest {
- private final static String LOGTAG = "testNativeCrypto";
-
- /**
- * Robocop supports only a single test function per test class. Therefore, we
- * have a single top-level test function that dispatches to sub-tests,
- * accepting that we might fail part way through the cycle. Proper JUnit 3
- * testing can't land soon enough!
- *
- * @throws Exception
- */
- public void test() throws Exception {
- // This test could complete very quickly. If it completes too soon, the
- // minidumps directory may not be created before the process is
- // taken down, causing bug 722166. But we can't run the test and then block
- // for Gecko:Ready, since it may have arrived before we block. So we wait.
- // Again, JUnit 3 can't land soon enough!
- GeckoHelper.blockForReady();
-
- _testPBKDF2SHA256A();
- _testPBKDF2SHA256B();
- _testPBKDF2SHA256C();
- _testPBKDF2SHA256scryptA();
- _testPBKDF2SHA256scryptB();
- _testPBKDF2SHA256InvalidLenArg();
-
- _testSHA1();
- _testSHA1AgainstMessageDigest();
-
- _testSHA256();
- _testSHA256MultiPart();
- _testSHA256AgainstMessageDigest();
- _testSHA256WithMultipleUpdatesFromStream();
- }
-
- public void _testPBKDF2SHA256A() throws UnsupportedEncodingException, GeneralSecurityException {
- final String p = "password";
- final String s = "salt";
- final int dkLen = 32;
-
- checkPBKDF2SHA256(p, s, 1, dkLen, "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b");
- checkPBKDF2SHA256(p, s, 4096, dkLen, "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a");
- }
-
- public void _testPBKDF2SHA256B() throws UnsupportedEncodingException, GeneralSecurityException {
- final String p = "passwordPASSWORDpassword";
- final String s = "saltSALTsaltSALTsaltSALTsaltSALTsalt";
- final int dkLen = 40;
-
- checkPBKDF2SHA256(p, s, 4096, dkLen, "348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9");
- }
-
- public void _testPBKDF2SHA256scryptA() throws UnsupportedEncodingException, GeneralSecurityException {
- final String p = "passwd";
- final String s = "salt";
- final int dkLen = 64;
-
- checkPBKDF2SHA256(p, s, 1, dkLen, "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783");
- }
-
- public void _testPBKDF2SHA256scryptB() throws UnsupportedEncodingException, GeneralSecurityException {
- final String p = "Password";
- final String s = "NaCl";
- final int dkLen = 64;
-
- checkPBKDF2SHA256(p, s, 80000, dkLen, "4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d");
- }
-
- public void _testPBKDF2SHA256C() throws UnsupportedEncodingException, GeneralSecurityException {
- final String p = "pass\0word";
- final String s = "sa\0lt";
- final int dkLen = 16;
-
- checkPBKDF2SHA256(p, s, 4096, dkLen, "89b69d0516f829893c696226650a8687");
- }
-
- public void _testPBKDF2SHA256InvalidLenArg() throws UnsupportedEncodingException, GeneralSecurityException {
- final String p = "password";
- final String s = "salt";
- final int c = 1;
- final int dkLen = -1; // Should always be positive.
-
- try {
- final byte[] key = NativeCrypto.pbkdf2SHA256(p.getBytes("US-ASCII"), s.getBytes("US-ASCII"), c, dkLen);
- fFail("Expected sha256 to throw with negative dkLen argument.");
- } catch (IllegalArgumentException e) { } // Expected.
- }
-
- private void _testSHA1() throws UnsupportedEncodingException {
- final String[] inputs = new String[] {
- "abc",
- "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
- "" // To be filled in below.
- };
- final String baseStr = "01234567";
- final int repetitions = 80;
- final StringBuilder builder = new StringBuilder(baseStr.length() * repetitions);
- for (int i = 0; i < 80; ++i) {
- builder.append(baseStr);
- }
- inputs[2] = builder.toString();
-
- final String[] expecteds = new String[] {
- "a9993e364706816aba3e25717850c26c9cd0d89d",
- "84983e441c3bd26ebaae4aa1f95129e5e54670f1",
- "dea356a2cddd90c7a7ecedc5ebb563934f460452"
- };
-
- for (int i = 0; i < inputs.length; ++i) {
- final byte[] input = inputs[i].getBytes("US-ASCII");
- final String expected = expecteds[i];
-
- final byte[] actual = NativeCrypto.sha1(input);
- fAssertNotNull("Hashed value is non-null", actual);
- assertExpectedBytes(expected, actual);
- }
- }
-
- /**
- * Test to ensure the output of our SHA1 algo is the same as MessageDigest's. This is important
- * because we intend to replace MessageDigest in FHR with this SHA-1 algo (bug 959652).
- */
- private void _testSHA1AgainstMessageDigest() throws UnsupportedEncodingException,
- NoSuchAlgorithmException {
- final String[] inputs = {
- "password",
- "saranghae",
- "aoeusnthaoeusnthaoeusnth \0 12345098765432109876_!"
- };
-
- final MessageDigest digest = MessageDigest.getInstance("SHA-1");
- for (final String input : inputs) {
- final byte[] inputBytes = input.getBytes("US-ASCII");
-
- final byte[] mdBytes = digest.digest(inputBytes);
- final byte[] ourBytes = NativeCrypto.sha1(inputBytes);
- fAssertArrayEquals("MessageDigest hash is the same as NativeCrypto SHA-1 hash", mdBytes, ourBytes);
- }
- }
-
- private void _testSHA256() throws UnsupportedEncodingException {
- final String[] inputs = new String[] {
- "abc",
- "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
- "" // To be filled in below.
- };
- final String baseStr = "01234567";
- final int repetitions = 80;
- final StringBuilder builder = new StringBuilder(baseStr.length() * repetitions);
- for (int i = 0; i < repetitions; ++i) {
- builder.append(baseStr);
- }
- inputs[2] = builder.toString();
-
- final String[] expecteds = new String[] {
- "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
- "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
- "594847328451bdfa85056225462cc1d867d877fb388df0ce35f25ab5562bfbb5"
- };
-
- for (int i = 0; i < inputs.length; ++i) {
- final byte[] input = inputs[i].getBytes("US-ASCII");
- final String expected = expecteds[i];
-
- final byte[] ctx = NativeCrypto.sha256init();
- NativeCrypto.sha256update(ctx, input, input.length);
- final byte[] actual = NativeCrypto.sha256finalize(ctx);
- fAssertNotNull("Hashed value is non-null", actual);
- assertExpectedBytes(expected, actual);
- }
- }
-
- private void _testSHA256MultiPart() throws UnsupportedEncodingException {
- final String input = "01234567";
- final int repetitions = 80;
- final String expected = "594847328451bdfa85056225462cc1d867d877fb388df0ce35f25ab5562bfbb5";
-
- final byte[] inputBytes = input.getBytes("US-ASCII");
- final byte[] ctx = NativeCrypto.sha256init();
- for (int i = 0; i < repetitions; ++i) {
- NativeCrypto.sha256update(ctx, inputBytes, inputBytes.length);
- }
- final byte[] actual = NativeCrypto.sha256finalize(ctx);
- fAssertNotNull("Hashed value is non-null", actual);
- assertExpectedBytes(expected, actual);
- }
-
- private void _testSHA256AgainstMessageDigest() throws UnsupportedEncodingException,
- NoSuchAlgorithmException {
- final String[] inputs = {
- "password",
- "saranghae",
- "aoeusnthaoeusnthaoeusnth \0 12345098765432109876_!"
- };
-
- final MessageDigest digest = MessageDigest.getInstance("SHA-256");
- for (final String input : inputs) {
- final byte[] inputBytes = input.getBytes("US-ASCII");
-
- final byte[] mdBytes = digest.digest(inputBytes);
-
- final byte[] ctx = NativeCrypto.sha256init();
- NativeCrypto.sha256update(ctx, inputBytes, inputBytes.length);
- final byte[] ourBytes = NativeCrypto.sha256finalize(ctx);
- fAssertArrayEquals("MessageDigest hash is the same as NativeCrypto SHA-256 hash", mdBytes, ourBytes);
- }
- }
-
- private void _testSHA256WithMultipleUpdatesFromStream() throws UnsupportedEncodingException {
- final String input = "HelloWorldThisIsASuperLongStringThatIsReadAsAStreamOfBytes";
- final ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes("UTF-8"));
- final String expected = "8b5cb76b80f7eb6fb83ee138bfd31e2922e71dd245daa21a8d9876e8dee9eef5";
-
- byte[] buffer = new byte[10];
- final byte[] ctx = NativeCrypto.sha256init();
- int c;
-
- try {
- while ((c = stream.read(buffer)) != -1) {
- NativeCrypto.sha256update(ctx, buffer, c);
- }
- final byte[] actual = NativeCrypto.sha256finalize(ctx);
- fAssertNotNull("Hashed value is non-null", actual);
- assertExpectedBytes(expected, actual);
- } catch (IOException e) {
- fFail("IOException while reading stream");
- }
- }
-
- private void checkPBKDF2SHA256(String p, String s, int c, int dkLen, final String expectedStr)
- throws GeneralSecurityException, UnsupportedEncodingException {
- final long start = SystemClock.elapsedRealtime();
-
- final byte[] key = NativeCrypto.pbkdf2SHA256(p.getBytes("US-ASCII"), s.getBytes("US-ASCII"), c, dkLen);
- fAssertNotNull("Hash result is non-null", key);
-
- final long end = SystemClock.elapsedRealtime();
- dumpLog(LOGTAG, "SHA-256 " + c + " took " + (end - start) + "ms");
-
- if (expectedStr == null) {
- return;
- }
-
- fAssertEquals("Hash result is the appropriate length", dkLen,
- Utils.hex2Byte(expectedStr).length);
- assertExpectedBytes(expectedStr, key);
- }
-
- private void assertExpectedBytes(final String expectedStr, byte[] key) {
- fAssertEquals("Expected string matches hash result", expectedStr, Utils.byte2Hex(key));
- final byte[] expected = Utils.hex2Byte(expectedStr);
-
- fAssertEquals("Expected byte array length matches key length", expected.length, key.length);
- fAssertArrayEquals("Expected byte array matches key byte array", expected, key);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNewTab.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNewTab.java
deleted file mode 100644
index d9b014c1a..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNewTab.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Element;
-import org.mozilla.gecko.R;
-
-import android.app.Activity;
-import android.view.View;
-
-import com.robotium.solo.Condition;
-
-/* A simple test that creates 2 new tabs and checks that the tab count increases. */
-public class testNewTab extends BaseTest {
- private Element tabCount = null;
- private Element tabs = null;
- private final Element closeTab = null;
- private int tabCountInt = 0;
-
- public void testNewTab() {
- String url = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- String url2 = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL);
-
- blockForGeckoReady();
-
- Activity activity = getActivity();
- tabCount = mDriver.findElement(activity, R.id.tabs_counter);
- tabs = mDriver.findElement(activity, R.id.tabs);
- mAsserter.ok(tabCount != null && tabs != null,
- "Checking elements", "all elements present");
-
- int expectedTabCount = 1;
- getTabCount(expectedTabCount);
- mAsserter.is(tabCountInt, expectedTabCount, "Initial number of tabs correct");
-
- addTab(url);
- expectedTabCount++;
- getTabCount(expectedTabCount);
- mAsserter.is(tabCountInt, expectedTabCount, "Number of tabs increased");
-
- addTab(url2);
- expectedTabCount++;
- getTabCount(expectedTabCount);
- mAsserter.is(tabCountInt, expectedTabCount, "Number of tabs increased");
-
- // cleanup: close all opened tabs
- closeAddedTabs();
- }
-
- private void getTabCount(final int expected) {
- waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- String newTabCountText = tabCount.getText();
- tabCountInt = Integer.parseInt(newTabCountText);
- if (tabCountInt == expected) {
- return true;
- }
- return false;
- }
- }, MAX_WAIT_MS);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testOSLocale.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testOSLocale.java
deleted file mode 100644
index 434594fee..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testOSLocale.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.util.Locale;
-
-import org.mozilla.gecko.BrowserLocaleManager;
-import org.mozilla.gecko.GeckoSharedPrefs;
-import org.mozilla.gecko.GeckoThread;
-import org.mozilla.gecko.Locales;
-import org.mozilla.gecko.PrefsHelper;
-
-import android.content.SharedPreferences;
-
-
-public class testOSLocale extends BaseTest {
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- // Clear per-profile SharedPreferences as a workaround for Bug 1069687.
- // We're trying to exercise logic that only applies on first onCreate!
- // We can't rely on this occurring prior to the first broadcast, though,
- // so see the main test method for more logic.
- final String profileName = getTestProfile().getName();
- mAsserter.info("Setup", "Clearing pref in " + profileName + ".");
- GeckoSharedPrefs.forProfileName(getActivity(), profileName)
- .edit()
- .remove("osLocale")
- .apply();
- }
-
- public static class PrefState extends PrefsHelper.PrefHandlerBase {
- private static final String PREF_LOCALE_OS = "intl.locale.os";
- private static final String PREF_ACCEPT_LANG = "intl.accept_languages";
-
- private static final String[] TO_FETCH = {PREF_LOCALE_OS, PREF_ACCEPT_LANG};
-
- public volatile String osLocale;
- public volatile String acceptLanguages;
-
- private final Object waiter = new Object();
-
- public void fetch() throws InterruptedException {
- // Wait for any pending changes to have taken. Bug 1092580.
- GeckoThread.waitOnGecko();
- synchronized (waiter) {
- PrefsHelper.getPrefs(TO_FETCH, this);
- waiter.wait(MAX_WAIT_MS);
- }
- }
-
- @Override
- public void prefValue(String pref, String value) {
- switch (pref) {
- case PREF_LOCALE_OS:
- osLocale = value;
- return;
- case PREF_ACCEPT_LANG:
- acceptLanguages = value;
- return;
- }
- }
-
- @Override
- public void finish() {
- synchronized (waiter) {
- waiter.notify();
- }
- }
- }
-
- public void testOSLocale() throws Exception {
- blockForDelayedStartup();
-
- final SharedPreferences prefs = GeckoSharedPrefs.forProfile(getActivity());
- final PrefState state = new PrefState();
-
- state.fetch();
-
- // We don't know at this point whether we were run against a dirty profile or not.
- //
- // If we cleared the pref above prior to BrowserApp's delayed init, or our Gecko
- // profile has been used before, then we're already going to be set up for en-US.
- //
- // If we cleared the pref after the initial broadcast, and our Android-side profile
- // has been used before but the Gecko profile is clean, then the Gecko prefs won't
- // have been set.
- //
- // Instead, we always send a new locale code, and see what we get.
- final Locale fr = Locales.parseLocaleCode("fr");
- BrowserLocaleManager.storeAndNotifyOSLocale(prefs, fr);
-
- state.fetch();
-
- mAsserter.is(state.osLocale, "fr", "We're in fr.");
-
- // Now we can see what the expected Accept-Languages header should be.
- // The OS locale is 'fr', so we have our app locale (en-US),
- // the OS locale (fr), then any remaining fallbacks from intl.properties.
- mAsserter.is(state.acceptLanguages, "en-us,fr,en", "We have the default en-US+fr Accept-Languages.");
-
- // Now set the app locale to be es-ES.
- BrowserLocaleManager.getInstance().setSelectedLocale(getActivity(), "es-ES");
-
- state.fetch();
-
- mAsserter.is(state.osLocale, "fr", "We're still in fr.");
-
- // The correct set here depends on whether the
- // browser was built with multiple locales or not.
- // This is exasperating, but hey.
- final boolean isMultiLocaleBuild = false;
-
- // This never changes.
- final String SELECTED_LOCALES = "es-es,fr,";
-
- // Expected, from es-ES's intl.properties:
- final String EXPECTED = SELECTED_LOCALES +
- (isMultiLocaleBuild ? "es,en-us,en" : // Expected, from es-ES's intl.properties.
- "en-us,en"); // Expected, from en-US (the default).
-
- mAsserter.is(state.acceptLanguages, EXPECTED, "We have the right es-ES+fr Accept-Languages for this build.");
-
- // And back to en-US.
- final Locale en_US = Locales.parseLocaleCode("en-US");
- BrowserLocaleManager.storeAndNotifyOSLocale(prefs, en_US);
- BrowserLocaleManager.getInstance().resetToSystemLocale(getActivity());
-
- state.fetch();
-
- mAsserter.is(state.osLocale, "en-US", "We're in en-US.");
- mAsserter.is(state.acceptLanguages, "en-us,en", "We have the default processed en-US Accept-Languages.");
- }
-} \ No newline at end of file
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPanCorrectness.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPanCorrectness.java
deleted file mode 100644
index e7d402607..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPanCorrectness.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.PaintedSurface;
-
-/**
- * A basic panning correctness test.
- * - Loads a page and verifies it draws
- * - drags page upwards by 100 pixels and verifies it draws
- * - drags page leftwards by 100 pixels and verifies it draws
- */
-public class testPanCorrectness extends PixelTest {
- public void testPanCorrectness() {
- String url = getAbsoluteUrl(mStringHelper.ROBOCOP_BOXES_URL);
-
- MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop());
-
- blockForGeckoReady();
-
- // load page and check we're at 0,0
- loadAndVerifyBoxes(url);
-
- // drag page upwards by 100 pixels
- Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
- meh.dragSync(10, 150, 10, 50);
- PaintedSurface painted = waitForPaint(paintExpecter);
- paintExpecter.unregisterListener();
- try {
- checkScrollWithBoxes(painted, 0, 100);
- } finally {
- painted.close();
- }
-
- // drag page leftwards by 100 pixels
- paintExpecter = mActions.expectPaint();
- meh.dragSync(150, 10, 50, 10);
- painted = waitForPaint(paintExpecter);
- paintExpecter.unregisterListener();
- try {
- checkScrollWithBoxes(painted, 100, 100);
- } finally {
- painted.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordEncrypt.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordEncrypt.java
deleted file mode 100644
index 65a4eaba6..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordEncrypt.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.File;
-
-import org.json.JSONObject;
-import org.mozilla.gecko.NSSBridge;
-import org.mozilla.gecko.db.BrowserContract;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class testPasswordEncrypt extends BaseTest {
- public void testPasswordEncrypt() {
- Context context = (Context)getActivity();
- ContentResolver cr = context.getContentResolver();
- mAsserter.isnot(cr, null, "Found a content resolver");
- ContentValues cvs = new ContentValues();
-
- blockForGeckoReady();
-
- File db = new File(mProfile, "signons.sqlite");
- String dbPath = db.getPath();
-
- Uri passwordUri;
- cvs.put("hostname", "http://www.example.com");
- cvs.put("encryptedUsername", "username");
- cvs.put("encryptedPassword", "password");
-
- // Attempt to insert into the db
- passwordUri = BrowserContract.Passwords.CONTENT_URI;
- Uri.Builder builder = passwordUri.buildUpon();
- passwordUri = builder.appendQueryParameter("profilePath", mProfile).build();
-
- Uri uri = cr.insert(passwordUri, cvs);
- Uri expectedUri = passwordUri.buildUpon().appendPath("1").build();
- mAsserter.is(uri.toString(), expectedUri.toString(), "Insert returned correct uri");
-
- Cursor list = mActions.querySql(dbPath, "SELECT encryptedUsername FROM moz_logins");
- list.moveToFirst();
- String decryptedU = null;
- try {
- decryptedU = NSSBridge.decrypt(context, mProfile, list.getString(0));
- } catch (Exception e) {
- mAsserter.ok(false, "NSSBridge.decrypt through Exception " + e, ""); // TODO: What is diag?
- }
- mAsserter.is(decryptedU, "username", "Username was encrypted correctly when inserting");
-
- list = mActions.querySql(dbPath, "SELECT encryptedPassword, encType FROM moz_logins");
- list.moveToFirst();
- String decryptedP = null;
- try {
- decryptedP = NSSBridge.decrypt(context, mProfile, list.getString(0));
- } catch (Exception e) {
- mAsserter.ok(false, "NSSBridge.decrypt through Exception " + e, ""); // TODO: What is diag?
- }
- mAsserter.is(decryptedP, "password", "Password was encrypted correctly when inserting");
- mAsserter.is(list.getInt(1), 1, "Password has correct encryption type");
-
- cvs.put("encryptedUsername", "username2");
- cvs.put("encryptedPassword", "password2");
- cr.update(passwordUri, cvs, null, null);
-
- list = mActions.querySql(dbPath, "SELECT encryptedUsername FROM moz_logins");
- list.moveToFirst();
- try {
- decryptedU = NSSBridge.decrypt(context, mProfile, list.getString(0));
- } catch (Exception e) {
- mAsserter.ok(false, "NSSBridge.decrypt through Exception " + e, ""); // TODO: What is diag?
- }
- mAsserter.is(decryptedU, "username2", "Username was encrypted when updating");
-
- list = mActions.querySql(dbPath, "SELECT encryptedPassword FROM moz_logins");
- list.moveToFirst();
- try {
- decryptedP = NSSBridge.decrypt(context, mProfile, list.getString(0));
- } catch (Exception e) {
- mAsserter.ok(false, "NSSBridge.decrypt through Exception " + e, ""); // TODO: What is diag?
- }
- mAsserter.is(decryptedP, "password2", "Password was encrypted when updating");
-
- // Trying to store a password while master password is enabled should throw,
- // but because Android can't send Exceptions across processes
- // it just results in a null uri/cursor being returned.
- toggleMasterPassword("password");
- try {
- uri = cr.insert(passwordUri, cvs);
- // TODO: restore this assertion -- see bug 764901
- // mAsserter.is(uri, null, "Storing a password while MP was set should fail");
-
- Cursor c = cr.query(passwordUri, null, null, null, null);
- // TODO: restore this assertion -- see bug 764901
- // mAsserter.is(c, null, "Querying passwords while MP was set should fail");
- } catch (Exception ex) {
- // Password provider currently can not throw across process
- // so we should not catch this exception here
- mAsserter.ok(false, "Caught exception", ex.toString());
- }
- toggleMasterPassword("password");
- }
-
- private void toggleMasterPassword(String passwd) {
- setPreferenceAndWaitForChange("privacy.masterpassword.enabled", passwd);
- }
-
- @Override
- public void tearDown() throws Exception {
- // remove the entire signons.sqlite file
- File profile = new File(mProfile);
- File db = new File(profile, "signons.sqlite");
- if (db.delete()) {
- mAsserter.dumpLog("tearDown deleted "+db.toString());
- } else {
- mAsserter.dumpLog("tearDown did not delete "+db.toString());
- }
-
- super.tearDown();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordProvider.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordProvider.java
deleted file mode 100644
index 8a2cc357e..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordProvider.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.io.File;
-
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserContract.GeckoDisabledHosts;
-import org.mozilla.gecko.db.BrowserContract.Passwords;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-
-/**
- * A basic password contentprovider test.
- * - inserts a password when the database is not yet set up
- * - inserts a password
- * - updates a password
- * - deletes a password
- * - inserts a disabled host
- * - queries for disabled host
- */
-public class testPasswordProvider extends BaseTest {
- private static final String DB_NAME = "signons.sqlite";
-
- public void testPasswordProvider() {
- Context context = (Context)getActivity();
- ContentResolver cr = context.getContentResolver();
- ContentValues[] cvs = new ContentValues[1];
- cvs[0] = new ContentValues();
-
- blockForGeckoReady();
-
- cvs[0].put("hostname", "http://www.example.com");
- cvs[0].put("httpRealm", "http://www.example.com");
- cvs[0].put("formSubmitURL", "http://www.example.com");
- cvs[0].put("usernameField", "usernameField");
- cvs[0].put("passwordField", "passwordField");
- cvs[0].put("encryptedUsername", "username");
- cvs[0].put("encryptedPassword", "password");
- cvs[0].put("encType", "1");
-
- // Attempt to insert into the db
- Uri passwordUri = Passwords.CONTENT_URI;
- Uri.Builder builder = passwordUri.buildUpon();
- passwordUri = builder.appendQueryParameter("profilePath", mProfile).build();
-
- Uri uri = cr.insert(passwordUri, cvs[0]);
- Uri expectedUri = passwordUri.buildUpon().appendPath("1").build();
- mAsserter.is(uri.toString(), expectedUri.toString(), "Insert returned correct uri");
- Cursor c = cr.query(passwordUri, null, null, null, null);
- SqliteCompare(c, cvs);
-
- cvs[0].put("usernameField", "usernameField2");
- cvs[0].put("passwordField", "passwordField2");
-
- int numUpdated = cr.update(passwordUri, cvs[0], null, null);
- mAsserter.is(1, numUpdated, "Correct number updated");
- c = cr.query(passwordUri, null, null, null, null);
- SqliteCompare(c, cvs);
-
- int numDeleted = cr.delete(passwordUri, null, null);
- mAsserter.is(1, numDeleted, "Correct number deleted");
- cvs = new ContentValues[0];
- c = cr.query(passwordUri, null, null, null, null);
- SqliteCompare(c, cvs);
-
- ContentValues values = new ContentValues();
- values.put("hostname", "http://www.example.com");
-
- // Attempt to insert into the db.
- Uri disabledHostUri = GeckoDisabledHosts.CONTENT_URI;
- builder = disabledHostUri.buildUpon();
- disabledHostUri = builder.appendQueryParameter("profilePath", mProfile).build();
-
- uri = cr.insert(disabledHostUri, values);
- expectedUri = disabledHostUri.buildUpon().appendPath("1").build();
- mAsserter.is(uri.toString(), expectedUri.toString(), "Insert returned correct uri");
- Cursor cursor = cr.query(disabledHostUri, null, null, null, null);
- assertNotNull(cursor);
- assertEquals(1, cursor.getCount());
- cursor.moveToFirst();
- CursorMatches(cursor, values);
- }
-
- @Override
- public void tearDown() throws Exception {
- // remove the entire signons.sqlite file
- File profile = new File(mProfile);
- File db = new File(profile, "signons.sqlite");
- if (db.delete()) {
- mAsserter.dumpLog("tearDown deleted "+db.toString());
- } else {
- mAsserter.dumpLog("tearDown did not delete "+db.toString());
- }
-
- super.tearDown();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPermissions.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPermissions.java
deleted file mode 100644
index e4d997895..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPermissions.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.util.ArrayList;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.PaintedSurface;
-
-import android.widget.CheckBox;
-
-public class testPermissions extends PixelTest {
- public void testPermissions() {
- blockForGeckoReady();
-
- geolocationTest();
- }
-
- private void geolocationTest() {
- Actions.RepeatedEventExpecter paintExpecter;
-
- // Test geolocation notification
- loadAndPaint(getAbsoluteUrl(mStringHelper.ROBOCOP_GEOLOCATION_URL));
- waitForText("wants your location");
-
- // Uncheck the "Don't ask again for this site" checkbox
- ArrayList<CheckBox> checkBoxes = mSolo.getCurrentViews(CheckBox.class);
- mAsserter.ok(checkBoxes.size() == 1, "checkbox count", "only one checkbox visible");
- mAsserter.ok(mSolo.isCheckBoxChecked(0), "checkbox checked", "checkbox is checked");
- mSolo.clickOnCheckBox(0);
- mAsserter.ok(!mSolo.isCheckBoxChecked(0), "checkbox not checked", "checkbox is not checked");
-
- // Test "Share" button functionality with unchecked checkbox
- paintExpecter = mActions.expectPaint();
- mSolo.clickOnText("Share");
- PaintedSurface painted = waitForPaint(paintExpecter);
- paintExpecter.unregisterListener();
- try {
- mAsserter.ispixel(painted.getPixelAt(10, 10), 0, 0x80, 0, "checking page background is green");
- } finally {
- painted.close();
- }
-
- // Re-trigger geolocation notification
- reloadAndPaint();
- waitForText("wants your location");
-
- // Make sure the checkbox is checked this time
- mAsserter.ok(mSolo.isCheckBoxChecked(0), "checkbox checked", "checkbox is checked");
-
- // Test "Share" button functionality with checked checkbox
- paintExpecter = mActions.expectPaint();
- mSolo.clickOnText("Share");
- painted = waitForPaint(paintExpecter);
- paintExpecter.unregisterListener();
- try {
- mAsserter.ispixel(painted.getPixelAt(10, 10), 0, 0x80, 0, "checking page background is green");
- } finally {
- painted.close();
- }
-
- // When we reload the page, location should be automatically shared
- painted = reloadAndGetPainted();
- try {
- mAsserter.ispixel(painted.getPixelAt(10, 10), 0, 0x80, 0, "checking page background is green");
- } finally {
- painted.close();
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPictureLinkContextMenu.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPictureLinkContextMenu.java
deleted file mode 100644
index 1461fd9be..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPictureLinkContextMenu.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-public class testPictureLinkContextMenu extends ContentContextMenuTest {
-
- // Test website strings
- private static String PICTURE_PAGE_URL;
- private static String BLANK_PAGE_URL;
- private static String PICTURE_URL;
- private static final String tabs [] = { "Image", "Link" };
- private static final String photoMenuItems [] = { "Copy Image Location", "Share Image", "View Image", "Set Image As", "Save Image" };
- private static final String imageTitle = "^Image$";
-
- public void testPictureLinkContextMenu() {
- final String PICTURE_PAGE_TITLE = mStringHelper.ROBOCOP_PICTURE_LINK_TITLE;
- final String linkMenuItems [] = mStringHelper.CONTEXT_MENU_ITEMS_IN_NORMAL_TAB;
-
- blockForGeckoReady();
-
- PICTURE_PAGE_URL=getAbsoluteUrl(mStringHelper.ROBOCOP_PICTURE_LINK_URL);
- BLANK_PAGE_URL=getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL);
- PICTURE_URL=getAbsoluteUrl(mStringHelper.ROBOCOP_PICTURE_URL);
- loadAndPaint(PICTURE_PAGE_URL);
- verifyUrlInContentDescription(PICTURE_PAGE_URL);
-
- switchTabs(imageTitle);
- verifyContextMenuItems(photoMenuItems);
- verifyTabs(tabs);
- switchTabs(imageTitle);
- verifyCopyOption(photoMenuItems[0], "Firefox.jpg"); // Test the "Copy Image Location" option
- switchTabs(imageTitle);
- verifyShareOption(photoMenuItems[1], PICTURE_PAGE_TITLE); // Test the "Share Image" option
- switchTabs(imageTitle);
- verifyViewImageOption(photoMenuItems[2], PICTURE_URL, PICTURE_PAGE_TITLE); // Test the "View Image" option
-
- verifyContextMenuItems(linkMenuItems);
- openTabFromContextMenu(linkMenuItems[0],2); // Test the "Open in New Tab" option - expecting 2 tabs: the original and the new one
- openTabFromContextMenu(linkMenuItems[1],2); // Test the "Open in Private Tab" option - expecting only 2 tabs in normal mode
- verifyCopyOption(linkMenuItems[2], BLANK_PAGE_URL); // Test the "Copy Link" option
- verifyShareOption(linkMenuItems[3], PICTURE_PAGE_TITLE); // Test the "Share Link" option
- verifyBookmarkLinkOption(linkMenuItems[4],BLANK_PAGE_URL); // Test the "Bookmark Link" option
- }
-
- @Override
- public void tearDown() throws Exception {
- mDatabaseHelper.deleteBookmark(BLANK_PAGE_URL);
- super.tearDown();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPrefsObserver.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPrefsObserver.java
deleted file mode 100644
index f63358d57..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPrefsObserver.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-
-/**
- * Basic test to check bounce-back from overscroll.
- * - Load the page and verify it draws
- * - Drag page downwards by 100 pixels into overscroll, verify it snaps back.
- * - Drag page rightwards by 100 pixels into overscroll, verify it snaps back.
- */
-public class testPrefsObserver extends BaseTest {
- private static final String PREF_TEST_PREF = "robocop.tests.dummy";
-
- private Actions.PrefWaiter prefWaiter;
- private boolean prefValue;
-
- public void setPref(boolean value) {
- mAsserter.dumpLog("Setting pref");
- mActions.setPref(PREF_TEST_PREF, value, /* flush */ false);
- }
-
- public void waitAndCheckPref(boolean value) {
- mAsserter.dumpLog("Waiting to check pref");
-
- mAsserter.isnot(prefWaiter, null, "Check pref waiter is not null");
- prefWaiter.waitForFinish();
-
- mAsserter.is(prefValue, value, "Check correct pref value");
- }
-
- public void verifyDisconnect() {
- mAsserter.dumpLog("Checking pref observer is removed");
-
- final boolean newValue = !prefValue;
- setPreferenceAndWaitForChange(PREF_TEST_PREF, newValue);
- mAsserter.isnot(prefValue, newValue, "Check pref value did not change");
- }
-
- public void observePref() {
- mAsserter.dumpLog("Setting up pref observer");
-
- // Setup the pref observer
- mAsserter.is(prefWaiter, null, "Check pref waiter is null");
- prefWaiter = mActions.addPrefsObserver(
- new String[] { PREF_TEST_PREF }, new Actions.PrefHandlerBase() {
- @Override // Actions.PrefHandlerBase
- public void prefValue(String pref, boolean value) {
- mAsserter.is(pref, PREF_TEST_PREF, "Check correct pref name");
- prefValue = value;
- }
- });
- }
-
- public void removePrefObserver() {
- mAsserter.dumpLog("Removing pref observer");
-
- mActions.removePrefsObserver(prefWaiter);
- }
-
- public void testPrefsObserver() {
- blockForGeckoReady();
-
- setPref(false);
- observePref();
- waitAndCheckPref(false);
-
- setPref(true);
- waitAndCheckPref(true);
-
- removePrefObserver();
- verifyDisconnect();
-
- // Removing again should be a no-op.
- removePrefObserver();
- }
-}
-
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPrivateBrowsing.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPrivateBrowsing.java
deleted file mode 100644
index 461e95aa7..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPrivateBrowsing.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.util.ArrayList;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.Tabs;
-
-/**
- * The test loads a new private tab and loads a page with a big link on it
- * Opens the link in a new private tab and checks that it is private
- * Adds a new normal tab and loads a 3rd URL
- * Checks that the bigLinkUrl loaded in the normal tab is present in the browsing history but the 2 urls opened in private tabs are not
- */
-public class testPrivateBrowsing extends ContentContextMenuTest {
-
- public void testPrivateBrowsing() {
- String bigLinkUrl = getAbsoluteUrl(mStringHelper.ROBOCOP_BIG_LINK_URL);
- String blank1Url = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
- String blank2Url = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL);
- Tabs tabs = Tabs.getInstance();
-
- blockForGeckoReady();
-
- Actions.EventExpecter tabExpecter = mActions.expectGeckoEvent("Tab:Added");
- Actions.EventExpecter contentExpecter = mActions.expectGeckoEvent("Content:PageShow");
- tabs.loadUrl(bigLinkUrl, Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_PRIVATE);
- tabExpecter.blockForEvent();
- tabExpecter.unregisterListener();
- contentExpecter.blockForEvent();
- contentExpecter.unregisterListener();
- verifyTabCount(1);
-
- // May intermittently get context menu for normal tab without additional wait
- mSolo.sleep(5000);
-
- // Open the link context menu and verify the options
- verifyContextMenuItems(mStringHelper.CONTEXT_MENU_ITEMS_IN_PRIVATE_TAB);
-
- // Check that "Open Link in New Tab" is not in the menu
- mAsserter.ok(!mSolo.searchText(mStringHelper.CONTEXT_MENU_ITEMS_IN_NORMAL_TAB[0]), "Checking that 'Open Link in New Tab' is not displayed in the context menu", "'Open Link in New Tab' is not displayed in the context menu");
-
- // Open the link in a new private tab and check that it is private
- tabExpecter = mActions.expectGeckoEvent("Tab:Added");
- contentExpecter = mActions.expectGeckoEvent("Content:PageShow");
- mSolo.clickOnText(mStringHelper.CONTEXT_MENU_ITEMS_IN_PRIVATE_TAB[0]);
- String eventData = tabExpecter.blockForEventData();
- tabExpecter.unregisterListener();
- contentExpecter.blockForEvent();
- contentExpecter.unregisterListener();
- mAsserter.ok(isTabPrivate(eventData), "Checking if the new tab opened from the context menu was a private tab", "The tab was a private tab");
- verifyTabCount(2);
-
- // Open a normal tab to check later that it was registered in the Firefox Browser History
- tabExpecter = mActions.expectGeckoEvent("Tab:Added");
- contentExpecter = mActions.expectGeckoEvent("Content:PageShow");
- tabs.loadUrl(blank2Url, Tabs.LOADURL_NEW_TAB);
- tabExpecter.blockForEvent();
- tabExpecter.unregisterListener();
- contentExpecter.blockForEvent();
- contentExpecter.unregisterListener();
- verifyTabCount(2);
-
- // wait for history updates to complete
- mSolo.sleep(3000);
-
- // Get the history list and check that the links open in private browsing are not saved
- final ArrayList<String> firefoxHistory = mDatabaseHelper.getBrowserDBUrls(DatabaseHelper.BrowserDataType.HISTORY);
-
- mAsserter.ok(!firefoxHistory.contains(bigLinkUrl), "Check that the link opened in the first private tab was not saved", bigLinkUrl + " was not added to history");
- mAsserter.ok(!firefoxHistory.contains(blank1Url), "Check that the link opened in the private tab from the context menu was not saved", blank1Url + " was not added to history");
- mAsserter.ok(firefoxHistory.contains(blank2Url), "Check that the link opened in the normal tab was saved", blank2Url + " was added to history");
- }
-
- private boolean isTabPrivate(String eventData) {
- try {
- JSONObject data = new JSONObject(eventData);
- return data.getBoolean("isPrivate");
- } catch (JSONException e) {
- mAsserter.ok(false, "Error parsing the event data", e.toString());
- return false;
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPromptGridInput.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPromptGridInput.java
deleted file mode 100644
index f645fe3be..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPromptGridInput.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-public class testPromptGridInput extends BaseTest {
- protected int index = 1;
- public void testPromptGridInput() {
- blockForGeckoReady();
-
- test(1);
-
- testGridItem("Icon 1");
- testGridItem("Icon 2");
- testGridItem("Icon 3");
- testGridItem("Icon 4");
- testGridItem("Icon 5");
- testGridItem("Icon 6");
- testGridItem("Icon 7");
- testGridItem("Icon 8");
- testGridItem("Icon 9");
- testGridItem("Icon 10");
- testGridItem("Icon 11");
-
- mSolo.clickOnText("Icon 11");
- mSolo.clickOnText("OK");
-
- mAsserter.ok(waitForText("PASS"), "test passed", "PASS");
- mSolo.goBack();
- }
-
- public void testGridItem(String title) {
- // Force the list to scroll if necessary
- mSolo.waitForText(title, 1, 500, true);
- mAsserter.ok(waitForText(title), "Found grid item", title);
- }
-
- public void test(final int num) {
- // Load about:blank between each test to ensure we reset state
- loadUrl(mStringHelper.ABOUT_BLANK_URL);
- mAsserter.ok(waitForText(mStringHelper.ABOUT_BLANK_URL), "Loaded blank page",
- mStringHelper.ABOUT_BLANK_URL);
-
- loadUrl("chrome://roboextender/content/robocop_prompt_gridinput.html#test" + num);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReaderCacheMigration.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReaderCacheMigration.java
deleted file mode 100644
index 6dbc70de5..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReaderCacheMigration.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.db.BrowserDatabaseHelper;
-
-import java.io.File;
-import java.io.IOException;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
-
-/**
- * Tests that our readercache-migration works correctly.
- *
- * Our main concern is ensuring that the hashed path for a given url is the same in Java
- * as it was in JS, or else our (Java-based) migration will lose track of valid cached items.
- */
-public class testReaderCacheMigration extends JavascriptBridgeTest {
-
- private final String[] TEST_DOMAINS = new String[] {
- "",
- "http://mozilla.org",
- "https://bugzilla.mozilla.org/show_bug.cgi?id=1234315#c41",
- "http://www.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.com/"
- };
-
- private static final String TEST_JS = "testReaderCacheMigration.js";
-
- /**
- * We compute the path-name in Java, and pass this through to JS, which conducts the actual
- * equality check. Our JavascriptBridge doesn't seem to support return values, so we need
- * to instead pass the computed path-name in at least one direction.
- */
- private void checkPathMatches(final String pageURL, final File cacheDir) {
- final String hashedName = BrowserDatabaseHelper.getReaderCacheFileNameForURL(pageURL);
-
- final File cacheFile = new File(cacheDir, hashedName);
-
- try {
- // We have to use the canonical path to match what the JS side will use. We could
- // instead just match on the file name, and not the path, but this helps
- // ensure that we've not broken any of the path finding either.
- getJS().syncCall("check_hashed_path_matches", pageURL, cacheFile.getCanonicalPath());
- } catch (IOException e) {
- fAssertTrue("Unable to getCanonicalPath(), this should never happen", false);
- }
-
- }
-
- public void testReaderCacheMigration() {
- blockForReadyAndLoadJS(TEST_JS);
-
- final File cacheDir = new File(GeckoProfile.get(getActivity()).getDir(), "readercache");
-
- for (final String URL : TEST_DOMAINS) {
- checkPathMatches(URL, cacheDir);
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReaderModeTitle.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReaderModeTitle.java
deleted file mode 100644
index 31e012070..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReaderModeTitle.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-import org.mozilla.gecko.tests.helpers.NavigationHelper;
-
-/**
- * This tests ensures that the toolbar in reader mode displays the original page url.
- */
-public class testReaderModeTitle extends UITest {
- public void testReaderModeTitle() {
- GeckoHelper.blockForReady();
-
- NavigationHelper.enterAndLoadUrl(mStringHelper.ROBOCOP_READER_MODE_BASIC_ARTICLE);
-
- mToolbar.pressReaderModeButton();
-
- mToolbar.assertTitle(mStringHelper.ROBOCOP_READER_MODE_BASIC_ARTICLE);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReadingListCache.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReadingListCache.java
deleted file mode 100644
index 2006bbbfc..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReadingListCache.java
+++ /dev/null
@@ -1,12 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-
-public class testReadingListCache extends JavascriptTest {
- public testReadingListCache() {
- super("testReadingListCache.js");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReadingListToBookmarksMigration.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReadingListToBookmarksMigration.java
deleted file mode 100644
index dc181defc..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testReadingListToBookmarksMigration.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.Uri;
-import android.util.Log;
-
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.GeckoProfileDirectories;
-import org.mozilla.gecko.db.*;
-import org.mozilla.gecko.reader.SavedReaderViewHelper;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-
-import static org.mozilla.gecko.db.BrowserContract.*;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
-
-// TODO: Move to junit 3 tests, once those run in automation. There is no ui testing to do so it's a better fit.
-
-/**
- * This test runs the 30 to 31 database upgrade, which moves reading-list INPUT_FILES from a separate
- * reading-list folder into mobile bookmarks.
- *
- * It is based on testBrowserDatabaseHelperUpgrades. We load a v30 db containing two reading list
- * INPUT_FILES, and test that these have successfully been converted into bookmarks.
- */
-public class testReadingListToBookmarksMigration extends UITest {
- private ArrayList<File> tempFiles;
-
- // These names are generated by hashing the URLs, see INPUT_URLS below, and
- // BrowserDatabaseHelper.getReaderCacheFileNameForURL()
- private static final ArrayList<String> INPUT_FILES = new ArrayList<String>() {{
- add("DWUP3U4ERC6TKJVSYXKJLHHEFY.json");
- add("KWNV7PXD3JFOJBQJVFXI3CQKNE.json");
- }};
-
- // same ordering as in INPUT_FILES, although we don't rely on ordering in this test
- private static final ArrayList<String> INPUT_URLS = new ArrayList<String>() {{
- add("http://www.bbc.com/news/election-us-2016-35962179");
- add("http://www.bbc.com/news/world-europe-35962670");
- }};
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- // TODO: We already install & remove the profile directory each run so it'd be safer for clean-up to store
- // this there. That being said, temporary files are still stored in the application directory so these temporary
- // files will get cleaned up when the application is uninstalled or when data is cleared.
- tempFiles = new ArrayList<>();
- }
-
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
- for (final File file : tempFiles) {
- file.delete();
- }
- }
-
- private void walkRLPreMigration(SQLiteDatabase db) {
- Set<String> urls = new HashSet<>(INPUT_URLS);
-
- final Cursor c = db.rawQuery("SELECT * FROM " + ReadingListItems.TABLE_NAME, null);
-
- fAssertNotNull("Cursor cannot be null", c);
- try {
- final boolean movedToFirst = c.moveToFirst();
- fAssertTrue("Cursor must have data", movedToFirst);
-
- int urlIndex = c.getColumnIndexOrThrow(ReadingListItems.URL);
- do {
- final String url = c.getString(urlIndex);
-
- boolean removed = urls.remove(url);
- fAssertTrue("Unexpected reading-list URL in database", removed);
- } while (c.moveToNext());
- } finally {
- c.close();
- }
-
- fAssertTrue("All urls should have been removed from set", urls.isEmpty());
- }
-
- private void walkRLPostMigration(SQLiteDatabase db) {
- Set<String> urls = new HashSet<>(INPUT_URLS);
-
- final Cursor c = db.rawQuery("SELECT * FROM " +
- Bookmarks.VIEW_WITH_ANNOTATIONS
- + " WHERE " + BrowserContract.UrlAnnotations.KEY + " = ?",
- new String[] {
- BrowserContract.UrlAnnotations.Key.READER_VIEW.getDbValue()
- });
-
- fAssertNotNull("Cursor cannot be null", c);
- try {
- final boolean movedToFirst = c.moveToFirst();
- fAssertTrue("Cursor must have data", movedToFirst);
-
- int urlIndex = c.getColumnIndexOrThrow(Bookmarks.URL);
- do {
- final String url = c.getString(urlIndex);
-
- boolean removed = urls.remove(url);
- fAssertTrue("Unexpected reading-list URL in database", removed);
- } while (c.moveToNext());
- } finally {
- c.close();
- }
-
- fAssertTrue("All urls should have been removed from set", urls.isEmpty());
- }
-
- /**
- * @throws IOException if the database or input files cannot be copied.
- */
- public void testReadingListToBookmarksMigration() throws IOException {
- final String tempDbPath = copyAssets();
- final SQLiteDatabase db = SQLiteDatabase.openDatabase(tempDbPath, null, 0);
-
- try {
- // This initialises the helper, but does not open the DB.
- BrowserDatabaseHelper dbHelper = new BrowserDatabaseHelper(getActivity(), tempDbPath);
-
- walkRLPreMigration(db);
-
- // Run just one upgrade - we don't know what future upgrades might do, whereas with one
- // upgrade we can guarantee a given DB state.
- dbHelper.onUpgrade(db, 30, 31);
-
- // SavedReaderViewHelper writes annotations directly to the GeckoProfile DB (as opposed
- // to our local DB copy). We aren't able to read this here (and the data isn't written
- // to our own db), hence we can't test the DB content yet.
-// walkRLPostMigration(db);
-
- SavedReaderViewHelper rvh = SavedReaderViewHelper.getSavedReaderViewHelper(getActivity());
-
- fAssertEquals("All input files should have been migrated", INPUT_FILES.size(), rvh.size());
- for (String url : INPUT_URLS) {
- boolean isCached = rvh.isURLCached(url);
- fAssertTrue("URL no longer in cache after migration", isCached);
- }
- } finally {
- db.close();
- }
- }
-
- private void copyAssetToFile(String inputPath, File destination) throws IOException {
- final InputStream inputStream = openFileFromAssets(inputPath);
- final OutputStream os = new BufferedOutputStream(new FileOutputStream(destination));
- try {
- final byte[] buffer = new byte[1024];
- int len;
- while ((len = inputStream.read(buffer)) > 0) {
- os.write(buffer, 0, len);
- }
- os.flush();
- } finally {
- os.close();
- inputStream.close();
- }
- }
-
- /**
- * Copies assets into the desired locations. We need to copy our DB into a temporary file,
- * and readercache items into the profile directory.
- *
- * @throws IOException if reading the existing files or writing the temporary files fails
- */
- private String copyAssets() throws IOException {
- final File profileDir = GeckoProfile.get(getActivity()).getDir();
- final File cacheDir = new File(profileDir, "readercache");
- cacheDir.mkdir();
-
- for (String name : INPUT_FILES) {
- final String path = "readercache" + File.separator + name;
- final File destination = new File(cacheDir, name);
- tempFiles.add(destination);
-
- Log.d(LOGTAG, "Moving readerview cache file to " + destination.getPath());
- copyAssetToFile(path, destination);
- }
-
- final File dbDestination = File.createTempFile("temporaryDB_", "db");
- tempFiles.add(dbDestination);
-
- Log.d(LOGTAG, "Moving DB from assets to " + dbDestination.getPath());
- copyAssetToFile("browser.db", dbDestination);
-
- return dbDestination.getPath();
- }
-
- private InputStream openFileFromAssets(final String name) throws IOException {
- final String assetPath = String.format("reading_list_bookmarks_migration" + File.separator + name);
- Log.d(LOGTAG, "Opening file from assets: " + assetPath);
- try {
- return new BufferedInputStream(getInstrumentation().getContext().getAssets().open(assetPath));
- } catch (final FileNotFoundException e) {
- throw new IllegalStateException("Declared input files must be provided", e);
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testRestrictions.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testRestrictions.java
deleted file mode 100644
index 8977aa177..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testRestrictions.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertFalse;
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
-
-import org.mozilla.gecko.restrictions.Restrictable;
-import org.mozilla.gecko.restrictions.Restrictions;
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-
-public class testRestrictions extends UITest {
- public void testRestrictions() {
- GeckoHelper.blockForReady();
-
- // No restrictions should be enforced when using a normal profile
- for (Restrictable restrictable : Restrictable.values()) {
- if (restrictable == Restrictable.BLOCK_LIST) {
- assertFeatureDisabled(restrictable);
- } else {
- assertFeatureEnabled(restrictable);
- }
- }
- }
-
- private void assertFeatureEnabled(Restrictable restrictable) {
- fAssertTrue(String.format("Restrictable feature %s is enabled", restrictable.name),
- Restrictions.isAllowed(getActivity(), restrictable)
- );
- }
-
- private void assertFeatureDisabled(Restrictable restrictable) {
- fAssertFalse(String.format("Restrictable feature %s is disabled", restrictable.name),
- Restrictions.isAllowed(getActivity(), restrictable)
- );
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testRuntimePermissionsAPI.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testRuntimePermissionsAPI.java
deleted file mode 100644
index df192fc43..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testRuntimePermissionsAPI.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.util.EventCallback;
-import org.mozilla.gecko.util.NativeEventListener;
-import org.mozilla.gecko.util.NativeJSObject;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail;
-
-public class testRuntimePermissionsAPI extends JavascriptTest implements NativeEventListener {
- public testRuntimePermissionsAPI() {
- super("testRuntimePermissionsAPI.js");
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- EventDispatcher.getInstance().registerGeckoThreadListener(this, "RuntimePermissions:Prompt");
- }
-
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
-
- EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "RuntimePermissions:Prompt");
- }
-
- @Override
- public void handleMessage(String event, NativeJSObject message, EventCallback callback) {
- mAsserter.is(event, "RuntimePermissions:Prompt", "Received RuntimePermissions:Prompt event");
-
- try {
- String[] permissions = message.getStringArray("permissions");
- mAsserter.is(3, permissions.length, "Received three permissions");
-
- mAsserter.is("android.permission.CAMERA", permissions[0], "Received CAMERA permission");
- mAsserter.is("android.permission.WRITE_EXTERNAL_STORAGE", permissions[1], "Received WRITE_EXTERNAL_STORAGE permission");
- mAsserter.is("android.permission.RECORD_AUDIO", permissions[2], "Received RECORD_AUDIO permission");
- } catch (Exception e) {
- fFail("Event does not contain expected data: " + e.getMessage());
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSearchHistoryProvider.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSearchHistoryProvider.java
deleted file mode 100644
index 3c22703bc..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSearchHistoryProvider.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import java.util.concurrent.Callable;
-
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserContract.SearchHistory;
-import org.mozilla.gecko.db.SearchHistoryProvider;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class testSearchHistoryProvider extends ContentProviderTest {
-
- // Translations of "United Kingdom" in several different languages
- private static final String[] testStrings = {
- "An Ríocht Aontaithe", // Irish
- "Angli", // Albanian
- "Britanniarum Regnum", // Latin
- "Britio", // Esperanto
- "Büyük Britanya", // Turkish
- "Egyesült Királyság", // Hungarian
- "Erresuma Batua", // Basque
- "Inggris Raya", // Indonesian
- "Ir-Renju Unit", // Maltese
- "Iso-Britannia", // Finnish
- "JungtinÄ— KaralystÄ—", // Lithuanian
- "LielbritÄnija", // Latvian
- "Regatul Unit", // Romanian
- "Regne Unit", // Catalan, Valencian
- "Regno Unito", // Italian
- "Royaume-Uni", // French
- "Spojené království", // Czech
- "Spojené kráľovstvo", // Slovak
- "Storbritannia", // Norwegian
- "Storbritannien", // Danish
- "Suurbritannia", // Estonian
- "Ujedinjeno Kraljevstvo", // Bosnian
- "United Alaeze", // Igbo
- "United Kingdom", // English
- "Vereinigtes Königreich", // German
- "Verenigd Koninkrijk", // Dutch
- "Verenigde Koninkryk", // Afrikaans
- "Vương quốc Anh", // Vietnamese
- "Wayòm Ini", // Haitian, Haitian Creole
- "Y Deyrnas Unedig", // Welsh
- "Združeno kraljestvo", // Slovene
- "Zjednoczone Królestwo", // Polish
- "Ηνωμένο Βασίλειο", // Greek (modern)
- "ВеликобританиÑ", // Russian
- "ÐÑгдÑÑн Вант УлÑ", // Mongolian
- "Обединетото КралÑтво", // Macedonian
- "Уједињено КраљевÑтво", // Serbian
- "Õ„Õ«Õ¡ÖÕµÕ¡Õ¬ Ô¹Õ¡Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶", // Armenian
- "בריטניה", // Hebrew (modern)
- "פֿ×ַר×ייניקטע מלכות", // Yiddish
- "المملكة المتحدة", // Arabic
- "برطانیÛ", // Urdu
- "پادشاهی متحده", // Persian (Farsi)
- "यूनाइटेड किंगडम", // Hindi
- "संयà¥à¤•à¥à¤¤ राजà¥à¤¯", // Nepali
- "যà§à¦•à§à¦¤à¦°à¦¾à¦œà§à¦¯", // Bengali, Bangla
- "યà«àª¨àª¾àª‡àªŸà«‡àª¡ કિંગડમ", // Gujarati
- "à®à®•à¯à®•à®¿à®¯ ராஜà¯à®¯à®®à¯", // Tamil
- "สหราชอาณาจัà¸à¸£", // Thai
- "ສະ​ຫະ​ປະ​ຊາ​ຊະ​ອາ​ນາ​ຈັàº", // Lao
- "გáƒáƒ”რთიáƒáƒœáƒ”ბული სáƒáƒ›áƒ”ფáƒ", // Georgian
- "イギリス", // Japanese
- "è”åˆçŽ‹å›½" // Chinese
- };
-
-
- private static final String DB_NAME = "searchhistory.db";
-
- /**
- * Boilerplate alert.
- * <p/>
- * Make sure this method is present and that it returns a new
- * instance of your class.
- */
- private static final Callable<ContentProvider> sProviderFactory =
- new Callable<ContentProvider>() {
- @Override
- public ContentProvider call() {
- return new SearchHistoryProvider();
- }
- };
-
- @Override
- public void setUp() throws Exception {
- super.setUp(sProviderFactory, BrowserContract.SEARCH_HISTORY_AUTHORITY, DB_NAME);
- mTests.add(new TestInsert());
- mTests.add(new TestUnicodeQuery());
- mTests.add(new TestTimestamp());
- mTests.add(new TestLimit());
- mTests.add(new TestDelete());
- mTests.add(new TestIncrement());
- }
-
- public void testSearchHistory() throws Exception {
- for (Runnable test : mTests) {
- String testName = test.getClass().getSimpleName();
- setTestName(testName);
- mAsserter.dumpLog(
- "testBrowserProvider: Database empty - Starting " + testName + ".");
- // Clear the db
- mProvider.delete(SearchHistory.CONTENT_URI, null, null);
- test.run();
- }
- }
-
- /**
- * Verify that we can pass a LIMIT clause using a query parameter.
- */
- private class TestLimit extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues cv;
- for (int i = 0; i < testStrings.length; i++) {
- cv = new ContentValues();
- cv.put(SearchHistory.QUERY, testStrings[i]);
- mProvider.insert(SearchHistory.CONTENT_URI, cv);
- }
-
- final int limit = 5;
-
- // Test 1: Handle proper input.
-
- Uri uri = SearchHistory.CONTENT_URI
- .buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_LIMIT, String.valueOf(limit))
- .build();
-
- Cursor c = mProvider.query(uri, null, null, null, null);
- try {
- mAsserter.is(c.getCount(), limit,
- String.format("Should have %d results", limit));
- } finally {
- c.close();
- }
-
- // Test 2: Empty input yields all results.
-
- uri = SearchHistory.CONTENT_URI
- .buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_LIMIT, "")
- .build();
-
- c = mProvider.query(uri, null, null, null, null);
- try {
- mAsserter.is(c.getCount(), testStrings.length, "Should have all results");
- } finally {
- c.close();
- }
-
- // Test 3: Illegal params.
-
- String[] illegalParams = new String[] {"a", "-1"};
- boolean success = true;
-
- for (String param : illegalParams) {
- success = true;
-
- uri = SearchHistory.CONTENT_URI
- .buildUpon()
- .appendQueryParameter(BrowserContract.PARAM_LIMIT, param)
- .build();
-
- try {
- c = mProvider.query(uri, null, null, null, null);
- success = false;
- } catch(IllegalArgumentException e) {
- // noop.
- } finally {
- if (c != null) {
- c.close();
- }
- }
-
- mAsserter.ok(success, "LIMIT", param + " should have been an invalid argument");
- }
-
- }
- }
-
- /**
- * Verify that we can insert values into the DB, including unicode.
- */
- private class TestInsert extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues cv;
- for (int i = 0; i < testStrings.length; i++) {
- cv = new ContentValues();
- cv.put(SearchHistory.QUERY, testStrings[i]);
- mProvider.insert(SearchHistory.CONTENT_URI, cv);
- }
-
- final Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
- try {
- mAsserter.is(c.getCount(), testStrings.length,
- "Should have one row for each insert");
- } finally {
- c.close();
- }
- }
- }
-
- /**
- * Verify that we can insert values into the DB, including unicode.
- */
- private class TestUnicodeQuery extends TestCase {
- @Override
- public void test() throws Exception {
- final String selection = SearchHistory.QUERY + " = ?";
-
- for (int i = 0; i < testStrings.length; i++) {
- final ContentValues cv = new ContentValues();
- cv.put(SearchHistory.QUERY, testStrings[i]);
- mProvider.insert(SearchHistory.CONTENT_URI, cv);
-
- final Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, selection,
- new String[]{ testStrings[i] }, null);
- try {
- mAsserter.is(c.getCount(), 1,
- "Should have one row for insert of " + testStrings[i]);
- } finally {
- c.close();
- }
- }
- }
- }
-
- /**
- * Verify that timestamps are updated on insert.
- */
- private class TestTimestamp extends TestCase {
- @Override
- public void test() throws Exception {
- String insertedTerm = "Courtside Seats";
- long insertStart;
- long insertFinish;
- long t1Db;
- long t2Db;
-
- ContentValues cv = new ContentValues();
- cv.put(SearchHistory.QUERY, insertedTerm);
-
- // First check that the DB has a value that is close to the
- // system time.
- insertStart = System.currentTimeMillis();
- mProvider.insert(SearchHistory.CONTENT_URI, cv);
- insertFinish = System.currentTimeMillis();
-
- final Cursor c1 = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
- try {
- c1.moveToFirst();
- t1Db = c1.getLong(c1.getColumnIndex(SearchHistory.DATE_LAST_VISITED));
- } finally {
- c1.close();
- }
-
- mAsserter.dumpLog("First insert:");
- mAsserter.dumpLog(" insertStart " + insertStart);
- mAsserter.dumpLog(" insertFinish " + insertFinish);
- mAsserter.dumpLog(" t1Db " + t1Db);
- mAsserter.ok(t1Db >= insertStart, "DATE_LAST_VISITED",
- "Date last visited should be set on insert.");
- mAsserter.ok(t1Db <= insertFinish, "DATE_LAST_VISITED",
- "Date last visited should be set on insert.");
-
- cv = new ContentValues();
- cv.put(SearchHistory.QUERY, insertedTerm);
-
- insertStart = System.currentTimeMillis();
- mProvider.insert(SearchHistory.CONTENT_URI, cv);
- insertFinish = System.currentTimeMillis();
-
- final Cursor c2 = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
- try {
- c2.moveToFirst();
- t2Db = c2.getLong(c2.getColumnIndex(SearchHistory.DATE_LAST_VISITED));
- } finally {
- c2.close();
- }
-
- mAsserter.dumpLog("Second insert:");
- mAsserter.dumpLog(" insertStart " + insertStart);
- mAsserter.dumpLog(" insertFinish " + insertFinish);
- mAsserter.dumpLog(" t2Db " + t2Db);
-
- mAsserter.ok(t2Db >= insertStart, "DATE_LAST_VISITED",
- "Date last visited should be set on insert.");
- mAsserter.ok(t2Db <= insertFinish, "DATE_LAST_VISITED",
- "Date last visited should be set on insert.");
- mAsserter.ok(t2Db >= t1Db, "DATE_LAST_VISITED",
- "Date last visited should be updated on key increment.");
- }
- }
-
- /**
- * Verify that sending a delete command empties the database.
- */
- private class TestDelete extends TestCase {
- @Override
- public void test() throws Exception {
- String insertedTerm = "Courtside Seats";
-
- ContentValues cv = new ContentValues();
- cv.put(SearchHistory.QUERY, insertedTerm);
- mProvider.insert(SearchHistory.CONTENT_URI, cv);
-
- final Cursor c1 = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
- try {
- mAsserter.is(c1.getCount(), 1, "Should have one value");
- mProvider.delete(SearchHistory.CONTENT_URI, null, null);
- } finally {
- c1.close();
- }
-
- final Cursor c2 = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
- try {
- mAsserter.is(c2.getCount(), 0, "Should be empty");
- mProvider.insert(SearchHistory.CONTENT_URI, cv);
- } finally {
- c2.close();
- }
-
- final Cursor c3 = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
- try {
- mAsserter.is(c3.getCount(), 1, "Should have one value");
- } finally {
- c3.close();
- }
- }
- }
-
-
- /**
- * Ensure that we only increment when the case matches.
- */
- private class TestIncrement extends TestCase {
- @Override
- public void test() throws Exception {
- ContentValues cv = new ContentValues();
- cv.put(SearchHistory.QUERY, "omaha");
- mProvider.insert(SearchHistory.CONTENT_URI, cv);
-
- cv = new ContentValues();
- cv.put(SearchHistory.QUERY, "omaha");
- mProvider.insert(SearchHistory.CONTENT_URI, cv);
-
- Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
- try {
- c.moveToFirst();
- mAsserter.is(c.getCount(), 1, "Should have one result");
- mAsserter.is(c.getInt(c.getColumnIndex(SearchHistory.VISITS)), 2,
- "Counter should be 2");
- } finally {
- c.close();
- }
-
- cv = new ContentValues();
- cv.put(SearchHistory.QUERY, "Omaha");
- mProvider.insert(SearchHistory.CONTENT_URI, cv);
- c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
- try {
- mAsserter.is(c.getCount(), 2, "Should have two results");
- } finally {
- c.close();
- }
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSearchSuggestions.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSearchSuggestions.java
deleted file mode 100644
index 6f82e5c51..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSearchSuggestions.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.SuggestClient;
-import org.mozilla.gecko.home.BrowserSearch;
-
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import com.robotium.solo.Condition;
-
-/**
- * Test for search suggestions.
- * Sends queries from AwesomeBar input and verifies that suggestions match
- * expected values.
- */
-public class testSearchSuggestions extends BaseTest {
- private static final int SUGGESTION_MAX = 3;
- private static final int SUGGESTION_TIMEOUT = 15000;
-
- private static final String TEST_QUERY = "foo barz";
- private static final String SUGGESTION_TEMPLATE = "/robocop/robocop_suggestions.sjs?query=__searchTerms__";
-
- public void testSearchSuggestions() {
- // Mock the search system.
- // The BrowserSearch UI only shows up once a non-empty
- // search term is entered, but we swizzle in a new factory beforehand.
- mockSuggestClientFactory();
-
- blockForGeckoReady();
-
- // Map of expected values. See robocop_suggestions.sjs.
- final HashMap<String, ArrayList<String>> suggestMap = new HashMap<String, ArrayList<String>>();
- buildSuggestMap(suggestMap);
-
- focusUrlBar();
-
- // At this point we rely on our swizzling having worked -- which relies
- // on us not having previously run a search.
- // The test will fail later if there's already a BrowserSearch object with a
- // suggest client set, so fail here.
- BrowserSearch browserSearch = (BrowserSearch) getBrowserSearch();
- mAsserter.ok(browserSearch == null ||
- browserSearch.mSuggestClient == null,
- "There is no existing search client.", "");
-
- // Now test the incremental suggestions.
- for (int i = 0; i < TEST_QUERY.length(); i++) {
- mActions.sendKeys(TEST_QUERY.substring(i, i+1));
-
- final String query = TEST_QUERY.substring(0, i+1);
- mSolo.waitForView(R.id.suggestion_text);
- boolean success = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- // Get the first suggestion row.
- ViewGroup suggestionGroup = (ViewGroup) getActivity().findViewById(R.id.suggestion_layout);
- if (suggestionGroup == null) {
- mAsserter.dumpLog("Fail: suggestionGroup is null.");
- return false;
- }
-
- final ArrayList<String> expected = suggestMap.get(query);
- for (int i = 0; i < expected.size(); i++) {
- View queryChild = suggestionGroup.getChildAt(i);
- if (queryChild == null || queryChild.getVisibility() == View.GONE) {
- mAsserter.dumpLog("Fail: queryChild is null or GONE.");
- return false;
- }
-
- String suggestion = ((TextView) queryChild.findViewById(R.id.suggestion_text)).getText().toString();
- if (!suggestion.equals(expected.get(i))) {
- mAsserter.dumpLog("Suggestion '" + suggestion + "' not equal to expected '" + expected.get(i) + "'.");
- return false;
- }
- }
-
- return true;
- }
- }, SUGGESTION_TIMEOUT);
-
- mAsserter.is(success, true, "Results for query '" + query + "' matched expected suggestions");
- }
- }
-
- private void buildSuggestMap(HashMap<String, ArrayList<String>> suggestMap) {
- // these values assume SUGGESTION_MAX = 3
- suggestMap.put("f", new ArrayList<String>() {{ add("f"); add("facebook"); add("fandango"); add("frys"); }});
- suggestMap.put("fo", new ArrayList<String>() {{ add("fo"); add("forever 21"); add("food network"); add("fox news"); }});
- suggestMap.put("foo", new ArrayList<String>() {{ add("foo"); add("food network"); add("foothill college"); add("foot locker"); }});
- suggestMap.put("foo ", new ArrayList<String>() {{ add("foo "); add("foo fighters"); add("foo bar"); add("foo bat"); }});
- suggestMap.put("foo b", new ArrayList<String>() {{ add("foo b"); add("foo bar"); add("foo bat"); add("foo bay"); }});
- suggestMap.put("foo ba", new ArrayList<String>() {{ add("foo ba"); add("foo bar"); add("foo bat"); add("foo bay"); }});
- suggestMap.put("foo bar", new ArrayList<String>() {{ add("foo bar"); }});
- suggestMap.put("foo barz", new ArrayList<String>() {{ add("foo barz"); }});
- }
-
- private void mockSuggestClientFactory() {
- BrowserSearch.sSuggestClientFactory = new BrowserSearch.SuggestClientFactory() {
- @Override
- public SuggestClient getSuggestClient(Context context, String template, int timeout, int max) {
- final String suggestTemplate = getAbsoluteRawUrl(SUGGESTION_TEMPLATE);
-
- // This one uses our template, and also doesn't check for network accessibility.
- return new SuggestClient(context, suggestTemplate, SUGGESTION_TIMEOUT, Integer.MAX_VALUE, false);
- }
- };
- }
-}
-
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionHistory.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionHistory.java
deleted file mode 100644
index 50d173461..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionHistory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-import org.mozilla.gecko.tests.helpers.NavigationHelper;
-
-/**
- * Tests that navigating through session history (ex: forward, back) sets the correct UI state.
- */
-public class testSessionHistory extends UITest {
- public void testSessionHistory() {
- GeckoHelper.blockForReady();
-
- String url = mStringHelper.ROBOCOP_BLANK_PAGE_01_URL;
- NavigationHelper.enterAndLoadUrl(url);
- mToolbar.assertTitle(url);
-
- url = mStringHelper.ROBOCOP_BLANK_PAGE_02_URL;
- NavigationHelper.enterAndLoadUrl(url);
- mToolbar.assertTitle(url);
-
- url = mStringHelper.ROBOCOP_BLANK_PAGE_03_URL;
- NavigationHelper.enterAndLoadUrl(url);
- mToolbar.assertTitle(url);
-
- NavigationHelper.goBack();
- mToolbar.assertTitle(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL);
-
- NavigationHelper.goBack();
- mToolbar.assertTitle(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL);
-
- NavigationHelper.goForward();
- mToolbar.assertTitle(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL);
-
- NavigationHelper.reload();
- mToolbar.assertTitle(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionOOMRestore.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionOOMRestore.java
deleted file mode 100644
index 5646311b1..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionOOMRestore.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-
-/**
- * Tests session OOM restore behavior.
- *
- * Loads a session and tests that it is restored correctly.
- */
-public class testSessionOOMRestore extends SessionTest {
- private Session mSession;
- private static final String PREFS_NAME = "GeckoApp";
- private static final String PREFS_ALLOW_STATE_BUNDLE = "allowStateBundle";
-
- @Override
- public void setActivityIntent(Intent intent) {
- PageInfo home = new PageInfo(StringHelper.STATIC_ABOUT_HOME_URL);
- PageInfo page1 = new PageInfo("page1");
- PageInfo page2 = new PageInfo("page2");
- PageInfo page3 = new PageInfo("page3");
- PageInfo page4 = new PageInfo("page4");
- PageInfo page5 = new PageInfo("page5");
- PageInfo page6 = new PageInfo("page6");
-
- SessionTab tab1 = new SessionTab(0, home, page1, page2);
- SessionTab tab2 = new SessionTab(1, home, page3, page4);
- SessionTab tab3 = new SessionTab(2, home, page5, page6);
-
- mSession = new Session(1, tab1, tab2, tab3);
-
- String sessionString = buildSessionJSON(mSession);
- writeProfileFile("sessionstore.js", sessionString);
-
- // This feature is pref-protected to prevent other apps from injecting
- // a state bundle, so enable it here.
- SharedPreferences prefs = getInstrumentation().getTargetContext()
- .getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
- prefs.edit().putBoolean(PREFS_ALLOW_STATE_BUNDLE, true).commit();
-
- Bundle bundle = new Bundle();
- bundle.putString("privateSession", null);
- intent.putExtra("stateBundle", bundle);
-
- super.setActivityIntent(intent);
- }
-
- public void testSessionOOMRestore() throws Exception {
- blockForGeckoReady();
- verifySessionTabs(mSession);
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionOOMSave.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionOOMSave.java
deleted file mode 100644
index f5e5ee099..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSessionOOMSave.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-
-import com.robotium.solo.Condition;
-
-/**
- * Tests session OOM save behavior.
- *
- * Builds a session and tests that the saved state is correct.
- */
-public class testSessionOOMSave extends SessionTest {
- private final static int SESSION_TIMEOUT = 25000;
-
- public void testSessionOOMSave() {
- Actions.EventExpecter pageShowExpecter = mActions.expectGeckoEvent("Content:PageShow");
- pageShowExpecter.blockForEvent();
- pageShowExpecter.unregisterListener();
-
- PageInfo home = new PageInfo(mStringHelper.ABOUT_HOME_URL);
- PageInfo page1 = new PageInfo("page1");
- PageInfo page2 = new PageInfo("page2");
- PageInfo page3 = new PageInfo("page3");
- PageInfo page4 = new PageInfo("page4");
- PageInfo page5 = new PageInfo("page5");
- PageInfo page6 = new PageInfo("page6");
-
- SessionTab tab1 = new SessionTab(0, home, page1, page2);
- SessionTab tab2 = new SessionTab(1, home, page3, page4);
- SessionTab tab3 = new SessionTab(2, home, page5, page6);
-
- final Session session = new Session(1, tab1, tab2, tab3);
-
- // Load the tabs into the browser
- loadSessionTabs(session);
-
- // Verify sessionstore.js written by Gecko. The session write is
- // delayed for certain interactions (such as changing the selected
- // tab), so the file is repeatedly read until it matches the expected
- // output. Because of the delay, this part of the test takes ~9 seconds
- // to pass.
- VerifyJSONCondition verifyJSONCondition = new VerifyJSONCondition(session);
- boolean success = waitForCondition(verifyJSONCondition, SESSION_TIMEOUT);
- if (success) {
- mAsserter.ok(true, "verified session JSON", null);
- } else {
- mAsserter.ok(false, "failed to verify session JSON",
- getStackTraceString(verifyJSONCondition.getLastException()));
- }
- }
-
- private class VerifyJSONCondition implements Condition {
- private AssertException mLastException;
- private final NonFatalAsserter mAsserter = new NonFatalAsserter();
- private final Session mSession;
-
- public VerifyJSONCondition(Session session) {
- mSession = session;
- }
-
- @Override
- public boolean isSatisfied() {
- try {
- String sessionString = readProfileFile("sessionstore.js");
- if (sessionString == null) {
- mLastException = new AssertException("Could not read sessionstore.js");
- return false;
- }
-
- verifySessionJSON(mSession, sessionString, mAsserter);
- } catch (AssertException e) {
- mLastException = e;
- return false;
- }
- return true;
- }
-
- /**
- * Gets the last AssertException thrown by verifySessionJSON().
- *
- * This is useful to get the stack trace if the test fails.
- */
- public AssertException getLastException() {
- return mLastException;
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testShareLink.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testShareLink.java
deleted file mode 100644
index 0df786136..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testShareLink.java
+++ /dev/null
@@ -1,265 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.home.HomePager;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Build;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.GridView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.robotium.solo.Condition;
-
-/**
- * This test covers the opening and content of the Share Link pop-up list
- * The test opens the Share menu from the app menu, the URL bar, a link context menu and the Awesomescreen tabs
- */
-public class testShareLink extends AboutHomeTest {
- String url;
- String urlTitle = mStringHelper.ROBOCOP_BIG_LINK_TITLE;
-
- public void testShareLink() {
- url = getAbsoluteUrl(mStringHelper.ROBOCOP_BIG_LINK_URL);
- ArrayList<String> shareOptions;
- blockForGeckoReady();
-
- // FIXME: This is a temporary hack workaround for a permissions problem.
- openAboutHomeTab(AboutHomeTabs.HISTORY);
-
- inputAndLoadUrl(url);
- verifyUrlBarTitle(url); // Waiting for page title to ensure the page is loaded
-
- selectMenuItem(mStringHelper.SHARE_LABEL);
- if (Build.VERSION.SDK_INT >= 14) {
- // Check for our own sync in the submenu.
- waitForText("Sync$");
- } else {
- waitForText("Share via");
- }
-
- // Get list of current available share activities and verify them
- shareOptions = getShareOptions();
- ArrayList<String> displayedOptions = getShareOptionsList();
- for (String option:shareOptions) {
- // Verify if the option is present in the list of displayed share options
- mAsserter.ok(optionDisplayed(option, displayedOptions), "Share option found", option);
- }
-
- // Test share from the urlbar context menu
- mSolo.goBack(); // Close the share menu
- mSolo.clickLongOnText(urlTitle);
- verifySharePopup(shareOptions,"urlbar");
-
- // The link has a 60px height, so let's try to hit the middle
- float top = mDriver.getGeckoTop() + 30 * mDevice.density;
- float left = mDriver.getGeckoLeft() + mDriver.getGeckoWidth() / 2;
- mSolo.clickLongOnScreen(left, top);
- verifySharePopup("Share Link",shareOptions,"Link");
-
- // Test the share popup in the Bookmarks page
- openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
-
- final ListView bookmarksList = findListViewWithTag(HomePager.LIST_TAG_BOOKMARKS);
- mAsserter.is(waitForNonEmptyListToLoad(bookmarksList), true, "list is properly loaded");
-
- int headerViewsCount = bookmarksList.getHeaderViewsCount();
- View bookmarksItem = bookmarksList.getChildAt(headerViewsCount);
- if (bookmarksItem == null) {
- mAsserter.dumpLog("no child at index " + headerViewsCount + "; waiting for one...");
- Condition listWaitCondition = new Condition() {
- @Override
- public boolean isSatisfied() {
- if (bookmarksList.getChildAt(bookmarksList.getHeaderViewsCount()) == null)
- return false;
- return true;
- }
- };
- waitForCondition(listWaitCondition, MAX_WAIT_MS);
- headerViewsCount = bookmarksList.getHeaderViewsCount();
- bookmarksItem = bookmarksList.getChildAt(headerViewsCount);
- }
-
- mSolo.clickLongOnView(bookmarksItem);
- verifySharePopup(shareOptions,"bookmarks");
-
- // Prepopulate top sites with history items to overflow tiles.
- // We are trying to move away from using reflection and doing more black-box testing.
- inputAndLoadUrl(getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL));
- inputAndLoadUrl(getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_02_URL));
- inputAndLoadUrl(getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_03_URL));
- inputAndLoadUrl(getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_04_URL));
- if (mDevice.type.equals("tablet")) {
- // Tablets have more tile spaces to fill.
- inputAndLoadUrl(getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_05_URL));
- inputAndLoadUrl(getAbsoluteUrl(mStringHelper.ROBOCOP_BOXES_URL));
- inputAndLoadUrl(getAbsoluteUrl(mStringHelper.ROBOCOP_SEARCH_URL));
- inputAndLoadUrl(getAbsoluteUrl(mStringHelper.ROBOCOP_TEXT_PAGE_URL));
- }
-
- // Test the share popup in Top Sites.
- openAboutHomeTab(AboutHomeTabs.TOP_SITES);
-
- // Scroll down a bit so that the top sites list has more items on screen.
- int width = mDriver.getGeckoWidth();
- int height = mDriver.getGeckoHeight();
- mActions.drag(width / 2, width / 2, height - 10, height / 2);
-
- ListView topSitesList = findListViewWithTag(HomePager.LIST_TAG_TOP_SITES);
- mAsserter.is(waitForNonEmptyListToLoad(topSitesList), true, "list is properly loaded");
- View mostVisitedItem = topSitesList.getChildAt(topSitesList.getHeaderViewsCount());
- mSolo.clickLongOnView(mostVisitedItem);
- verifySharePopup(shareOptions,"top_sites");
-
- // Test the share popup in the history tab
- openAboutHomeTab(AboutHomeTabs.HISTORY);
-
- ListView mostRecentList = findListViewWithTag(HomePager.LIST_TAG_HISTORY);
- mAsserter.is(waitForNonEmptyListToLoad(mostRecentList), true, "list is properly loaded");
-
- // Getting second child after header views because the first is the "Today" label
- View mostRecentItem = mostRecentList.getChildAt(mostRecentList.getHeaderViewsCount() + 1);
- mSolo.clickLongOnView(mostRecentItem);
- verifySharePopup(shareOptions,"most recent");
- }
-
- public void verifySharePopup(ArrayList<String> shareOptions, String openedFrom) {
- verifySharePopup("Share", shareOptions, openedFrom);
- }
-
- public void verifySharePopup(String shareItemText, ArrayList<String> shareOptions, String openedFrom) {
- waitForText(shareItemText);
- mSolo.clickOnText(shareItemText);
- waitForText("Share via");
- ArrayList<String> displayedOptions = getSharePopupOption();
- for (String option:shareOptions) {
- // Verify if the option is present in the list of displayed share options
- mAsserter.ok(optionDisplayed(option, displayedOptions), "Share option for " + openedFrom + (openedFrom.equals("urlbar") ? "" : " item") + " found", option);
- }
- mSolo.goBack();
- /**
- * Adding a wait for the page title to make sure the Awesomebar will be dismissed
- * Because of Bug 712370 the Awesomescreen will be dismissed when the Share Menu is closed
- * so there is no need for handling this different depending on where the share menu was invoked from
- * TODO: Look more into why the delay is needed here now and it was working before
- */
- waitForText(urlTitle);
- }
-
- // Create a SEND intent and get the possible activities offered
- public ArrayList<String> getShareOptions() {
- ArrayList<String> shareOptions = new ArrayList<>();
- Activity currentActivity = getActivity();
- final Intent shareIntent = new Intent(Intent.ACTION_SEND);
- shareIntent.putExtra(Intent.EXTRA_TEXT, url);
- shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Robocop Blank 01");
- shareIntent.setType("text/plain");
- PackageManager pm = currentActivity.getPackageManager();
- List<ResolveInfo> activities = pm.queryIntentActivities(shareIntent, 0);
- for (ResolveInfo activity : activities) {
- shareOptions.add(activity.loadLabel(pm).toString());
- }
- return shareOptions;
- }
-
- // Traverse the group of views, adding strings from TextViews to the list.
- private void getGroupTextViews(ViewGroup group, ArrayList<String> list) {
- for (int i = 0; i < group.getChildCount(); i++) {
- View child = group.getChildAt(i);
- if (child instanceof AbsListView) {
- getGroupTextViews((AbsListView)child, list);
- } else if (child instanceof ViewGroup) {
- getGroupTextViews((ViewGroup)child, list);
- } else if (child instanceof TextView) {
- String viewText = ((TextView)child).getText().toString();
- if (viewText != null && viewText.length() > 0) {
- list.add(viewText);
- }
- }
- }
- }
-
- // Traverse the group of views, adding strings from TextViews to the list.
- // This override is for AbsListView, which has adapters. If adapters are
- // available, it is better to use them so that child views that are not
- // yet displayed can be examined.
- private void getGroupTextViews(AbsListView group, ArrayList<String> list) {
- for (int i = 0; i < group.getAdapter().getCount(); i++) {
- View child = group.getAdapter().getView(i, null, group);
- if (child instanceof AbsListView) {
- getGroupTextViews((AbsListView)child, list);
- } else if (child instanceof ViewGroup) {
- getGroupTextViews((ViewGroup)child, list);
- } else if (child instanceof TextView) {
- String viewText = ((TextView)child).getText().toString();
- if (viewText != null && viewText.length() > 0) {
- list.add(viewText);
- }
- }
- }
- }
-
- public ArrayList<String> getSharePopupOption() {
- ArrayList<String> displayedOptions = new ArrayList<>();
- AbsListView shareMenu = getDisplayedShareList();
- getGroupTextViews(shareMenu, displayedOptions);
- return displayedOptions;
- }
-
- public ArrayList<String> getShareSubMenuOption() {
- ArrayList<String> displayedOptions = new ArrayList<>();
- AbsListView shareMenu = getDisplayedShareList();
- getGroupTextViews(shareMenu, displayedOptions);
- return displayedOptions;
- }
-
- public ArrayList<String> getShareOptionsList() {
- if (Build.VERSION.SDK_INT >= 14) {
- return getShareSubMenuOption();
- } else {
- return getSharePopupOption();
- }
- }
-
- private boolean optionDisplayed(String shareOption, ArrayList<String> displayedOptions) {
- for (String displayedOption: displayedOptions) {
- if (shareOption.equals(displayedOption)) {
- return true;
- }
- }
- return false;
- }
-
- private AbsListView mViewGroup;
-
- private AbsListView getDisplayedShareList() {
- mViewGroup = null;
- boolean success = waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- ArrayList<View> views = mSolo.getCurrentViews();
- for (View view : views) {
- // List may be displayed in different view formats.
- // On JB, GridView is common; on ICS-, ListView is common.
- if (view instanceof ListView ||
- view instanceof GridView) {
- mViewGroup = (AbsListView)view;
- return true;
- }
- }
- return false;
- }
- }, MAX_WAIT_MS);
- mAsserter.ok(success,"Got the displayed share options?", "Got the share options view");
- return mViewGroup;
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSnackbarAPI.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSnackbarAPI.java
deleted file mode 100644
index 893f98a51..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSnackbarAPI.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail;
-
-import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.util.EventCallback;
-import org.mozilla.gecko.util.NativeEventListener;
-import org.mozilla.gecko.util.NativeJSObject;
-
-public class testSnackbarAPI extends JavascriptTest implements NativeEventListener {
- // Snackbar.LENGTH_INDEFINITE: To avoid tests depending on the android design support library
- private static final int SNACKBAR_LENGTH_INDEFINITE = -2;
-
- public testSnackbarAPI() {
- super("testSnackbarAPI.js");
- }
-
- @Override
- public void handleMessage(String event, NativeJSObject message, EventCallback callback) {
- mAsserter.is(event, "Snackbar:Show", "Received Snackbar:Show event");
-
- try {
- mAsserter.is(message.getString("message"), "This is a Snackbar", "Snackbar message");
- mAsserter.is(message.getInt("duration"), SNACKBAR_LENGTH_INDEFINITE, "Snackbar duration");
-
- NativeJSObject action = message.getObject("action");
-
- mAsserter.is(action.getString("label"), "Click me", "Snackbar action label");
-
- } catch (Exception e) {
- fFail("Event does not contain expected data: " + e.getMessage());
- }
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- EventDispatcher.getInstance().registerGeckoThreadListener(this, "Snackbar:Show");
- }
-
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
-
- EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "Snackbar:Show");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testStateWhileLoading.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testStateWhileLoading.java
deleted file mode 100644
index 7f7b47450..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testStateWhileLoading.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.tests.helpers.DeviceHelper;
-import org.mozilla.gecko.tests.helpers.GeckoClickHelper;
-import org.mozilla.gecko.tests.helpers.GeckoHelper;
-import org.mozilla.gecko.tests.helpers.NavigationHelper;
-import org.mozilla.gecko.tests.helpers.WaitHelper;
-
-/**
- * This test ensures the back/forward state is correct when switching to loading pages
- * to prevent regressions like Bug 1124190.
- */
-public class testStateWhileLoading extends UITest {
- public void testStateWhileLoading() {
- if (!DeviceHelper.isTablet()) {
- // This test case only covers tablets currently.
- return;
- }
-
- GeckoHelper.blockForReady();
-
- NavigationHelper.enterAndLoadUrl(mStringHelper.ROBOCOP_LINK_TO_SLOW_LOADING);
-
- GeckoClickHelper.openCentralizedLinkInNewTab();
-
- WaitHelper.waitForPageLoad(new Runnable() {
- @Override
- public void run() {
- mTabStrip.switchToTab(1);
-
- // Assert that the state of the back button is correct
- // after switching to the new (still loading) tab.
- mToolbar.assertBackButtonIsNotEnabled();
- }
- });
-
- // Assert that the state of the back button is still correct after the page has loaded.
- mToolbar.assertBackButtonIsNotEnabled();
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testStumblerSetting.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testStumblerSetting.java
deleted file mode 100644
index ac551b97f..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testStumblerSetting.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * * License, v. 2.0. If a copy of the MPL was not distributed with this
- * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.preferences.GeckoPreferences;
-import org.mozilla.mozstumbler.service.AppGlobals;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-
-import com.robotium.solo.Condition;
-
-/*
- * This test enables (checkbox checked) the Fennec setting to contribute to MLS, then waits for
- * a response Intent from the stumbler service to confirm it has started. Then, it disables the
- * service in the setting, and waits for confirmation that the servie has stopped.
- */
-public class testStumblerSetting extends BaseTest {
- boolean mIsEnabled;
-
- public void testStumblerSetting() {
- if (!AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED) {
- mAsserter.info("Checking stumbler build config.", "Skipping test as Stumbler is not enabled in this build.");
- return;
- }
-
- blockForGeckoReady();
-
- selectMenuItem(mStringHelper.SETTINGS_LABEL);
- mAsserter.ok(mSolo.waitForText(mStringHelper.SETTINGS_LABEL),
- "The Settings menu did not load", mStringHelper.SETTINGS_LABEL);
-
- String section = "^" + mStringHelper.MOZILLA_SECTION_LABEL + "$";
- waitForEnabledText(section);
- mSolo.clickOnText(section);
-
- String itemTitle = "^" + mStringHelper.LOCATION_SERVICES_LABEL + "$";
- boolean foundText = waitForPreferencesText(itemTitle);
- mAsserter.ok(foundText, "Waiting for settings item " + itemTitle + " in section " + section,
- "The " + itemTitle + " option is present in section " + section);
-
- BroadcastReceiver enabledDisabledReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(AppGlobals.ACTION_TEST_SETTING_ENABLED)) {
- mIsEnabled = true;
- } else {
- mIsEnabled = false;
- }
- }
- };
-
- Context context = getInstrumentation().getTargetContext();
- IntentFilter intentFilter = new IntentFilter(AppGlobals.ACTION_TEST_SETTING_ENABLED);
- intentFilter.addAction(AppGlobals.ACTION_TEST_SETTING_DISABLED);
- context.registerReceiver(enabledDisabledReceiver, intentFilter);
-
- boolean checked = mSolo.isCheckBoxChecked(itemTitle);
- try {
- mAsserter.ok(!checked, "Checking stumbler setting is unchecked.", "Unchecked as expected.");
-
- waitForEnabledText(itemTitle);
- mSolo.clickOnText(itemTitle);
-
- mSolo.waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return mIsEnabled;
- }
- }, 15000);
-
- mAsserter.ok(mIsEnabled, "Checking if stumbler became enabled.", "Stumbler is enabled.");
- mSolo.clickOnText(itemTitle);
-
- mSolo.waitForCondition(new Condition() {
- @Override
- public boolean isSatisfied() {
- return !mIsEnabled;
- }
- }, 15000);
-
- mAsserter.ok(!mIsEnabled, "Checking if stumbler became disabled.", "Stumbler is disabled.");
- } finally {
- context.unregisterReceiver(enabledDisabledReceiver);
- }
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testThumbnails.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testThumbnails.java
deleted file mode 100644
index 6cb42f37c..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testThumbnails.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.db.BrowserDB;
-
-import android.content.ContentResolver;
-import android.graphics.Color;
-
-import com.robotium.solo.Condition;
-
-/**
- * Test for thumbnail updates.
- * - loads 2 pages, each of which yield an HTTP 200
- * - verifies thumbnails are updated for both pages
- * - loads pages again; first page yields HTTP 200, second yields HTTP 404
- * - verifies thumbnail is updated for HTTP 200, but not HTTP 404
- * - finally, test that BrowserDB.removeThumbnails drops the thumbnails
- */
-public class testThumbnails extends BaseTest {
- public void testThumbnails() {
- final String site1Url = getAbsoluteUrl("/robocop/robocop_404.sjs?type=changeColor");
- final String site2Url = getAbsoluteUrl("/robocop/robocop_404.sjs?type=do404");
- final String site1Title = "changeColor";
- final String site2Title = "do404";
-
- // the session snapshot runnable is run 500ms after document stop. a
- // 3000ms delay gives us 2.5 seconds to take the screenshot, which
- // should be plenty of time, even on slow devices
- final int thumbnailDelay = 3000;
-
- blockForGeckoReady();
-
- // load sites; both will return HTTP 200 with a green background
- inputAndLoadUrl(site1Url);
- mSolo.sleep(thumbnailDelay);
- inputAndLoadUrl(site2Url);
- mSolo.sleep(thumbnailDelay);
- inputAndLoadUrl(mStringHelper.ABOUT_HOME_URL);
- waitForCondition(new ThumbnailTest(site1Title, Color.GREEN), 5000);
- mAsserter.is(getTopSiteThumbnailColor(site1Title), Color.GREEN, "Top site thumbnail updated for HTTP 200");
- waitForCondition(new ThumbnailTest(site2Title, Color.GREEN), 5000);
- mAsserter.is(getTopSiteThumbnailColor(site2Title), Color.GREEN, "Top site thumbnail updated for HTTP 200");
-
- // load sites again; both will have red background, and do404 will return HTTP 404
- inputAndLoadUrl(site1Url);
- mSolo.sleep(thumbnailDelay);
- inputAndLoadUrl(site2Url);
- mSolo.sleep(thumbnailDelay);
- inputAndLoadUrl(mStringHelper.ABOUT_HOME_URL);
- waitForCondition(new ThumbnailTest(site1Title, Color.RED), 5000);
- mAsserter.is(getTopSiteThumbnailColor(site1Title), Color.RED, "Top site thumbnail updated for HTTP 200");
- waitForCondition(new ThumbnailTest(site2Title, Color.GREEN), 5000);
- mAsserter.is(getTopSiteThumbnailColor(site2Title), Color.GREEN, "Top site thumbnail not updated for HTTP 404");
-
- // test dropping thumbnails
- final ContentResolver resolver = getActivity().getContentResolver();
- final DatabaseHelper helper = new DatabaseHelper(getActivity(), mAsserter);
- final BrowserDB db = helper.getProfileDB();
-
- // check that the thumbnail is non-null
- byte[] thumbnailData = db.getThumbnailForUrl(resolver, site1Url);
- mAsserter.ok(thumbnailData != null && thumbnailData.length > 0, "Checking for thumbnail data", "No thumbnail data found");
- // drop thumbnails
- db.removeThumbnails(resolver);
- // check that the thumbnail is now null
- thumbnailData = db.getThumbnailForUrl(resolver, site1Url);
- mAsserter.ok(thumbnailData == null || thumbnailData.length == 0, "Checking for thumbnail data", "Thumbnail data found");
- }
-
- private class ThumbnailTest implements Condition {
- private final String mTitle;
- private final int mColor;
-
- public ThumbnailTest(String title, int color) {
- mTitle = title;
- mColor = color;
- }
-
- @Override
- public boolean isSatisfied() {
- return getTopSiteThumbnailColor(mTitle) == mColor;
- }
- }
-
- private int getTopSiteThumbnailColor(String title) {
- // This test is not currently run, so this just needs to compile.
- return -1;
-// ViewGroup topSites = (ViewGroup) getActivity().findViewById(mTopSitesId);
-// if (topSites != null) {
-// final int childCount = topSites.getChildCount();
-// for (int i = 0; i < childCount; i++) {
-// View child = topSites.getChildAt(i);
-// if (child != null) {
-// TextView titleView = (TextView) child.findViewById(R.id.title);
-// if (titleView != null) {
-// if (titleView.getText().equals(title)) {
-// ImageView thumbnailView = (ImageView) child.findViewById(R.id.thumbnail);
-// if (thumbnailView != null) {
-// Bitmap thumbnail = ((BitmapDrawable) thumbnailView.getDrawable()).getBitmap();
-// return thumbnail.getPixel(0, 0);
-// } else {
-// mAsserter.dumpLog("getTopSiteThumbnailColor: unable to find mThumbnailId: "+R.id.thumbnail);
-// }
-// }
-// } else {
-// mAsserter.dumpLog("getTopSiteThumbnailColor: unable to find R.id.title: "+R.id.title);
-// }
-// } else {
-// mAsserter.dumpLog("getTopSiteThumbnailColor: skipped null child at index "+i);
-// }
-// }
-// } else {
-// mAsserter.dumpLog("getTopSiteThumbnailColor: unable to find mTopSitesId: " + mTopSitesId);
-// }
-// return -1;
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testTrackingProtection.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testTrackingProtection.java
deleted file mode 100644
index c27ff0094..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testTrackingProtection.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail;
-
-import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.GeckoApp;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.util.GeckoEventListener;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-public class testTrackingProtection extends JavascriptTest implements GeckoEventListener {
- private String mLastTracking;
-
- public testTrackingProtection() {
- super("testTrackingProtection.js");
- }
-
- @Override
- public void handleMessage(String event, final JSONObject message) {
- if (event.equals("Content:SecurityChange")) {
- try {
- JSONObject identity = message.getJSONObject("identity");
- JSONObject mode = identity.getJSONObject("mode");
- mLastTracking = mode.getString("tracking");
- mAsserter.dumpLog("Security change (tracking): " + mLastTracking);
- } catch (Exception e) {
- fFail("Can't extract tracking state from JSON");
- }
- }
-
- if (event.equals("Test:Expected")) {
- try {
- String expected = message.getString("expected");
- mAsserter.is(mLastTracking, expected, "Tracking matched expectation");
- mAsserter.dumpLog("Testing (tracking): " + mLastTracking + " = " + expected);
- } catch (Exception e) {
- fFail("Can't extract expected state from JSON");
- }
- }
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- EventDispatcher.getInstance().registerGeckoThreadListener(this,
- "Content:SecurityChange",
- "Test:Expected");
- }
-
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
-
- EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
- "Content:SecurityChange",
- "Test:Expected");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testUITelemetry.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testUITelemetry.java
deleted file mode 100644
index 30d7c169c..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testUITelemetry.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.PrefsHelper;
-import org.mozilla.gecko.Telemetry;
-import org.mozilla.gecko.TelemetryContract.Event;
-import org.mozilla.gecko.TelemetryContract.Method;
-import org.mozilla.gecko.TelemetryContract.Reason;
-import org.mozilla.gecko.TelemetryContract.Session;
-
-import android.util.Log;
-
-public class testUITelemetry extends JavascriptTest {
- public testUITelemetry() {
- super("testUITelemetry.js");
- }
-
- @Override
- public void testJavascript() throws Exception {
- blockForGeckoReady();
-
- // We can't run these tests unless telemetry is turned on --
- // the events will be dropped on the floor.
- Log.i("GeckoTest", "Enabling telemetry.");
- PrefsHelper.setPref(AppConstants.TELEMETRY_PREF_NAME, true);
-
- Log.i("GeckoTest", "Adding telemetry events.");
- try {
- Telemetry.sendUIEvent(Event._TEST1, Method._TEST1);
- Telemetry.startUISession(Session._TEST_STARTED_TWICE);
- Telemetry.sendUIEvent(Event._TEST2, Method._TEST1);
-
- // We can only start one session per name, so this call should be ignored.
- Telemetry.startUISession(Session._TEST_STARTED_TWICE);
-
- Telemetry.sendUIEvent(Event._TEST2, Method._TEST2);
- Telemetry.startUISession(Session._TEST_STOPPED_TWICE);
- Telemetry.sendUIEvent(Event._TEST3, Method._TEST1, "foobarextras");
- Telemetry.stopUISession(Session._TEST_STARTED_TWICE, Reason._TEST1);
- Telemetry.sendUIEvent(Event._TEST4, Method._TEST1, "barextras");
- Telemetry.stopUISession(Session._TEST_STOPPED_TWICE, Reason._TEST2);
-
- // This session is already stopped, so this call should be ignored.
- Telemetry.stopUISession(Session._TEST_STOPPED_TWICE, Reason._TEST_IGNORED);
-
- // Method defaults to Method.NONE
- Telemetry.sendUIEvent(Event._TEST1);
- } catch (Exception e) {
- Log.e("GeckoTest", "Oops.", e);
- }
-
- Log.i("GeckoTest", "Running remaining JS test code.");
- super.testJavascript();
- }
-}
-
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testUnifiedTelemetryClientId.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testUnifiedTelemetryClientId.java
deleted file mode 100644
index aaaded4c8..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testUnifiedTelemetryClientId.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tests;
-
-import static org.mozilla.gecko.tests.helpers.AssertionHelper.*;
-
-import android.util.Log;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.gecko.GeckoProfile;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.UUID;
-
-public class testUnifiedTelemetryClientId extends JavascriptBridgeTest {
- private static final String TEST_JS = "testUnifiedTelemetryClientId.js";
-
- private static final String CLIENT_ID_PATH = "datareporting/state.json";
- private static final String FHR_DIR_PATH = "healthreport/";
- private static final String FHR_CLIENT_ID_PATH = FHR_DIR_PATH + "state.json";
-
- private GeckoProfile profile;
- private File profileDir;
- private File[] filesToDeleteOnReset;
-
- public void setUp() throws Exception {
- super.setUp();
- profile = getTestProfile();
- profileDir = profile.getDir(); // Assumes getDir is tested.
- filesToDeleteOnReset = new File[] {
- getClientIdFile(),
- getFHRClientIdFile(),
- getFHRClientIdParentDir(),
- };
- }
-
- public void tearDown() throws Exception {
- // Don't clear cache because who knows what state Gecko is in.
- deleteClientIDFiles();
- super.tearDown();
- }
-
- private void deleteClientIDFiles() {
- Log.d(LOGTAG, "deleteClientIDFiles: begin");
-
- for (final File file : filesToDeleteOnReset) {
- file.delete(); // can't check return value because the file may not exist before deletion.
- fAssertFalse("Deleted file in reset does not exist", file.exists()); // sanity check.
- }
-
- Log.d(LOGTAG, "deleteClientIDFiles: end");
- }
-
- public void testUnifiedTelemetryClientId() throws Exception {
- blockForReadyAndLoadJS(TEST_JS);
- fAssertTrue("Profile directory exists", profileDir.exists());
-
- // Important note: we cannot stop Gecko from running while we run this test and
- // Gecko is capable of creating client ID files while we run this test. However,
- // ClientID.jsm will not touch modify the client ID files on disk if its client
- // ID cache is filled. As such, we prevent it from touching the disk by intentionally
- // priming the cache & deleting the files it added now, and resetting the cache at the
- // latest possible moment before we attempt to test the client ID file.
- //
- // This is fragile because it relies on the ClientID cache's implementation, however,
- // some alternatives (e.g. changing file system permissions, file locking) are worse
- // because they can fire error handling code, which is not currently under test.
- //
- // First, we delete the test files - we don't want the cache prime to fail which could happen if
- // these files are around & corrupted from a previous test/install. Then we prime the cache,
- // and delete the files the cache priming added, so the tests are ready to add their own version
- // of these files.
- deleteClientIDFiles();
- primeJsClientIdCache();
- deleteClientIDFiles();
-
- // TODO: If these tests weren't so expensive to run in automation,
- // this should be two separate tests to avoid storing state between tests.
- testJavaCreatesClientId(); // leaves cache filled.
- deleteClientIDFiles();
- testJsCreatesClientId(); // leaves cache filled.
- deleteClientIDFiles();
- testJavaMigratesFromHealthReport(); // leaves cache filled.
- deleteClientIDFiles();
- testJsMigratesFromHealthReport(); // leaves cache filled.
-
- getJS().syncCall("endTest");
- }
-
- /**
- * Scenario: Java creates client ID:
- * * Fennec starts on fresh profile
- * * Java code creates the client ID in datareporting/state.json
- * * Js accesses client ID from the same file
- * * Assert the client IDs are the same
- */
- private void testJavaCreatesClientId() throws Exception {
- Log.d(LOGTAG, "testJavaCreatesClientId: start");
-
- fAssertFalse("Client id file does not exist yet", getClientIdFile().exists());
-
- final String clientIdFromJava = getClientIdFromJava();
- resetJSCache();
- final String clientIdFromJS = getClientIdFromJS();
- // allow for the case where gecko updates the client ID after the first get
- final String clientIdFromJavaAgain = getClientIdFromJava();
- fAssertTrue("Client ID from Java equals ID from JS",
- clientIdFromJava.equals(clientIdFromJS) ||
- clientIdFromJavaAgain.equals(clientIdFromJS));
-
- final String clientIdFromJSCache = getClientIdFromJS();
- resetJSCache();
- final String clientIdFromJSFileAgain = getClientIdFromJS();
- fAssertEquals("Same client ID retrieved from JS cache", clientIdFromJavaAgain, clientIdFromJSCache);
- fAssertEquals("Same client ID retrieved from JS file", clientIdFromJavaAgain, clientIdFromJSFileAgain);
- }
-
- /**
- * Scenario: JS creates client ID
- * * Fennec starts on a fresh profile
- * * Js creates the client ID in datareporting/state.json
- * * Java access the client ID from the same file
- * * Assert the client IDs are the same
- */
- private void testJsCreatesClientId() throws Exception {
- Log.d(LOGTAG, "testJsCreatesClientId: start");
-
- fAssertFalse("Client id file does not exist yet", getClientIdFile().exists());
-
- resetJSCache();
- final String clientIdFromJS = getClientIdFromJS();
- final String clientIdFromJava = getClientIdFromJava();
- fAssertEquals("Client ID from JS equals ID from Java", clientIdFromJS, clientIdFromJava);
-
- final String clientIdFromJSCache = getClientIdFromJS();
- final String clientIdFromJavaAgain = getClientIdFromJava();
- resetJSCache();
- final String clientIdFromJSFileAgain = getClientIdFromJS();
- fAssertEquals("Same client ID retrieved from JS cache", clientIdFromJS, clientIdFromJSCache);
- fAssertEquals("Same client ID retrieved from JS file", clientIdFromJS, clientIdFromJSFileAgain);
- fAssertEquals("Same client ID retrieved from Java", clientIdFromJS, clientIdFromJavaAgain);
- }
-
- /**
- * Scenario: Java migrates client ID from FHR client ID file.
- * * FHR file already exists.
- * * Fennec starts on fresh profile
- * * Java code merges client ID to datareporting/state.json from healthreport/state.json
- * * Js accesses client ID from the same file
- * * Assert the client IDs are the same
- */
- private void testJavaMigratesFromHealthReport() throws Exception {
- Log.d(LOGTAG, "testJavaMigratesFromHealthReport: start");
-
- fAssertFalse("Client id file does not exist yet", getClientIdFile().exists());
- fAssertFalse("Health report file does not exist yet", getFHRClientIdFile().exists());
-
- final String expectedClientId = UUID.randomUUID().toString();
- createFHRClientIdFile(expectedClientId);
-
- final String clientIdFromJava = getClientIdFromJava();
- fAssertEquals("Health report client ID merged by Java", expectedClientId, clientIdFromJava);
- resetJSCache();
- final String clientIdFromJS = getClientIdFromJS();
- fAssertEquals("Merged client ID read by JS", expectedClientId, clientIdFromJS);
-
- final String clientIdFromJavaAgain = getClientIdFromJava();
- final String clientIdFromJSCache = getClientIdFromJS();
- resetJSCache();
- final String clientIdFromJSFileAgain = getClientIdFromJS();
- fAssertEquals("Same client ID retrieved from Java", expectedClientId, clientIdFromJavaAgain);
- fAssertEquals("Same client ID retrieved from JS cache", expectedClientId, clientIdFromJSCache);
- fAssertEquals("Same client ID retrieved from JS file", expectedClientId, clientIdFromJSFileAgain);
- }
-
- /**
- * Scenario: JS merges client ID from FHR client ID file.
- * * FHR file already exists.
- * * Fennec starts on a fresh profile
- * * Js merges the client ID to datareporting/state.json from healthreport/state.json
- * * Java access the client ID from the same file
- * * Assert the client IDs are the same
- */
- private void testJsMigratesFromHealthReport() throws Exception {
- Log.d(LOGTAG, "testJsMigratesFromHealthReport: start");
-
- fAssertFalse("Client id file does not exist yet", getClientIdFile().exists());
- fAssertFalse("Health report file does not exist yet", getFHRClientIdFile().exists());
-
- final String expectedClientId = UUID.randomUUID().toString();
- createFHRClientIdFile(expectedClientId);
-
- resetJSCache();
- final String clientIdFromJS = getClientIdFromJS();
- fAssertEquals("Health report client ID merged by JS", expectedClientId, clientIdFromJS);
- final String clientIdFromJava = getClientIdFromJava();
- fAssertEquals("Merged client ID read by Java", expectedClientId, clientIdFromJava);
-
- final String clientIdFromJavaAgain = getClientIdFromJava();
- final String clientIdFromJSCache = getClientIdFromJS();
- resetJSCache();
- final String clientIdFromJSFileAgain = getClientIdFromJS();
- fAssertEquals("Same client ID retrieved from Java", expectedClientId, clientIdFromJavaAgain);
- fAssertEquals("Same client ID retrieved from JS cache", expectedClientId, clientIdFromJSCache);
- fAssertEquals("Same client ID retrieved from JS file", expectedClientId, clientIdFromJSFileAgain);
- }
-
- private String getClientIdFromJava() throws IOException {
- // This assumes implementation details: it assumes the client ID
- // file is created when Java attempts to retrieve it if it does not exist.
- final String clientId = profile.getClientId();
- fAssertNotNull("Returned client ID is not null", clientId);
- fAssertTrue("Client ID file exists after getClientId call", getClientIdFile().exists());
- return clientId;
- }
-
- private String getClientIdFromJS() {
- return getBlockingFromJsString("clientId");
- }
-
- /**
- * Must be called after Gecko is loaded.
- */
- private void primeJsClientIdCache() {
- // Not the cleanest way, but it works.
- getClientIdFromJS();
- }
-
- /**
- * Resets the client ID cache in ClientID.jsm. This method *must* be called after
- * Gecko is loaded or else this method will hang.
- *
- * Note: we do this for very specific reasons - see the comment in the test method
- * ({@link #testUnifiedTelemetryClientId()}) for more.
- */
- private void resetJSCache() {
- // HACK: the backing JS method is a promise with no return value. Rather than writing a method
- // to handle this (for time reasons), I call the get String method and don't access the return value.
- getBlockingFromJsString("reset");
- }
-
- private File getClientIdFile() {
- return new File(profileDir, CLIENT_ID_PATH);
- }
-
- private File getFHRClientIdParentDir() {
- return new File(profileDir, FHR_DIR_PATH);
- }
-
- private File getFHRClientIdFile() {
- return new File(profileDir, FHR_CLIENT_ID_PATH);
- }
-
- private void createFHRClientIdFile(final String clientId) throws JSONException {
- fAssertTrue("FHR directory created", getFHRClientIdParentDir().mkdirs());
-
- final JSONObject obj = new JSONObject();
- obj.put("clientID", clientId);
- profile.writeFile(FHR_CLIENT_ID_PATH, obj.toString());
- fAssertTrue("FHR client ID file exists after writing", getFHRClientIdFile().exists());
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testVideoControls.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testVideoControls.java
deleted file mode 100644
index 5164815c4..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testVideoControls.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.mozilla.gecko.tests;
-
-
-
-public class testVideoControls extends JavascriptTest {
- public testVideoControls() {
- super("testVideoControls.js");
- }
-}
diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testVkbOverlap.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testVkbOverlap.java
deleted file mode 100644
index f5a54a0e9..000000000
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testVkbOverlap.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package org.mozilla.gecko.tests;
-
-import org.mozilla.gecko.Actions;
-import org.mozilla.gecko.PaintedSurface;
-
-import android.net.Uri;
-
-/**
- * A test to ensure that when an input field is focused, it is not obscured by the VKB.
- * - Loads a page with an input field past the bottom of the visible area.
- * - scrolls down to make the input field visible at the bottom of the screen.
- * - taps on the input field to bring up the VKB
- * - verifies that the input field is still visible.
- */
-public class testVkbOverlap extends PixelTest {
- private static final int CURSOR_BLINK_PERIOD = 500;
- private static final int LESS_THAN_CURSOR_BLINK_PERIOD = CURSOR_BLINK_PERIOD - 50;
- private static final int PAGE_SETTLE_TIME = 5000;
-
- public void testVkbOverlap() {
- blockForGeckoReady();
- testSetup("initial-scale=1.0, user-scalable=no", false);
- testSetup("initial-scale=1.0", false);
- testSetup("", "phone".equals(mDevice.type));
- }
-
- private void testSetup(String viewport, boolean shouldZoom) {
- loadAndPaint(getAbsoluteUrl("/robocop/test_viewport.sjs?metadata=" + Uri.encode(viewport)));
-
- // scroll to the bottom of the page and let it settle
- Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
- MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop());
- meh.dragSync(10, 150, 10, 50);
-
- // the input field has a green background, so let's count the number of green pixels
- int greenPixelCount = 0;
-
- PaintedSurface painted = waitForPaint(paintExpecter);
- paintExpecter.unregisterListener();
- try {
- greenPixelCount = countGreenPixels(painted);
- } finally {
- painted.close();
- }
-
- mAsserter.ok(greenPixelCount > 0, "testInputVisible", "Found " + greenPixelCount + " green pixels after scrolling");
-
- paintExpecter = mActions.expectPaint();
- // the input field should be in the bottom-left corner, so tap thereabouts
- meh.tap(5, mDriver.getGeckoHeight() - 5);
-
- // After tapping in the input field, the page needs some time to do stuff, like draw and undraw the focus highlight
- // on the input field, trigger the VKB, process any resulting events generated by the system, and scroll the page. So
- // we give it a few seconds to do all that. We are sufficiently generous with our definition of "few seconds" to
- // prevent intermittent test failures.
- try {
- Thread.sleep(PAGE_SETTLE_TIME);
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
-
- // now that the focus is in the text field we will repaint every 500ms as the cursor blinks, so we need to use a smaller
- // "no paints" threshold to consider the page painted
- paintExpecter.blockUntilClear(LESS_THAN_CURSOR_BLINK_PERIOD);
- paintExpecter.unregisterListener();
- painted = mDriver.getPaintedSurface();
- try {
- // if the vkb scrolled into view as expected, then the number of green pixels now visible should be about the
- // same as it was before, since the green pixels indicate the text input is in view. use a fudge factor of 0.9 to
- // account for borders and such of the text input which might still be out of view.
- int newCount = countGreenPixels(painted);
-
- // if zooming is allowed, the number of green pixels visible should have increased substantially
- if (shouldZoom) {
- mAsserter.ok(newCount > greenPixelCount * 1.5, "testVkbOverlap", "Found " + newCount + " green pixels after tapping; expected " + greenPixelCount);
- } else {
- mAsserter.ok((Math.abs(greenPixelCount - newCount) / greenPixelCount < 0.1), "testVkbOverlap", "Found " + newCount + " green pixels after tapping; expected " + greenPixelCount);
- }
- } finally {
- painted.close();
- }
- }
-
- private int countGreenPixels(PaintedSurface painted) {
- int count = 0;
- for (int y = painted.getHeight() - 1; y >= 0; y--) {
- for (int x = painted.getWidth() - 1; x >= 0; x--) {
- int pixel = painted.getPixelAt(x, y);
- int r = (pixel >> 16) & 0xFF;
- int g = (pixel >> 8) & 0xFF;
- int b = (pixel & 0xFF);
- if (g > (r + 0x30) && g > (b + 0x30)) {
- // there's more green in this pixel than red or blue, so count it.
- // the reason this is so hacky-looking is because even though green is supposed to
- // be (r,g,b) = (0x00, 0x80, 0x00), the GL readback ends up coming back quite
- // different.
- count++;
- }
- // uncomment for debugging:
- // if (pixel != -1) mAsserter.dumpLog("Pixel at " + x + ", " + y + ": " + Integer.toString(pixel, 16));
- }
- }
- return count;
- }
-}
diff --git a/mobile/android/tests/browser/robocop/testAccessibleCarets.html b/mobile/android/tests/browser/robocop/testAccessibleCarets.html
deleted file mode 100644
index 99ae949e4..000000000
--- a/mobile/android/tests/browser/robocop/testAccessibleCarets.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<html>
- <head>
- <title>ActionBar Handler and AccessibleCarets tests</title>
- <meta name="viewport"
- content="initial-scale=1, allowZoom=no, maximum-scale=1,
- user-scalable=no, width=device-width">
- </head>
-
- <body>
- <div id="LTRcontenteditable"
- style="direction: ltr; width: 10em; height: 2em; word-wrap: break-word;
- overflow: auto; -moz-user-select:text"
- contenteditable="true">Find my book</div>
- <div id="RTLcontenteditable"
- style="direction: rtl; width: 10em; height: 2em; word-wrap: break-word;
- overflow: auto; -moz-user-select:text"
- contenteditable="true">×יפה ×”×וטו שלי</div>
-
- <div id="LTRtextContent"
- style="direction: ltr; width: 10em; height: 2em; word-wrap: break-word;
- overflow: auto; -moz-user-select:text">Open the door</div>
- <div id="RTLtextContent"
- style="direction: rtl; width: 10em; height: 2em; word-wrap: break-word;
- overflow: auto; -moz-user-select:text">תן לי מי×</div>
-
- <input id="LTRinput" style="direction: ltr;" value="Type something">
- <input id="RTLinput" style="direction: rtl;" value="לרוץ במעלה הגבעה">
- <br><br><br>
-
- <textarea id="LTRtextarea" style="direction: ltr;"
- rows="3" cols="8">Words in a box</textarea>
- <textarea id="RTLtextarea" style="direction: rtl;"
- rows="3" cols="8">הספר ×”×•× ×˜×•×‘</textarea>
-
- <br>
- <input id="LTRphone" style="direction: ltr;" size="40"
- value="09876543210 .-.)(wp#*1034103410341034X">
- <br>
- <input id="RTLphone" style="direction: rtl;" size="40"
- value="התקשר +972 3 7347514 במשך זמן טוב">
- <br><br><br>
- <div><input value="DDs12">3 45<em id="bug1265750"> 678</em> 90</div>
-
- </body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/testAccessibleCarets.js b/mobile/android/tests/browser/robocop/testAccessibleCarets.js
deleted file mode 100644
index a71ed22ee..000000000
--- a/mobile/android/tests/browser/robocop/testAccessibleCarets.js
+++ /dev/null
@@ -1,323 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Messaging.jsm");
-Cu.import('resource://gre/modules/Geometry.jsm');
-
-const ACCESSIBLECARET_PREF = "layout.accessiblecaret.enabled";
-const BASE_TEST_URL = "http://mochi.test:8888/tests/robocop/testAccessibleCarets.html";
-const DESIGNMODE_TEST_URL = "http://mochi.test:8888/tests/robocop/testAccessibleCarets2.html";
-
-// Ensures Tabs are completely loaded, viewport and zoom constraints updated, etc.
-const TAB_CHANGE_EVENT = "testAccessibleCarets:TabChange";
-const TAB_STOP_EVENT = "STOP";
-
-const gChromeWin = Services.wm.getMostRecentWindow("navigator:browser");
-
-/**
- * Wait for and return, when an expected tab change event occurs.
- *
- * @param tabId, The id of the target tab we're observing.
- * @param eventType, The event type we expect.
- * @return {Promise}
- * @resolves The tab change object, including the matched tab id and event.
- */
-function do_promiseTabChangeEvent(tabId, eventType) {
- return new Promise(resolve => {
- let observer = (subject, topic, data) => {
- let message = JSON.parse(data);
-
- if (message.event === eventType && message.tabId === tabId) {
- Services.obs.removeObserver(observer, TAB_CHANGE_EVENT);
- resolve(data);
- }
- }
-
- Services.obs.addObserver(observer, TAB_CHANGE_EVENT, false);
- });
-}
-
-/**
- * Selection methods vary if we have an input / textarea element,
- * or if we have basic content.
- */
-function isInputOrTextarea(element) {
- return ((element instanceof Ci.nsIDOMHTMLInputElement) ||
- (element instanceof Ci.nsIDOMHTMLTextAreaElement));
-}
-
-/**
- * Return the selection controller based on element.
- */
-function elementSelection(element) {
- return (isInputOrTextarea(element)) ?
- element.editor.selection :
- element.ownerDocument.defaultView.getSelection();
-}
-
-/**
- * Select the requested character of a target element, w/o affecting focus.
- */
-function selectElementChar(doc, element, char) {
- if (isInputOrTextarea(element)) {
- element.setSelectionRange(char, char + 1);
- return;
- }
-
- // Simple test cases designed firstChild == #text node.
- let range = doc.createRange();
- range.setStart(element.firstChild, char);
- range.setEnd(element.firstChild, char + 1);
-
- let selection = elementSelection(element);
- selection.removeAllRanges();
- selection.addRange(range);
-}
-
-/**
- * Get longpress point. Determine the midpoint in the requested character of
- * the content in the element. X will be midpoint from left to right.
- * Y will be 1/3 of the height up from the bottom to account for both
- * LTR and smaller RTL characters. ie: |X| vs. |×|
- */
-function getCharPressPoint(doc, element, char, expected) {
- // Select the first char in the element.
- selectElementChar(doc, element, char);
-
- // Reality check selected char to expected.
- let selection = elementSelection(element);
- is(selection.toString(), expected, "Selected char should match expected char.");
-
- // Return a point where long press should select entire word.
- let rect = selection.getRangeAt(0).getBoundingClientRect();
- let r = new Point(rect.left + (rect.width / 2), rect.bottom - (rect.height / 3));
-
- return r;
-}
-
-/**
- * Long press an element (RTL/LTR) at its calculated first character
- * position, and return the result.
- *
- * @param midPoint, The screen coord for the longpress.
- * @return Selection state helper-result object.
- */
-function getLongPressResult(browser, midPoint) {
- let domWinUtils = browser.contentWindow.
- QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-
- // AccessibleCarets expect longtap between touchstart/end.
- domWinUtils.sendTouchEventToWindow("touchstart", [0], [midPoint.x], [midPoint.y],
- [1], [1], [0], [1], 1, 0);
- domWinUtils.sendMouseEventToWindow("mouselongtap", midPoint.x, midPoint.y,
- 0, 1, 0);
- domWinUtils.sendTouchEventToWindow("touchend", [0], [midPoint.x], [midPoint.y],
- [1], [1], [0], [1], 1, 0);
-
- let ActionBarHandler = gChromeWin.ActionBarHandler;
- return { focusedElement: ActionBarHandler._targetElement,
- text: ActionBarHandler._getSelectedText(),
- selectionID: ActionBarHandler._selectionID,
- };
-}
-
-/**
- * Checks the Selection UI (ActionBar or FloatingToolbar)
- * for the availability of an expected action.
- *
- * @param expectedActionID, The Selection UI action we expect to be available.
- * @return Result boolean.
- */
-function UIhasActionByID(expectedActionID) {
- let actions = gChromeWin.ActionBarHandler._actionBarActions;
- return actions.some(action => {
- return action.id === expectedActionID;
- });
-}
-
-/**
- * Messages the ActionBarHandler to close the Selection UI.
- */
-function closeSelectionUI() {
- Services.obs.notifyObservers(null, "TextSelection:End",
- JSON.stringify({selectionID: gChromeWin.ActionBarHandler._selectionID}));
-}
-
-/**
- * Main test method.
- */
-add_task(function* testAccessibleCarets() {
- // Wait to start loading our test page until after the initial browser tab is
- // completely loaded. This allows each tab to complete its layer initialization,
- // importantly, its viewport and zoomContraints info.
- let BrowserApp = gChromeWin.BrowserApp;
- yield do_promiseTabChangeEvent(BrowserApp.selectedTab.id, TAB_STOP_EVENT);
-
- // Ensure Gecko Selection and Touch carets are enabled.
- Services.prefs.setBoolPref(ACCESSIBLECARET_PREF, true);
-
- // Load test page, wait for load completion, register cleanup.
- let browser = BrowserApp.addTab(BASE_TEST_URL).browser;
- let tab = BrowserApp.getTabForBrowser(browser);
- yield do_promiseTabChangeEvent(tab.id, TAB_STOP_EVENT);
-
- do_register_cleanup(function cleanup() {
- BrowserApp.closeTab(tab);
- Services.prefs.clearUserPref(ACCESSIBLECARET_PREF);
- });
-
- // References to test document elements.
- let doc = browser.contentDocument;
- let ce_LTR_elem = doc.getElementById("LTRcontenteditable");
- let tc_LTR_elem = doc.getElementById("LTRtextContent");
- let i_LTR_elem = doc.getElementById("LTRinput");
- let ta_LTR_elem = doc.getElementById("LTRtextarea");
-
- let ce_RTL_elem = doc.getElementById("RTLcontenteditable");
- let tc_RTL_elem = doc.getElementById("RTLtextContent");
- let i_RTL_elem = doc.getElementById("RTLinput");
- let ta_RTL_elem = doc.getElementById("RTLtextarea");
-
- let ip_LTR_elem = doc.getElementById("LTRphone");
- let ip_RTL_elem = doc.getElementById("RTLphone");
- let bug1265750_elem = doc.getElementById("bug1265750");
-
- // Locate longpress midpoints for test elements, ensure expactations.
- let ce_LTR_midPoint = getCharPressPoint(doc, ce_LTR_elem, 0, "F");
- let tc_LTR_midPoint = getCharPressPoint(doc, tc_LTR_elem, 0, "O");
- let i_LTR_midPoint = getCharPressPoint(doc, i_LTR_elem, 0, "T");
- let ta_LTR_midPoint = getCharPressPoint(doc, ta_LTR_elem, 0, "W");
-
- let ce_RTL_midPoint = getCharPressPoint(doc, ce_RTL_elem, 0, "×");
- let tc_RTL_midPoint = getCharPressPoint(doc, tc_RTL_elem, 0, "ת");
- let i_RTL_midPoint = getCharPressPoint(doc, i_RTL_elem, 0, "ל");
- let ta_RTL_midPoint = getCharPressPoint(doc, ta_RTL_elem, 0, "×”");
-
- let ip_LTR_midPoint = getCharPressPoint(doc, ip_LTR_elem, 8, "2");
- let ip_RTL_midPoint = getCharPressPoint(doc, ip_RTL_elem, 9, "2");
- let bug1265750_midPoint = getCharPressPoint(doc, bug1265750_elem, 2, "7");
-
- // Longpress various LTR content elements. Test focused element against
- // expected, and selected text against expected.
- let result = getLongPressResult(browser, ce_LTR_midPoint);
- is(result.focusedElement, ce_LTR_elem, "Focused element should match expected.");
- is(result.text, "Find", "Selected text should match expected text.");
-
- result = getLongPressResult(browser, tc_LTR_midPoint);
- is(result.focusedElement, null, "No focused element is expected.");
- is(result.text, "Open", "Selected text should match expected text.");
-
- result = getLongPressResult(browser, i_LTR_midPoint);
- is(result.focusedElement, i_LTR_elem, "Focused element should match expected.");
- is(result.text, "Type", "Selected text should match expected text.");
-
- result = getLongPressResult(browser, ta_LTR_midPoint);
- is(result.focusedElement, ta_LTR_elem, "Focused element should match expected.");
- is(result.text, "Words", "Selected text should match expected text.");
-
- result = getLongPressResult(browser, ip_LTR_midPoint);
- is(result.focusedElement, ip_LTR_elem, "Focused element should match expected.");
- is(result.text, "09876543210 .-.)(wp#*103410341",
- "Selected phone number should match expected text.");
- is(result.text.length, 30,
- "Selected phone number length should match expected maximum.");
-
- result = getLongPressResult(browser, bug1265750_midPoint);
- is(result.focusedElement, null, "Focused element should match expected.");
- is(result.text, "3 45 678 90",
- "Selected phone number should match expected text.");
-
- // Longpress various RTL content elements. Test focused element against
- // expected, and selected text against expected.
- result = getLongPressResult(browser, ce_RTL_midPoint);
- is(result.focusedElement, ce_RTL_elem, "Focused element should match expected.");
- is(result.text, "×יפה", "Selected text should match expected text.");
-
- result = getLongPressResult(browser, tc_RTL_midPoint);
- is(result.focusedElement, null, "No focused element is expected.");
- is(result.text, "תן", "Selected text should match expected text.");
-
- result = getLongPressResult(browser, i_RTL_midPoint);
- is(result.focusedElement, i_RTL_elem, "Focused element should match expected.");
- is(result.text, "לרוץ", "Selected text should match expected text.");
-
- result = getLongPressResult(browser, ta_RTL_midPoint);
- is(result.focusedElement, ta_RTL_elem, "Focused element should match expected.");
- is(result.text, "הספר", "Selected text should match expected text.");
-
- result = getLongPressResult(browser, ip_RTL_midPoint);
- is(result.focusedElement, ip_RTL_elem, "Focused element should match expected.");
- is(result.text, "+972 3 7347514 ",
- "Selected phone number should match expected text.");
-
- // Close Selection UI (ActionBar or FloatingToolbar) and complete test.
- closeSelectionUI();
- ok(true, "Finished testAccessibleCarets tests.");
-});
-
-/**
- * DesignMode test method.
- */
-add_task(function* testAccessibleCarets_designMode() {
- let BrowserApp = gChromeWin.BrowserApp;
-
- // Pre-populate the clipboard to ensure PASTE action available.
- Cc["@mozilla.org/widget/clipboardhelper;1"].
- getService(Ci.nsIClipboardHelper).copyString("somethingMagical");
-
- // Load test page, wait for load completion.
- let browser = BrowserApp.addTab(DESIGNMODE_TEST_URL).browser;
- let tab = BrowserApp.getTabForBrowser(browser, { selected: true });
- yield do_promiseTabChangeEvent(tab.id, TAB_STOP_EVENT);
-
- // References to test document elements, ActionBarHandler.
- let doc = browser.contentDocument;
- let tc_LTR_elem = doc.getElementById("LTRtextContent");
- let tc_RTL_elem = doc.getElementById("RTLtextContent");
-
- // Locate longpress midpoints for test elements, ensure expactations.
- let tc_LTR_midPoint = getCharPressPoint(doc, tc_LTR_elem, 5, "x");
- let tc_RTL_midPoint = getCharPressPoint(doc, tc_RTL_elem, 9, "ת");
-
- let flavors = ["text/unicode"];
- let clipboardHasText = Services.clipboard.hasDataMatchingFlavors(
- flavors, flavors.length, Ci.nsIClipboard.kGlobalClipboard);
- is(clipboardHasText, true, "There should now be paste-able text in the clipboard.");
-
- // Toggle designMode on/off/on, check UI expectations.
- ["on", "off"].forEach(designMode => {
- doc.designMode = designMode;
-
- // Text content in a document, whether in designMode or not, never receives focus.
- // Available ActionBar/FloatingToolbar UI actions should vary depending on mode.
-
- let result = getLongPressResult(browser, tc_LTR_midPoint);
- is(result.focusedElement, null, "No focused element is expected.");
- is(result.text, "existence", "Selected text should match expected text.");
- is(UIhasActionByID("cut_action"), (designMode === "on"),
- "CUT action UI Visibility should match designMode state.");
- is(UIhasActionByID("paste_action"), (designMode === "on"),
- "PASTE action UI Visibility should match designMode state.");
-
- result = getLongPressResult(browser, tc_RTL_midPoint);
- is(result.focusedElement, null, "No focused element is expected.");
- is(result.text, "×ותו", "Selected text should match expected text.");
- is(UIhasActionByID("cut_action"), (designMode === "on"),
- "CUT action UI Visibility should match designMode state.");
- is(UIhasActionByID("paste_action"), (designMode === "on"),
- "PASTE action UI Visibility should match designMode state.");
- });
-
- // Close Selection UI (ActionBar or FloatingToolbar) and complete test.
- closeSelectionUI();
- ok(true, "Finished testAccessibleCarets_designMode tests.");
-});
-
-
-// Start all the test tasks.
-run_next_test();
diff --git a/mobile/android/tests/browser/robocop/testAccessibleCarets2.html b/mobile/android/tests/browser/robocop/testAccessibleCarets2.html
deleted file mode 100644
index fc1268462..000000000
--- a/mobile/android/tests/browser/robocop/testAccessibleCarets2.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<html>
- <head>
- <title>ActionBar Handler and AccessibleCarets tests for DesignMode</title>
- <meta name="viewport"
- content="initial-scale=1, allowZoom=no, maximum-scale=1,
- user-scalable=no, width=device-width">
- </head>
-
- <body>
- <div id="LTRtextContent" style="direction: ltr;">The existence of right-handed
- neutrinos is theoretically well-motivated, as all other known fermions have
- been observed with left and right chirality, and they can explain the
- observed active neutrino masses in a natural way.
- </div>
- <br><br><br> <!-- Rule out caret overlay on next field -->
-
- <div id="RTLtextContent" style="direction: rtl;">זהו ×œ× ×ותו הטקסט כפי למבחן שמ×ל לימין,
- ×בל מה לעז×זל? הסוקר שלי ×œ×¢×•×œ× ×œ× ×œ×ª×¤×•×¡ ×ותי. ×× ×™ רק ×ª×•×¨× × ×—×•×ª מנסה להשתעשע קצת.
- </div>
- <br><br><br>
-
- </body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/testBrowserDiscovery.js b/mobile/android/tests/browser/robocop/testBrowserDiscovery.js
deleted file mode 100644
index 3b3421dc2..000000000
--- a/mobile/android/tests/browser/robocop/testBrowserDiscovery.js
+++ /dev/null
@@ -1,150 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-// We use a global variable to track the <browser> where the tests are happening
-var browser;
-
-function setHandlerFunc(handler, test) {
- browser.addEventListener("DOMLinkAdded", function linkAdded(event) {
- browser.removeEventListener("DOMLinkAdded", linkAdded, false);
- Services.tm.mainThread.dispatch(handler.bind(this, test), Ci.nsIThread.DISPATCH_NORMAL);
- }, false);
-}
-
-add_test(function setup_browser() {
- let BrowserApp = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp;
- do_register_cleanup(function cleanup() {
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
- });
-
- let url = "http://mochi.test:8888/tests/robocop/link_discovery.html";
- browser = BrowserApp.addTab(url, { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
- browser.addEventListener("load", function startTests(event) {
- browser.removeEventListener("load", startTests, true);
- Services.tm.mainThread.dispatch(run_next_test, Ci.nsIThread.DISPATCH_NORMAL);
- }, true);
-});
-
-var searchDiscoveryTests = [
- { text: "rel search discovered" },
- { rel: "SEARCH", text: "rel is case insensitive" },
- { rel: "-search-", pass: false, text: "rel -search- not discovered" },
- { rel: "foo bar baz search quux", text: "rel may contain additional rels separated by spaces" },
- { href: "https://not.mozilla.com", text: "HTTPS ok" },
- { href: "ftp://not.mozilla.com", text: "FTP ok" },
- { href: "data:text/foo,foo", pass: false, text: "data URI not permitted" },
- { href: "javascript:alert(0)", pass: false, text: "JS URI not permitted" },
- { type: "APPLICATION/OPENSEARCHDESCRIPTION+XML", text: "type is case insensitve" },
- { type: " application/opensearchdescription+xml ", text: "type may contain extra whitespace" },
- { type: "application/opensearchdescription+xml; charset=utf-8", text: "type may have optional parameters (RFC2046)" },
- { type: "aapplication/opensearchdescription+xml", pass: false, text: "type should not be loosely matched" },
- { rel: "search search search", count: 1, text: "only one engine should be added" }
-];
-
-function execute_search_test(test) {
- if (browser.engines) {
- let matchCount = (!("count" in test) || browser.engines.length === test.count);
- let matchTitle = (test.title == browser.engines[0].title);
- ok(matchCount && matchTitle, test.text);
- browser.engines = null;
- } else {
- ok(!test.pass, test.text);
- }
- run_next_test();
-}
-
-function prep_search_test(test) {
- // Syncrhonously load the search service.
- Services.search.getVisibleEngines();
-
- setHandlerFunc(execute_search_test, test);
-
- let rel = test.rel || "search";
- let href = test.href || "http://so.not.here.mozilla.com/search.xml";
- let type = test.type || "application/opensearchdescription+xml";
- let title = test.title;
- if (!("pass" in test)) {
- test.pass = true;
- }
-
- let head = browser.contentDocument.getElementById("linkparent");
- let link = browser.contentDocument.createElement("link");
- link.rel = rel;
- link.href = href;
- link.type = type;
- link.title = title;
- head.appendChild(link);
-}
-
-var feedDiscoveryTests = [
- { text: "rel feed discovered" },
- { rel: "ALTERNATE", text: "rel is case insensitive" },
- { rel: "-alternate-", pass: false, text: "rel -alternate- not discovered" },
- { rel: "foo bar baz alternate quux", text: "rel may contain additional rels separated by spaces" },
- { href: "https://not.mozilla.com", text: "HTTPS ok" },
- { href: "ftp://not.mozilla.com", text: "FTP ok" },
- { href: "data:text/foo,foo", pass: false, text: "data URI not permitted" },
- { href: "javascript:alert(0)", pass: false, text: "JS URI not permitted" },
- { type: "application/rss+xml", text: "type can be RSS" },
- { type: "aPPliCAtion/RSS+xml", text: "type is case insensitve" },
- { type: " application/atom+xml ", text: "type may contain extra whitespace" },
- { type: "application/atom+xml; charset=utf-8", text: "type may have optional parameters (RFC2046)" },
- { type: "aapplication/atom+xml", pass: false, text: "type should not be loosely matched" },
- { rel: "alternate alternate alternate", count: 1, text: "only one feed should be added" }
-];
-
-function execute_feed_test(test) {
- if (browser.feeds) {
- let matchCount = (!("count" in test) || browser.feeds.length === test.count);
- let matchTitle = (test.title == browser.feeds[0].title);
- ok(matchCount && matchTitle, test.text);
- browser.feeds = null;
- } else {
- ok(!test.pass, test.text);
- }
- run_next_test();
-}
-
-function prep_feed_test(test) {
- setHandlerFunc(execute_feed_test, test);
-
- let rel = test.rel || "alternate";
- let href = test.href || "http://so.not.here.mozilla.com/feed.xml";
- let type = test.type || "application/atom+xml";
- let title = test.title;
- if (!("pass" in test)) {
- test.pass = true;
- }
-
- let head = browser.contentDocument.getElementById("linkparent");
- let link = browser.contentDocument.createElement("link");
- link.rel = rel;
- link.href = href;
- link.type = type;
- link.title = title;
- head.appendChild(link);
-}
-
-var searchTest;
-while ((searchTest = searchDiscoveryTests.shift())) {
- let title = searchTest.title || searchDiscoveryTests.length;
- searchTest.title = title;
- add_test(prep_search_test.bind(this, searchTest));
-}
-
-var feedTest;
-while ((feedTest = feedDiscoveryTests.shift())) {
- let title = feedTest.title || feedDiscoveryTests.length;
- feedTest.title = title;
- add_test(prep_feed_test.bind(this, feedTest));
-}
-
-run_next_test();
diff --git a/mobile/android/tests/browser/robocop/testEventDispatcher.js b/mobile/android/tests/browser/robocop/testEventDispatcher.js
deleted file mode 100644
index f70d2fdae..000000000
--- a/mobile/android/tests/browser/robocop/testEventDispatcher.js
+++ /dev/null
@@ -1,44 +0,0 @@
-Components.utils.import("resource://gre/modules/Messaging.jsm");
-
-var java = new JavaBridge(this);
-
-do_register_cleanup(() => {
- java.disconnect();
-});
-do_test_pending();
-
-function send_test_message(type) {
- let innerObject = {
- boolean: true,
- booleanArray: [false, true],
- int: 1,
- intArray: [2, 3],
- double: 0.5,
- doubleArray: [1.5, 2.5],
- null: null,
- emptyString: "",
- string: "foo",
- stringArray: ["bar", "baz"],
- }
-
- // Make a copy
- let outerObject = JSON.parse(JSON.stringify(innerObject));
-
- outerObject.type = type;
- outerObject.object = innerObject;
- outerObject.objectArray = [null, innerObject];
-
- Messaging.sendRequest(outerObject);
-}
-
-function send_message_for_response(type, response) {
- Messaging.sendRequestForResult({
- type: type,
- response: response,
- }).then(result => do_check_eq(result, response),
- error => do_check_eq(error, response));
-}
-
-function finish_test() {
- do_test_finished();
-}
diff --git a/mobile/android/tests/browser/robocop/testFilePicker.js b/mobile/android/tests/browser/robocop/testFilePicker.js
deleted file mode 100644
index 69be415a5..000000000
--- a/mobile/android/tests/browser/robocop/testFilePicker.js
+++ /dev/null
@@ -1,73 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-add_test(function filepicker_open() {
- let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
-
- do_test_pending();
-
- let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
- fp.appendFilter("Martian files", "*.martian");
- fp.appendFilters(Ci.nsIFilePicker.filterAll);
- fp.filterIndex = 0;
-
- let fpCallback = function(result) {
- if (result == Ci.nsIFilePicker.returnOK || result == Ci.nsIFilePicker.returnReplace) {
- do_print("File: " + fp.file.path);
- is(fp.file.path, "/mnt/sdcard/my-favorite-martian.png", "Retrieve the right martian file!");
-
- let files = fp.files;
- while (files.hasMoreElements()) {
- let file = files.getNext().QueryInterface(Ci.nsIFile);
- do_print("File: " + file.path);
- is(file.path, "/mnt/sdcard/my-favorite-martian.png", "Retrieve the right martian file from array!");
- }
-
- let file = fp.domFileOrDirectory;
- do_print("DOMFile: " + file.mozFullPath);
- is(file.mozFullPath, "/mnt/sdcard/my-favorite-martian.png", "Retrieve the right martian DOM File!");
-
- let e = fp.domFileOrDirectoryEnumerator;
- while (e.hasMoreElements()) {
- let file = e.getNext();
- do_print("DOMFile: " + file.mozFullPath);
- is(file.mozFullPath, "/mnt/sdcard/my-favorite-martian.png", "Retrieve the right martian file from domFileOrDirectoryEnumerator array!");
- }
-
- do_test_finished();
-
- run_next_test();
- }
- };
-
- try {
- fp.init(chromeWin, "Open", Ci.nsIFilePicker.modeOpen);
- } catch(ex) {
- ok(false, "Android should support FilePicker.modeOpen: " + ex);
- }
- fp.open(fpCallback);
-});
-
-add_test(function filepicker_save() {
- let failed = false;
- let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
- try {
- fp.init(null, "Save", Ci.nsIFilePicker.modeSave);
- } catch(ex) {
- failed = true;
- }
- ok(failed, "Android does not support FilePicker.modeSave");
-
- run_next_test();
-});
-
-run_next_test();
-
diff --git a/mobile/android/tests/browser/robocop/testFindInPage.js b/mobile/android/tests/browser/robocop/testFindInPage.js
deleted file mode 100644
index 485ae5e4e..000000000
--- a/mobile/android/tests/browser/robocop/testFindInPage.js
+++ /dev/null
@@ -1,89 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-var Cu = Components.utils;
-
-Cu.import("resource://gre/modules/Messaging.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-const TEST_URL = "http://mochi.test:8888/tests/robocop/robocop_text_page.html";
-
-function promiseBrowserEvent(browser, eventType) {
- return new Promise((resolve) => {
- function handle(event) {
- do_print("Received event " + eventType + " from browser");
- browser.removeEventListener(eventType, handle, true);
- resolve(event);
- }
-
- browser.addEventListener(eventType, handle, true);
- do_print("Now waiting for " + eventType + " event from browser");
- });
-}
-
-function openTabWithUrl(url) {
- do_print("Going to open " + url);
- let browserApp = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp;
- let browser = browserApp.addTab(url, { selected: true, parentId: browserApp.selectedTab.id }).browser;
-
- return promiseBrowserEvent(browser, "load")
- .then(() => { return browser; });
-}
-
-function findInPage(browser, text, nrOfMatches) {
- let repaintPromise = promiseBrowserEvent(browser, "MozAfterPaint");
- do_print("Send findInPageMessage: " + text + " nth: " + nrOfMatches);
- Messaging.sendRequest({ type: "Test:FindInPage", text: text, nrOfMatches: nrOfMatches });
- return repaintPromise;
-}
-
-function closeFindInPage(browser) {
- let repaintPromise = promiseBrowserEvent(browser, "MozAfterPaint");
- do_print("Send closeFindInPageMessage");
- Messaging.sendRequest({ type: "Test:CloseFindInPage" });
- return repaintPromise;
-}
-
-function assertSelection(document, expectedSelection = false, expectedAnchorText = false) {
- let sel = document.getSelection();
- if (!expectedSelection) {
- do_print("Assert empty selection");
- do_check_eq(sel.toString(), "");
- } else {
- do_print("Assert selection to be " + expectedSelection);
- do_check_eq(sel.toString(), expectedSelection);
- }
- if (expectedAnchorText) {
- do_print("Assert anchor text to be " + expectedAnchorText);
- do_check_eq(sel.anchorNode.textContent, expectedAnchorText);
- }
-}
-
-add_task(function* testFindInPage() {
- let browser = yield openTabWithUrl(TEST_URL);
- let document = browser.contentDocument;
-
- yield findInPage(browser, "Robocoop", 1);
- assertSelection(document);
-
- yield closeFindInPage(browser);
- assertSelection(document);
-
- yield findInPage(browser, "Robocop", 1);
- assertSelection(document, "Robocop", " Robocop 1 ");
-
- yield closeFindInPage(browser);
- assertSelection(document);
-
- yield findInPage(browser, "Robocop", 3);
- assertSelection(document, "Robocop", " Robocop 3 ");
-
- yield closeFindInPage(browser);
- assertSelection(document);
-});
-
-run_next_test();
diff --git a/mobile/android/tests/browser/robocop/testGeckoRequest.js b/mobile/android/tests/browser/robocop/testGeckoRequest.js
deleted file mode 100644
index cedaf825c..000000000
--- a/mobile/android/tests/browser/robocop/testGeckoRequest.js
+++ /dev/null
@@ -1,40 +0,0 @@
-Components.utils.import("resource://gre/modules/Messaging.jsm");
-
-var java = new JavaBridge(this);
-
-do_register_cleanup(() => {
- java.disconnect();
-});
-do_test_pending();
-
-function add_request_listener(message) {
- Messaging.addListener(function (data) {
- return { result: data + "bar" };
- }, message);
-}
-
-function add_exception_listener(message) {
- Messaging.addListener(function (data) {
- throw "error!";
- }, message);
-}
-
-function add_second_request_listener(message) {
- let exceptionCaught = false;
-
- try {
- Messaging.addListener(() => {}, message);
- } catch (e) {
- exceptionCaught = true;
- }
-
- do_check_true(exceptionCaught);
-}
-
-function remove_request_listener(message) {
- Messaging.removeListener(message);
-}
-
-function finish_test() {
- do_test_finished();
-}
diff --git a/mobile/android/tests/browser/robocop/testHistoryService.js b/mobile/android/tests/browser/robocop/testHistoryService.js
deleted file mode 100644
index 612928c4c..000000000
--- a/mobile/android/tests/browser/robocop/testHistoryService.js
+++ /dev/null
@@ -1,128 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-// Make the timer global so it doesn't get GC'd
-var gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-
-function sleep(wait) {
- return new Promise((resolve, reject) => {
- do_print("sleep start");
- gTimer.initWithCallback({
- notify: function () {
- do_print("sleep end");
- resolve();
- },
- }, wait, gTimer.TYPE_ONE_SHOT);
- });
-}
-
-function promiseLoadEvent(browser, url, eventType="load") {
- return new Promise((resolve, reject) => {
- do_print("Wait browser event: " + eventType);
-
- function handle(event) {
- // Since we'll be redirecting, don't make assumptions about the given URL and the loaded URL
- if (event.target != browser.contentDocument || event.target.location.href == "about:blank") {
- do_print("Skipping spurious '" + eventType + "' event" + " for " + event.target.location.href);
- return;
- }
-
- browser.removeEventListener(eventType, handle, true);
- do_print("Browser event received: " + eventType);
- resolve(event);
- }
-
- browser.addEventListener(eventType, handle, true);
- if (url) {
- browser.loadURI(url);
- }
- });
-}
-
-// Wait 6 seconds for the pending visits to flush (which should happen in 3 seconds)
-const PENDING_VISIT_WAIT = 6000;
-// Longer wait required after first load
-const PENDING_VISIT_WAIT_LONG = 20000;
-
-// Manage the saved history visits so we can compare in the tests
-var gVisitURLs = [];
-function visitObserver(subject, topic, data) {
- let uri = subject.QueryInterface(Ci.nsIURI);
- do_print("Observer: " + uri.spec);
- gVisitURLs.push(uri.spec);
-};
-
-// Track the <browser> where the tests are happening
-var gBrowser;
-
-add_test(function setup_browser() {
- let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- do_register_cleanup(function cleanup() {
- Services.obs.removeObserver(visitObserver, "link-visited");
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(gBrowser));
- });
-
- Services.obs.addObserver(visitObserver, "link-visited", false);
-
- // Load a blank page
- let url = "about:blank";
- gBrowser = BrowserApp.addTab(url, { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
- gBrowser.addEventListener("load", function startTests(event) {
- gBrowser.removeEventListener("load", startTests, true);
- Services.tm.mainThread.dispatch(run_next_test, Ci.nsIThread.DISPATCH_NORMAL);
- }, true);
-});
-
-add_task(function* () {
- // Wait for any initial page loads to be saved to history
- yield sleep(PENDING_VISIT_WAIT);
-
- // Load a simple HTML page with no redirects
- gVisitURLs = [];
- yield promiseLoadEvent(gBrowser, "http://example.org/tests/robocop/robocop_blank_01.html");
- yield sleep(PENDING_VISIT_WAIT_LONG);
-
- do_print("visit counts: " + gVisitURLs.length);
- ok(gVisitURLs.length == 1, "Simple visit makes 1 history item");
-
- do_print("visit URL: " + gVisitURLs[0]);
- ok(gVisitURLs[0] == "http://example.org/tests/robocop/robocop_blank_01.html", "Simple visit makes final history item");
-
- // Load a simple HTML page via a 301 temporary redirect
- gVisitURLs = [];
- yield promiseLoadEvent(gBrowser, "http://example.org/tests/robocop/simple_redirect.sjs?http://example.org/tests/robocop/robocop_blank_02.html");
- yield sleep(PENDING_VISIT_WAIT);
-
- do_print("visit counts: " + gVisitURLs.length);
- ok(gVisitURLs.length == 1, "Simple 301 redirect makes 1 history item");
-
- do_print("visit URL: " + gVisitURLs[0]);
- ok(gVisitURLs[0] == "http://example.org/tests/robocop/robocop_blank_02.html", "Simple 301 redirect makes final history item");
-
- // Load a simple HTML page via a JavaScript redirect
- gVisitURLs = [];
- yield promiseLoadEvent(gBrowser, "http://example.org/tests/robocop/javascript_redirect.sjs?http://example.org/tests/robocop/robocop_blank_03.html");
- yield sleep(PENDING_VISIT_WAIT);
-
- do_print("visit counts: " + gVisitURLs.length);
- ok(gVisitURLs.length == 2, "JavaScript redirect makes 2 history items");
-
- do_print("visit URL 1: " + gVisitURLs[0]);
- ok(gVisitURLs[0] == "http://example.org/tests/robocop/javascript_redirect.sjs?http://example.org/tests/robocop/robocop_blank_03.html", "JavaScript redirect makes intermediate history item");
-
- do_print("visit URL 2: " + gVisitURLs[1]);
- ok(gVisitURLs[1] == "http://example.org/tests/robocop/robocop_blank_03.html", "JavaScript redirect makes final history item");
-});
-
-run_next_test();
diff --git a/mobile/android/tests/browser/robocop/testJavascriptBridge.js b/mobile/android/tests/browser/robocop/testJavascriptBridge.js
deleted file mode 100644
index 3bfd89f88..000000000
--- a/mobile/android/tests/browser/robocop/testJavascriptBridge.js
+++ /dev/null
@@ -1,52 +0,0 @@
-var java = new JavaBridge(this);
-var javaResponded = false;
-
-do_register_cleanup(() => {
- java.disconnect();
-});
-do_test_pending();
-
-function check_js_int_arg(int1) {
- // Sync call from Java
- do_check_eq(int1, 1);
- java.asyncCall("checkJavaIntArg", 2);
-}
-
-function check_js_double_arg(double3) {
- // Sync call from Java
- do_check_eq(double3, 3.0);
- java.asyncCall("checkJavaDoubleArg", 4.0);
-}
-
-function check_js_boolean_arg(boolfalse) {
- // Sync call from Java
- do_check_eq(boolfalse, false);
- java.asyncCall("checkJavaBooleanArg", true);
-}
-
-function check_js_string_arg(stringfoo) {
- do_check_eq(stringfoo, "foo");
- java.asyncCall("checkJavaStringArg", "bar");
-}
-
-function check_js_object_arg(obj) {
- // Sync call from Java
- do_check_eq(obj.caller, "java");
- java.asyncCall("checkJavaObjectArg", {caller: "js"});
-}
-
-function check_js_sync_call() {
- // Sync call from Java
- java.syncCall("doJSSyncCall");
- // respond_to_js_sync_call should have run by now because
- // do_js_sync_call calls it from Java code
- do_check_true(javaResponded);
-
- java.asyncCall("checkJSSyncCallReceived");
- // End of test
- do_test_finished();
-}
-
-function respond_to_js_sync_call() {
- javaResponded = true;
-}
diff --git a/mobile/android/tests/browser/robocop/testReaderCacheMigration.js b/mobile/android/tests/browser/robocop/testReaderCacheMigration.js
deleted file mode 100644
index dbd5ae432..000000000
--- a/mobile/android/tests/browser/robocop/testReaderCacheMigration.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-Components.utils.import("resource://gre/modules/ReaderMode.jsm");
-
-var java = new JavaBridge(this);
-
-do_register_cleanup(() => {
- java.disconnect();
-});
-do_test_pending();
-
-function check_hashed_path_matches(url, hashedPath) {
- var jsHashedPath = ReaderMode._toHashedPath(url);
- do_check_eq(hashedPath, jsHashedPath);
-}
-
-function finish_test() {
- do_test_finished();
-} \ No newline at end of file
diff --git a/mobile/android/tests/browser/robocop/testReadingListCache.js b/mobile/android/tests/browser/robocop/testReadingListCache.js
deleted file mode 100644
index d438dfb1e..000000000
--- a/mobile/android/tests/browser/robocop/testReadingListCache.js
+++ /dev/null
@@ -1,126 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*globals ReaderMode */
-
-var { utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/ReaderMode.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-
-var Reader = Services.wm.getMostRecentWindow("navigator:browser").Reader;
-
-const URL_PREFIX = "http://mochi.test:8888/tests/robocop/reader_mode_pages/";
-
-var TEST_PAGES = [
- {
- url: URL_PREFIX + "basic_article.html",
- expected: {
- title: "Article title",
- byline: "by Jane Doe",
- excerpt: "This is the article description.",
- }
- },
- {
- url: URL_PREFIX + "not_an_article.html",
- expected: null
- },
- {
- url: URL_PREFIX + "developer.mozilla.org/en/XULRunner/Build_Instructions.html",
- expected: {
- title: "Building XULRunner",
- byline: null,
- excerpt: "XULRunner is built using basically the same process as Firefox or other applications. Please read and follow the general Build Documentation for instructions on how to get sources and set up build prerequisites.",
- }
- },
-];
-
-add_task(function* test_article_not_found() {
- let article = yield ReaderMode.getArticleFromCache(TEST_PAGES[0].url);
- do_check_eq(article, null);
-});
-
-add_task(function* test_store_article() {
- // Create an article object to store in the cache.
- yield ReaderMode.storeArticleInCache({
- url: TEST_PAGES[0].url,
- content: "Lorem ipsum",
- title: TEST_PAGES[0].expected.title,
- byline: TEST_PAGES[0].expected.byline,
- excerpt: TEST_PAGES[0].expected.excerpt,
- });
-
- let article = yield ReaderMode.getArticleFromCache(TEST_PAGES[0].url);
- checkArticle(article, TEST_PAGES[0]);
-});
-
-add_task(function* test_remove_article() {
- yield ReaderMode.removeArticleFromCache(TEST_PAGES[0].url);
- let article = yield ReaderMode.getArticleFromCache(TEST_PAGES[0].url);
- do_check_eq(article, null);
-});
-
-add_task(function* test_parse_articles() {
- for (let testcase of TEST_PAGES) {
- let article = yield ReaderMode.downloadAndParseDocument(testcase.url);
- checkArticle(article, testcase);
- }
-});
-
-add_task(function* test_migrate_cache() {
- // Store an article in the old indexedDB reader mode cache.
- let cacheDB = yield new Promise((resolve, reject) => {
- let win = Services.wm.getMostRecentWindow("navigator:browser");
- let request = win.indexedDB.open("about:reader", 1);
- request.onerror = event => reject(request.error);
-
- // This will always happen because there is no pre-existing data store.
- request.onupgradeneeded = event => {
- let cacheDB = event.target.result;
- cacheDB.createObjectStore("articles", { keyPath: "url" });
- };
-
- request.onsuccess = event => resolve(event.target.result);
- });
-
- yield new Promise((resolve, reject) => {
- let transaction = cacheDB.transaction(["articles"], "readwrite");
- let store = transaction.objectStore("articles");
-
- let request = store.add({
- url: TEST_PAGES[0].url,
- content: "Lorem ipsum",
- title: TEST_PAGES[0].expected.title,
- byline: TEST_PAGES[0].expected.byline,
- excerpt: TEST_PAGES[0].expected.excerpt,
- });
- request.onerror = event => reject(request.error);
- request.onsuccess = event => resolve();
- });
-
- // Migrate the cache.
- yield Reader.migrateCache();
-
- // Check to make sure the article made it into the new cache.
- let article = yield ReaderMode.getArticleFromCache(TEST_PAGES[0].url);
- checkArticle(article, TEST_PAGES[0]);
-});
-
-function checkArticle(article, testcase) {
- if (testcase.expected == null) {
- do_check_eq(article, null);
- return;
- }
-
- do_check_neq(article, null);
- do_check_eq(!!article.content, true); // A bit of a hack to avoid spamming the test log.
- do_check_eq(article.url, testcase.url);
- do_check_eq(article.title, testcase.expected.title);
- do_check_eq(article.byline, testcase.expected.byline);
- do_check_eq(article.excerpt, testcase.expected.excerpt);
-}
-
-run_next_test();
diff --git a/mobile/android/tests/browser/robocop/testRuntimePermissionsAPI.js b/mobile/android/tests/browser/robocop/testRuntimePermissionsAPI.js
deleted file mode 100644
index d3f34b87d..000000000
--- a/mobile/android/tests/browser/robocop/testRuntimePermissionsAPI.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "RuntimePermissions", "resource://gre/modules/RuntimePermissions.jsm");
-
-add_task(function* test_snackbar_api() {
- RuntimePermissions.waitForPermissions([
- RuntimePermissions.CAMERA,
- RuntimePermissions.RECORD_AUDIO,
- RuntimePermissions.WRITE_EXTERNAL_STORAGE
- ]);
-});
-
-run_next_test();
diff --git a/mobile/android/tests/browser/robocop/testSnackbarAPI.js b/mobile/android/tests/browser/robocop/testSnackbarAPI.js
deleted file mode 100644
index 1031528df..000000000
--- a/mobile/android/tests/browser/robocop/testSnackbarAPI.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Snackbars", "resource://gre/modules/Snackbars.jsm");
-
-add_task(function* test_snackbar_api() {
- Snackbars.show("This is a Snackbar", Snackbars.LENGTH_INDEFINITE, {
- action: {
- label: "Click me",
- callback: function () {}
- }
- });
-});
-
-run_next_test();
diff --git a/mobile/android/tests/browser/robocop/testTrackingProtection.js b/mobile/android/tests/browser/robocop/testTrackingProtection.js
deleted file mode 100644
index d81efd6c6..000000000
--- a/mobile/android/tests/browser/robocop/testTrackingProtection.js
+++ /dev/null
@@ -1,166 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Messaging.jsm");
-
-function promiseLoadEvent(browser, url, eventType="load", runBeforeLoad) {
- return new Promise((resolve, reject) => {
- do_print("Wait browser event: " + eventType);
-
- function handle(event) {
- if (event.target != browser.contentDocument || event.target.location.href == "about:blank" || (url && event.target.location.href != url)) {
- do_print("Skipping spurious '" + eventType + "' event" + " for " + event.target.location.href);
- return;
- }
-
- browser.removeEventListener(eventType, handle, true);
- do_print("Browser event received: " + eventType);
- resolve(event);
- }
-
- browser.addEventListener(eventType, handle, true);
-
- if (runBeforeLoad) {
- runBeforeLoad();
- }
- if (url) {
- browser.loadURI(url);
- }
- });
-}
-
-// Test that the Tracking Protection is active and has the correct state when
-// tracking content is blocked (Bug 1063831)
-
-// Code is mostly stolen from:
-// http://dxr.mozilla.org/mozilla-central/source/browser/base/content/test/general/browser_trackingUI.js
-
-var TABLE = "urlclassifier.trackingTable";
-
-// Update tracking database
-function doUpdate() {
- // Add some URLs to the tracking database (to be blocked)
- var testData = "tracking.example.com/";
- var testUpdate =
- "n:1000\ni:test-track-simple\nad:1\n" +
- "a:524:32:" + testData.length + "\n" +
- testData;
-
- let dbService = Cc["@mozilla.org/url-classifier/dbservice;1"].getService(Ci.nsIUrlClassifierDBService);
-
- return new Promise((resolve, reject) => {
- let listener = {
- QueryInterface: function(iid) {
- if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIUrlClassifierUpdateObserver))
- return this;
-
- throw Cr.NS_ERROR_NO_INTERFACE;
- },
- updateUrlRequested: function(url) { },
- streamFinished: function(status) { },
- updateError: function(errorCode) {
- ok(false, "Couldn't update classifier.");
- resolve();
- },
- updateSuccess: function(requestedTimeout) {
- resolve();
- }
- };
-
- dbService.beginUpdate(listener, "test-track-simple", "");
- dbService.beginStream("", "");
- dbService.updateStream(testUpdate);
- dbService.finishStream();
- dbService.finishUpdate();
- });
-}
-
-var BrowserApp = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp;
-
-// Tests the tracking protection UI in private browsing. By default, tracking protection is
-// enabled in private browsing ("privacy.trackingprotection.pbmode.enabled").
-add_task(function* test_tracking_pb() {
- // Load a blank page
- let browser = BrowserApp.addTab("about:blank", { selected: true, parentId: BrowserApp.selectedTab.id, isPrivate: true }).browser;
- yield new Promise((resolve, reject) => {
- browser.addEventListener("load", function startTests(event) {
- browser.removeEventListener("load", startTests, true);
- Services.tm.mainThread.dispatch(resolve, Ci.nsIThread.DISPATCH_NORMAL);
- }, true);
- });
-
- // Populate and use 'test-track-simple' for tracking protection lookups
- Services.prefs.setCharPref(TABLE, "test-track-simple");
- yield doUpdate();
-
- // Point tab to a test page NOT containing tracking elements
- yield promiseLoadEvent(browser, "http://tracking.example.org/tests/robocop/tracking_good.html");
- Messaging.sendRequest({ type: "Test:Expected", expected: "unknown" });
-
- // Point tab to a test page containing tracking elements
- yield promiseLoadEvent(browser, "http://tracking.example.org/tests/robocop/tracking_bad.html");
- Messaging.sendRequest({ type: "Test:Expected", expected: "tracking_content_blocked" });
-
- // Simulate a click on the "Disable protection" button in the site identity popup.
- // We need to wait for a "load" event because "Session:Reload" will cause a full page reload.
- yield promiseLoadEvent(browser, undefined, undefined, () => {
- Services.obs.notifyObservers(null, "Session:Reload", "{\"allowContent\":true,\"contentType\":\"tracking\"}");
- });
- Messaging.sendRequest({ type: "Test:Expected", expected: "tracking_content_loaded" });
-
- // Simulate a click on the "Enable protection" button in the site identity popup.
- yield promiseLoadEvent(browser, undefined, undefined, () => {
- Services.obs.notifyObservers(null, "Session:Reload", "{\"allowContent\":false,\"contentType\":\"tracking\"}");
- });
- Messaging.sendRequest({ type: "Test:Expected", expected: "tracking_content_blocked" });
-
- // Disable tracking protection to make sure we don't show the UI when the pref is disabled.
- Services.prefs.setBoolPref("privacy.trackingprotection.pbmode.enabled", false);
-
- // Point tab to a test page containing tracking elements
- yield promiseLoadEvent(browser, "http://tracking.example.org/tests/robocop/tracking_bad.html");
- Messaging.sendRequest({ type: "Test:Expected", expected: "unknown" });
-
- // Point tab to a test page NOT containing tracking elements
- yield promiseLoadEvent(browser, "http://tracking.example.org/tests/robocop/tracking_good.html");
- Messaging.sendRequest({ type: "Test:Expected", expected: "unknown" });
-
- // Reset the pref before the next testcase
- Services.prefs.clearUserPref("privacy.trackingprotection.pbmode.enabled");
-});
-
-add_task(function* test_tracking_not_pb() {
- // Load a blank page
- let browser = BrowserApp.addTab("about:blank", { selected: true }).browser;
- yield new Promise((resolve, reject) => {
- browser.addEventListener("load", function startTests(event) {
- browser.removeEventListener("load", startTests, true);
- Services.tm.mainThread.dispatch(resolve, Ci.nsIThread.DISPATCH_NORMAL);
- }, true);
- });
-
- // Point tab to a test page NOT containing tracking elements
- yield promiseLoadEvent(browser, "http://tracking.example.org/tests/robocop/tracking_good.html");
- Messaging.sendRequest({ type: "Test:Expected", expected: "unknown" });
-
- // Point tab to a test page containing tracking elements (tracking protection UI *should not* be shown)
- yield promiseLoadEvent(browser, "http://tracking.example.org/tests/robocop/tracking_bad.html");
- Messaging.sendRequest({ type: "Test:Expected", expected: "unknown" });
-
- // Enable tracking protection in normal tabs
- Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
-
- // Point tab to a test page containing tracking elements (tracking protection UI *should* be shown)
- yield promiseLoadEvent(browser, "http://tracking.example.org/tests/robocop/tracking_bad.html");
- Messaging.sendRequest({ type: "Test:Expected", expected: "tracking_content_blocked" });
-});
-
-run_next_test();
diff --git a/mobile/android/tests/browser/robocop/testUITelemetry.js b/mobile/android/tests/browser/robocop/testUITelemetry.js
deleted file mode 100644
index 5edf06f19..000000000
--- a/mobile/android/tests/browser/robocop/testUITelemetry.js
+++ /dev/null
@@ -1,154 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-const EVENT_TEST1 = "_test_event_1.1";
-const EVENT_TEST2 = "_test_event_2.1";
-const EVENT_TEST3 = "_test_event_3.1";
-const EVENT_TEST4 = "_test_event_4.1";
-
-const METHOD_TEST1 = "_test_method_1";
-const METHOD_TEST2 = "_test_method_2";
-
-const METHOD_NONE = null;
-
-const REASON_TEST1 = "_test_reason_1";
-const REASON_TEST2 = "_test_reason_2";
-
-const SESSION_STARTED_TWICE = "_test_session_started_twice.1";
-const SESSION_STOPPED_TWICE = "_test_session_stopped_twice.1";
-
-function do_check_array_eq(a1, a2) {
- do_check_eq(a1.length, a2.length);
- for (let i = 0; i < a1.length; ++i) {
- do_check_eq(a1[i], a2[i]);
- }
-}
-
-/**
- * Asserts that the given measurements are equal. Assumes that measurements
- * of type "event" have their sessions arrays sorted.
- */
-function do_check_measurement_eq(m1, m2) {
- do_check_eq(m1.type, m2.type);
-
- switch (m1.type) {
- case "event":
- do_check_eq(m1.action, m2.action);
- do_check_eq(m1.method, m2.method);
- do_check_array_eq(m1.sessions, m2.sessions);
- do_check_eq(m1.extras, m2.extras);
- break;
-
- case "session":
- do_check_eq(m1.name, m2.name);
- do_check_eq(m1.reason, m2.reason);
- break;
-
- default:
- do_throw("Unknown event type: " + m1.type);
- }
-}
-
-function getObserver() {
- let bridge = Cc["@mozilla.org/android/bridge;1"]
- .getService(Ci.nsIAndroidBridge);
- let obsXPCOM = bridge.browserApp.getUITelemetryObserver();
- do_check_true(!!obsXPCOM);
- return obsXPCOM.wrappedJSObject;
-}
-
-/**
- * The following event test will fail if telemetry isn't enabled. The Java-side
- * part of this test should have turned it on; fail if it didn't work.
- */
-add_test(function test_enabled() {
- let obs = getObserver();
- do_check_true(!!obs);
- do_check_true(obs.enabled);
- run_next_test();
-});
-
-add_test(function test_telemetry_events() {
- let expected = expectedArraysToObjs([
- ["event", EVENT_TEST1, METHOD_TEST1, [], undefined],
- ["event", EVENT_TEST2, METHOD_TEST1, [SESSION_STARTED_TWICE], undefined],
- ["event", EVENT_TEST2, METHOD_TEST2, [SESSION_STARTED_TWICE], undefined],
- ["event", EVENT_TEST3, METHOD_TEST1, [SESSION_STARTED_TWICE, SESSION_STOPPED_TWICE], "foobarextras"],
- ["session", SESSION_STARTED_TWICE, REASON_TEST1],
- ["event", EVENT_TEST4, METHOD_TEST1, [SESSION_STOPPED_TWICE], "barextras"],
- ["session", SESSION_STOPPED_TWICE, REASON_TEST2],
- ["event", EVENT_TEST1, METHOD_NONE, [], undefined],
- ]);
-
- let clearMeasurements = false;
- let obs = getObserver();
- let measurements = removeNonTestMeasurements(obs.getUIMeasurements(clearMeasurements));
-
- measurements.forEach(function (m, i) {
- if (m.type === "event") {
- m.sessions = removeNonTestSessions(m.sessions);
- m.sessions.sort(); // Mutates.
- }
-
- do_check_measurement_eq(expected[i], m);
- });
-
- expected.forEach(function (m, i) {
- do_check_measurement_eq(m, measurements[i]);
- });
-
- run_next_test();
-});
-
-/**
- * Converts the expected value arrays to objects,
- * for less typing when initializing the expected arrays.
- */
-function expectedArraysToObjs(expectedArrays) {
- return expectedArrays.map(function (arr) {
- let type = arr[0];
- if (type === "event") {
- return {
- type: type,
- action: arr[1],
- method: arr[2],
- sessions: arr[3].sort(), // Sort, just in case it's not sorted by hand!
- extras: arr[4],
- };
-
- } else if (type === "session") {
- return {
- type: type,
- name: arr[1],
- reason: arr[2],
- };
- }
- });
-}
-
-function removeNonTestMeasurements(measurements) {
- return measurements.filter(function (measurement) {
- if (measurement.type === "event") {
- return measurement.action.startsWith("_test_event_");
- } else if (measurement.type === "session") {
- return measurement.name.startsWith("_test_session_");
- }
- return false;
- });
-}
-
-function removeNonTestSessions(sessions) {
- return sessions.filter(function (sessionName) {
- return sessionName.startsWith("_test_session_");
- });
-}
-
-run_next_test();
diff --git a/mobile/android/tests/browser/robocop/testUnifiedTelemetryClientId.js b/mobile/android/tests/browser/robocop/testUnifiedTelemetryClientId.js
deleted file mode 100644
index d574aaef1..000000000
--- a/mobile/android/tests/browser/robocop/testUnifiedTelemetryClientId.js
+++ /dev/null
@@ -1,50 +0,0 @@
-var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import('resource://gre/modules/ClientID.jsm');
-
-var java = new JavaBridge(this);
-do_register_cleanup(() => {
- java.disconnect();
-});
-do_test_pending();
-
-var isClientIDSet;
-var clientID;
-
-var isResetDone;
-
-function getAsyncClientId() {
- isClientIDSet = false;
- ClientID.getClientID().then(function (retClientID) {
- // Ideally, we'd directly send the client ID back to Java but Java won't listen for
- // js messages after we return from the containing function (bug 1253467).
- //
- // Note that my brief attempts to get synchronous Promise resolution (via Task.jsm)
- // working failed - I have other things to focus on.
- clientID = retClientID;
- isClientIDSet = true;
- }, function (fail) {
- // Since Java doesn't listen to our messages (bug 1253467), I don't expect
- // this throw to work correctly but we should timeout in Java.
- do_throw('Could not retrieve client ID: ' + fail);
- });
-}
-
-function pollGetAsyncClientId() {
- java.asyncCall('blockingFromJsResponseString', isClientIDSet, clientID);
-}
-
-function getAsyncReset() {
- isResetDone = false;
- ClientID._reset().then(function () {
- isResetDone = true;
- });
-}
-
-function pollGetAsyncReset() {
- java.asyncCall('blockingFromJsResponseString', isResetDone, '');
-}
-
-function endTest() {
- do_test_finished();
-}
diff --git a/mobile/android/tests/browser/robocop/testVideoControls.js b/mobile/android/tests/browser/robocop/testVideoControls.js
deleted file mode 100644
index e0a41b5b6..000000000
--- a/mobile/android/tests/browser/robocop/testVideoControls.js
+++ /dev/null
@@ -1,157 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/SimpleServiceDiscovery.jsm");
-
-// The chrome window
-var chromeWin;
-
-// Track the <browser> where the tests are happening
-var browser;
-
-// The document of the video_controls web content
-var contentDocument;
-
-// The <video> we will be testing
-var video;
-
-add_test(function setup_browser() {
- chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- do_register_cleanup(function cleanup() {
- BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
- });
-
- // Load our test web page with <video> elements
- let url = "http://mochi.test:8888/tests/robocop/video_controls.html";
- browser = BrowserApp.addTab(url, { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
- browser.addEventListener("load", function startTests(event) {
- browser.removeEventListener("load", startTests, true);
- contentDocument = browser.contentDocument;
-
- video = contentDocument.getElementById("video");
- ok(video, "Found the video element");
-
- Services.tm.mainThread.dispatch(run_next_test, Ci.nsIThread.DISPATCH_NORMAL);
- }, true);
-});
-
-add_test(function test_webm() {
- // Load the test video
- video.src = "http://mochi.test:8888/tests/robocop/video-pattern.webm";
-
- Services.tm.mainThread.dispatch(testLoad, Ci.nsIThread.DISPATCH_NORMAL);
-});
-
-add_test(function test_ogg() {
- // Load the test video
- video.src = "http://mochi.test:8888/tests/robocop/video-pattern.ogg";
-
- Services.tm.mainThread.dispatch(testLoad, Ci.nsIThread.DISPATCH_NORMAL);
-});
-
-function getButtonByAttribute(aName, aValue) {
- let domUtil = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
- let kids = domUtil.getChildrenForNode(video, true);
- let videocontrols = kids[1];
- return contentDocument.getAnonymousElementByAttribute(videocontrols, aName, aValue);
-}
-
-function getPixelColor(aCanvas, aX, aY) {
- let cx = aCanvas.getContext("2d");
- let pixel = cx.getImageData(aX, aY, 1, 1);
- return {
- r: pixel.data[0],
- g: pixel.data[1],
- b: pixel.data[2],
- a: pixel.data[3]
- };
-}
-
-function testLoad() {
- // The video is not auto-play, so it starts paused
- let playButton = getButtonByAttribute("class", "playButton");
- ok(playButton.getAttribute("paused") == "true", "Play button is paused");
-
- // Let's start playing it
- video.play();
- video.addEventListener("play", testPlay, false);
-}
-
-function testPlay(aEvent) {
- video.removeEventListener("play", testPlay, false);
- let playButton = getButtonByAttribute("class", "playButton");
- ok(playButton.hasAttribute("paused") == false, "Play button is not paused");
-
- // Let the video play for 2 seconds, then pause it
- chromeWin.setTimeout(function() {
- video.pause();
- video.addEventListener("pause", testPause, false);
- }, 2000);
-}
-
-function testPause(aEvent) {
- video.removeEventListener("pause", testPause, false);
-
- // If we got here, the play button should be paused
- let playButton = getButtonByAttribute("class", "playButton");
- ok(playButton.getAttribute("paused") == "true", "Play button is paused again");
-
- // Let's grab an image of the frame and test it
- let width = 640;
- let height = 480;
- let canvas = contentDocument.getElementById("canvas");
- canvas.width = width;
- canvas.height = height;
- canvas.getContext("2d").drawImage(video, 0, 0, width, height);
-
- // Let's grab some pixel colors to verify we actually displayed a video.
- // For some reason the canvas copy of the frame does not recreate the colors
- // exactly for some devices. To keep things passing on automation and local
- // runs, we fudge it.
-
- // The purpose of this code is not to test drawImage, but whether a video
- // frame was displayed.
- const MAX_COLOR = 235; // ideally, 255
- const MIN_COLOR = 20; // ideally, 0
-
- let bar1 = getPixelColor(canvas, 45, 10);
- do_print("Color at (45, 10): " + JSON.stringify(bar1));
- ok(bar1.r >= MAX_COLOR && bar1.g >= MAX_COLOR && bar1.b >= MAX_COLOR, "Bar 1 is white");
-
- let bar2 = getPixelColor(canvas, 135, 10);
- do_print("Color at (135, 10): " + JSON.stringify(bar2));
- ok(bar2.r >= MAX_COLOR && bar2.g >= MAX_COLOR && bar2.b <= MIN_COLOR, "Bar 2 is yellow");
-
- let bar3 = getPixelColor(canvas, 225, 10);
- do_print("Color at (225, 10): " + JSON.stringify(bar3));
- ok(bar3.r <= MIN_COLOR && bar3.g >= MAX_COLOR && bar3.b >= MAX_COLOR, "Bar 3 is Cyan");
-
- let bar4 = getPixelColor(canvas, 315, 10);
- do_print("Color at (315, 10): " + JSON.stringify(bar4));
- ok(bar4.r <= MIN_COLOR && bar4.g >= MAX_COLOR && bar4.b <= MIN_COLOR, "Bar 4 is Green");
-
- let bar5 = getPixelColor(canvas, 405, 10);
- do_print("Color at (405, 10): " + JSON.stringify(bar5));
- ok(bar5.r >= MAX_COLOR && bar5.g <= MIN_COLOR && bar5.b >= MAX_COLOR, "Bar 5 is Purple");
-
- let bar6 = getPixelColor(canvas, 495, 10);
- do_print("Color at (495, 10): " + JSON.stringify(bar6));
- ok(bar6.r >= MAX_COLOR && bar6.g <= MIN_COLOR && bar6.b <= MIN_COLOR, "Bar 6 is Red");
-
- let bar7 = getPixelColor(canvas, 585, 10);
- do_print("Color at (585, 10): " + JSON.stringify(bar7));
- ok(bar7.r <= MIN_COLOR && bar7.g <= MIN_COLOR && bar7.b >= MAX_COLOR, "Bar 7 is Blue");
-
- run_next_test();
-}
-
-run_next_test();
diff --git a/mobile/android/tests/browser/robocop/test_viewport.sjs b/mobile/android/tests/browser/robocop/test_viewport.sjs
deleted file mode 100644
index aa83d6cbd..000000000
--- a/mobile/android/tests/browser/robocop/test_viewport.sjs
+++ /dev/null
@@ -1,33 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
- function decodeQuery(query) {
- let result = {};
- query.split("&").forEach(function(pair) {
- let [key, val] = pair.split("=");
- result[key] = decodeURIComponent(val);
- });
- return result;
- }
-
-function handleRequest(request, response) {
- response.setStatusLine(request.httpVersion, 200, "OK");
- response.setHeader("Content-Type", "text/html", false);
-
- let params = decodeQuery(request.queryString || "");
-
- response.write('<html>\n' +
- '<head>\n' +
- '<title>Browser VKB Overlapping content</title> <meta charset="utf-8">');
-
- if (params.metadata)
- response.write("<meta name=\"viewport\" content=\"" + params.metadata + "\"/>");
-
- /* Write a spacer div into the document, above an input element*/
- response.write('</head>\n' +
- '<body style="margin: 0; padding: 0">\n' +
- '<div style="width: 100%; height: 100%"></div>\n' +
- '<input type="text" style="background-color: green">\n' +
- '</body>\n</html>');
-}
diff --git a/mobile/android/tests/browser/robocop/tracking_bad.html b/mobile/android/tests/browser/robocop/tracking_bad.html
deleted file mode 100644
index 17f0e459e..000000000
--- a/mobile/android/tests/browser/robocop/tracking_bad.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE HTML>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
- - License, v. 2.0. If a copy of the MPL was not distributed with this
- - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<html dir="ltr" xml:lang="en-US" lang="en-US">
- <head>
- <meta charset="utf8">
- </head>
- <body>
- <iframe src="http://tracking.example.com/"></iframe>
- </body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/tracking_good.html b/mobile/android/tests/browser/robocop/tracking_good.html
deleted file mode 100644
index 8e9429acd..000000000
--- a/mobile/android/tests/browser/robocop/tracking_good.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE HTML>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
- - License, v. 2.0. If a copy of the MPL was not distributed with this
- - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<html dir="ltr" xml:lang="en-US" lang="en-US">
- <head>
- <meta charset="utf8">
- </head>
- <body>
- <iframe src="http://not-tracking.example.com/"></iframe>
- </body>
-</html>
diff --git a/mobile/android/tests/browser/robocop/video-pattern.ogg b/mobile/android/tests/browser/robocop/video-pattern.ogg
deleted file mode 100644
index c86d9946b..000000000
--- a/mobile/android/tests/browser/robocop/video-pattern.ogg
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/video-pattern.webm b/mobile/android/tests/browser/robocop/video-pattern.webm
deleted file mode 100644
index 8ed761099..000000000
--- a/mobile/android/tests/browser/robocop/video-pattern.webm
+++ /dev/null
Binary files differ
diff --git a/mobile/android/tests/browser/robocop/video_controls.html b/mobile/android/tests/browser/robocop/video_controls.html
deleted file mode 100644
index a31212409..000000000
--- a/mobile/android/tests/browser/robocop/video_controls.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML>
-<html>
- <head>
- <title>Video Controls Test</title>
- </head>
- <body>
- <video id="video" style="height: 480px; width: 640px" controls mozNoDynamicControls></video>
- <canvas id="canvas" style="height: 480px; width: 640px"></canvas>
- </body>
-</html>
diff --git a/mobile/android/tests/javaaddons/AndroidManifest.xml.in b/mobile/android/tests/javaaddons/AndroidManifest.xml.in
deleted file mode 100644
index b44930b1b..000000000
--- a/mobile/android/tests/javaaddons/AndroidManifest.xml.in
+++ /dev/null
@@ -1,14 +0,0 @@
-#filter substitution
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.mozilla.javaaddons.test"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-sdk android:minSdkVersion="@MOZ_ANDROID_MIN_SDK_VERSION@"
-#ifdef MOZ_ANDROID_MAX_SDK_VERSION
- android:maxSdkVersion="@MOZ_ANDROID_MAX_SDK_VERSION@"
-#endif
- android:targetSdkVersion="@ANDROID_TARGET_SDK@"/>
-
-</manifest>
diff --git a/mobile/android/tests/javaaddons/Makefile.in b/mobile/android/tests/javaaddons/Makefile.in
deleted file mode 100644
index 4baac3f16..000000000
--- a/mobile/android/tests/javaaddons/Makefile.in
+++ /dev/null
@@ -1,11 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ANDROID_MANIFEST_FILE := $(CURDIR)/AndroidManifest.xml
-
-ANDROID_EXTRA_JARS := javaaddons-test.jar
-
-include $(topsrcdir)/config/rules.mk
-
-tools libs:: $(ANDROID_APK_NAME).apk
diff --git a/mobile/android/tests/javaaddons/moz.build b/mobile/android/tests/javaaddons/moz.build
deleted file mode 100644
index 2fabebc56..000000000
--- a/mobile/android/tests/javaaddons/moz.build
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ANDROID_APK_NAME = 'javaaddons-test'
-ANDROID_APK_PACKAGE = 'org.mozilla.javaaddons.test'
-
-jar = add_java_jar('javaaddons-test')
-jar.extra_jars += [
- TOPOBJDIR + '/mobile/android/javaaddons/javaaddons-1.0.jar',
-]
-jar.javac_flags += ['-Xlint:all']
-jar.sources += [
- 'src/org/mozilla/javaaddons/test/ClassWithNoRecognizedConstructors.java',
- 'src/org/mozilla/javaaddons/test/JavaAddonV0.java',
- 'src/org/mozilla/javaaddons/test/JavaAddonV1.java',
-]
-
-OBJDIR_PP_FILES.mobile.android.tests.javaaddons += [
- 'AndroidManifest.xml.in',
-]
diff --git a/mobile/android/tests/javaaddons/res/values/strings.xml b/mobile/android/tests/javaaddons/res/values/strings.xml
deleted file mode 100644
index e4602bbdf..000000000
--- a/mobile/android/tests/javaaddons/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<resources>
- <string name="app_name">org.mozilla.javaaddons.test</string>
-</resources>
diff --git a/mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/ClassWithNoRecognizedConstructors.java b/mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/ClassWithNoRecognizedConstructors.java
deleted file mode 100644
index 93bf5e7cd..000000000
--- a/mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/ClassWithNoRecognizedConstructors.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.javaaddons.test;
-
-public class ClassWithNoRecognizedConstructors {
- public ClassWithNoRecognizedConstructors(int a, String b, boolean c) {
- }
-}
diff --git a/mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/JavaAddonV0.java b/mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/JavaAddonV0.java
deleted file mode 100644
index f0ea79535..000000000
--- a/mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/JavaAddonV0.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.javaaddons.test;
-
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-import java.util.Map;
-
-public class JavaAddonV0 implements Handler.Callback {
- public JavaAddonV0(Map<String, Handler.Callback> callbacks) {
- callbacks.put("JavaAddon:V0", this);
- }
-
- @Override
- public boolean handleMessage(Message message) {
- Log.i("JavaAddon", "handleMessage " + message.toString());
- return true;
- }
-}
diff --git a/mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/JavaAddonV1.java b/mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/JavaAddonV1.java
deleted file mode 100644
index 803a0d740..000000000
--- a/mobile/android/tests/javaaddons/src/org/mozilla/javaaddons/test/JavaAddonV1.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.javaaddons.test;
-
-import android.content.Context;
-import android.util.Log;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.javaaddons.JavaAddonInterfaceV1.EventCallback;
-import org.mozilla.javaaddons.JavaAddonInterfaceV1.EventDispatcher;
-import org.mozilla.javaaddons.JavaAddonInterfaceV1.EventListener;
-import org.mozilla.javaaddons.JavaAddonInterfaceV1.RequestCallback;
-
-public class JavaAddonV1 implements EventListener, RequestCallback {
- protected final EventDispatcher mDispatcher;
-
- public JavaAddonV1(Context context, EventDispatcher dispatcher) {
- mDispatcher = dispatcher;
- mDispatcher.registerEventListener(this, "JavaAddon:V1");
- }
-
- @Override
- public void handleMessage(Context context, String event, JSONObject message, EventCallback callback) {
- Log.i("JavaAddon", "handleMessage: " + event + ", " + message.toString());
- final JSONObject output = new JSONObject();
- try {
- output.put("outputStringKey", "inputStringKey=" + message.getString("inputStringKey"));
- output.put("outputIntKey", 1 + message.getInt("inputIntKey"));
- } catch (JSONException e) {
- // Should never happen; ignore.
- }
- // Respond.
- if (callback != null) {
- callback.sendSuccess(output);
- }
-
- // And send an independent Gecko event.
- final JSONObject input = new JSONObject();
- try {
- input.put("inputStringKey", "raw");
- input.put("inputIntKey", 3);
- } catch (JSONException e) {
- // Should never happen; ignore.
- }
- mDispatcher.sendRequestToGecko("JavaAddon:V1:Request", input, this);
- }
-
- @Override
- public void onResponse(Context context, JSONObject jsonObject) {
- Log.i("JavaAddon", "onResponse: " + jsonObject.toString());
- // Unregister event listener, so that the JavaScript side can send a test message and
- // check it is not handled.
- mDispatcher.unregisterEventListener(this);
- mDispatcher.sendRequestToGecko("JavaAddon:V1:VerificationRequest", jsonObject, null);
- }
-}
diff --git a/mobile/android/tests/moz.build b/mobile/android/tests/moz.build
deleted file mode 100644
index 2ec31396e..000000000
--- a/mobile/android/tests/moz.build
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-if not CONFIG['MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE']:
- TEST_DIRS += [
- 'background',
- ]
-
-TEST_DIRS += [
- 'browser',
- 'javaaddons', # Must be built before browser/robocop/roboextender.
- # This is enforced in config/recurse.mk.
-]
-
-ANDROID_INSTRUMENTATION_MANIFESTS += ['browser/robocop/robocop.ini']