Here is the format to use for the following two services of the memory manager.
ID: 3754352 • Letter: H
Question
Here is the format to use for the following two services of the memory manager. 1. Report_Jobs For each job you should report each block of memory they use. You should report the blocks in order but you do NOT have to report the jobs in order of job number. The Colum Headers should also be printed (the green below) JOB Memory Usage 1 10 – 50 54 – 75 200 – 240 5 1 – 9 101 – 134 3 180 – 184 185 – 192 2. Report_Memory This should be a sequential dump of all memory showing usage. Memory Block JOB 0 – 9 5 10 – 50 1 51 – 53 FREE 54 – 75 1 76 – 100 FREE 101 – 134 5 135 – 179 FREE 180 – 184 3 185- 192 3 193 – 199 FREE 200 – 240 1 241 – 255 FREE
#include #include // for setw() using namespace std; /******************************************* Author : Program : Memory Manager (MM3 - NO REPORTS) Due Date: Course : CSC 300 Data Structures - Fall 2018 - DSU Instr : Krebsbach ******************************************** */ // GLOBAL DATA STRUCTURES ======================= typedef struct FREE_NODE * FREEPTR; typedef struct ALLOCNODE * ALLOCPTR; struct FREE_NODE // FREE LIST NODES { int start_byte; int end_byte; int size; FREEPTR next; }; struct ALLOCNODE // ALLOCTADED LIST NODES { int start_byte; int end_byte; int size; int id; ALLOCPTR next; }; // ====== GLOBAL DATA ========================= FREEPTR freelist = NULL; // the FREE link list ALLOCPTR alloclist = NULL; // the ALLOCATED link list int total_memory_managed = 0; // the amount of memory managed //====== PROTOTYPES =========================== //--- test only --- void dump_freelist(void); void dump_alloclist(void); //--- utility --- void remove_empty_freenodes(void); void insert_freeblock(FREEPTR fptr); void merge_freenodes(void); //--- interface --- void init_memory_manager(const int amount); int allocate_memory(const int job, const int amount); void release_memory(const int job); int total_free(void); int total_allocated(void); int largest_free(void); int job_allocated(const int job); void report_memory(void); //STUB void report_jobs(void); // STUB //========== MAIN ============================= int main(void) { char ch ; // used to pause between tests int r; // results of allocate_memory // ================================================================================ cout << "====================================" << endl; cout << " AUTHOR : " << endl; cout << "====================================" << endl; cout << endl; cout << "ENTER A CHARACTER "; cin >>ch; cout << endl; //================================================================================= cout << "====================================" << endl; cout << "TEST # 1" << endl; cout << "====================================" << endl << endl; init_memory_manager(200); r = allocate_memory(1,200); cout << "allocate_memory returns : " << r << endl << endl; // ALL memory r = allocate_memory(2,30); cout << "allocate_memory returns : " << r << endl << endl; // over allocate release_memory(1); // free all memory r = allocate_memory(1,-1); cout << "allocate_memory returns : " << r << endl << endl; // try allocate -1 r = allocate_memory(3,0); cout << "allocate_memory returns : " << r << endl << endl; // allocate 0 r = allocate_memory(1,256); cout << "allocate_memory returns : " << r << endl << endl; // over allocate r = allocate_memory(1,100); cout << "allocate_memory returns : " << r << endl << endl; //Ok allocate 100 cout << "total free memory is : " << total_free() << endl; // 100 cout << "total alloc memory is : " << total_allocated() << endl; // 100 release_memory(1); //free up memory cout << endl; cout << "ENTER A CHARACTER "; cin >>ch; cout << endl; /* // ================================================================================= cout << "====================================" << endl; cout << "TEST # 2 [Deallocate several of same ] " << endl; cout << "====================================" << endl << endl; init_memory_manager(200); r = allocate_memory(1,20); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(2,30); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(1,20); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(3,30); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(1,20); cout << "allocate_memory returns : " << r << endl << endl; cout << "total free memory is : " << total_free() << endl; cout << "total alloc memory is : " << total_allocated() << endl; release_memory(1); //====================== //report_memory(); //report_jobs(); //for testing until reports done *** remove from final *** dump_freelist(); dump_alloclist(); //================================================== cout << "total free memory is : " << total_free() << endl; // 100 cout << "total alloc memory is : " << total_allocated() << endl; // 100 cout << endl; cout << "ENTER A CHARACTER "; cin >>ch; cout << endl; /* // ================================================================================= cout << "====================================" << endl; cout << "TEST # 3 BETWEEN [merge to both blocks]" << endl; cout << "====================================" << endl << endl; init_memory_manager(200); r = allocate_memory(1,25); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(2,25); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(3,25); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(4,25); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(5,25); cout << "allocate_memory returns : " << r << endl << endl; //===================== cout << "========================" << endl << endl; cout << "total free memory is : " << total_free() << endl; // 100 cout << "total alloc memory is : " << total_allocated() << endl; // 100 release_memory(1); release_memory(3); release_memory(2); //====================== //report_memory(); //report_jobs(); //for testing until reports done *** remove from final *** //dump_freelist(); //dump_alloclist(); cout << endl; cout << "ENTER A CHARACTER "; cin >>ch; cout << endl; //================================================== // ================================================================================= cout << " ====================================" << endl; cout << "TEST # 4 [Deallocate several of same make merge ] " << endl; cout << "====================================" << endl << endl; init_memory_manager(200); r = allocate_memory(1,20); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(3,20); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(1,30); cout << "allocate_memory returns : " << r << endl << endl; //(A) r = allocate_memory(4,20); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(1,20); cout << "allocate_memory returns : " << r << endl << endl; r = allocate_memory(1,20); cout << "allocate_memory returns : " << r << endl << endl; // (B) cout << "total free memory is : " << total_free() << endl; cout << "total alloc memory is : " << total_allocated() << endl; release_memory(1); // (C) //================================================== cout << " total free memory is : " << total_free() << endl; // 100 cout << "total alloc memory is : " << total_allocated() << endl; // 100 cout << endl; cout << "ENTER A CHARACTER "; cin >>ch; cout << endl; */ return 0; } //============================================== //======= INTERFACE FUNCTIONS ================== //============================================== /*============================================== void init_memory_manager (const int amount) Description: Set the initial data structures for the Memory Manager. Parameters: amount : the number of bytes to be managed Return value: NONE Notes: Should set up lists and set the total_memory_managed variable ================================================*/ void init_memory_manager (const int amount) { total_memory_managed = amount; // set up the allocation list alloclist = NULL; // set up the Free list with starting node freelist = new FREE_NODE; // freelist -> start_byte = 0; freelist -> end_byte = amount - 1; freelist -> size = amount; freelist -> next = NULL; return ; } /* ======================================== int total_free(void); Description: compute the total number of bytes not allocated Parameters: NONE Return value: the amount of total free bytes Notes: ===========================================*/ int total_free(void) { int amount = 0; FREEPTR tmp = freelist; while (tmp != NULL) { amount = amount + tmp->size; tmp = tmp->next; } return amount; // return amount of free memory } /* ======================================== int total_allocated(void); Description: compute the total number of bytes allocated Parameters: NONE Return value: the amount of total allocated bytes Notes: ===========================================*/ int total_allocated(void) { int amount = 0; ALLOCPTR tmp = alloclist; while (tmp != NULL) { amount = amount + tmp->size; tmp = tmp->next; } return amount; // return amount of allocated memory }; /* ======================================== int largest_free(void); Description: find the largest available free block of memory Parameters: NONE Return value: the amount of free memory in the block Notes: ===========================================*/ int largest_free(void) { int amount = 0; FREEPTR tmp = freelist; while (tmp != NULL) { if (tmp->size > amount) amount = tmp->size; tmp = tmp->next; } return amount; } /* ======================================== int job_allocated(const int job); Description: compute the total amount of memory allocated to a particular job. Parameters: - job : the number of the job Return value: the total amount of memory allocated to the job Notes: ===========================================*/ int job_allocated(const int job) { int amount = 0; ALLOCPTR tmp = alloclist; while (tmp != NULL) { if (tmp->id == job) amount = amount + tmp->size; tmp = tmp->next; } return amount; // return amount of allocated memory } /* ======================================== int allocate_memory(const int job, const int amount); Description: reflect allocation of memory to a particular job Parameters: - job : the id of the user (can assume positive integer value) - amount : then number of bytes asked to allocate Return value: the number of bytes actually allocated Notes: Special cases: amount <= 0 : return 0 amount > total_memory_managed : return 0 amount > largest_free( ) : return 0 ===========================================*/ int allocate_memory(const int job, const int amount) { FREEPTR tmpfree = NULL; // pointer to move through list ALLOCPTR tmpalloc = NULL; // use to point to new alloc node // check if should continue if (amount < 1) // 0 or neg value - invalid return 0; if (amount > total_memory_managed) return 0; // more then total managed if (largest_free() < amount) // no block big enough return 0; // there is a node with enough memory!!! //create alloc node to hold information tmpalloc = new ALLOCNODE; tmpalloc->next = NULL; // move to first node big enough and use it tmpfree = freelist; while (tmpfree != NULL) { if (tmpfree->size >= amount) //found node { // fill up the new alloc node tmpalloc->end_byte = tmpfree->end_byte; tmpalloc->start_byte = tmpalloc->end_byte - amount + 1; tmpalloc->size = amount; tmpalloc->id = job; //update freenode tmpfree->end_byte = tmpfree->end_byte - amount; tmpfree->size = tmpfree->size - amount; break; // exit the while loop } tmpfree = tmpfree->next; } // check for empty free node remove_empty_freenodes(); // now inset allocnode into list ------------------------ // check if alloclist is empty if (alloclist == NULL) { alloclist = tmpalloc; } else // check if insert as first node if (alloclist->start_byte > tmpalloc->start_byte) { tmpalloc->next = alloclist; alloclist = tmpalloc; } else // find where to insert in list (After first node) { ALLOCPTR t = alloclist; while (t->next != NULL) { if (t->next->start_byte > tmpalloc->start_byte) { tmpalloc->next = t->next; t->next = tmpalloc; break; } t = t->next; }//while if (t->next == NULL) t->next = tmpalloc; } return amount; // return amount allocated } /* ======================================== void release_memory(const int job); Description: reflect the deallocation of ALL memory held by a particular job Parameters: - job : the job whose memory to deallocate Return value: NONE Notes: ===========================================*/ void release_memory(const int job) { // Free all memory allocated to process ALLOCPTR a1 = alloclist; ALLOCPTR temp = NULL; FREEPTR f1 = NULL; if (a1 == NULL) return; // empty list // remove all first nodes THIS effects the alloclist pointer !!!!! while(a1 != NULL && a1->id == job) // { // set up freenode to be inserted f1 = new FREE_NODE; f1->next = NULL; f1->start_byte = a1->start_byte; f1->end_byte = a1->end_byte; f1->size = a1-> size; // INSERT f1 into FREELIST insert_freeblock(f1); f1 = NULL; // just to make sure; // clean up alloclist alloclist = a1->next; delete a1; a1 = alloclist; } // all first nodes have been deleted if (alloclist == NULL) return; // empty list while (a1->next != NULL) { while ((a1->next != NULL) && (a1->next->id == job)) { // set up freenode to be inserted f1 = new FREE_NODE; f1->next = NULL; f1->start_byte = a1->next->start_byte; f1->end_byte = a1->next->end_byte; f1->size = a1->next-> size; // INSERT f1 into free list insert_freeblock(f1); f1 =NULL; // just to make sure // clean up alloclist temp = a1->next ; a1->next = temp->next; delete temp; } if (a1->next != NULL) a1 = a1->next; } return; } /* ======================================== void report_memory(void); Description: Report the use of the continuous memory usage Parameters: NONE Return value: NONE Notes: See Report Formats 2018 document for format ===========================================*/ void report_memory(void) { // STUB ===== return; //=========== } /* ======================================== void report_jobs(void); Description: Report the memory blocks used by each job Parameters: NONE Return value: NONE Notes: See Report Formats 2018 document for format ===========================================*/ void report_jobs(void) { // STUB ===== return; //=========== } //============================================== //======= UTILITY FUNCTIONS ==================== //============================================== /* ======================================== void remove_empty_freenode(void); Description: remove all size == 0 nodes from freelist Parameters: NONE Return value: NONE Notes: supports: allocate_memory() ===========================================*/ void remove_empty_freenodes(void) { FREEPTR t1 = NULL; FREEPTR t2 = NULL; if (freelist == NULL) return; // empty list while ((freelist != NULL) && (freelist->size == 0)) // remove front nodes { t1 = freelist; freelist = freelist->next; delete t1; } if (freelist == NULL) return; // empty list t1 = freelist; // t points to first node and it is not an empty (SIZE =0) node!! while (t1!= NULL) // DOES REMOVE ALL ZERO NODES :) { if ((t1->next != NULL) && (t1->next->size == 0)) // remove the empty node { t2 = t1->next; t1->next = t2->next; //***************************** delete t2; } else // will move to next node or t1 becomes NULL t1 = t1->next; } return; } /* ======================================== void merge_freenodes(void); Description: merge any freenodes that need it Parameters: NONE Return value: NONE Notes: supports: insert_freeblock() ===========================================*/ void merge_freenodes(void) { if (freelist == NULL) //empty list return; // merge nodes FREEPTR t = freelist; FREEPTR d = NULL; while (t->next != NULL) { d = t->next; // points to next node if ((t->end_byte +1) == d->start_byte) // merge needed! { t->end_byte = d->end_byte; t->size = t->size + d->size; t->next = d->next; delete d; } else { t = t->next; } }//while return; } /* ======================================== void insert_freeblock(FREEPTR fptr); Description: place a freeblock into the freelist Parameters: - fptr : pointer to freenode to ne inserted Return value: NONE Notes: supports: release_memory() ===========================================*/ // insert freeblock (alt version) void insert_freeblock(FREEPTR fptr) { if (freelist == NULL) { freelist = fptr; return; } // handle if inserted at front of freelist; if (fptr ->start_byte < freelist->start_byte) // need to insert { //insert at front fptr->next = freelist; freelist = fptr; } else { // NOT inserting into front of list. FREEPTR t = freelist; while (t->next != NULL) { if (t->next->start_byte > fptr->start_byte) // need to insert between nodes { fptr->next = t->next; t->next = fptr; break; } t = t->next; }//while // check if needs to be inserted at end of list if (t->next == NULL) t->next = fptr; // insert end of list } // else // have inserted node now merge if needed merge_freenodes(); return; } //============================================== //======= TESTING FUNCTIONS ==================== //============================================== void dump_freelist(void) { FREEPTR tmp = freelist; // temp pointer to list cout << "==================" << endl; cout << " FREE LIST DUMP " << endl; cout << "==================" << endl; while (tmp !=NULL) { cout << tmp->start_byte << " : "; cout << tmp->end_byte << " : "; cout << tmp->size << endl; tmp = tmp->next; //move pointer to next node (or NULL) } return; } //---------------------- void dump_alloclist(void) { ALLOCPTR tmp = alloclist; // temp pointer to list cout << "========================" << endl; cout << " ALLOCATED LIST DUMP " << endl; cout << "========================" << endl; while (tmp !=NULL) { cout << tmp->start_byte << " : "; cout << tmp->end_byte << " : "; cout << tmp->size << " : "; cout << tmp->id << endl; tmp = tmp->next; //move pointer to next node (or NULL) } return; }
Explanation / Answer
//Have added codings wherever is required by using (//) symbol for explanation
#include<iostream>
#include<stdlib.h>
using namespace std;
// defining the global variable
int a=5;
int main()
{
//local variable
int a=10;
cout<<"local a: "<<a<<" Global a: "<<::a;
// Re-defining global variable by using ::
::a=15;
cout<<" local a: "<<a<<" Global a: "<<::a;
return 0;
}//declaration of global data structures
typedef struct FREE_NODE * FREEPTR;
typedef struct ALLOCNODE * ALLOCPTR;
struct FREE_NODE // FREE LIST NODES
{
int start_byte;
int end_byte;
int size; FREEPTR next;
};
struct ALLOCNODE // ALLOCTADED LIST NODES
{
int start_byte;
int end_byte;
int size;
int id;
ALLOCPTR next;
};
FREEPTR freelist = NULL; //
the FREE link list ALLOCPTR alloclist = NULL;//allocating list for memory pointer
the ALLOCATED link list int total_memory_managed = 0; // the amount of memory managed //
//prototypes to define
void *calloc(size_t num_elements, size_t element_size}; //to define the prototypes in memory allocation
int //integer elements that are all initially zero
ip = (int *) calloc(100, sizeof(int));
void dump_freelist(void);
void dump_alloclist(void); //allocating dumb code
void remove_empty_freenodes(void); //removing empty free nodes
void insert_freeblock(FREEPTR fptr);
void merge_freenodes(void); //--- interface ---
void init_memory_manager(const int amount);
int allocate_memory(const int job, const int amount);
void release_memory(const int job);
int total_free(void);
int total_allocated(void);
int largest_free(void);
int job_allocated(const int job);
void report_memory(void); //STUB
void report_jobs(void);
void *realloc( void *ptr, size_t new_size);
int main();
{
int main(void)
{ char ch ; // used to pause between tests
int r;
// results of allocate_memory //
struct S {
S() { std::cout << "S::S()" << std::endl; }
S() { std::cout << "S::~S()" << std::endl; }
};
void f() {
S s1;
S *s2 = new (&s1) S;
// ...
delete s2;
}
" << endl << endl;
init_memory_manager(200);
r = allocate_memory(1,200);
cout << "allocate_memory returns :
" << r << endl << endl; // ALL memory r = allocate_memory(2,30);
cout << "allocate_memory returns : " << r << endl << endl; // over allocate release_memory(1);
// free all memory r = allocate_memory(1,-1);
cout << "allocate_memory returns : " << r << endl << endl; // try allocate -1
r = allocate_memory(3,0);
cout << "allocate_memory returns : " << r << endl << endl;
// allocate 0 r = allocate_memory(1,256);
cout << "allocate_memory returns : " << r << endl << endl;
// over allocate r = allocate_memory(1,100);
cout << "allocate_memory returns : " << r << endl << endl; //Ok allocate 100
cout << "total free memory is : " << total_free() << endl; // 100
cout << "total alloc memory is : " << total_allocated() << endl; // 100 release_memory(1);
//free up memory cout << endl;
cout << "ENTER A CHARACTER ";
cin >>ch; cout << endl; /* //
//deallocation of memory init
void f() {
int *i1, *i2;
try {
i1 = new int;
i2 = new int;
} catch (std::bad_alloc &) {
delete i1;
delete i2;
}
}
" << endl << endl;
init_memory_manager(200);
r = allocate_memory(1,20);
cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(2,30);
cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(1,20);
cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(3,30);
cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(1,20);
cout << "allocate_memory returns : " << r << endl << endl;
cout << "total free memory is : " << total_free() << endl;
cout << "total alloc memory is : " << total_allocated() << endl;
release_memory(1);
//release of memory from allocation
int *i1 = nullptr, *i2 = nullptr;
try {
i1 = new int;
i2 = new int;
} catch (std::bad_alloc &) {
delete i1;
delete i2;
}
}
report_memory();
//report_jobs();
//for testing until reports done *** remove from final *** dump_freelist();
dump_alloclist();
cout << "total free memory is : " << total_free() << endl; // 100
cout << "total alloc memory is : " << total_allocated() << endl; // 100
cout << endl; cout << "ENTER A CHARACTER "; cin >>ch; cout << endl; /
//test between merge of blocks
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
int L[n1], R[n2];
/* Copy data to temp arrays L[] and R[] */
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1+ j];
/* Merge the temp arrays back into arr[l..r]*/ to test the merge of blocks
i = 0; // Initial index of first subarray
j = 0; // Initial index of second subarray
k = l; // Initial index of merged subarray
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
remove.finaldumplist();
}
k++;
}
<< endl << endl;
init_memory_manager(200);
r = allocate_memory(1,25);
cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(2,25); cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(3,25); cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(4,25); cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(5,25); cout << "allocate_memory returns : " << r << endl << endl;
<< endl << endl; cout << "total free memory is : " << total_free() << endl;
// 100 cout << "total alloc memory is : " << total_allocated()
<< endl; // 100 release_memory(1); release_memory(3); release_memory(2);
report_memory();
report_jobs();
//dump_freelist();
//dump_alloclist();
cout << endl;
cout << "ENTER A CHARACTER ";
cin >>ch; cout << endl;
//deallocation in merge
int *p = NULL; //request memory for a variable
p = new int;
pointer-variable = new data-type[size];
init_memory_manager(200);
r = allocate_memory(1,20);
cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(3,20);
cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(1,30);
cout << "allocate_memory returns : " << r << endl << endl; //(A)
r = allocate_memory(4,20);
cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(1,20);
cout << "allocate_memory returns : " << r << endl << endl;
r = allocate_memory(1,20); cout << "allocate_memory returns : " << r << endl << endl; // (B)
cout << "total free memory is : " << total_free() << endl;
cout << "total alloc memory is : " << total_allocated() << endl;
release_memory(1)
cout << " total free memory is : " << total_free() << endl; /
cout << "ENTER A CHARACTER "; cin >>ch;
cout << endl; */
return 0;
}
void release_memory(const int job) {
// Free all memory allocated to process ALLOCPTR a1 = alloclist;
ALLOCPTR temp = NULL;
FREEPTR f1 = NULL;
if (a1 == NULL) return; // empty list // remove all first nodes THIS effects the alloclist pointer !!!!!
while(a1 != NULL && a1->id == job) // {
// set up freenode to be inserted f1 = new FREE_NODE; f1->next = NULL;
f1->start_byte = a1->start_byte;
f1->end_byte = a1->end_byte;
f1->size = a1-> size;
// INSERT f1 into FREELIST insert_freeblock(f1);
f1 = NULL; // just to make sure;
// clean up alloclist alloclist = a1->next; delete a1; a1 = alloclist; }
// all first nodes have been deleted if (alloclist == NULL) return;
// empty list while (a1->next != NULL) { while ((a1->next != NULL) && (a1->next->id == job))
{ // set up freenode to be inserted f1 = new FREE_NODE; f1->next = NULL; f1->start_byte = a1->next->start_byte;
f1->end_byte = a1->next->end_byte; f1->size = a1->next-> size; // INSERT f1 into free list insert_freeblock(f1);
f1 =NULL; // just to make sure // clean up alloclist temp = a1->next ; a1->next = temp->next; delete temp; } if (a1->next != NULL) a1 = a1->next; }
return; } /
//testing functions
class TestALLOCATED LIST DUMP :
public BaseTest
ALLOCPTR tmp = alloclist;,
{
public:
Test(tmp!NULL);
void
apply(const float &l1,
const float &l2,
const float &l3, bool &result)
{
move pointer to next node (or NULL)
}
result =
cout << tmp->id << endl;
tmp = tmp->next;
}
const char *getName() const
{
return "Test results";
}
};
Hope this helps you.All the best