рд░рд┐рдВрдЧрдЯреЛрди рдЪреБрдирдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдВрд╡рд╛рдж рдмрдирд╛рдирд╛

рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ рд░рд┐рдВрдЧрдЯреЛрди рдХреА рдкрд╕рдВрдж рдХреЗ рд╕рд╛рде рдЕрдкрдирд╛ рд╕рдВрд╡рд╛рдж рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдпрд╣рд╛рдВ рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рд▓реЗ рдЧрдпрд╛ред рддреБрд░рдВрдд 2 рдХрд╛рд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП - рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╕рдорд░реНрдерди рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ рдХреЛрдИ RingtonePreference рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП PreferenceFragmentCompat FrakmentCompat рдореЗрдВ рдорд╛рдирдХ рд╕рдВрд╡рд╛рдж рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рдФрд░ рджреВрд╕рд░реА рдмрд╛рдд, рдорд╛рдирдХ рдзреБрдиреЛрдВ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореБрдЭреЗ рд╡рд╣рд╛рдВ рдХреЗ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рд╕реЗ рдХреБрдЫ рдзреНрд╡рдирд┐рдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рдерд╛ред рдЗрд╕рд▓рд┐рдП рдЖрдкрдХрд╛ рд╕рдВрд╡рд╛рдж рд▓рд┐рдЦрдирд╛ рддрдп рд╣реБрдЖред


рдореИрдВ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдХ рд╕рдВрд╡рд╛рдж рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХрд╛ рдкреНрд░рджрд░реНрд╢рди рдХрд░реВрдВрдЧрд╛: рдПрдХ рд╕реНрдХреНрд░реАрди рдкрд░ "рдкреНрд▓реЗ рд░рд┐рдВрдЧрдЯреЛрди" рдмрдЯрди рд╣реЛрддрд╛ рд╣реИ, рдЬрд┐рд╕ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рд╕реЗ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ рд╕реЗрдЯ рд░рд┐рдВрдЧрдЯреЛрди рдмрдЬрддреА рд╣реИ, рдФрд░ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рд╕реНрдХреНрд░реАрди рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ:



рдореИрдВ рдЗрди рджреЛ рд╕реНрдХреНрд░реАрди рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХрд╛ рд╡рд░реНрдгрди рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛ - рд╕рдм рдХреБрдЫ рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣ рд╣реИред рдмрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЕрдВрдд рдореЗрдВ рдЖрд╡реЗрджрди рдХреЛрдб рдХреЗ рд╕рд╛рде рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХрд╛ рдПрдХ рд▓рд┐рдВрдХ рд╣реЛрдЧрд╛ред


рддреЛ, рдЖрдЗрдП рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рд╕реНрдХреНрд░реАрди рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде xml рдлрд╝рд╛рдЗрд▓ рд╕реЗ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде res/xml рдореЗрдВ settings.xml рдлрд╝рд╛рдЗрд▓ рд░рдЦреЗрдВ:


 <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <Preference android:key="ringtone" android:title="Ringtone"/> </PreferenceScreen> 

рдФрд░ рдЕрдм рдЗрди рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЛ рд╣рдорд╛рд░реЗ рдЯреБрдХрдбрд╝реЗ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:


 class SettingsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.settings, rootKey) } } 

рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ, рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рд╕реНрдХреНрд░реАрди рдЦреЛрд▓реЗрдВ, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рджреЗрдЦреЗрдВ:



рдкрд░рд┐рдЪрдп рдпрд╣рд╛рдВ рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рд╣рдо рд▓реЗрдЦ рдХреЗ рдЙрджреНрджреЗрд╢реНрдп рдкрд░ рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВред рдпреЛрдЬрдирд╛ рдпрд╣ рд╣реИ: рдЬрдм рдЖрдк "рд░рд┐рдВрдЧрдЯреЛрдиреНрд╕" рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдПрдХ рд░рд┐рдВрдЧрдЯреЛрди рд░рд┐рдВрдЧрдЯреЛрди рдХреА рд╕реВрдЪреА рдФрд░ рдУрдХреЗ рдФрд░ рд░рджреНрдж рдХрд░реЗрдВ рдмрдЯрди рдХреЗ рд╕рд╛рде рдЦреБрд▓рддреА рд╣реИ, рдЬрдм рдЖрдк рдПрдХ рд░рд┐рдВрдЧрдЯреЛрди рдХрд╛ рдЪрдпрди рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдЦреЗрд▓рддрд╛ рд╣реИ (рдорд╛рдирдХ RingtonePreference рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ), рдЬрдм рдЖрдк рдУрдХреЗ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ рд╕рд╣реЗрдЬрд╛ рдЬрд╛рддрд╛ рд╣реИред


рддреЛ, рдПрдХ рд╕рдВрд╡рд╛рдж рдЯреБрдХрдбрд╝рд╛ рдмрдирд╛рдПрдБ:


 class RingtonePreferenceDialog : DialogFragment() { private val prefKey: String get() = arguments?.getString(ARG_PREF_KEY) ?: throw IllegalArgumentException("ARG_PREF_KEY not set") companion object { private const val ARG_PREF_KEY = "ARG_PREF_KEY" fun create(prefKey: String): RingtonePreferenceDialog { val fragment = RingtonePreferenceDialog() fragment.arguments = Bundle().apply { putString(ARG_PREF_KEY, prefKey) } return fragment } } } 

prefKey рд╣рдо рдЙрд╕ рдХреБрдВрдЬреА рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╡рд░реНрддрдорд╛рди рд░рд┐рдВрдЧрдЯреЛрди рдХреЛ рдирд┐рдХрд╛рд▓рд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рд╡рд╣рд╛рдВ рдЗрд╕реЗ OK рдмрдЯрди рджрдмрд╛рдХрд░ рд░рд┐рдХреЙрд░реНрдб рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред


рдЖрдЧреЗ рдХреЗ рдХрд╛рдо рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рд╕рд╣рд╛рдпрдХ рд╡рд░реНрдЧ Ringtone рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕реЗ рд╣рдорд╛рд░реЗ рдЯреБрдХрдбрд╝реЗ рдХреЗ рдЕрдВрджрд░ рдШреЛрд╖рд┐рдд рдХрд░реЗрдВ:


 private data class Ringtone(val title: String, val uri: Uri) 

рдФрд░ рдПрдХ рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦреЗрдВ рдЬреЛ рдПрдВрдбреНрд░реЙрдЗрдб рдореЗрдВ рд╕рднреА рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рд░рд┐рдВрдЧрдЯреЛрди рдХреЛ рдмрд╛рд╣рд░ рдирд┐рдХрд╛рд▓ рджреЗрдЧрд╛, рдФрд░ Ringtone рд╕реЗ рд╕реВрдЪреА Ringtone рд╡рд╛рдкрд╕ Ringtone :


 private fun getAndroidRingtones(): List<Ringtone> { val ringtoneManager = RingtoneManager(context) val cursor = ringtoneManager.cursor return (0 until cursor.count).map { cursor.moveToPosition(it) Ringtone( title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX), uri = ringtoneManager.getRingtoneUri(it) ) } } 

рдпрд╣рд╛рдБ ringtoneManager.cursor рд╕рднреА рдЙрдкрд▓рдмреНрдз рд░рд┐рдВрдЧрдЯреЛрди рдХреЗ рд╕рд╛рде рдХрд░реНрд╕рд░ рд▓реМрдЯрд╛рдПрдЧрд╛, рд╣рдо рдмрд╕ рд╕рднреА рддрддреНрд╡реЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЬрд╛рддреЗ рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рд╣рдорд╛рд░реЗ рд╕рд╣рд╛рдпрдХ рд╡рд░реНрдЧ рдХреЗ Ringtone (рдпрд╣ рдЙрдирдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ) рдореЗрдВ рдореИрдк рдХрд░рддреЗ рд╣реИрдВред


рдкрд╣рд▓реЗ, рдЪрд▓реЛ рд░рд┐рдВрдЧрдЯреЛрди рдХреА рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рд╕реВрдЪреА рдХреЗ рд╕рд╛рде рдХрд╛рдо рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░реЗрдВ - рдмрд╛рдж рдореЗрдВ рд╣рдорд╛рд░реЗ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реЛрдЧрд╛ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, onCreateDialog рд╡рд┐рдзрд┐ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдХреЗ рдПрдХ рд╕рдВрд╡рд╛рдж рдмрдирд╛рдПрдВ:


 private var ringtones: List<Ringtone> = emptyList() private var currentUri: Uri? = null override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { ringtones = getAndroidRingtones() currentUri = getCurrentRingtoneUri() val currentPosition = ringtones.indexOfFirst { currentUri == it.uri } return AlertDialog.Builder(context!!) .setPositiveButton(android.R.string.ok) { _, _ -> saveCurrentUri() } .setNegativeButton(android.R.string.cancel) { _, _ -> dialog.dismiss() } .setSingleChoiceItems(adapter, currentPosition) { _, which -> currentUri = ringtones[which].uri } .create() } 

рдПрдХ рд╕рдВрд╡рд╛рдж рдореЗрдВ рддрддреНрд╡реЛрдВ рдХреА рд╕реВрдЪреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдбреЗрдкреНрдЯрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ; рдЗрд╕реЗ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:


 private val adapter by lazy { SimpleAdapter( context, ringtones.map { mapOf("title" to it.title) }, R.layout.simple_list_item_single_choice, arrayOf("title"), intArrayOf(R.id.text1) ) } 

рдФрд░ рдЖрдкрдХреЛ рдЪрдпрдирд┐рдд рд╕реНрдерд┐рддрд┐ рдХреЛ рдмрдЪрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдФрд░ рд╕рд╣рд╛рдпрдХ рд╡рд┐рдзрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдЗрд╕реЗ рддрдм рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬрдм рдЖрдк рдУрдХреЗ рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВрдЧреЗ):


 private fun saveCurrentUri() { PreferenceManager.getDefaultSharedPreferences(context) .edit() .putString(prefKey, currentUri?.toString()) .apply() } 

рдпрд╣ рд╣рдорд╛рд░реЗ рддрддреНрд╡ рдХреЛ рд╕рдВрд╡рд╛рдж рд╕реЗ рдмрд╛рдВрдзрддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо рд╕рдВрд╡рд╛рдж рдХреЗ рд╕рд╛рде рдлрд╛рдЗрд▓ рдореЗрдВ рдПрдХ рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВ:


 fun Preference.connectRingtoneDialog(fragmentManager: FragmentManager?) = setOnPreferenceClickListener { RingtonePreferenceDialog.create(key).apply { fragmentManager?.let { show(it, "SOUND") } } true } 

рдФрд░ findPreference("ringtone").connectRingtoneDialog(fragmentManager) рд╣рдорд╛рд░реЗ SettingsFragment findPreference("ringtone").connectRingtoneDialog(fragmentManager) , рдЕрдм рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП:


 class SettingsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.settings, rootKey) findPreference("ringtone").connectRingtoneDialog(fragmentManager) } } 

рдпрджрд┐ рд╣рдо рдЕрдм рд╕реЗрдЯрд┐рдВрдЧ рд╕реНрдХреНрд░реАрди рдкрд░ рдЬрд╛рддреЗ рд╣реИрдВ рдФрд░ "рд░рд┐рдВрдЧрдЯреЛрдиреНрд╕" рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджреЗрдЦреЗрдВрдЧреЗ:



рдЕрдм рд╕рдВрд╕рд╛рдзрдиреЛрдВ рд╕реЗ рд░рд┐рдВрдЧрдЯреЛрди рдХреЛ рд╣рдорд╛рд░реЗ рд╕рдВрд╡рд╛рдж рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ res/raw рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдПрдХ sample.mp3 рд░рд┐рдВрдЧрдЯреЛрди рд╣реИ, рдФрд░ рд╣рдо рдЗрд╕реЗ рд╕реВрдЪреА рдореЗрдВ рд╕рдмрд╕реЗ рдКрдкрд░ рджрд┐рдЦрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╕рдВрд╡рд╛рдж рд╡рд░реНрдЧ рдореЗрдВ рдПрдХ рдФрд░ рд╡рд┐рдзрд┐ рдЬреЛрдбрд╝реЗрдВ:


 private fun getResourceRingtones(): List<Ringtone> = listOf( Ringtone( title = "Sample ringtone", uri = Uri.parse("${ContentResolver.SCHEME_ANDROID_RESOURCE}://${context!!.packageName}/raw/sample") ) ) 

рдФрд░ onCreateDialog рд╡рд┐рдзрд┐ рдореЗрдВ рдкрд╣рд▓реА рдкрдВрдХреНрддрд┐ рдмрджрд▓реЗрдВ:


 ringtones = getResourceRingtones() + getAndroidRingtones() 

рд╣рдо рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рджреЗрдЦреЛ, рдЖрдирдиреНрджрд┐рдд рд╣реЛрддреЗ рд╣реИрдВ рдХрд┐ рд╕рдм рдХреБрдЫ рдЗрддрдирд╛ рд╕рд░рд▓ рд╣реИ:



рдпрд╣ рд░рд┐рдВрдЧрдЯреЛрди рдХреЗ рд▓рд┐рдП "рдкреВрд░реНрд╡рд╛рд╡рд▓реЛрдХрди" рдЬреЛрдбрд╝рдирд╛ рд░рд╣рддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдлрд╝реАрд▓реНрдб рджрд░реНрдЬ рдХрд░реЗрдВ:


 private var playingRingtone: android.media.Ringtone? = null 

рдФрд░ setSingleChoiceItems рд▓рд┐рдП рдХреЙрд▓рдмреИрдХ рд╡рд┐рдзрд┐ рдХреЛ рдереЛрдбрд╝рд╛ рдмрджрд▓реЗрдВ:


 playingRingtone?.stop() ringtones[which].also { currentUri = it.uri playingRingtone = it.uri?.let { RingtoneManager.getRingtone(context, it) } playingRingtone?.play() } 

рдпрд╣рд╛рдВ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ: рд╣рдо рд╡рд░реНрддрдорд╛рди рд░рд┐рдВрдЧрдЯреЛрди рдХреЛ рдЦреЗрд▓рдирд╛ рдмрдВрдж рдХрд░ рджреЗрддреЗ рд╣реИрдВ (рдпрджрд┐ рдпрд╣ рд╢реВрдиреНрдп рдирд╣реАрдВ рд╣реИ), рдЪрдпрдирд┐рдд рдХреЛ рд╡рд░реНрддрдорд╛рди рдПрдХ рдХреЗ рд░реВрдк рдореЗрдВ рд╕реЗрдЯ рдХрд░реЗрдВ, рдФрд░ рдкреНрд▓реЗрдмреИрдХ рд╢реБрд░реВ рдХрд░реЗрдВред рдЕрдм рдЬрдм рдЖрдк рд╕рдВрд╡рд╛рдж рдореЗрдВ рдПрдХ рд░рд┐рдВрдЧрдЯреЛрди рдХрд╛ рдЪрдпрди рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдЦреЗрд▓ рд╣реЛрдЧрд╛ред рдбрд╛рдпрд▓реЙрдЧ рдмрдВрдж рд╣реЛрдиреЗ рдкрд░ рдкреНрд▓реЗрдмреИрдХ рдХреЛ рд░реЛрдХрдиреЗ рдХреЗ рд▓рд┐рдП onPause рд╡рд┐рдзрд┐ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ:


 override fun onPause() { super.onPause() playingRingtone?.stop() } 

рдЦреИрд░, рд╡рд╣ рд╕рдм рдЬреЛ рдореБрдЦреНрдп рд╕реНрдХреНрд░реАрди рдкрд░ рдмрдЯрди рдХреЛ рд░рд┐рдВрдЧрдЯреЛрди рдХреЗ рд▓рд┐рдП рд╕рдВрд▓рдЧреНрди рдХрд░рдирд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрд╕ рддрд░рд╣:


 findViewById<Button>(R.id.playRingtone).setOnClickListener { val ringtone = PreferenceManager.getDefaultSharedPreferences(this) .getString("ringtone", null) ?.let { RingtoneManager.getRingtone(this, Uri.parse(it)) } if (ringtone == null) { Toast.makeText(this, "Select ringtone in settings", Toast.LENGTH_SHORT).show() } else { ringtone.play() } } 

рд╡рд╣ рд╕рдм рд╣реИред рдЬреИрд╕рд╛ рдХрд┐ рд╡рд╛рджрд╛ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдпрд╣рд╛рдВ рд╕реНрд░реЛрдд рдХреЛрдб рд▓рд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ред

Source: https://habr.com/ru/post/hi417883/


All Articles