Java tutorial
/** * Copyright (C) 2016 eBusiness Information * * This file is part of OSM Contributor. * * OSM Contributor is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OSM Contributor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OSM Contributor. If not, see <http://www.gnu.org/licenses/>. */ package io.jawg.osmcontributor.ui.activities; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.design.widget.NavigationView; import android.support.v4.app.DialogFragment; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.ImageView; import android.widget.Toast; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.inject.Inject; import com.mapbox.mapboxsdk.location.LocationServices; import butterknife.BindView; import butterknife.ButterKnife; import io.jawg.osmcontributor.BuildConfig; import io.jawg.osmcontributor.OsmTemplateApplication; import io.jawg.osmcontributor.R; import io.jawg.osmcontributor.model.entities.Poi; import io.jawg.osmcontributor.model.entities.PoiType; import io.jawg.osmcontributor.model.events.PleaseLoadPoiTypes; import io.jawg.osmcontributor.setting.activities.SettingsActivity; import io.jawg.osmcontributor.setting.dialog.NoticeDialogFragment; import io.jawg.osmcontributor.ui.activity.ContributeActivity; import io.jawg.osmcontributor.ui.events.login.UpdateFirstConnectionEvent; import io.jawg.osmcontributor.ui.events.map.ChangeMapModeEvent; import io.jawg.osmcontributor.ui.events.map.ChangesInDB; import io.jawg.osmcontributor.ui.events.map.MapCenterValueEvent; import io.jawg.osmcontributor.ui.events.map.OnBackPressedMapEvent; import io.jawg.osmcontributor.ui.events.map.PleaseApplyAccessibilityFilter; import io.jawg.osmcontributor.ui.events.map.PleaseApplyNoteFilterEvent; import io.jawg.osmcontributor.ui.events.map.PleaseApplyPoiFilter; import io.jawg.osmcontributor.ui.events.map.PleaseChangeToolbarColor; import io.jawg.osmcontributor.ui.events.map.PleaseDisplayTutorialEvent; import io.jawg.osmcontributor.ui.events.map.PleaseGiveMeMapCenterEvent; import io.jawg.osmcontributor.ui.events.map.PleaseInitializeArpiEvent; import io.jawg.osmcontributor.ui.events.map.PleaseInitializeDrawer; import io.jawg.osmcontributor.ui.events.map.PleaseInitializeNoteDrawerEvent; import io.jawg.osmcontributor.ui.events.map.PleaseShowMeArpiglEvent; import io.jawg.osmcontributor.ui.events.map.PleaseSwitchMapStyleEvent; import io.jawg.osmcontributor.ui.events.map.PleaseSwitchWayEditionModeEvent; import io.jawg.osmcontributor.ui.events.map.PleaseTellIfDbChanges; import io.jawg.osmcontributor.ui.events.map.PleaseToggleArpiEvent; import io.jawg.osmcontributor.ui.events.map.PleaseToggleDrawer; import io.jawg.osmcontributor.ui.events.map.PleaseToggleDrawerLock; import io.jawg.osmcontributor.ui.utils.ArpiPoiProvider; import io.jawg.osmcontributor.ui.utils.BitmapHandler; import io.jawg.osmcontributor.ui.utils.MapMode; import io.jawg.osmcontributor.ui.utils.PoiTypeFilter; import io.jawg.osmcontributor.utils.ConfigManager; import io.jawg.osmcontributor.utils.FlavorUtils; import mobi.designmyapp.arpigl.engine.ArpiGlController; import mobi.designmyapp.arpigl.listener.PoiSelectionListener; import mobi.designmyapp.arpigl.provider.impl.NetworkTileProvider; import mobi.designmyapp.arpigl.ui.ArpiGlFragment; import timber.log.Timber; import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; public class MapActivity extends AppCompatActivity implements NoticeDialogFragment.NoticeDialogListener { private final int SETTING_ACTIVITY = 1; @Inject EventBus eventBus; @BindView(R.id.drawer_layout) DrawerLayout drawerLayout; @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.navigation) NavigationView navigationView; @BindView(R.id.filter) NavigationView filterView; @BindView(R.id.AR_screenshot) ImageView arpiScreenshot; @Inject BitmapHandler bitmapHandler; @Inject ConfigManager configManager; @Inject SharedPreferences sharedPreferences; @Inject ArpiPoiProvider poiProvider; private ArpiGlController arpiController; private ArpiGlFragment arpiGlFragment; private NetworkTileProvider networkTileProvider; private List<PoiTypeFilter> filters = new ArrayList<>(); private List<Long> poiTypesHidden; private List<Poi.AccessibilityType> poiAccessibilityTypesHidden; private MenuItem selectAllMenuItem; private List<MenuItem> filtersItemList; private boolean displayOpenNotes; private boolean displayClosedNotes; private boolean isSatelliteMode; private boolean isMapnikMode; @Override protected void onCreate(Bundle savedInstanceState) { ((OsmTemplateApplication) getApplication()).init(this); super.onCreate(savedInstanceState); setContentView(R.layout.activity_map); ((OsmTemplateApplication) getApplication()).getOsmTemplateComponent().inject(this); ButterKnife.bind(this); PreferenceManager.setDefaultValues(this, R.xml.pref_accessibility, false); PreferenceManager.setDefaultValues(this, R.xml.pref_connection, false); PreferenceManager.setDefaultValues(this, R.xml.pref_data_sync, false); PreferenceManager.setDefaultValues(this, R.xml.pref_general, false); PreferenceManager.setDefaultValues(this, R.xml.pref_notification, false); setSupportActionBar(toolbar); eventBus.post(new UpdateFirstConnectionEvent()); checkFirstStart(); navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem menuItem) { switch (menuItem.getGroupId()) { case R.id.drawer_options_group: onOptionsClick(menuItem); break; case R.id.sync: onOptionsSyncClick(menuItem); break; } return true; } }); filterView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem menuItem) { if (menuItem.getItemId() == R.id.select_all_item) { selectAllMenuItem.setChecked(!selectAllMenuItem.isChecked()); onSelectAllClick(); } else if (menuItem.getItemId() != R.id.display_open_notes_item && menuItem.getItemId() != R.id.display_closed_notes_item && menuItem.getItemId() != R.id.display_yes_accessibility && menuItem.getItemId() != R.id.display_limited_accessibility && menuItem.getItemId() != R.id.display_no_accessibility && menuItem.getItemId() != R.id.display_unknown_accessibility) { menuItem.setChecked(!menuItem.isChecked()); onFilterItemClick(menuItem); } else { menuItem.setChecked(!menuItem.isChecked()); onOtherItemClick(menuItem); } return true; } }); selectAllMenuItem = filterView.getMenu().findItem(R.id.select_all_item); if (configManager.hasPoiAddition()) { navigationView.getMenu().findItem(R.id.replay_tuto_menu).setVisible(true); } navigationView.getMenu().findItem(R.id.save_changes).setEnabled(false); drawerLayout.setDrawerListener(new DrawerLayout.DrawerListener() { @Override public void onDrawerSlide(View drawerView, float slideOffset) { } @Override public void onDrawerOpened(View drawerView) { eventBus.post(new PleaseTellIfDbChanges()); } @Override public void onDrawerClosed(View drawerView) { } @Override public void onDrawerStateChanged(int newState) { } }); if (FlavorUtils.isBus()) { eventBus.post(new PleaseApplyNoteFilterEvent(false, false)); List<Poi.AccessibilityType> accessibilityTypesToHide = new ArrayList<>(); eventBus.post(new PleaseApplyAccessibilityFilter(accessibilityTypesToHide)); } navigationView.getMenu().findItem(R.id.manage_poi_types) .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { startPoiTypeEditionActivity(); return true; } }); // Get the arpi fragment. arpiGlFragment = (ArpiGlFragment) getFragmentManager().findFragmentById(R.id.engine_fragment); getFragmentManager().beginTransaction().hide(arpiGlFragment).commit(); if (sharedPreferences.getBoolean(getString(R.string.easter_egg), false)) { navigationView.getMenu().findItem(R.id.arpi_view).setVisible(true); } } @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); } public void checkFirstStart() { SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); if (settings.getBoolean("first_start", true)) { //the app is being launched for first time, do something Log.d("Comments", "First start off the application"); DialogFragment newFragment = new NoticeDialogFragment(); newFragment.show(this.getSupportFragmentManager(), String.valueOf(R.string.setup)); // record the fact that the app has been started at least once settings.edit().putBoolean("first_start", false).commit(); } } @Override protected void onResume() { super.onResume(); eventBus.register(this); if (!sharedPreferences.getBoolean(getString(R.string.shared_prefs_preset_default), false) || !BuildConfig.FLAVOR.equals("store")) { navigationView.getMenu().findItem(R.id.edit_way).setVisible(false); navigationView.getMenu().findItem(R.id.manage_poi_types).setVisible(false); eventBus.post(new PleaseLoadPoiTypes()); } else { navigationView.getMenu().findItem(R.id.edit_way).setVisible(true); navigationView.getMenu().findItem(R.id.manage_poi_types) .setVisible(sharedPreferences.getBoolean(getString(R.string.shared_prefs_expert_mode), false)); } poiProvider.register(); } @Override protected void onPause() { eventBus.unregister(this); poiProvider.unregister(); super.onPause(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_map, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.action_filter_drawer) { if (drawerLayout.isDrawerOpen(filterView)) { drawerLayout.closeDrawer(filterView); } else { drawerLayout.openDrawer(filterView); } return true; } return super.onOptionsItemSelected(item); } @Override public void onBackPressed() { if (drawerLayout.isDrawerOpen(navigationView)) { drawerLayout.closeDrawer(navigationView); } else if (drawerLayout.isDrawerOpen(filterView)) { drawerLayout.closeDrawer(filterView); } else { eventBus.post(new OnBackPressedMapEvent()); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseInitializeArpiEvent(PleaseInitializeArpiEvent event) { // Set engine into poi provider poiProvider.setEngine(arpiGlFragment.getEngine()); // Create a controller to manage the arpi fragment arpiController = new ArpiGlController(arpiGlFragment); arpiController.setPoiSelectionListener(new PoiSelectionListener() { @Override public void onPoiSelected(String id) { arpiController.setPoiColor(id, ArpiPoiProvider.SELECTED_COLOR); } @Override public void onPoiDeselected(String id) { switch (id.split(":")[0]) { case "POI": arpiController.setPoiColor(id, ArpiPoiProvider.POI_COLOR); break; case "NOTE": arpiController.setPoiColor(id, ArpiPoiProvider.NOTE_COLOR); break; } } }); networkTileProvider = new NetworkTileProvider(configManager.getMapUrl()) { }; // Add the OSM tile provider to the controller arpiController.setTileProvider(networkTileProvider); arpiController.addPoiProvider(poiProvider); arpiController.setSkyBoxEnabled(true); arpiController.setUserLocationEnabled(false); } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseShowMeArpiglEvent(PleaseShowMeArpiglEvent event) { navigationView.getMenu().findItem(R.id.arpi_view).setVisible(true); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMapCenterValueEvent(MapCenterValueEvent event) { if (arpiController != null) { arpiController.setCameraPosition(event.getMapCenter().getLatitude(), event.getMapCenter().getLongitude()); } } List<PoiType> poiTypesSave; @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseInitializeDrawer(PleaseInitializeDrawer event) { Timber.d("initializing drawer with poiType"); if (filtersItemList == null) { filtersItemList = new ArrayList<>(); } List<PoiType> poiTypes = event.getPoiTypes(); poiTypesHidden = event.getPoiTypeHidden(); poiAccessibilityTypesHidden = new ArrayList<>(); filters.clear(); for (PoiType poiType : poiTypes) { Long id = poiType.getId(); filters.add(new PoiTypeFilter(poiType.getName(), id, poiType.getIcon(), !poiTypesHidden.contains(id))); } Collections.sort(filters); Menu menu = filterView.getMenu(); int order = 1; for (PoiTypeFilter poiTypeFilter : filters) { PoiTypeFilter nextPoiTypeFilter = null; if (order < filters.size()) { nextPoiTypeFilter = filters.get(order); } // Add only menu if not present if (menu.findItem(poiTypeFilter.getPoiTypeId().intValue()) == null) { filtersItemList.add(menu .add(Menu.NONE, poiTypeFilter.getPoiTypeId().intValue(), (nextPoiTypeFilter != null ? (poiTypeFilter.compareTo(nextPoiTypeFilter) > 0 ? order - 1 : order) : order), poiTypeFilter.getPoiTypeName()) .setChecked(poiTypeFilter.isActive()) .setIcon(bitmapHandler.getDrawable(poiTypeFilter.getPoiTypeIconName()))); } order++; } // Remove only filter removed by user if (filters.size() < filtersItemList.size()) { List<MenuItem> temp = new ArrayList<>(filters.size()); for (MenuItem menuItem : filtersItemList) { PoiTypeFilter poiTypeFilter = new PoiTypeFilter("", (long) menuItem.getItemId(), "", true); if (!filters.contains(poiTypeFilter)) { menu.removeItem(poiTypeFilter.getPoiTypeId().intValue()); } else { temp.add(menuItem); } } filtersItemList.clear(); filtersItemList.addAll(temp); temp.clear(); } selectAllMenuItem.setChecked(poiTypesHidden.isEmpty()); } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseInitializeNoteDrawerEvent(PleaseInitializeNoteDrawerEvent event) { Menu menu = filterView.getMenu(); if (!FlavorUtils.isPoiStorage()) { displayOpenNotes = event.isDisplayOpenNotes(); displayClosedNotes = event.isDisplayClosedNotes(); menu.findItem(R.id.display_open_notes_item).setChecked(displayOpenNotes); menu.findItem(R.id.display_closed_notes_item).setChecked(displayClosedNotes); menu.findItem(R.id.display_yes_accessibility).setChecked(true); menu.findItem(R.id.display_limited_accessibility).setChecked(true); menu.findItem(R.id.display_no_accessibility).setChecked(true); menu.findItem(R.id.display_unknown_accessibility).setChecked(true); } else { menu.removeItem(R.id.drawer_filter_notes_menu); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseToggleDrawer(PleaseToggleDrawer event) { if (drawerLayout.isDrawerOpen(navigationView)) { Timber.d("Closing Drawer"); drawerLayout.closeDrawer(navigationView); } else { Timber.d("Opening Drawer"); drawerLayout.openDrawer(navigationView); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseChangeToolbarColor(PleaseChangeToolbarColor event) { if (toolbar != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { changeNotificationToolbarColor(event.isCreation()); } if (event.isCreation()) { toolbar.setBackgroundColor(getResources().getColor(R.color.colorCreation)); } else { toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); } } } @TargetApi(21) private void changeNotificationToolbarColor(boolean isCreation) { Window window = getWindow(); if (window != null) { if (isCreation) { window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.setStatusBarColor(getResources().getColor(R.color.colorCreationDark)); } else { window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } } } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseToggleDrawerLock(PleaseToggleDrawerLock event) { if (event.isLock()) { drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); } else { drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); } } private void onSelectAllClick() { if (selectAllMenuItem.isChecked()) { poiTypesHidden.clear(); for (MenuItem filter : filtersItemList) { filter.setChecked(true); } } else { for (MenuItem filter : filtersItemList) { poiTypesHidden.add((long) filter.getItemId()); filter.setChecked(false); } } eventBus.post(new PleaseApplyPoiFilter(poiTypesHidden)); } private void onFilterItemClick(MenuItem item) { long id = item.getItemId(); if (item.isChecked()) { poiTypesHidden.remove(id); } else { poiTypesHidden.add(id); } selectAllMenuItem.setChecked(poiTypesHidden.isEmpty()); eventBus.post(new PleaseApplyPoiFilter(poiTypesHidden)); } private void onOptionsClick(MenuItem menuItem) { switch (menuItem.getItemId()) { case R.id.profile_load: startProfileLoadingActivity(); break; case R.id.replay_tuto_menu: replayTutorial(); break; case R.id.edit_way: eventBus.post(new PleaseSwitchWayEditionModeEvent()); break; case R.id.arpi_view: toggleArpiGl(); break; case R.id.switch_style: isSatelliteMode = !isSatelliteMode; eventBus.post(new PleaseSwitchMapStyleEvent(isSatelliteMode)); drawerLayout.closeDrawer(navigationView); menuItem.setTitle(isSatelliteMode ? R.string.switch_style_mapnik : R.string.switch_style_satellite); break; case R.id.offline_regions: startOfflineRegionsActivity(); break; case R.id.preferences_menu: startPreferencesActivity(); break; case R.id.about_menu: startAboutActivity(); break; case R.id.contribute_menu: startContributeActivity(); break; case R.id.report: startNewReportActivity(); break; } } private void onOptionsSyncClick(MenuItem menuItem) { switch (menuItem.getItemId()) { case R.id.save_changes: drawerLayout.closeDrawer(navigationView); Intent intent = new Intent(this, UploadActivity.class); startActivity(intent); break; } } private void startPoiTypeEditionActivity() { drawerLayout.closeDrawer(navigationView); Intent intent = new Intent(this, TypeListActivity.class); startActivity(intent); } private void startPreferencesActivity() { drawerLayout.closeDrawer(navigationView); Intent intent = new Intent(this, SettingsActivity.class); startActivityForResult(intent, SETTING_ACTIVITY); } private void startAboutActivity() { drawerLayout.closeDrawer(navigationView); Intent intent = new Intent(this, AboutActivity.class); startActivity(intent); } private void startContributeActivity() { drawerLayout.closeDrawer(navigationView); Intent intent = new Intent(this, ContributeActivity.class); startActivity(intent); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); if (requestCode == SETTING_ACTIVITY) { finish(); startActivity(getIntent()); } } private void startNewReportActivity() { drawerLayout.closeDrawer(navigationView); Intent intent = new Intent(this, NewReportActivity.class); startActivity(intent); } private void startProfileLoadingActivity() { drawerLayout.closeDrawer(navigationView); Intent intent = new Intent(this, LoadProfileActivity.class); startActivity(intent); } private void startOfflineRegionsActivity() { drawerLayout.closeDrawer(navigationView); Intent intent = new Intent(this, OfflineRegionsActivity.class); startActivity(intent); } private void replayTutorial() { drawerLayout.closeDrawer(navigationView); eventBus.post(new PleaseDisplayTutorialEvent()); } private void onOtherItemClick(MenuItem menuItem) { boolean checked = menuItem.isChecked(); Poi.AccessibilityType accessibilityType = null; switch (menuItem.getItemId()) { case R.id.display_open_notes_item: displayOpenNotes = checked; break; case R.id.display_closed_notes_item: displayClosedNotes = checked; break; case R.id.display_yes_accessibility: accessibilityType = Poi.AccessibilityType.YES; break; case R.id.display_limited_accessibility: accessibilityType = Poi.AccessibilityType.LIMITED; break; case R.id.display_no_accessibility: accessibilityType = Poi.AccessibilityType.NO; break; case R.id.display_unknown_accessibility: accessibilityType = Poi.AccessibilityType.UNKNOWN; break; } if (accessibilityType != null) { if (checked) { poiAccessibilityTypesHidden.remove(accessibilityType); } else { poiAccessibilityTypesHidden.add(accessibilityType); } eventBus.post(new PleaseApplyAccessibilityFilter(poiAccessibilityTypesHidden)); } else { eventBus.post(new PleaseApplyNoteFilterEvent(displayOpenNotes, displayClosedNotes)); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onChangesInDB(ChangesInDB event) { navigationView.getMenu().findItem(R.id.save_changes).setEnabled(event.hasChanges()) .setChecked(event.hasChanges()); } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseToggleArpiEvent(PleaseToggleArpiEvent event) { toggleArpiGl(); } public void toggleArpiGl() { PackageManager pm = getPackageManager(); // Switch to ArpiGl fragment if the sensors are present. IF they aren't, just display a screenshot of ArpiGl view if (pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_GYROSCOPE) && pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER)) { if (arpiGlFragment.isVisible()) { getFragmentManager().beginTransaction().hide(arpiGlFragment).commit(); eventBus.post(new ChangeMapModeEvent(MapMode.DEFAULT)); } else { getFragmentManager().beginTransaction().show(arpiGlFragment).commit(); eventBus.post(new PleaseGiveMeMapCenterEvent()); eventBus.post(new ChangeMapModeEvent(MapMode.ARPIGL)); } } else { if (arpiScreenshot.getVisibility() == View.GONE) { arpiScreenshot.setVisibility(View.VISIBLE); eventBus.post(new ChangeMapModeEvent(MapMode.ARPIGL)); Toast.makeText(this, R.string.arpi_not_supported, Toast.LENGTH_LONG).show(); } else { arpiScreenshot.setVisibility(View.GONE); eventBus.post(new ChangeMapModeEvent(MapMode.DEFAULT)); } } } public NavigationView getNavigationView() { return navigationView; } @Override public void onDialogPositiveClick(DialogFragment dialog) { Intent myIntent = new Intent(this, SettingsActivity.class); this.startActivityForResult(myIntent, SETTING_ACTIVITY); } }