Axios: рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдкреИрд░рд╛рдореАрдЯрд░ рдЬреЛрдбрд╝рдирд╛

рдХреЛ рдирд┐рд░реНрдорд┐рдд 27 рдирд╡ре░ 2015  ┬╖  23рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: axios/axios

рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рдПрдкреАрдЖрдИ рд╣реИ рдЬреЛ рд╕рдордп-рд╕рдордп рдкрд░ ECONNRESET рд▓реМрдЯрд╛рддреА рд╣реИред рддреЛ рдореИрдВ рдРрд╕реА рддреНрд░реБрдЯрд┐ рдкрд░ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдХреНрдпрд╛ рдЖрдкрдХреА рдЗрд╕ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ retry рд╕реБрд╡рд┐рдзрд╛ рдЬреЛрдбрд╝рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рд╣реИ?

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

@mericsson рдореБрдЭреЗ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╕рдордп рдШрд╛рддреАрдп

axios.interceptors.response.use(undefined, function axiosRetryInterceptor(err) {
    var config = err.config;
    // If config does not exist or the retry option is not set, reject
    if(!config || !config.retry) return Promise.reject(err);

    // Set the variable for keeping track of the retry count
    config.__retryCount = config.__retryCount || 0;

    // Check if we've maxed out the total number of retries
    if(config.__retryCount >= config.retry) {
        // Reject with the error
        return Promise.reject(err);
    }

    // Increase the retry count
    config.__retryCount += 1;

    // Create new promise to handle exponential backoff
    var backoff = new Promise(function(resolve) {
        setTimeout(function() {
            resolve();
        }, config.retryDelay || 1);
    });

    // Return the promise in which recalls axios to retry the request
    return backoff.then(function() {
        return axios(config);
    });
});

рдХрд╛рдо рдореЗрдВ рд▓рд╛рдирд╛:

axios.get('/some/endpoint', { retry: 5, retryDelay: 1000 })
    .then(function(res) {
        console.log('success', res.data);
    })
    .catch(function(err) {
        console.log('failed', err);
    });

рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╡рд┐рдХрд▓реНрдк:
retry - рдкрд╣рд▓реЗ рдЕрд╕рдлрд▓ рдЕрдиреБрд░реЛрдз рдХреЗ рдмрд╛рдж рдЕрдиреБрд░реЛрдз рдХреЛ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рдХреА рд╕рдВрдЦреНрдпрд╛ред
retryDelay - рд╡рд┐рдлрд▓ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдмреАрдЪ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдорд┐рд▓реАрд╕реЗрдХрдВрдб рдХреА рд╕рдВрдЦреНрдпрд╛ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ 1 рд╣реИ)ред

рдореИрдВ рдЗрд╕реЗ рдХрд┐рд╕реА рдмрд┐рдВрджреБ рдкрд░ рдПрдХ рд╕рд╛рд░ рдореЗрдВ рдереЛрдбрд╝рд╛ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рдиреНрдпрд╛рд╕ рдпреЛрдЧреНрдп рдмрдирд╛ рд╕рдХрддрд╛ рд╣реВрдВред

рд╕рднреА 23 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдЗрд╕ рдкрд░ рдХрд┐рд╕реА рднреА рдЕрджреНрдпрддрди?

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

рдореБрдЭреЗ рдирд╣реАрдВ рд▓рдЧрддрд╛ рдХрд┐ рдЗрд╕ рддрд░рд╣ рдХреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдЗрд╕ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред рдЕрдЧрд░ рдЖрдкрдХреЛ рдЗрд╕рдХреА рдЬрд░реВрд░рдд рд╣реИ рддреЛ рдЖрдк рдЗрд╕рдХреЗ рд▓рд┐рдП рдЗрдВрдЯрд░рд╕реЗрдкреНрдЯрд░ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред

@jtangellder рдХреЛрдИ рд╡рд┐рдЪрд╛рд░ рдпрд╣ рдХреИрд╕рд╛ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП?

function retryFailedRequest (err) {
  if (err.status === 500 && err.config && !err.config.__isRetryRequest) {
    err.config.__isRetryRequest = true;
    return axios(err.config);
  }
  throw err;
}
axios.interceptors.response.use(undefined, retryFailedRequest);

рдХреБрдЫ рдЗрд╕ рддрд░рд╣! рдпрд╣ рдПрдХ рдмрд╛рд░ 500 рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХрд╛ рдкреБрди: рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реИред

рдореИрдВ @jtangelder рд╕реЗ рд╕рд╣рдордд

@jtangelder @mzabriskie рдзрдиреНрдпрд╡рд╛рдж! рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдХреЗ рд▓рд┐рдП рднреА рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдЙрджрд╛рд╣рд░рдг рд╣реИ

+1 рдореЗрд░реА рдЗрдЪреНрдЫрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЙрджрд╛рд╣рд░рдг рдвреВрдВрдврдирд╛ рдЖрд╕рд╛рди рд╣реЛ!

@jtangellder рд╕реНрдирд┐рдкреЗрдЯ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рдж

рд╕реНрдирд┐рдкреЗрдЯ рдкрд░ рдереЛрдбрд╝рд╛ рд╕реБрдзрд╛рд░, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд▓реМрдЯрд╛рдИ рдЧрдИ рддреНрд░реБрдЯрд┐ рд╕реНрдерд┐рддрд┐ 500 тАЛтАЛрдХреЗ рдмрдЬрд╛рдп 504 рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред

@jtangellder рдмрд╣реБрдд рдЙрдкрдпреЛрдЧреА рдЙрджрд╛рд╣рд░рдгред

рдореИрдВ рд╕реЛрдЪ рд░рд╣рд╛ рд╣реВрдВ, рдШрд╛рддреАрдп рдмреИрдХрдСрдл рдХреЗ рд╕рд╛рде рдХреБрдЫ рдХреИрд╕реЗ рдХрд░реЗрдВ рдЗрд╕ рдкрд░ рдХреЛрдИ рд╡рд┐рдЪрд╛рд░? рдХреНрдпрд╛ retryFailedRequest рд╕реЗ рдХреЛрдИ рд╡рд╛рджрд╛ рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ? рдпрд╛ рдЕрдиреНрдп рд╕реБрдЭрд╛рд╡? рдзрдиреНрдпрд╡рд╛рдж!

@jtangelder рдореЗрдВ рдЙрджрд╛рд╣рд░рдг рдХреЛ рдХреБрдХрдмреБрдХ рдкреЗрдЬ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП

рдЕрдм рдЖрдк рдЗрд╕рдХреЗ рд▓рд┐рдП axios-retry рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдореИрдВ рд╕рд╣рдордд рд╣реВрдВред рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдпрд╛ рдХрдо рд╕реЗ рдХрдо рдмреЗрд╣рддрд░ рджрд╕реНрддрд╛рд╡реЗрдЬ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред

@mericsson рдореБрдЭреЗ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╕рдордп рдШрд╛рддреАрдп

axios.interceptors.response.use(undefined, function axiosRetryInterceptor(err) {
    var config = err.config;
    // If config does not exist or the retry option is not set, reject
    if(!config || !config.retry) return Promise.reject(err);

    // Set the variable for keeping track of the retry count
    config.__retryCount = config.__retryCount || 0;

    // Check if we've maxed out the total number of retries
    if(config.__retryCount >= config.retry) {
        // Reject with the error
        return Promise.reject(err);
    }

    // Increase the retry count
    config.__retryCount += 1;

    // Create new promise to handle exponential backoff
    var backoff = new Promise(function(resolve) {
        setTimeout(function() {
            resolve();
        }, config.retryDelay || 1);
    });

    // Return the promise in which recalls axios to retry the request
    return backoff.then(function() {
        return axios(config);
    });
});

рдХрд╛рдо рдореЗрдВ рд▓рд╛рдирд╛:

axios.get('/some/endpoint', { retry: 5, retryDelay: 1000 })
    .then(function(res) {
        console.log('success', res.data);
    })
    .catch(function(err) {
        console.log('failed', err);
    });

рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╡рд┐рдХрд▓реНрдк:
retry - рдкрд╣рд▓реЗ рдЕрд╕рдлрд▓ рдЕрдиреБрд░реЛрдз рдХреЗ рдмрд╛рдж рдЕрдиреБрд░реЛрдз рдХреЛ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рдХреА рд╕рдВрдЦреНрдпрд╛ред
retryDelay - рд╡рд┐рдлрд▓ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдмреАрдЪ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдорд┐рд▓реАрд╕реЗрдХрдВрдб рдХреА рд╕рдВрдЦреНрдпрд╛ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ 1 рд╣реИ)ред

рдореИрдВ рдЗрд╕реЗ рдХрд┐рд╕реА рдмрд┐рдВрджреБ рдкрд░ рдПрдХ рд╕рд╛рд░ рдореЗрдВ рдереЛрдбрд╝рд╛ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рдиреНрдпрд╛рд╕ рдпреЛрдЧреНрдп рдмрдирд╛ рд╕рдХрддрд╛ рд╣реВрдВред

@KyleRoss рдХреЛрдб рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдореИрдВрдиреЗ рдкреБрдирд░реНрдкреНрд░рдпрд╛рд╕реЛрдВ рдХреЗ рд▓рд┐рдП рдШрд╛рддреАрдп рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдорд╛рдпреЛрдЬрди рдХрд┐рдпрд╛ рд╣реИ

// Create new promise to handle exponential backoff. formula (2^c - 1 / 2) * 1000(for mS to seconds)
    const backOffDelay = config.retryDelay 
        ? ( (1/2) * (Math.pow(2, config.__retryCount) - 1) ) * 1000
        : 1;

    const backoff = new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        },  backOffDelay);
    });

@KyleRoss рд╕рд╛рдЭрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред

рджреЗрд░реА рддреЗрдЬреА рд╕реЗ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИ:

const RETRY_TIMEOUTS = [1, 3, 5, 10]; // seconds
const delay = RETRY_TIMEOUTS[config.retryCount] * 1000;

рдпрджрд┐ рдЖрдк 4xx рдпрд╛ 5xx рдЕрдиреБрд░реЛрдз рдХрд╛ рдкреБрди: рдкреНрд░рдпрд╛рд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреИрд╕реЗ:

рдЖрдкрдХреЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд░реЛрдХрдиреЗ рдХреЗ рд▓рд┐рдП:

axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

рдЕрдкрдиреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рдЗрдВрдЯрд░рд╕реЗрдкреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП:

axios.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
  });

рд╢рд╛рдирджрд╛рд░ рд╡рд┐рдЪрд╛рд░ред рдпрджрд┐ рд▓реЛрдЧ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, рддреЛ рдореИрдВрдиреЗ рдЗрд╕реЗ npm рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рдХрд╛рдлреА рд╣рдж рддрдХ рд░реЛрд▓ рдХрд┐рдпрд╛:
https://github.com/JustinBeckwith/retry-axios

рд╕реБрд╡рд┐рдзрд╛ рдЕрдиреБрд░реЛрдз рд▓реЗрдиреЗ рдореЗрдВ рдЦреБрд╢реА рд╣реБрдИ

axios-retry рдмрдирд╛рдо retry-axios

@KyleRoss рдореИрдВрдиреЗ

@lawloretienne рдЖрдкрдХреЛ рдХрд┐рд╕реА рднреА рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдкреИрд░рд╛рдореАрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдореЗрд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдХреЛрдб рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред рдЪреВрдВрдХрд┐ рдпрд╣ рдПрдХ рдкреНрд▓рдЧрдЗрди рдХреА рддрд░рд╣ рдЕрдзрд┐рдХ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ, рдирдП рдЧреБрдгреЛрдВ рдХреЛ рд╕реНрд╡рдпрдВ рдЕрдХреНрд╖ рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд▓реЗрдЦрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

config.__retryCount = config.__retryCount || 0;

@KyleRoss config config рдкрд╛рд╕ рдХрд░рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрде, рдкреНрд░рддреНрдпреЗрдХ 'config.__reyCount' рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рд╣реИред
https://github.com/axios/axios/blob/v0.19.0/lib/core/mergeConfig.js
рдХрд╕реНрдЯрдо рдЧреБрдг рдЕрдм рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░ рджрд┐рдП рдЧрдП рд╣реИрдВред

@dennisreimann рдХрд╕реНрдЯрдо рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдЕрдм v0.19 рдореЗрдВ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдЕрдм рд╣рдо рдЗрд╕ рддрд░рд╣ рд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

axios.defaults.headers.common['retry'] = 3
axios.defaults.headers.common['retryDelay'] = 1000
axios.defaults.headers.common['retryCount'] = 0

@mericsson рдореБрдЭреЗ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╕рдордп рдШрд╛рддреАрдп

axios.interceptors.response.use(undefined, function axiosRetryInterceptor(err) {
    var config = err.config;
    // If config does not exist or the retry option is not set, reject
    if(!config || !config.retry) return Promise.reject(err);

    // Set the variable for keeping track of the retry count
    config.__retryCount = config.__retryCount || 0;

    // Check if we've maxed out the total number of retries
    if(config.__retryCount >= config.retry) {
        // Reject with the error
        return Promise.reject(err);
    }

    // Increase the retry count
    config.__retryCount += 1;

    // Create new promise to handle exponential backoff
    var backoff = new Promise(function(resolve) {
        setTimeout(function() {
            resolve();
        }, config.retryDelay || 1);
    });

    // Return the promise in which recalls axios to retry the request
    return backoff.then(function() {
        return axios(config);
    });
});

рдХрд╛рдо рдореЗрдВ рд▓рд╛рдирд╛:

axios.get('/some/endpoint', { retry: 5, retryDelay: 1000 })
    .then(function(res) {
        console.log('success', res.data);
    })
    .catch(function(err) {
        console.log('failed', err);
    });

рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╡рд┐рдХрд▓реНрдк:
retry - рдкрд╣рд▓реЗ рдЕрд╕рдлрд▓ рдЕрдиреБрд░реЛрдз рдХреЗ рдмрд╛рдж рдЕрдиреБрд░реЛрдз рдХреЛ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рдХреА рд╕рдВрдЦреНрдпрд╛ред
retryDelay - рд╡рд┐рдлрд▓ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдмреАрдЪ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдорд┐рд▓реАрд╕реЗрдХрдВрдб рдХреА рд╕рдВрдЦреНрдпрд╛ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ 1 рд╣реИ)ред

рдореИрдВ рдЗрд╕реЗ рдХрд┐рд╕реА рдмрд┐рдВрджреБ рдкрд░ рдПрдХ рд╕рд╛рд░ рдореЗрдВ рдереЛрдбрд╝рд╛ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рдиреНрдпрд╛рд╕ рдпреЛрдЧреНрдп рдмрдирд╛ рд╕рдХрддрд╛ рд╣реВрдВред

рдорджрдж рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

StefH picture StefH  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

Spartano picture Spartano  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

Adman picture Adman  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

Baoyx007 picture Baoyx007  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

ildella picture ildella  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ