Getting concurrent multiple api calls hits to the backend server in redux saga with apisauce












0















We are using ignite boilerplate and apisuace for my application. There is a weird problem where some of the POST api's are hitting multiple times to the backend server which chokes the server and makes the server down. Has anyone faced this problem?



Backend server gets more than 500 concurrent requests within a second. And this behavior intermittent.



indexsaga.js



import { takeLatest, takeEvery } from "redux-saga/effects";
import API from "../Services/Api";
import FixtureAPI from "../Services/FixtureApi";
/* ------------- Types ------------- */
import { LoginTypes } from "../Redux/LoginRedux";


/* ------------- Sagas ------------- */

import {
loginWithOther,
} from "./LoginSaga";

/* ------------- API ------------- */

// The API we use is only used from Sagas, so we create it here and pass along
// to the sagas which need it.
const api = DebugConfig.useFixtures ? FixtureAPI : API.create();

/* ------------- Connect Types To Sagas ------------- */

export default function* root() {
yield [// some sagas receive extra parameters in addition to an action
takeLatest(LoginTypes.USER_REQUEST, loginWithOther, api),
];
}


LoginSaga.js



import { call, put, all, fork, select } from "redux-saga/effects";
import LoginActions from "../Redux/LoginRedux";

export function* loginWithOther(api, action) {
const { email, password, navigation } = action;
let payload = {
user_id: email,
password: password,
};
const response = yield call(api.loginWithEmail, payload);
if (response.ok) {
yield put(LoginActions.userSuccess(response));
} else {
yield put(LoginActions.userFailure());
}
} else {
yield put(LoginActions.userFailure());
}
}


Loginredux.js



import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'

/* ------------- Types and Action Creators ------------- */

const { Types, Creators } = createActions({
userRequest: ['email', 'password'],
userSuccess: ['data'],
userFailure: null
})

export const LoginTypes = Types
export default Creators

/* ------------- Initial State ------------- */

export const INITIAL_STATE = Immutable({
fetching: false,
login_error: false,
data:null
})

/* ------------- Reducers ------------- */


export const request = (state, action) => {
return state.merge({ fetching: true, login_error: false })
}

export const success = (state, action) => {
const { data } = action
return state.merge({
fetching: false,
login_error: false,
data: data
})
}

export const userFailure = (state) =>
state.merge({ fetching: false, login_error: true })



/* ------------- Hookup Reducers To Types ------------- */

export const reducer = createReducer(INITIAL_STATE, {

[Types.USER_REQUEST]: request,
[Types.USER_SUCCESS]: success,
[Types.USER_FAILURE]: userFailure
})


Api.js



// a library to wrap and simplify api calls
import apisauce from "apisauce";

const create = (baseURL = Config.API_URL) => {
// ------
// STEP 1
// ------
//
// Create and configure an apisauce-based api object.
//
const api = apisauce.create({
// base URL is read from the "constructor"
baseURL,
// here are some default headers
headers: {
"Cache-Control": "no-cache",
"Transfer-Encoding": "chunked"
// 'Content-Encoding': 'gzip'
},
// 10 second timeout...
timeout: 20000
});


const URL_STRINGS = {
LOGIN_WITH_OTHER_EMAIL: "/api/v1/login/email",
}

const loginWithEmail = obj => {
return api.post(URL_STRINGS.LOGIN_WITH_OTHER_EMAIL, obj);
};


return {
loginWithEmail,
}
};

// let's return back our create method as the default.
export default {
create
};


LoginScreen.js



import React, { Component } from 'react'
import LoginActions from '../Redux/LoginRedux'
class LoginScreen extends Component {

render(){
<View>
<Text>Login</Text>
</View>
}

onLoginClick(){
this.props.loginWithEmail("exampleemail@example.com","123456")
Ï
}
}

const mapStateToProps = (state) => {
return {
}
}

const mapDispatchToProps = (dispatch) => {
return {
loginWithEmail: (email, password) =>
dispatch(LoginActions.userRequest(email, password))
}
}

export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen)









share|improve this question

























  • Can you please update your question with you Saga implementation of watcher and worker ? and also the action you are dispatching ?

    – Suraj Malviya
    Nov 28 '18 at 6:34











  • @suraj updated with code

    – John
    Nov 28 '18 at 10:00











  • where from LoginTypes.USER_REQUEST this is being swapned ? Also, i suspect may be the root saga is not having all effect with it. I am not confirmed with that but you should give it a try by writing yield all([...]) instead of yield [... ]

    – Suraj Malviya
    Nov 28 '18 at 10:18













  • @surajmalviya I have added LoginScren.js in which I call USER_REQUEST. Did you face this multiple API hitting issue from your code ?. I just want to know if someone is also facing this kind of issue

    – John
    Nov 28 '18 at 10:52













  • I don't see anything obvious that might be causing this. Try debugging it. One gotcha: takeLatest() allows new requests while old ones are still executing. Make sure you block "Login" button when a login request is in progress, or users will click the button and make concurrent requests.

    – Andrey Moiseev
    Nov 28 '18 at 22:58
















0















We are using ignite boilerplate and apisuace for my application. There is a weird problem where some of the POST api's are hitting multiple times to the backend server which chokes the server and makes the server down. Has anyone faced this problem?



Backend server gets more than 500 concurrent requests within a second. And this behavior intermittent.



indexsaga.js



import { takeLatest, takeEvery } from "redux-saga/effects";
import API from "../Services/Api";
import FixtureAPI from "../Services/FixtureApi";
/* ------------- Types ------------- */
import { LoginTypes } from "../Redux/LoginRedux";


/* ------------- Sagas ------------- */

import {
loginWithOther,
} from "./LoginSaga";

/* ------------- API ------------- */

// The API we use is only used from Sagas, so we create it here and pass along
// to the sagas which need it.
const api = DebugConfig.useFixtures ? FixtureAPI : API.create();

/* ------------- Connect Types To Sagas ------------- */

export default function* root() {
yield [// some sagas receive extra parameters in addition to an action
takeLatest(LoginTypes.USER_REQUEST, loginWithOther, api),
];
}


LoginSaga.js



import { call, put, all, fork, select } from "redux-saga/effects";
import LoginActions from "../Redux/LoginRedux";

export function* loginWithOther(api, action) {
const { email, password, navigation } = action;
let payload = {
user_id: email,
password: password,
};
const response = yield call(api.loginWithEmail, payload);
if (response.ok) {
yield put(LoginActions.userSuccess(response));
} else {
yield put(LoginActions.userFailure());
}
} else {
yield put(LoginActions.userFailure());
}
}


Loginredux.js



import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'

/* ------------- Types and Action Creators ------------- */

const { Types, Creators } = createActions({
userRequest: ['email', 'password'],
userSuccess: ['data'],
userFailure: null
})

export const LoginTypes = Types
export default Creators

/* ------------- Initial State ------------- */

export const INITIAL_STATE = Immutable({
fetching: false,
login_error: false,
data:null
})

/* ------------- Reducers ------------- */


export const request = (state, action) => {
return state.merge({ fetching: true, login_error: false })
}

export const success = (state, action) => {
const { data } = action
return state.merge({
fetching: false,
login_error: false,
data: data
})
}

export const userFailure = (state) =>
state.merge({ fetching: false, login_error: true })



/* ------------- Hookup Reducers To Types ------------- */

export const reducer = createReducer(INITIAL_STATE, {

[Types.USER_REQUEST]: request,
[Types.USER_SUCCESS]: success,
[Types.USER_FAILURE]: userFailure
})


Api.js



// a library to wrap and simplify api calls
import apisauce from "apisauce";

const create = (baseURL = Config.API_URL) => {
// ------
// STEP 1
// ------
//
// Create and configure an apisauce-based api object.
//
const api = apisauce.create({
// base URL is read from the "constructor"
baseURL,
// here are some default headers
headers: {
"Cache-Control": "no-cache",
"Transfer-Encoding": "chunked"
// 'Content-Encoding': 'gzip'
},
// 10 second timeout...
timeout: 20000
});


const URL_STRINGS = {
LOGIN_WITH_OTHER_EMAIL: "/api/v1/login/email",
}

const loginWithEmail = obj => {
return api.post(URL_STRINGS.LOGIN_WITH_OTHER_EMAIL, obj);
};


return {
loginWithEmail,
}
};

// let's return back our create method as the default.
export default {
create
};


LoginScreen.js



import React, { Component } from 'react'
import LoginActions from '../Redux/LoginRedux'
class LoginScreen extends Component {

render(){
<View>
<Text>Login</Text>
</View>
}

onLoginClick(){
this.props.loginWithEmail("exampleemail@example.com","123456")
Ï
}
}

const mapStateToProps = (state) => {
return {
}
}

const mapDispatchToProps = (dispatch) => {
return {
loginWithEmail: (email, password) =>
dispatch(LoginActions.userRequest(email, password))
}
}

export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen)









share|improve this question

























  • Can you please update your question with you Saga implementation of watcher and worker ? and also the action you are dispatching ?

    – Suraj Malviya
    Nov 28 '18 at 6:34











  • @suraj updated with code

    – John
    Nov 28 '18 at 10:00











  • where from LoginTypes.USER_REQUEST this is being swapned ? Also, i suspect may be the root saga is not having all effect with it. I am not confirmed with that but you should give it a try by writing yield all([...]) instead of yield [... ]

    – Suraj Malviya
    Nov 28 '18 at 10:18













  • @surajmalviya I have added LoginScren.js in which I call USER_REQUEST. Did you face this multiple API hitting issue from your code ?. I just want to know if someone is also facing this kind of issue

    – John
    Nov 28 '18 at 10:52













  • I don't see anything obvious that might be causing this. Try debugging it. One gotcha: takeLatest() allows new requests while old ones are still executing. Make sure you block "Login" button when a login request is in progress, or users will click the button and make concurrent requests.

    – Andrey Moiseev
    Nov 28 '18 at 22:58














0












0








0








We are using ignite boilerplate and apisuace for my application. There is a weird problem where some of the POST api's are hitting multiple times to the backend server which chokes the server and makes the server down. Has anyone faced this problem?



Backend server gets more than 500 concurrent requests within a second. And this behavior intermittent.



indexsaga.js



import { takeLatest, takeEvery } from "redux-saga/effects";
import API from "../Services/Api";
import FixtureAPI from "../Services/FixtureApi";
/* ------------- Types ------------- */
import { LoginTypes } from "../Redux/LoginRedux";


/* ------------- Sagas ------------- */

import {
loginWithOther,
} from "./LoginSaga";

/* ------------- API ------------- */

// The API we use is only used from Sagas, so we create it here and pass along
// to the sagas which need it.
const api = DebugConfig.useFixtures ? FixtureAPI : API.create();

/* ------------- Connect Types To Sagas ------------- */

export default function* root() {
yield [// some sagas receive extra parameters in addition to an action
takeLatest(LoginTypes.USER_REQUEST, loginWithOther, api),
];
}


LoginSaga.js



import { call, put, all, fork, select } from "redux-saga/effects";
import LoginActions from "../Redux/LoginRedux";

export function* loginWithOther(api, action) {
const { email, password, navigation } = action;
let payload = {
user_id: email,
password: password,
};
const response = yield call(api.loginWithEmail, payload);
if (response.ok) {
yield put(LoginActions.userSuccess(response));
} else {
yield put(LoginActions.userFailure());
}
} else {
yield put(LoginActions.userFailure());
}
}


Loginredux.js



import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'

/* ------------- Types and Action Creators ------------- */

const { Types, Creators } = createActions({
userRequest: ['email', 'password'],
userSuccess: ['data'],
userFailure: null
})

export const LoginTypes = Types
export default Creators

/* ------------- Initial State ------------- */

export const INITIAL_STATE = Immutable({
fetching: false,
login_error: false,
data:null
})

/* ------------- Reducers ------------- */


export const request = (state, action) => {
return state.merge({ fetching: true, login_error: false })
}

export const success = (state, action) => {
const { data } = action
return state.merge({
fetching: false,
login_error: false,
data: data
})
}

export const userFailure = (state) =>
state.merge({ fetching: false, login_error: true })



/* ------------- Hookup Reducers To Types ------------- */

export const reducer = createReducer(INITIAL_STATE, {

[Types.USER_REQUEST]: request,
[Types.USER_SUCCESS]: success,
[Types.USER_FAILURE]: userFailure
})


Api.js



// a library to wrap and simplify api calls
import apisauce from "apisauce";

const create = (baseURL = Config.API_URL) => {
// ------
// STEP 1
// ------
//
// Create and configure an apisauce-based api object.
//
const api = apisauce.create({
// base URL is read from the "constructor"
baseURL,
// here are some default headers
headers: {
"Cache-Control": "no-cache",
"Transfer-Encoding": "chunked"
// 'Content-Encoding': 'gzip'
},
// 10 second timeout...
timeout: 20000
});


const URL_STRINGS = {
LOGIN_WITH_OTHER_EMAIL: "/api/v1/login/email",
}

const loginWithEmail = obj => {
return api.post(URL_STRINGS.LOGIN_WITH_OTHER_EMAIL, obj);
};


return {
loginWithEmail,
}
};

// let's return back our create method as the default.
export default {
create
};


LoginScreen.js



import React, { Component } from 'react'
import LoginActions from '../Redux/LoginRedux'
class LoginScreen extends Component {

render(){
<View>
<Text>Login</Text>
</View>
}

onLoginClick(){
this.props.loginWithEmail("exampleemail@example.com","123456")
Ï
}
}

const mapStateToProps = (state) => {
return {
}
}

const mapDispatchToProps = (dispatch) => {
return {
loginWithEmail: (email, password) =>
dispatch(LoginActions.userRequest(email, password))
}
}

export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen)









share|improve this question
















We are using ignite boilerplate and apisuace for my application. There is a weird problem where some of the POST api's are hitting multiple times to the backend server which chokes the server and makes the server down. Has anyone faced this problem?



Backend server gets more than 500 concurrent requests within a second. And this behavior intermittent.



indexsaga.js



import { takeLatest, takeEvery } from "redux-saga/effects";
import API from "../Services/Api";
import FixtureAPI from "../Services/FixtureApi";
/* ------------- Types ------------- */
import { LoginTypes } from "../Redux/LoginRedux";


/* ------------- Sagas ------------- */

import {
loginWithOther,
} from "./LoginSaga";

/* ------------- API ------------- */

// The API we use is only used from Sagas, so we create it here and pass along
// to the sagas which need it.
const api = DebugConfig.useFixtures ? FixtureAPI : API.create();

/* ------------- Connect Types To Sagas ------------- */

export default function* root() {
yield [// some sagas receive extra parameters in addition to an action
takeLatest(LoginTypes.USER_REQUEST, loginWithOther, api),
];
}


LoginSaga.js



import { call, put, all, fork, select } from "redux-saga/effects";
import LoginActions from "../Redux/LoginRedux";

export function* loginWithOther(api, action) {
const { email, password, navigation } = action;
let payload = {
user_id: email,
password: password,
};
const response = yield call(api.loginWithEmail, payload);
if (response.ok) {
yield put(LoginActions.userSuccess(response));
} else {
yield put(LoginActions.userFailure());
}
} else {
yield put(LoginActions.userFailure());
}
}


Loginredux.js



import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'

/* ------------- Types and Action Creators ------------- */

const { Types, Creators } = createActions({
userRequest: ['email', 'password'],
userSuccess: ['data'],
userFailure: null
})

export const LoginTypes = Types
export default Creators

/* ------------- Initial State ------------- */

export const INITIAL_STATE = Immutable({
fetching: false,
login_error: false,
data:null
})

/* ------------- Reducers ------------- */


export const request = (state, action) => {
return state.merge({ fetching: true, login_error: false })
}

export const success = (state, action) => {
const { data } = action
return state.merge({
fetching: false,
login_error: false,
data: data
})
}

export const userFailure = (state) =>
state.merge({ fetching: false, login_error: true })



/* ------------- Hookup Reducers To Types ------------- */

export const reducer = createReducer(INITIAL_STATE, {

[Types.USER_REQUEST]: request,
[Types.USER_SUCCESS]: success,
[Types.USER_FAILURE]: userFailure
})


Api.js



// a library to wrap and simplify api calls
import apisauce from "apisauce";

const create = (baseURL = Config.API_URL) => {
// ------
// STEP 1
// ------
//
// Create and configure an apisauce-based api object.
//
const api = apisauce.create({
// base URL is read from the "constructor"
baseURL,
// here are some default headers
headers: {
"Cache-Control": "no-cache",
"Transfer-Encoding": "chunked"
// 'Content-Encoding': 'gzip'
},
// 10 second timeout...
timeout: 20000
});


const URL_STRINGS = {
LOGIN_WITH_OTHER_EMAIL: "/api/v1/login/email",
}

const loginWithEmail = obj => {
return api.post(URL_STRINGS.LOGIN_WITH_OTHER_EMAIL, obj);
};


return {
loginWithEmail,
}
};

// let's return back our create method as the default.
export default {
create
};


LoginScreen.js



import React, { Component } from 'react'
import LoginActions from '../Redux/LoginRedux'
class LoginScreen extends Component {

render(){
<View>
<Text>Login</Text>
</View>
}

onLoginClick(){
this.props.loginWithEmail("exampleemail@example.com","123456")
Ï
}
}

const mapStateToProps = (state) => {
return {
}
}

const mapDispatchToProps = (dispatch) => {
return {
loginWithEmail: (email, password) =>
dispatch(LoginActions.userRequest(email, password))
}
}

export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen)






react-native redux axios redux-saga






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 28 '18 at 10:51







John

















asked Nov 28 '18 at 6:24









JohnJohn

6,11043667




6,11043667













  • Can you please update your question with you Saga implementation of watcher and worker ? and also the action you are dispatching ?

    – Suraj Malviya
    Nov 28 '18 at 6:34











  • @suraj updated with code

    – John
    Nov 28 '18 at 10:00











  • where from LoginTypes.USER_REQUEST this is being swapned ? Also, i suspect may be the root saga is not having all effect with it. I am not confirmed with that but you should give it a try by writing yield all([...]) instead of yield [... ]

    – Suraj Malviya
    Nov 28 '18 at 10:18













  • @surajmalviya I have added LoginScren.js in which I call USER_REQUEST. Did you face this multiple API hitting issue from your code ?. I just want to know if someone is also facing this kind of issue

    – John
    Nov 28 '18 at 10:52













  • I don't see anything obvious that might be causing this. Try debugging it. One gotcha: takeLatest() allows new requests while old ones are still executing. Make sure you block "Login" button when a login request is in progress, or users will click the button and make concurrent requests.

    – Andrey Moiseev
    Nov 28 '18 at 22:58



















  • Can you please update your question with you Saga implementation of watcher and worker ? and also the action you are dispatching ?

    – Suraj Malviya
    Nov 28 '18 at 6:34











  • @suraj updated with code

    – John
    Nov 28 '18 at 10:00











  • where from LoginTypes.USER_REQUEST this is being swapned ? Also, i suspect may be the root saga is not having all effect with it. I am not confirmed with that but you should give it a try by writing yield all([...]) instead of yield [... ]

    – Suraj Malviya
    Nov 28 '18 at 10:18













  • @surajmalviya I have added LoginScren.js in which I call USER_REQUEST. Did you face this multiple API hitting issue from your code ?. I just want to know if someone is also facing this kind of issue

    – John
    Nov 28 '18 at 10:52













  • I don't see anything obvious that might be causing this. Try debugging it. One gotcha: takeLatest() allows new requests while old ones are still executing. Make sure you block "Login" button when a login request is in progress, or users will click the button and make concurrent requests.

    – Andrey Moiseev
    Nov 28 '18 at 22:58

















Can you please update your question with you Saga implementation of watcher and worker ? and also the action you are dispatching ?

– Suraj Malviya
Nov 28 '18 at 6:34





Can you please update your question with you Saga implementation of watcher and worker ? and also the action you are dispatching ?

– Suraj Malviya
Nov 28 '18 at 6:34













@suraj updated with code

– John
Nov 28 '18 at 10:00





@suraj updated with code

– John
Nov 28 '18 at 10:00













where from LoginTypes.USER_REQUEST this is being swapned ? Also, i suspect may be the root saga is not having all effect with it. I am not confirmed with that but you should give it a try by writing yield all([...]) instead of yield [... ]

– Suraj Malviya
Nov 28 '18 at 10:18







where from LoginTypes.USER_REQUEST this is being swapned ? Also, i suspect may be the root saga is not having all effect with it. I am not confirmed with that but you should give it a try by writing yield all([...]) instead of yield [... ]

– Suraj Malviya
Nov 28 '18 at 10:18















@surajmalviya I have added LoginScren.js in which I call USER_REQUEST. Did you face this multiple API hitting issue from your code ?. I just want to know if someone is also facing this kind of issue

– John
Nov 28 '18 at 10:52







@surajmalviya I have added LoginScren.js in which I call USER_REQUEST. Did you face this multiple API hitting issue from your code ?. I just want to know if someone is also facing this kind of issue

– John
Nov 28 '18 at 10:52















I don't see anything obvious that might be causing this. Try debugging it. One gotcha: takeLatest() allows new requests while old ones are still executing. Make sure you block "Login" button when a login request is in progress, or users will click the button and make concurrent requests.

– Andrey Moiseev
Nov 28 '18 at 22:58





I don't see anything obvious that might be causing this. Try debugging it. One gotcha: takeLatest() allows new requests while old ones are still executing. Make sure you block "Login" button when a login request is in progress, or users will click the button and make concurrent requests.

– Andrey Moiseev
Nov 28 '18 at 22:58












0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53513337%2fgetting-concurrent-multiple-api-calls-hits-to-the-backend-server-in-redux-saga-w%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53513337%2fgetting-concurrent-multiple-api-calls-hits-to-the-backend-server-in-redux-saga-w%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

Calculate evaluation metrics using cross_val_predict sklearn

Insert data from modal to MySQL (multiple modal on website)