Выход из системы Google и отключение не работают, а также не работает интеграция входа в facebook - PullRequest
1 голос
/ 20 июня 2020

Я создаю простое приложение, когда я вхожу в систему через Google или Facebook из LoginActivity, приложение должно начать новое действие и сохранить данные для входа в систему на будущее, чтобы пользователю не приходилось в следующий раз входить в систему с той же учетной записью.

Я создал пользовательскую кнопку для входа в Facebook и Google, но вход в Facebook не работает, и как только я вошел в систему с учетной записью Google, а затем выйду из MainActivity, метод выхода из Google не работает и снова перейти к MainActivity без запроса входа.

Я также добавил кнопку в панели навигации, которая должна выходить из системы, но учетная запись Google не отключается. Я не знаю, в чем проблема, потому что я новичок в android . поэтому, пожалуйста, помогите мне.

Вот LoginActivity. java файл

public class LoginActivity extends AppCompatActivity implements View.OnClickListener {
    
        private static final String TAG = "LoginActivity";
        MaterialTextView txtLogin, txtSignUp;
        MaterialButton btnLogin;
        FrameLayout fb, google;
        ImageView fb_icon, google_icon;
        LoginButton facebook_login_button;
        SignInButton google_signIn_button;
        GoogleSignInClient mGoogleSignInClient;
    
        SharedPreferences newsharedPreferences;
    
        public ConstraintLayout LoginLayout;
    
        public int RC_SIGN_IN = 1001;
    
        public String FBemail, FBfirstname, FBlastname, FBid, FBprofile_pic_url;
    
    
        CallbackManager callbackManager;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
    
    
            txtLogin = findViewById(R.id.txtLogin);
            txtSignUp = findViewById(R.id.txtSignUp);
            fb = findViewById(R.id.fb);
            google = findViewById(R.id.g);
            fb_icon = findViewById(R.id.fb_icon);
            google_icon = findViewById(R.id.google_icon);
            facebook_login_button = findViewById(R.id.facebook_login_button);
            google_signIn_button = findViewById(R.id.google_signIn_button);
            LoginLayout = (ConstraintLayout) findViewById(R.id.LoginLayout);
    
    
            //Google login
    
            GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                    .requestEmail()
                    .build();
    
    
            mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
    
            newsharedPreferences = getSharedPreferences("UserData", MODE_PRIVATE);
    
    
            callbackManager = CallbackManager.Factory.create();
    
            txtLogin.setOnClickListener(this);
            txtSignUp.setOnClickListener(this);
            facebook_login_button.setOnClickListener(this);
            google_signIn_button.setOnClickListener(this);
            fb_icon.setOnClickListener(this);
            google_icon.setOnClickListener(this);
    
    
    
    
        }
    
        @Override
        public void onClick(View v) {
    
            switch (v.getId())
            {
    
            case R.id.txtSignUp:
    
            txtanimation();
            break;
    
    
            case R.id.fb_icon:
                if(v == fb_icon)
                    {
                        facebook_login_button.performClick();
                    }
    
                facebook_login_button.setReadPermissions(Arrays.asList("email", "public_profile"));
                facebook_login_button.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
                @Override
                public void onSuccess(final LoginResult loginResult) {
    
                    String accessToken = loginResult.getAccessToken().getToken();
                    Log.i("accessToken", accessToken);
    
    
                    GraphRequest request = GraphRequest.newMeRequest(loginResult.getAccessToken(), new GraphRequest.GraphJSONObjectCallback() {
                        @Override
                        public void onCompleted(JSONObject object, GraphResponse response) {
    
                            String accessToken = loginResult.getAccessToken().getToken();
                            Log.i("accessToken", accessToken);
    
                            try {
                                FBfirstname = object.getString("first_name");
                                FBlastname = object.getString("last_name");
                                FBemail = object.getString("email");
                                FBid = object.getString("id");
    
                                FBprofile_pic_url = "https://graph.facebook.com/" + FBid + "/picture?type=normal";
    
    
                                SharedPreferences.Editor editor = newsharedPreferences.edit();
    
                                editor.putString("ProfileName", FBfirstname + FBlastname);
                                editor.putString("ProfileEmail", FBemail);
                                editor.putString("ProfilePhoto", FBprofile_pic_url);
                                editor.apply();
                                editor.commit();
    
                                startActivity(new Intent(LoginActivity.this, MainActivity.class));
    
                                Log.i("OnCompelete", FBfirstname);
    
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
    
    
                        }
                    });
    
                    Bundle parameteres = new Bundle();
                    parameteres.putString("Fields", "id, first_name, last_name, public_profile, email");
                    request.setParameters(parameteres);
                    request.executeAsync();
    
    
                }
    
                @Override
                public void onCancel() {
    
                }
    
                @Override
                public void onError(FacebookException error) {
    
                }
            });
    
            break;
    
    
            case R.id.google_icon:
                if(v == google_icon)
                    {
                        google_signIn_button.performClick();
                    }
            Intent signInIntent = mGoogleSignInClient.getSignInIntent();
            startActivityForResult(signInIntent, RC_SIGN_IN);
            break;
    
    
            case R.id.btnLogin:
            break;
        }
    
        }
        
        //Check for the last signed in account when activity starts.
    
        @Override
        protected void onStart () {
            super.onStart();
    
            GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
            Log.i("googleAccount", String.valueOf(account));
            updateUI(account);
        }
    
    
        //for sign out from google.
        public void googleSignOUT () {
    
    
            mGoogleSignInClient.signOut()
                    .addOnCompleteListener(this, new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {
                            // ...
                        }
                    });
            }
            
            // for disconnect the google account from the app.
    
        public void revokeAccess() {
            mGoogleSignInClient.revokeAccess()
                    .addOnCompleteListener(this, new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {
                            // ...
                        }
                    });
        }
    
           
        // App ui will change upon the if the user logged in or not
    
            private void updateUI (GoogleSignInAccount account){
    
                if (account != null) {
                    Toast.makeText(this, "User already logged in ", LENGTH_LONG).show();
    
    
                    String ACName = account.getDisplayName();
                    String personEmail = account.getEmail();
                    Uri personPhoto = account.getPhotoUrl();
    
                    Log.i("gphoto", String.valueOf(personPhoto));
    
    
                    SharedPreferences.Editor editor = newsharedPreferences.edit();
    
                    editor.putString("ProfileName", ACName);
                    editor.putString("ProfileEmail", personEmail);
                    editor.putString("ProfilePhoto", String.valueOf(personPhoto));
                    editor.apply();
                    editor.commit();
    
                   startActivity(new Intent(LoginActivity.this, MainActivity.class));
                }
                else
                {
                    Toast.makeText(this, "User not logged in Please log in first", LENGTH_LONG).show();
                    revokeAccess();
                }
    
            }
    
    
    
            @Override
            protected void onActivityResult ( int requestCode, int resultCode, @Nullable Intent data){
    
                //facebook login
                callbackManager.onActivityResult(requestCode, resultCode, data);
                super.onActivityResult(requestCode, resultCode, data);
    
                //Google Sign in
                if (requestCode == RC_SIGN_IN) {
                    Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
                    handleSignInResult(task);
                }
            }
    
            private void handleSignInResult (Task < GoogleSignInAccount > task) {
    
    
                try {
                    GoogleSignInAccount account = task.getResult(ApiException.class);
    
                    updateUI(account);
                } catch (ApiException e) {
                    e.printStackTrace();
    
                    new MaterialAlertDialogBuilder(this).setTitle("Sign In Error")
                            .setMessage(e.getStatusCode() + "\n" + GoogleSignInStatusCodes.getStatusCodeString(e.getStatusCode()))
                            .setPositiveButton("Retry", null)
                            .show();
    
                    Log.i("FailedCode", "SignInResulte- Failed Code" + e.getStatusCode());
                    Log.i("StatusMessage", "SignInFailed--Reason" + e.getStatusMessage());
                }
    
            }
    
            private void txtanimation () {
    
                Animation animation = AnimationUtils.loadAnimation(this, R.anim.txtanimation);
                txtSignUp.setTextSize(36);
                txtSignUp.setTextColor(Color.parseColor("#FFFCFF"));
    
                //to change the margin
                ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) txtSignUp.getLayoutParams();
                params.setMargins(100, 15, 0, 0);
                txtSignUp.setLayoutParams(params);
    
                txtSignUp.startAnimation(animation);
    
                txtLogin.setTextSize(26);
                txtLogin.setTextColor(Color.parseColor("#645853"));
                ConstraintLayout.LayoutParams secondparams = (ConstraintLayout.LayoutParams) txtLogin.getLayoutParams();
                params.setMargins(200, 5, 0, 0);
                txtLogin.setLayoutParams(secondparams);
    
                startActivity(new Intent(LoginActivity.this, RegisterActivity.class));
            }
        }

Вот login_activity. XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".LoginActivity"
    android:background="@color/mattBlackone"
    android:id="@+id/LoginLayout">


    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/txtLogin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:text="Login"
        app:textAllCaps="false"
        android:textColor="@color/Snow"
        android:textSize="35sp"
        android:fontFamily="@font/roboto_regular"
        android:layout_marginTop="10dp"
        android:layout_marginRight="200dp"
        android:elevation="10dp"
        android:shadowColor="@color/SnowShadow"
        android:clickable="true"/>


    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/txtSignUp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="@+id/txtLogin"
        android:text="Sign Up"
        android:textSize="26sp"
        app:textAllCaps="false"
        android:textColor="@color/Umber"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="100dp"
        android:fontFamily="@font/roboto_regular"
        android:elevation="10dp"
        android:shadowColor="@color/SnowShadow"
        android:clickable="true"/>



    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/loginId"
        android:layout_width="300dp"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:boxStrokeColor="@color/Nblue"
        android:layout_marginTop="200dp"
        app:boxStrokeWidth="2dp"
        android:elevation="10dp"
        app:hintTextColor="@color/Nblue">

        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:inputType="text"
            android:maxLines="1"
            android:hint="Email ID"
            android:imeOptions="actionNext"/>
    </com.google.android.material.textfield.TextInputLayout>


    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/loginPassword"
        android:layout_width="300dp"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:boxStrokeColor="@color/Nblue"
        android:layout_marginTop="300dp"
        app:boxStrokeWidth="2dp"
        app:endIconMode="password_toggle"
        app:hintTextColor="@color/Nblue"
        >

    <com.google.android.material.textfield.TextInputEditText
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:inputType="text"
        android:maxLines="1"
        android:hint="Password"
        android:imeOptions="actionNext"
        />

    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/txtForgatPassword"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Forgate Password ?"
        android:textSize="16sp"
        android:textColor="@color/Umber"
        app:textAllCaps="false"
        android:fontFamily="@font/roboto_regular"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="@id/btnLogin"
        app:layout_constraintTop_toBottomOf="@id/loginPassword"
        android:layout_marginLeft="155dp"
        android:layout_marginBottom="10dp"
        android:clickable="true"/>



    <com.google.android.material.button.MaterialButton
        android:id="@+id/btnLogin"
        style="@style/Widget.MaterialComponents.Button.OutlinedButton"
        android:layout_width="250dp"
        android:layout_height="50dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/loginPassword"
        app:strokeColor="@color/Nblue"
        app:strokeWidth="1dp"
        android:text="Login"
        android:textSize="22sp"
        android:textColor="@color/Snow"
        android:elevation="10dp"
        app:cornerRadius="12dp"
        android:fontFamily="@font/roboto_light"
        android:textAllCaps="false"
        android:layout_marginTop="60dp"
        app:rippleColor="@color/Nblue"
        android:shadowColor="@color/SnowShadow"/>


    <FrameLayout
        android:id="@+id/fb"
        android:layout_width="50dp"
        android:layout_height="50dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginRight="200dp"
        android:layout_marginBottom="100dp">

        <com.facebook.login.widget.LoginButton
            android:id="@+id/facebook_login_button"
            android:layout_width="250dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginBottom="40dp"
            android:visibility="gone"/>

        <ImageView
            android:id="@+id/fb_icon"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/facebook_icon"
            android:layout_gravity="center"
            android:clickable="true"/>

    </FrameLayout>

    <FrameLayout
        android:id="@+id/g"
        android:layout_width="50dp"
        android:layout_height="50dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginBottom="100dp"
        android:layout_marginStart="200dp"
        android:clickable="true">

        <com.google.android.gms.common.SignInButton
            android:id="@+id/google_signIn_button"
            android:layout_width="250dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:visibility="gone"
            android:layout_marginBottom="60dp"/>

        <ImageView
            android:id="@+id/google_icon"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/google_icon"
            android:layout_gravity="center"
            android:clickable="true"/>

    </FrameLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Вот MainActivity . java файл, в котором я выполняю процесс выхода

 public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {


    private AppBarConfiguration mAppBarConfiguration;
    DrawerLayout drawerLayout;

    TextView upperText, LowerText;
    ImageView profile_imageView;
    SharedPreferences mysharedPreferences;

    MaterialButton btn_sign_out;
    String Name, Email, Photo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        FloatingActionButton fab = findViewById(R.id.fab);


        //To set the porfile information in the header of the navigation drawer

        mysharedPreferences = getSharedPreferences("UserData", MODE_PRIVATE);



        View header = ((NavigationView)findViewById(R.id.nav_view)).getHeaderView(0);

        btn_sign_out =  findViewById(R.id.btn_log_out);
        upperText = header.findViewById(R.id.upperText);
        LowerText = header.findViewById(R.id.LowerText);
        profile_imageView = header.findViewById(R.id.profile_imageView);


        Name = mysharedPreferences.getString("ProfileName", Name);
        Email = mysharedPreferences.getString("ProfileEmail", Email);
        Photo = mysharedPreferences.getString("ProfilePhoto", Photo);

        Log.i("profile" ,Name);
        Log.i("profileEmail" ,Email);
        Log.i("profilePhoto" ,Photo);

        upperText.setText(Name);
        LowerText.setText(Email);
        Glide.with(header).load(Photo).into(profile_imageView);

        btn_sign_out.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LoginActivity loginActivity = new LoginActivity();
                loginActivity.googleSignOUT();
                loginActivity.revokeAccess();
                startActivity(new Intent(MainActivity.this, LoginActivity.class));
                finish();
            }
        });

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });


        drawerLayout = findViewById(R.id.drawer_layout);

        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this,
                drawerLayout, toolbar, R.string.nav_app_bar_open_drawer_description,
                R.string.navigation_drawer_close);

        NavigationView navigationView = findViewById(R.id.nav_view);

        drawerLayout.addDrawerListener(toggle);
        toggle.syncState();

        navigationView.setNavigationItemSelectedListener(this);

        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.


        mAppBarConfiguration = new AppBarConfiguration.Builder(
                R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow,
                R.id.nav_tools, R.id.nav_share, R.id.nav_send)
                .setDrawerLayout(drawerLayout)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
        NavigationUI.setupWithNavController(navigationView, navController);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        return NavigationUI.navigateUp(navController, mAppBarConfiguration)
                || super.onSupportNavigateUp();
    }

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {

        switch(item.getItemId())
        {
            case R.id.nav_log_out:

                break;
        }

        return true;
    }
}

Здесь находится activity_main. xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        style="@style/Widget.Custom.NavigationView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer">


        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:layout_marginBottom="30dp">

            <com.google.android.material.button.MaterialButton
                android:id="@+id/btn_log_out"
                android:layout_width="250dp"
                android:layout_height="50dp"
                style="@style/Widget.MaterialComponents.Button.OutlinedButton"
                android:text="Sign Out"
                android:textColor="@color/Snow"
                android:textSize="18sp"
                android:textAllCaps="false"
                app:strokeColor="@color/Dwhite"
                app:strokeWidth="1dp"
                app:cornerRadius="12dp"/>
        </LinearLayout>
    </com.google.android.material.navigation.NavigationView>

</androidx.drawerlayout.widget.DrawerLayout>

Вот Manifest. XML file

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.akapplicationsinc.nillu_hair_saloon">

<uses-permission android:name="android.permission.INTERNET"/>
<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <meta-data android:name="com.facebook.sdk.ApplicationId"
            android:value="@string/facebook_app_id"/>

        <activity android:name="com.facebook.FacebookActivity"
            android:configChanges=
                "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name" />
        <activity
            android:name="com.facebook.CustomTabActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>
        <activity android:name=".SplashActivity">
        </activity>
        <activity android:name=".RegisterActivity" />
        <activity android:name=".MainActivity" />
        <activity
            android:name=".LoginActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Может ли кто-нибудь сказать мне, как выполнить оба выхода (Facebook и Google) с помощью одного элемента или кнопки в панели навигации. Ваши знания научат меня новым вещам, и я буду восхищаться вашей помощью.

1 Ответ

1 голос
/ 20 июня 2020

Попробуйте выйти, используя этот код

btn_sign_out.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                GoogleSignIn.getClient(
                        getContext(),
                        new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).build()
                ).signOut();
                    LoginManager.getInstance().logOut();
                startActivity(new Intent(MainActivity.this, LoginActivity.class));            }
        });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...