ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllccclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccllccccclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllcccclllclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllcclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllcclclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllcllllllllllllllclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllclllllllllclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllcllllllllllllcllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccllllllcllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllcclllllllllllllllllllcclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllccllllllllllllllllllllllllllllllllllllllllllllllllllllllcccccccccc:cclccclcccllllllllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllllllclllllllllllllllllllllllllllllllllllllllllllllllllcc::;:..,;;ccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcllllllllllllllllllllllllllllllllllllllllllllllllllllllllc,..';::::,;''',,,,;:clllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcccclllllcclllllllllllllllllllllllllllllllllllllllllllllllllll::c:,,,;;;;':::;.':,;:;;,,,;:cllllllllllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllcclcclcllllllllllllllllllllllllllllllllllllllllllllllllllllc:clllll::clc,;,,,,;'..:::::c;':;;::::clllllllllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccclllclllcllllllllllclllllllllllllllllllllllllllllllllllc:clllllllllc::,:;;,,,,.'....,:,,::;''.. .,:;:clllllllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcccclccclcccllclllllllllllllllllllllllllllllllllllllllllllllllccllllllllllllll;;clllll,lll;'.'..',;',,;.,.;,:;'..;::cllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllcccllllllllllllllllllllllllllllllllllllllllllclllllllllllllllllllc::lll;lllc:;,...,;;',' ....;,..',,:;;;;,;cllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcccclcccccccccccccccllllllllllllllllllllllllllllllllllllllllllccllllllllllllllllllllllc::c,:;;::::''. ';:,,.,,;...,''::,:cc,';,,;;;;:clllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccccccccccccccclccclllllllllllllllllllllllllllllllllllllllllcclllllllllllllllllllllllllllc',:lllll,cc;...cl.c;.,;.c:.,;;,,;,,ccc;;:.;:;;;,,,;cllllllcclllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllll::clll;l;''.'';.,;c;;:.;;lcccl;'.,;;;;,.,;:;;;:ccllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccllllllllllllllllllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllc::l';.::c.,, .;,::::.'lllc;;'.,','',:lllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllcclllllllllllllllllllllllllllllllllllllllll; ..,,::...,.;:;,.. ',,,;::cllclllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllllllllllllllllllllllllllllllllllllllcllllllllllllllllllllllllllllllllllllllllllll'',,,;,:' ':.'::'.'clllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcllllllllllllllllllllllllllllllllllllllllllllcllllllllllllllllllllllllllllllllllllllllllllll;c.,;:c:,.;:c'.,;c:clllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccccccclclclclllllllllllllllllllllllllllllllllllllllcllllllllllllllllllllllllllllllllllllllllllllllll,c:..,,:l.cc,';.;c;:lllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcccclccllccclclllllllllllllllllllllllllllllllllllllllllclllllllllllllllllllllllllllllllllllllllllllllllllc:l,'..;;c.;,cc;:';c:lllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllcccccllccccccccllllllllllllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllllllllllllllllc:'.':,.c: .cccllc'';lllllllllllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccccccccccccclcllllllllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllllllllllllllllll;.:cl:lc.;.:.;lllll.'lllllllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllccccccccccccccllllllllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllllllllllllllllllll:,':lcl:c' ;l,;llc,,;lllloolllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllllllllllllllllllllll:l:.;::c:' ;:c;,;;:o;looolllllllllllllllllllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccccccccccccccclllllllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllllllllllllllllllllllll;cc,...,cl.cc:,,.,c:,looooooolllllllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccccccccccccclllllllllllllllllllllllllllllllllllcllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll;cc,'.';:o.:;,:,,',c;looooolooolooooollollllllllllllllllll
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccccccccccccccclllllllllllllllllllllllllllllllllcclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllooo;l,':c;;c, .cl:llc,;;looooooooooooooollollllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllclccllllllllllllllllllllllllllllllllllcllllllllllllllllllllllllllllllllllllllllllllllllllllllloooloooll.',;,',,.' .',;:::;' coooooooooooooooooooolloolooooolooool
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllclllllllllllllllllllllllllllllllllllllllllllllllllllllllolollllcc:. .,.,;lo;' ,',llllc' .:loooooooooooooooooooooooooooooooooo
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllclllllllllllllllllllllllllllllllllllcclllllllllllllllllllllllllllllllllllllllllllllllllllllllool:;,,,;::l''';';,,:. .c;.loo,.'colcclooooooooooooooooooooooooooooooo
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllcclllllllllllllllllllllllllllllllllllllllllllllllll:,',::,,,',,.;:::loo'l'.c';l;, ',;'.:,;l;:oooolcccoooooooooooooooooooooooooooo
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllllllllllllllllllllllllllllllllllcclllllllllllllllllllllllllllllllllllllllllllc;,',',;, . ...',,,;',;,,;'c;..',.cl :l:c..'::'.;ccccc::..:lllllllllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccccccllllllllllllllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllllllll,.'',.'''. ......,,...'.....'..'....... ........'. .oooool;.,:c::ooooooooooooooooooolll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllccccllllllllllllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllllllllll;:lc:';;;'...,';;;,,;.',::;''.. ......c;, ,,cl:cc'',.'';cc,.;..,;;.,::cllllllllllllllllll
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllccccllllllllllllllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllllllllllll,.';..looool'cc:;,;;'.,:llll:c;.,.';.. . ;:;oooc,''lc,...,;cloocccoolcclooooooooooooooo
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllcllllllllllllllllllllllllllllllllllllllllllllllcclllllllllllllllllllllllllllllllllllllllllllllll;..,..clooool,cllooooocc:;''''...;;'...... . .,...'.. ,cc'':';:lococ:oddool::loddooodooooo
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllllllllllllllllllllllllllllllllllllllcclllllllllllllllllllllllllllllllllllllllllllllll:.....;looooool,coooooooooooooooc. ''''.;;.. . ''.,''. ,;,.',':c:',ll:ddolllo:lccloodddddoo
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcccccccclcclclcclllllllllllllllllllllllllllllllllllllllllllllclllllllllllllllllllllllllllllllllollllllllllllc:'.''..coooooooll;coooooooooooooooo,;.,;:c';;. '. ... . ,,..,'. .'....;cloooo:odlc:cloooooo
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcllcllllllcllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllolllollllll,'.....:,looooolooo:;oooooooooooooooo,ol. ',l:., ';cc. ..,'. ..'.',.cc:c.:;..';;,.::,,,;;',,;;;
ccccccccccccccccccccccccccccccccccccccccccccccccccclccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllcllllllllllllllllllllllllllllllllllllloooooooooc:'. ..',cl,loolloooooc,oooooooooooooood'llc. ..,oo :d;..; .c:.;:'..;;;;::,;.::::',,::';:::::,lolcl
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllloooooooooo:c;..;,;ccol,clloooooool,oooooooooooddodd'ol'...';;: .',o;,:'.;,,odccdddolcc;';:;;c:c,,';cccc:'...',
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllloololoooooooooooooooolll::.,':ooool::oooooooooo;looooooooooodddo.:..:cc..o; :o;ldl'. :dd:cdddddddo:dddlccccc'......,;;,c:
cccccccccccccccccccccccccccccccccccccccccccccccccccccccclllccclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllooooooooloooooooooooooooooooooollllcl:;::loollol;oooooooooo;loooooodoooodddl 'lloldd;.. '..ooc..:: ,dd::dddddddl;dddddddddooo;'':oddood
ccccccccccccccccccccccccccccccccccccccccccccccccccclcclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllloooloooooooooooooooooooooooooooooooolllllollocolclooool,ooolllccc:';loooooddddddddl..cloldo;c. .c;.;:oo;..;ddc:dddddddo;dddddddddoccoo:ddooodd
cccccccccccccccccccccccccccccccccccclcllclcccclclccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllolloooooooooooooooooooooooooooooooooooooolllllollooolcocoooooo,;c:cllloooolllllododddddddc'o..clc:o:. .,cc.,:''cc,ddc:dddddddo;ddddddo:.,oddo;ooodddd
ccccccccccccccccccccccccccccccclllllllllcllllcllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllollollollloloooooooooooooooooooooooooooooooooooooooooooolllllolloooooolocoooolc;,cooooooooooooodollllodddd:,dd'..,;.,; 'l:c:..;odl'ddl:oooooooolododo:.;odoooo;odddddd
ccccccccccccccccccccccccclccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllooooooooollooooooooooooooooooooooooooooooooooooooooooooooolllllolloooooooolocooolclcoooooooooooooooodddddollcc''cc,. .,:oc ,d:',,,.cdo.dooodddddddddddoocodddodddo;ddddddd
ccccccccccccccccccccclllclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllloloooooooooooooooooollooooooooooooooooooooooooooooooooooooooooooooooolllllollooooooooooollooococooooooooooooooooodddddddddd,;o,..;.'l;; .,cd:c:c''o.oddddddddddddoldddodddddddd:ddddddo
ccccccccccccccccccclllllllllllllllllllllllllllllllllllllllllllllllolloooollllolllllooolollooooolooooooooooooooooooollooooooooooooooooooooooooooooooooooooooooooooooollllloloooooooooooooololococooooooooooooodddoddddddddddd,;.';l:l;.o: :o;odddc'..ddddddddddooldddddodddddddd;ooooood
llllllllllllllllllllllllllllllllllllllllllllllllllllllloolooloolooooooooolooooooooooolooooooooooooooooooooooooooollooooooooooooooooooooooooooooooooooooooooooooooollllloloooooooooooooooooll:llloooooddodddodddddddddddddddd..lololddl.. '..odddddd' oddddddoodddddddddoodddddoooddddddd
llllllllllllllllllllllllllllllllllllllllllllllllllllloooooooooooooooooooooooooooooooooooooooooooooooooooooooooollooooooooooooooooooooooooooooooooooooooooooooooololllolooooooooooooooooooooloooodddddddddddddddddddddddddddo..'oloodo:l. .l:.cdddl'..oddddooddddddddddddooddoodddddddddd
llllllllllllllllllllllllllllllllllllllllllllllllllllooooooooooooooooooooooooooooooooooooooooooooooooooooooooollooooooooooooooooooooooooooooooooooooooooooooooololloolooooooooooooddoddoddddddddddddddddddddddddddddddddddood.o;.,loc:o;. .ldo.,o,.'o'ldooddddddddddddddddddddddddddddddd
lllllllllllllllllllllllllllllllllllllllllllllllllooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooollooloooooooooooddddddddddddddddddddddddddddddddddddddddoodddd.ddc .'c;'cl ,l:lo. ':dd,cddddddxxdddddddddddddddddddddddddd
lllllllllllllllllllllllllllllllllllllllllllolloooolooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooollooooooodododddddddddddddddddddddddddddddddddddddddddddoodddddd.dxo;...'dxo ,xd,.,,.;dd;:xxxxxxxxxxdddddddddddddddddddddddd
lllllllllllllllllllllllllllllllllllllllllllooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooolloooooooddddddddddddddddddddddddddddddddddddddddddddddoodddddxxxo.xd;..,.c::l ,;.co,;:..d::xxxxxxxxxxxxxddddddddddddddddddddd
lllllllllllllllllllllllllllllllllllllllllloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodooooooooooooooooooooolloooooooddddddddddddddddddddddddddddddddddddddddddddddoodddddxxxxxl'o..,cl:.:o, :dc:dxoc'.';xxxxxxxxxxxxdddddddddddddddddddddd
lllllllllllllllllllllllllllllllllllllllolooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodddddddooooooodoooooloooooodddddddddddddddddddddddddddddddddddddddddddddddooddddddxxxxxxxc..cooldxd.', ..,lxxxxxo; .dxxxxxxxxxxxxddddddddddddddddddddd
llllllllllllllllllllllllllllllllllllooolooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodddoddoodddddddddddddddddddooooloooooddddddddddddddddddddddddddddddddddddddddddddddddodddddddddxxxxxxx; :xoolxxxc'. .;.;xxxxxxc..dxxxxxxxxxdddddddddddddddddddddddd
llllllllllllllllllllllllllllllooloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddddddddddddddddddddddddddddddddooollooooddddddddddddddddddddddddddddddddddddddddddddddddooddddddddddddxxxxxd;;,':olxo:ld' 'xx;'oxxl'.c.xxxxxxxxdddddddddddddddddddddddddd
lllllllllllllllllllllllollolloooloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodoooddoooddddddddddddddddddddddddddddddooolloooodddddddddddddddddddddddddddddddddddddddddddddddoooddddddddddddddxddxxx,cdc.'cc:o;., .;ldl.;,,;dd.dxxxxxxddxdddddddddddddddddddddddd
llllllllllllllllllllloollooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddddoddddddddddddddddddddddddddddooolloooddddddddddddddddddddddddddddddddddddddddddddddddoodddddddddddddddxxxxxxxx':lo:...''ldl ,xo;;...,lll.dxxxxxxxxxxxdddddddddddddddddddddd
lllllllllllllllllllllllooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooododoooddddddddddddddddddddddddddoooloooodddddddddddddddddddddddddddddddddddddddddddddddooddddddddddddddddxxxxxxxxxd.:oo:,. ,:dxl ,xo'',.'.;lc.oxxxxxxxxxxxxxxxdddddddddddddddddd
lllllllllllllllllloolooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddoddddddddddddddddddddddddoooloooodddddddddddddddddddddddddddddddddddddddddddddddoodddddddddddddddxxdxxxxxxdddd.cx:...,.:c,: .';ol:':c',d lxxxxxxxxxxxxxxxxxdddddxxxddddddxx
llllllllllllllllllooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddoooooooodddddodddddddddddddddddddoooolooodddddddddddddddddddddddddddddddddddddddddddddddooddddddddddddddddddxxdxxxddddxxd c''cd,lo.,c. :l:cx,do:'. cxxxxxxxxxxxxxxxxxxxdxxxxxxxxdxxxx
lllllllllllllloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddooooooooddooddddddddddddddddddddddooccloooddddddddddddddddddddddddddddddddddddddddddddddooddddddddddddddddddddxxxxxddddxxxxc .:l:c,:;;,.. ..,llc;ccc:. ,dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
llllllollllloolloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddddddddddddddddddddddddooolccloddddddddddddddddddddddddddddddddddddddddddddddooddddddddddddddddddddxxxxddddxxxolll' .c;''.;ll:;. .:.,locoool' .:loxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
llllllloollloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddddddddddddddddddddddoooloooodddddddddddddddddddddddddddddddddddddddddddddooddddddddddddddddddddxxxxddddxdlllloxxo:.;.cl::,o:ll. .;oc.oxxd:.';;xxdllldxxxxxxxxxxxxxxxxxxxxxxxxxx
llloooooooollloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodddddddddddddddddddoooloooddddddddddddddddddddddddddddddddddddddddddddddodddddddddddddddddddddxxxddddolllc,:l:;c;;:'xd..;l:'l;,: .,,:;.;:,,cxc,xxxxxxolloxxxxxxxxxxxxxxxxxxxxxxx
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodddddddddddddddddddooooooodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddxdocc,..':cc:,c:oxxlx;'oxx;..:;':xo ,xo:;....cooc'xxxxxxxxxdllldxxxxxxxxxxxxxxxxxxx
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddddddddddddddddddoooloooodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddolccc,:,',,;: .. ...',':,';..',;,...;llcl ,xx:,;,;..';;.oododc,clccc:..codddddddddddddddd
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddddddddddddddddddddddoooooooodddddddddddddddddddddddddddddddddddddddddddoddddddddddddddddddd;.;,;'' ...... ',,.';c,cc:,..;.... .... ....''..'. c .'::;.':lccl:l;dolccodddddddddddd
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodddddddddddddddddddddddoooooooddddddddddddddddddddddddddddddddddddddddddddoddddddddddddddddddddd::lc;.lddolc::,.',;:;;c,ccccc.'.,;..,:',' .. 'c:;odo;. ...:;.,,..'coo:ld;ddddoccccddddddddd
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodooddddddddddddddddddddoooooooodddddddddddddddddddddddddddddddddddddddddddooddddddddddddddddddddddo' .;.'dddxxxxxd::dddoc:,;,.',, .;lc,, .. .,,....',. ,:;'oc;,ll;oxx:xxxxdooccllldxxxxx
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddoodddoddddddddddddddddddooooooooddddddddddddddddddddddddddddddddddddddddddoodddddddddddddddddddddddo,.....cddddxxxxxxl;dxxxxxxxxxxxd; ,,'.'.:;,'. ....,:',,,,. .,,:,,,...';lo:xdoodxxolxxxolloxx
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodddodddddoddddddddddddddddddlooodooddddddddddddddddddddddddddddddddddddddddddoodddddddddddddddddddddddcc. '. ,ddddxxxxxxxxo;dxxxxxxxxxxxxx...xxccc,o:.. c; ...;co;. .;:,. ... .:dxxxxdcxxxxdl;,o
Django signal optimization diagram Introduction# When dealing with financial transactions in Django applications, maintaining an accurate ledger is critical. However, inefficient signal handling can lead to performance bottlenecks. In this article, we’ll explore an optimized approach to recalculating ledger balances while ensuring minimal database impact.
The Problem# A typical ledger system requires recalculating balances when transactions are inserted, updated, or deleted. Using Django signals, many implementations trigger redundant recalculations, causing excessive database queries and slowing down the application.
Common Issues with Signals:# Unnecessary Queries : Each save or delete operation triggers a recalculation, even if no meaningful change occurs.Cascade Effects : Bulk operations lead to multiple redundant recalculations.Performance Overhead : Large transaction volumes cause significant slowdowns.Optimized Approach# To address these inefficiencies, we introduce a flag-based recalculation strategy that minimizes unnecessary database interactions.
Step 1: Adding a Recalculation Flag# Instead of recalculating every time a transaction is saved, we introduce a _needs_recalc flag:
from django.db import models
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
class Transaction (models. Model):
amount = models. DecimalField(max_digits= 10 , decimal_places= 2 )
ledger = models. ForeignKey('Ledger' , on_delete= models. CASCADE)
def save (self, * args, ** kwargs):
self. ledger. _needs_recalc = True
super(). save(* args, ** kwargs)
@receiver (post_delete, sender= Transaction)
def mark_ledger_for_recalc (sender, instance, ** kwargs):
instance. ledger. _needs_recalc = True
Step 2: Efficient Ledger Recalculation# Recalculating balances should only occur when necessary, ideally after all related operations are complete:
from django.db import transaction
def recalculate_ledger_balances ():
ledgers_to_update = Ledger. objects. filter(_needs_recalc= True )
for ledger in ledgers_to_update:
ledger. recalculate_balance()
ledger. _needs_recalc = False
ledger. save(update_fields= ['balance' ])
Step 3: Using Post-Transaction Hooks# Using Django’s on_commit() ensures recalculations only happen after successful transactions:
from django.db.transaction import on_commit
@receiver (post_save, sender= Transaction)
def trigger_ledger_recalc (sender, instance, ** kwargs):
on_commit(lambda : recalculate_ledger_balances())
With this approach, we achieve:
Reduced Queries : Recalculation happens once per affected ledger, not per transaction.Better Scalability : Batch updates improve efficiency.Consistent Data : Using on_commit() ensures recalculations only happen after successful writes.Conclusion# By intelligently managing recalculations, we significantly improve the performance of our ledger system in Django applications. This approach ensures efficiency without sacrificing data accuracy, making it ideal for high-volume financial applications.