1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/command_line.h" 6 #include "build/build_config.h" 7 #include "chrome/browser/about_flags.h" 8 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 9 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h" 10 #include "chrome/browser/browser_process.h" 11 #include "chrome/browser/dom_distiller/dom_distiller_service_factory.h" 12 #include "chrome/browser/extensions/api/storage/settings_frontend.h" 13 #include "chrome/browser/extensions/extension_service.h" 14 #include "chrome/browser/extensions/extension_sync_service.h" 15 #include "chrome/browser/extensions/extension_system.h" 16 #include "chrome/browser/extensions/extension_system_factory.h" 17 #include "chrome/browser/history/history_service.h" 18 #include "chrome/browser/history/history_service_factory.h" 19 #include "chrome/browser/pref_service_flags_storage.h" 20 #include "chrome/browser/prefs/pref_model_associator.h" 21 #include "chrome/browser/prefs/pref_service_syncable.h" 22 #include "chrome/browser/profiles/profile.h" 23 #include "chrome/browser/search_engines/template_url_service.h" 24 #include "chrome/browser/search_engines/template_url_service_factory.h" 25 #include "chrome/browser/signin/signin_manager.h" 26 #include "chrome/browser/signin/signin_manager_factory.h" 27 #include "chrome/browser/sync/glue/autofill_data_type_controller.h" 28 #include "chrome/browser/sync/glue/autofill_profile_data_type_controller.h" 29 #include "chrome/browser/sync/glue/bookmark_change_processor.h" 30 #include "chrome/browser/sync/glue/bookmark_data_type_controller.h" 31 #include "chrome/browser/sync/glue/bookmark_model_associator.h" 32 #include "chrome/browser/sync/glue/data_type_manager_impl.h" 33 #include "chrome/browser/sync/glue/data_type_manager_observer.h" 34 #include "chrome/browser/sync/glue/extension_data_type_controller.h" 35 #include "chrome/browser/sync/glue/extension_setting_data_type_controller.h" 36 #include "chrome/browser/sync/glue/generic_change_processor.h" 37 #include "chrome/browser/sync/glue/password_change_processor.h" 38 #include "chrome/browser/sync/glue/password_data_type_controller.h" 39 #include "chrome/browser/sync/glue/password_model_associator.h" 40 #include "chrome/browser/sync/glue/proxy_data_type_controller.h" 41 #include "chrome/browser/sync/glue/search_engine_data_type_controller.h" 42 #include "chrome/browser/sync/glue/session_change_processor.h" 43 #include "chrome/browser/sync/glue/session_data_type_controller.h" 44 #include "chrome/browser/sync/glue/session_model_associator.h" 45 #include "chrome/browser/sync/glue/shared_change_processor.h" 46 #include "chrome/browser/sync/glue/sync_backend_host.h" 47 #include "chrome/browser/sync/glue/sync_backend_host_impl.h" 48 #include "chrome/browser/sync/glue/theme_data_type_controller.h" 49 #include "chrome/browser/sync/glue/typed_url_change_processor.h" 50 #include "chrome/browser/sync/glue/typed_url_data_type_controller.h" 51 #include "chrome/browser/sync/glue/typed_url_model_associator.h" 52 #include "chrome/browser/sync/glue/ui_data_type_controller.h" 53 #include "chrome/browser/sync/profile_sync_components_factory_impl.h" 54 #include "chrome/browser/sync/profile_sync_service.h" 55 #include "chrome/browser/sync/profile_sync_service_factory.h" 56 #include "chrome/browser/sync/sessions2/session_data_type_controller2.h" 57 #include "chrome/browser/themes/theme_service.h" 58 #include "chrome/browser/themes/theme_service_factory.h" 59 #include "chrome/browser/themes/theme_syncable_service.h" 60 #include "chrome/browser/ui/app_list/app_list_syncable_service.h" 61 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h" 62 #include "chrome/browser/webdata/autocomplete_syncable_service.h" 63 #include "chrome/browser/webdata/autofill_profile_syncable_service.h" 64 #include "chrome/browser/webdata/web_data_service_factory.h" 65 #include "chrome/common/chrome_switches.h" 66 #include "chrome/common/pref_names.h" 67 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" 68 #include "components/dom_distiller/core/dom_distiller_service.h" 69 #include "content/public/browser/browser_thread.h" 70 #include "sync/api/syncable_service.h" 71 72 #if defined(ENABLE_MANAGED_USERS) 73 #include "chrome/browser/managed_mode/managed_user_settings_service.h" 74 #include "chrome/browser/managed_mode/managed_user_settings_service_factory.h" 75 #include "chrome/browser/managed_mode/managed_user_sync_service.h" 76 #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h" 77 #endif 78 79 #if !defined(OS_ANDROID) 80 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h" 81 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h" 82 #endif 83 84 #if defined(ENABLE_SPELLCHECK) 85 #include "chrome/browser/spellchecker/spellcheck_factory.h" 86 #include "chrome/browser/spellchecker/spellcheck_service.h" 87 #endif 88 89 using browser_sync::AutofillDataTypeController; 90 using browser_sync::AutofillProfileDataTypeController; 91 using browser_sync::BookmarkChangeProcessor; 92 using browser_sync::BookmarkDataTypeController; 93 using browser_sync::BookmarkModelAssociator; 94 using browser_sync::DataTypeController; 95 using browser_sync::DataTypeErrorHandler; 96 using browser_sync::DataTypeManager; 97 using browser_sync::DataTypeManagerImpl; 98 using browser_sync::DataTypeManagerObserver; 99 using browser_sync::ExtensionDataTypeController; 100 using browser_sync::ExtensionSettingDataTypeController; 101 using browser_sync::GenericChangeProcessor; 102 using browser_sync::PasswordChangeProcessor; 103 using browser_sync::PasswordDataTypeController; 104 using browser_sync::PasswordModelAssociator; 105 using browser_sync::ProxyDataTypeController; 106 using browser_sync::SearchEngineDataTypeController; 107 using browser_sync::SessionChangeProcessor; 108 using browser_sync::SessionDataTypeController; 109 using browser_sync::SessionDataTypeController2; 110 using browser_sync::SessionModelAssociator; 111 using browser_sync::SharedChangeProcessor; 112 using browser_sync::SyncBackendHost; 113 using browser_sync::ThemeDataTypeController; 114 using browser_sync::TypedUrlChangeProcessor; 115 using browser_sync::TypedUrlDataTypeController; 116 using browser_sync::TypedUrlModelAssociator; 117 using browser_sync::UIDataTypeController; 118 using content::BrowserThread; 119 120 ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl( 121 Profile* profile, CommandLine* command_line) 122 : profile_(profile), 123 command_line_(command_line), 124 extension_system_( 125 extensions::ExtensionSystemFactory::GetForProfile(profile)), 126 web_data_service_( 127 WebDataServiceFactory::GetAutofillWebDataForProfile( 128 profile_, Profile::EXPLICIT_ACCESS)) { 129 } 130 131 ProfileSyncComponentsFactoryImpl::~ProfileSyncComponentsFactoryImpl() { 132 } 133 134 void ProfileSyncComponentsFactoryImpl::RegisterDataTypes( 135 ProfileSyncService* pss) { 136 RegisterCommonDataTypes(pss); 137 #if !defined(OS_ANDROID) 138 RegisterDesktopDataTypes(pss); 139 #endif 140 } 141 142 void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes( 143 ProfileSyncService* pss) { 144 // Autofill sync is enabled by default. Register unless explicitly 145 // disabled. 146 if (!command_line_->HasSwitch(switches::kDisableSyncAutofill)) { 147 pss->RegisterDataTypeController( 148 new AutofillDataTypeController(this, profile_, pss)); 149 } 150 151 // Autofill profile sync is enabled by default. Register unless explicitly 152 // disabled. 153 if (!command_line_->HasSwitch(switches::kDisableSyncAutofillProfile)) { 154 pss->RegisterDataTypeController( 155 new AutofillProfileDataTypeController(this, profile_, pss)); 156 } 157 158 // Bookmark sync is enabled by default. Register unless explicitly 159 // disabled. 160 if (!command_line_->HasSwitch(switches::kDisableSyncBookmarks)) { 161 pss->RegisterDataTypeController( 162 new BookmarkDataTypeController(this, profile_, pss)); 163 } 164 165 // TypedUrl sync is enabled by default. Register unless explicitly disabled, 166 // or if saving history is disabled. 167 if (!profile_->GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled) && 168 !command_line_->HasSwitch(switches::kDisableSyncTypedUrls)) { 169 pss->RegisterDataTypeController( 170 new TypedUrlDataTypeController(this, profile_, pss)); 171 } 172 173 // Delete directive sync is enabled by default. Register unless full history 174 // sync is disabled. 175 if (!command_line_->HasSwitch(switches::kHistoryDisableFullHistorySync)) { 176 pss->RegisterDataTypeController( 177 new UIDataTypeController( 178 syncer::HISTORY_DELETE_DIRECTIVES, this, profile_, pss)); 179 } 180 181 // Session sync is enabled by default. Register unless explicitly disabled. 182 if (!command_line_->HasSwitch(switches::kDisableSyncTabs)) { 183 pss->RegisterDataTypeController( 184 new ProxyDataTypeController(syncer::PROXY_TABS)); 185 if (!command_line_->HasSwitch(switches::kEnableSyncSessionsV2)) { 186 pss->RegisterDataTypeController( 187 new SessionDataTypeController(this, profile_, pss)); 188 } else { 189 pss->RegisterDataTypeController( 190 new SessionDataTypeController2(this, profile_, pss)); 191 } 192 } 193 194 // Favicon sync is enabled by default. Register unless explicitly disabled. 195 if (!command_line_->HasSwitch(switches::kDisableSyncFavicons)) { 196 pss->RegisterDataTypeController( 197 new UIDataTypeController(syncer::FAVICON_IMAGES, 198 this, 199 profile_, 200 pss)); 201 pss->RegisterDataTypeController( 202 new UIDataTypeController(syncer::FAVICON_TRACKING, 203 this, 204 profile_, 205 pss)); 206 } 207 208 // Password sync is enabled by default. Register unless explicitly 209 // disabled. 210 if (!command_line_->HasSwitch(switches::kDisableSyncPasswords)) { 211 pss->RegisterDataTypeController( 212 new PasswordDataTypeController(this, profile_, pss)); 213 } 214 // Article sync is disabled by default. Register only if explicitly enabled. 215 if (IsEnableSyncArticlesSet()) { 216 pss->RegisterDataTypeController( 217 new UIDataTypeController(syncer::ARTICLES, this, profile_, pss)); 218 } 219 220 #if defined(ENABLE_MANAGED_USERS) 221 if (profile_->IsManaged()) { 222 pss->RegisterDataTypeController( 223 new UIDataTypeController( 224 syncer::MANAGED_USER_SETTINGS, this, profile_, pss)); 225 } else { 226 pss->RegisterDataTypeController( 227 new UIDataTypeController( 228 syncer::MANAGED_USERS, this, profile_, pss)); 229 } 230 #endif 231 } 232 233 void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( 234 ProfileSyncService* pss) { 235 // App sync is enabled by default. Register unless explicitly 236 // disabled. 237 if (!command_line_->HasSwitch(switches::kDisableSyncApps)) { 238 pss->RegisterDataTypeController( 239 new ExtensionDataTypeController(syncer::APPS, this, profile_, pss)); 240 } 241 242 // Extension sync is enabled by default. Register unless explicitly 243 // disabled. 244 if (!command_line_->HasSwitch(switches::kDisableSyncExtensions)) { 245 pss->RegisterDataTypeController( 246 new ExtensionDataTypeController(syncer::EXTENSIONS, 247 this, profile_, pss)); 248 } 249 250 // Preference sync is enabled by default. Register unless explicitly 251 // disabled. 252 if (!command_line_->HasSwitch(switches::kDisableSyncPreferences)) { 253 pss->RegisterDataTypeController( 254 new UIDataTypeController(syncer::PREFERENCES, this, profile_, pss)); 255 256 } 257 258 if (!command_line_->HasSwitch(switches::kDisableSyncPriorityPreferences)) { 259 pss->RegisterDataTypeController( 260 new UIDataTypeController(syncer::PRIORITY_PREFERENCES, 261 this, profile_, pss)); 262 } 263 264 #if defined(ENABLE_THEMES) 265 // Theme sync is enabled by default. Register unless explicitly disabled. 266 if (!command_line_->HasSwitch(switches::kDisableSyncThemes)) { 267 pss->RegisterDataTypeController( 268 new ThemeDataTypeController(this, profile_, pss)); 269 } 270 #endif 271 272 // Search Engine sync is enabled by default. Register unless explicitly 273 // disabled. 274 if (!command_line_->HasSwitch(switches::kDisableSyncSearchEngines)) { 275 pss->RegisterDataTypeController( 276 new SearchEngineDataTypeController(this, profile_, pss)); 277 } 278 279 // Extension setting sync is enabled by default. Register unless explicitly 280 // disabled. 281 if (!command_line_->HasSwitch(switches::kDisableSyncExtensionSettings)) { 282 pss->RegisterDataTypeController( 283 new ExtensionSettingDataTypeController( 284 syncer::EXTENSION_SETTINGS, this, profile_, pss)); 285 } 286 287 // App setting sync is enabled by default. Register unless explicitly 288 // disabled. 289 if (!command_line_->HasSwitch(switches::kDisableSyncAppSettings)) { 290 pss->RegisterDataTypeController( 291 new ExtensionSettingDataTypeController( 292 syncer::APP_SETTINGS, this, profile_, pss)); 293 } 294 295 #if defined(ENABLE_APP_LIST) 296 // App List sync is disabled by default. Register only if enabled. 297 if (command_line_->HasSwitch(switches::kEnableSyncAppList)) { 298 pss->RegisterDataTypeController( 299 new UIDataTypeController(syncer::APP_LIST, this, profile_, pss)); 300 } 301 #endif 302 303 // Synced Notifications are enabled by default. 304 pss->RegisterDataTypeController( 305 new UIDataTypeController( 306 syncer::SYNCED_NOTIFICATIONS, this, profile_, pss)); 307 308 #if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_CHROMEOS) 309 // Dictionary sync is enabled by default. 310 if (!command_line_->HasSwitch(switches::kDisableSyncDictionary)) { 311 pss->RegisterDataTypeController( 312 new UIDataTypeController(syncer::DICTIONARY, this, profile_, pss)); 313 } 314 #endif 315 } 316 317 DataTypeManager* ProfileSyncComponentsFactoryImpl::CreateDataTypeManager( 318 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>& 319 debug_info_listener, 320 const DataTypeController::TypeMap* controllers, 321 const browser_sync::DataTypeEncryptionHandler* encryption_handler, 322 SyncBackendHost* backend, 323 DataTypeManagerObserver* observer, 324 browser_sync::FailedDataTypesHandler* failed_data_types_handler) { 325 return new DataTypeManagerImpl(debug_info_listener, 326 controllers, 327 encryption_handler, 328 backend, 329 observer, 330 failed_data_types_handler); 331 } 332 333 browser_sync::SyncBackendHost* 334 ProfileSyncComponentsFactoryImpl::CreateSyncBackendHost( 335 const std::string& name, 336 Profile* profile, 337 const base::WeakPtr<browser_sync::SyncPrefs>& sync_prefs) { 338 return new browser_sync::SyncBackendHostImpl(name, profile, sync_prefs); 339 } 340 341 browser_sync::GenericChangeProcessor* 342 ProfileSyncComponentsFactoryImpl::CreateGenericChangeProcessor( 343 ProfileSyncService* profile_sync_service, 344 browser_sync::DataTypeErrorHandler* error_handler, 345 const base::WeakPtr<syncer::SyncableService>& local_service, 346 const base::WeakPtr<syncer::SyncMergeResult>& merge_result) { 347 syncer::UserShare* user_share = profile_sync_service->GetUserShare(); 348 return new GenericChangeProcessor(error_handler, 349 local_service, 350 merge_result, 351 user_share); 352 } 353 354 browser_sync::SharedChangeProcessor* ProfileSyncComponentsFactoryImpl:: 355 CreateSharedChangeProcessor() { 356 return new SharedChangeProcessor(); 357 } 358 359 base::WeakPtr<syncer::SyncableService> ProfileSyncComponentsFactoryImpl:: 360 GetSyncableServiceForType(syncer::ModelType type) { 361 if (!profile_) { // For tests. 362 return base::WeakPtr<syncer::SyncableService>(); 363 } 364 switch (type) { 365 case syncer::PREFERENCES: 366 return PrefServiceSyncable::FromProfile( 367 profile_)->GetSyncableService(syncer::PREFERENCES)->AsWeakPtr(); 368 case syncer::PRIORITY_PREFERENCES: 369 return PrefServiceSyncable::FromProfile(profile_)->GetSyncableService( 370 syncer::PRIORITY_PREFERENCES)->AsWeakPtr(); 371 case syncer::AUTOFILL: 372 case syncer::AUTOFILL_PROFILE: { 373 if (!web_data_service_.get()) 374 return base::WeakPtr<syncer::SyncableService>(); 375 if (type == syncer::AUTOFILL) { 376 return AutocompleteSyncableService::FromWebDataService( 377 web_data_service_.get())->AsWeakPtr(); 378 } else { 379 return AutofillProfileSyncableService::FromWebDataService( 380 web_data_service_.get())->AsWeakPtr(); 381 } 382 } 383 case syncer::APPS: 384 case syncer::EXTENSIONS: 385 return ExtensionSyncService::Get(profile_)->AsWeakPtr(); 386 case syncer::SEARCH_ENGINES: 387 return TemplateURLServiceFactory::GetForProfile(profile_)->AsWeakPtr(); 388 case syncer::APP_SETTINGS: 389 case syncer::EXTENSION_SETTINGS: 390 return extension_system_->extension_service()->settings_frontend()-> 391 GetBackendForSync(type)->AsWeakPtr(); 392 #if defined(ENABLE_APP_LIST) 393 case syncer::APP_LIST: 394 return app_list::AppListSyncableServiceFactory::GetForProfile(profile_)-> 395 AsWeakPtr(); 396 #endif 397 #if defined(ENABLE_THEMES) 398 case syncer::THEMES: 399 return ThemeServiceFactory::GetForProfile(profile_)-> 400 GetThemeSyncableService()->AsWeakPtr(); 401 #endif 402 case syncer::HISTORY_DELETE_DIRECTIVES: { 403 HistoryService* history = 404 HistoryServiceFactory::GetForProfile( 405 profile_, Profile::EXPLICIT_ACCESS); 406 return history ? history->AsWeakPtr() : base::WeakPtr<HistoryService>(); 407 } 408 #if !defined(OS_ANDROID) 409 case syncer::SYNCED_NOTIFICATIONS: { 410 notifier::ChromeNotifierService* notifier_service = 411 notifier::ChromeNotifierServiceFactory::GetForProfile( 412 profile_, Profile::EXPLICIT_ACCESS); 413 return notifier_service ? notifier_service->AsWeakPtr() 414 : base::WeakPtr<syncer::SyncableService>(); 415 } 416 #endif 417 #if defined(ENABLE_SPELLCHECK) 418 case syncer::DICTIONARY: 419 return SpellcheckServiceFactory::GetForContext(profile_)-> 420 GetCustomDictionary()->AsWeakPtr(); 421 #endif 422 case syncer::FAVICON_IMAGES: 423 case syncer::FAVICON_TRACKING: { 424 browser_sync::FaviconCache* favicons = 425 ProfileSyncServiceFactory::GetForProfile(profile_)-> 426 GetFaviconCache(); 427 return favicons ? favicons->AsWeakPtr() 428 : base::WeakPtr<syncer::SyncableService>(); 429 } 430 #if defined(ENABLE_MANAGED_USERS) 431 case syncer::MANAGED_USER_SETTINGS: 432 return ManagedUserSettingsServiceFactory::GetForProfile(profile_)-> 433 AsWeakPtr(); 434 case syncer::MANAGED_USERS: 435 return ManagedUserSyncServiceFactory::GetForProfile(profile_)-> 436 AsWeakPtr(); 437 #endif 438 case syncer::ARTICLES: { 439 dom_distiller::DomDistillerService* service = 440 dom_distiller::DomDistillerServiceFactory::GetForBrowserContext( 441 profile_); 442 if (service) 443 return service->GetSyncableService()->AsWeakPtr(); 444 return base::WeakPtr<syncer::SyncableService>(); 445 } 446 case syncer::SESSIONS: { 447 DCHECK(command_line_->HasSwitch(switches::kEnableSyncSessionsV2)); 448 return ProfileSyncServiceFactory::GetForProfile(profile_)-> 449 GetSessionsSyncableService()->AsWeakPtr(); 450 } 451 default: 452 // The following datatypes still need to be transitioned to the 453 // syncer::SyncableService API: 454 // Bookmarks 455 // Passwords 456 // Typed URLs 457 NOTREACHED(); 458 return base::WeakPtr<syncer::SyncableService>(); 459 } 460 } 461 462 ProfileSyncComponentsFactory::SyncComponents 463 ProfileSyncComponentsFactoryImpl::CreateBookmarkSyncComponents( 464 ProfileSyncService* profile_sync_service, 465 DataTypeErrorHandler* error_handler) { 466 BookmarkModel* bookmark_model = 467 BookmarkModelFactory::GetForProfile(profile_sync_service->profile()); 468 syncer::UserShare* user_share = profile_sync_service->GetUserShare(); 469 // TODO(akalin): We may want to propagate this switch up eventually. 470 #if defined(OS_ANDROID) 471 const bool kExpectMobileBookmarksFolder = true; 472 #else 473 const bool kExpectMobileBookmarksFolder = false; 474 #endif 475 BookmarkModelAssociator* model_associator = 476 new BookmarkModelAssociator(bookmark_model, 477 profile_sync_service->profile(), 478 user_share, 479 error_handler, 480 kExpectMobileBookmarksFolder); 481 BookmarkChangeProcessor* change_processor = 482 new BookmarkChangeProcessor(model_associator, 483 error_handler); 484 return SyncComponents(model_associator, change_processor); 485 } 486 487 ProfileSyncComponentsFactory::SyncComponents 488 ProfileSyncComponentsFactoryImpl::CreatePasswordSyncComponents( 489 ProfileSyncService* profile_sync_service, 490 PasswordStore* password_store, 491 DataTypeErrorHandler* error_handler) { 492 PasswordModelAssociator* model_associator = 493 new PasswordModelAssociator(profile_sync_service, 494 password_store, 495 error_handler); 496 PasswordChangeProcessor* change_processor = 497 new PasswordChangeProcessor(model_associator, 498 password_store, 499 error_handler); 500 return SyncComponents(model_associator, change_processor); 501 } 502 503 ProfileSyncComponentsFactory::SyncComponents 504 ProfileSyncComponentsFactoryImpl::CreateTypedUrlSyncComponents( 505 ProfileSyncService* profile_sync_service, 506 history::HistoryBackend* history_backend, 507 browser_sync::DataTypeErrorHandler* error_handler) { 508 TypedUrlModelAssociator* model_associator = 509 new TypedUrlModelAssociator(profile_sync_service, 510 history_backend, 511 error_handler); 512 TypedUrlChangeProcessor* change_processor = 513 new TypedUrlChangeProcessor(profile_, 514 model_associator, 515 history_backend, 516 error_handler); 517 return SyncComponents(model_associator, change_processor); 518 } 519 520 ProfileSyncComponentsFactory::SyncComponents 521 ProfileSyncComponentsFactoryImpl::CreateSessionSyncComponents( 522 ProfileSyncService* profile_sync_service, 523 DataTypeErrorHandler* error_handler) { 524 SessionModelAssociator* model_associator = 525 new SessionModelAssociator(profile_sync_service, error_handler); 526 SessionChangeProcessor* change_processor = 527 new SessionChangeProcessor(error_handler, model_associator); 528 return SyncComponents(model_associator, change_processor); 529 } 530